You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(automation): surface silently-stripped write fields as step warnings (#3407)
update_record reported an unconditional success even when the data layer
legally stripped the requested write fields (static readonly #2948,
conditional readonlyWhen #3042) — the only trace was a server-side logger
warn, invisible in the flow run trace, which is how #3356's approval stage
write-backs failed behind a clean 3ms success.
- spec: new DroppedFieldsEventSchema ({object, fields, reason}) in
data/data-engine.zod.ts (Zod-first, JSON-representable, published to the
schema manifest) + a WriteObservabilityOptions mixin (onFieldsDropped
listener) on IDataEngine.insert/update option params in
contracts/data-engine.ts. The listener is TS-contract-level and
in-process only — a function is unrepresentable in JSON Schema and never
crosses the RPC boundary. Core's mirror contract kept in sync.
- objectql: engine.update() reports each strip pass's dropped keys +
reason through options.onFieldsDropped at all four strip sites
(single-id + bulk x readonly + readonly_when), diffing before/after key
sets (exact: strips return the same reference when nothing dropped). A
throwing listener never breaks the write. System-context writes skip the
readonly strip and report nothing, as before. insert() accepts the
option for signature symmetry but strips nothing today (INSERT is
readonly-exempt; FLS write denial throws).
- service-automation: NodeExecutionResult and StepLogEntry gain advisory
warnings?: string[] (persisted through run history; success semantics
unchanged). update_record / create_record attach one warning per strip
event naming the dropped fields and expose a structured droppedFields
output ({<nodeId>.droppedFields}) for downstream nodes.
Design per issue #3407 direction 1 (engine structured feedback) — chosen
over run-scoped logger routing (direction 3): shallower intrusion, and the
node gets a structured field list instead of log text. FLS is not wired:
its write gate now throws (fail-closed) instead of stripping, so it is no
longer a silent-drop case.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HaofCZbsPTHE2oJedvKd77
0 commit comments