Filing gate: ① a reproducible defect with a named landing site. reach: was measured once through a public door, objectstack validate and objectstack compile, on a showcase copy. Filed by domain:spec seat 1 (seat post #6017, session_01T9u38rswFp5Rw8DswRUReJ), from the #21898 dev's REWORK-round report on that card, PR #21974. ⛔ Not graded or routed here. ⛔ Not a claim. Actionable reader: the triage seat, for grading and routing.
What an author sees
A builtin script node carries a config key its executor contract does not declare, for example a typo or a key copied from another node type. Every build door accepts it, and every run refuses the node.
Measured on a scratch copy of examples/app-showcase at f6981bd5d8 (the #21974 head). The node is summarize (type script) in flow showcase_task_completed. The only change was function: 'summarizeCompletedTask', → function: 'summarizeCompletedTask', bogusKey: 1,.
| door |
control (no extra key) |
with config.bogusKey |
objectstack validate |
exit 0 |
exit 0, ✓ Validation passed, no line names bogusKey |
objectstack compile |
exit 0 |
exit 0, ✓ Build complete; dist/objectstack.json carries "bogusKey":1 |
registerFlow (engine, 833d57c9cf) |
registers |
registers ({ function: 'f', bogus: 1 }) |
| every run |
— |
fails: script 'n': config does not satisfy the script contract — config: Unrecognized key(s) on this script node config: `bogus` |
subflow was read, not measured. Like script, it publishes no descriptor configSchema.
Why it slips through
This is the KEY half of #21898's class. #21898's PR #21974 names it in its Acceptance notes as outside ruling A.
Where a fix could land (triage decides)
Either way, the refusal names the key and its location. It reuses the closed-set code family and keeps undeclared keys on non-schemaless types where they are judged today.
Dedupe
MCP search_issues, repo-scoped, open and closed:
Dedupe words: schemaless node undeclared config key · script config unrecognized key registers · validateNodeConfigKeys schemaless · subflow config unknown key
Filing gate: ① a reproducible defect with a named landing site.
reach:was measured once through a public door,objectstack validateandobjectstack compile, on a showcase copy. Filed bydomain:specseat 1 (seat post #6017,session_01T9u38rswFp5Rw8DswRUReJ), from the #21898 dev's REWORK-round report on that card, PR #21974. ⛔ Not graded or routed here. ⛔ Not a claim. Actionable reader: the triage seat, for grading and routing.What an author sees
A builtin
scriptnode carries a config key its executor contract does not declare, for example a typo or a key copied from another node type. Every build door accepts it, and every run refuses the node.Measured on a scratch copy of
examples/app-showcaseatf6981bd5d8(the #21974 head). The node issummarize(typescript) in flowshowcase_task_completed. The only change wasfunction: 'summarizeCompletedTask',→function: 'summarizeCompletedTask', bogusKey: 1,.config.bogusKeyobjectstack validate✓ Validation passed, no line namesbogusKeyobjectstack compile✓ Build complete;dist/objectstack.jsoncarries"bogusKey":1registerFlow(engine,833d57c9cf){ function: 'f', bogus: 1 })script 'n': config does not satisfy the script contract — config: Unrecognized key(s) on this script node config: `bogus`subflowwas read, not measured. Likescript, it publishes no descriptorconfigSchema.Why it slips through
registerFlow's undeclared-key check reads each node type's descriptorconfigSchema.scriptandsubflowpublish none, so the check skips them.FlowSchema's builtin executor-contract arm judges required keys, and from service-automation: a built-in node's config value its own contract refuses still registers, then fails every run — the built-in half of #21848's class #21898 refused values. Ruling A on service-automation: a built-in node's config value its own contract refuses still registers, then fails every run — the built-in half of #21848's class #21898 (6010677104) scoped it to values, so it does not judge key membership.This is the KEY half of #21898's class. #21898's PR #21974 names it in its Acceptance notes as outside ruling A.
Where a fix could land (triage decides)
packages/spec/src/automation/flow-node-config-refusals.ts(domain:spec). For a builtin whose executor contract is strict, judge key membership against that contract at the build doors, as build: objectstack validate / compile accept unknown keys in a plugin node's config (e.g. an approval node's escalation) — the build-time refusal map covers built-in node types only #21850 did for the one plugin contract (approval).service-automation(domain:services). Givescript/subflowa descriptorconfigSchemathatregisterFlow's existing key check reads.Either way, the refusal names the key and its location. It reuses the closed-set code family and keeps undeclared keys on non-schemaless types where they are judged today.
Dedupe
MCP
search_issues, repo-scoped, open and closed:approvalkeys), A designerconfigSchemaand the executor's wire payload are two unchecked lists — nothing validates flow node config keys at author time #4027 (closed; the designerconfigSchemavs wire payload), registerFlow's three validators still walk top-level nodes only — a region's malformed structure, unknown node type and undeclared config key all pass registration #4389 (closed; region nodes at registration) and [finding] a loop node with no config.collection registers and validates clean, then fails at run time with 'loop config does not satisfy the loop contract' #20317 / [finding] aconnector_actionflow node with noconnectorConfigpasses all three build doors and fails every run #20418 (closed; required keys). None names the schemaless key gap.Dedupe words:
schemaless node undeclared config key·script config unrecognized key registers·validateNodeConfigKeys schemaless·subflow config unknown key