Found while implementing #8796 (the resume body's outer envelope became a closed key set). Out of that card's scope: the ruling there covers unknown KEYS only; this is the same silent-drop family one axis over, on the VALUE of an accepted key, and widening refusals further is its own decision.
Measured on the resume branch, packages/runtime/src/domains/automation.ts
The signal assembly (deliberately field-by-field, per #3801) type-guards each accepted key and silently skips a value that fails the guard:
constinputs=(b.inputs??b.variables);if(inputs&&typeofinputs==='object')signal.variables=inputs;if(b.output&&typeofb.output==='object')signal.output=b.output;if(typeofb.branchLabel==='string')signal.branchLabel=b.branchLabel;
So after #8796's closed set lands, POST .../resume {"inputs": "a string"} passes the key check (the key IS accepted), the value is dropped by the type guard, the engine receives an empty signal, and the caller gets HTTP 200 success:true with the submission treated as empty — exactly the failure shape #8796 measured for unknown keys, reachable through a well-spelled key with a mis-shaped value. Same for {"output": 42} and {"branchLabel": 7}. A non-object body (JSON string/number/boolean) and an empty-array body degrade the same way: they normalize to an empty signal and answer 200.
The decision this needs
Option A is the shape the sibling arms already chose; filed rather than fixed because it widens refusals on an accepted public surface beyond the #8796 ruling's text.
Refs
Generated by Claude Code
Found while implementing #8796 (the resume body's outer envelope became a closed key set). Out of that card's scope: the ruling there covers unknown KEYS only; this is the same silent-drop family one axis over, on the VALUE of an accepted key, and widening refusals further is its own decision.
Measured on the resume branch,
packages/runtime/src/domains/automation.tsThe signal assembly (deliberately field-by-field, per #3801) type-guards each accepted key and silently skips a value that fails the guard:
So after #8796's closed set lands,
POST .../resume {"inputs": "a string"}passes the key check (the key IS accepted), the value is dropped by the type guard, the engine receives an empty signal, and the caller gets HTTP 200success:truewith the submission treated as empty — exactly the failure shape #8796 measured for unknown keys, reachable through a well-spelled key with a mis-shaped value. Same for{"output": 42}and{"branchLabel": 7}. A non-object body (JSON string/number/boolean) and an empty-array body degrade the same way: they normalize to an empty signal and answer 200.The decision this needs
enabled(a truthy non-boolean is refused there, not coerced or dropped).variables/outputas objects, so this hands a service a shape its contract excludes (the same class finding:GET /api/v1/automation/:name/runs?limit=abccoerces to NaN and reacheslistRuns({ limit: NaN })— the same unvalidated query coercion #6928 fixed on the notifications route #7300 closed for?limit=abconlistRuns).Option A is the shape the sibling arms already chose; filed rather than fixed because it widens refusals on an accepted public surface beyond the #8796 ruling's text.
Refs
enabledis refused, not droppedGenerated by Claude Code