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
#4027 described two hand-written lists nobody reconciled: a node type's designer configSchema, and what the rest of the platform does with the keys it declares. #4040 built a ledger + ratchet for the expression slots — every xExpression property a builtin declares is now validated and cannot silently go unchecked again.
The other half is untouched. A configSchema is written by hand next to an executor that reads config by hand, and nothing compares them. A property can be:
declared but never read — an author fills in a Studio field that does nothing (the visibleWhen shape, now covered for expressions only);
read but never declared — the executor honours a key the designer never offers, so it is reachable only by hand-authored metadata.
Its configSchema declares recipients, title, message, channels, topic, severity, sourceObject, sourceId, actorId, actionUrl, payload — no source. So:
An author using Studio's generated form can never set the nested shape.
Metadata that does carry source works at run time, with no schema describing it and no test pinning it.
The cfg.sourceObject ?? src?.object line is a consumer-side fallback of exactly the kind Prime Directive Add comprehensive test suite for Zod schema validation #12 calls debt — a second de-facto contract next to the declared one. If source is legacy, it belongs in the ADR-0087 D2 conversion layer (like flow-node-notify-config-aliases already does for to/subject/body/url) so it is declared, tested and removable on a schedule. If it is current, it belongs in the configSchema.
Either way the current state is the one #4027 was filed about: two lists, no reconciliation, drift invisible until someone trips on it.
Scope caveat — this is one instance, not an audit
I only checked the four executors whose config reads were easy to enumerate (crud, screen, notify, http) while working on #4040. notify.source is what that turned up; crud and http looked consistent, and I did not check connector_action, loop, map, parallel, try_catch, subflow, wait or script. The remaining node types have the same structure, so more drift is likely.
Two non-findings worth recording so nobody re-chases them: config.expand appears in crud-nodes.ts only inside an error-message string (it is a start-node key, and start is structural with no descriptor), and update_record / delete_record neither declare nor read outputVariable — consistent, not drift.
Proposed
Decide notify.source — conversion-layer alias, or declared property. Not something to guess at; it changes the designer form.
A declared-vs-read ratchet. Harder than the expression one, because "what the executor reads" is not machine-readable today. Options, roughly in increasing cost:
static analysis of cfg.<key> / destructuring in each executor (fragile against indirection, but zero maintenance);
derive the configSchemafrom a Zod schema the executor itself parses config with, so the two cannot diverge by construction. Most correct, most invasive, and the only option that also gets the runtime the type/required/unknown-key enforcement configSchema currently does not provide (see the corrected TSDoc in fix(automation,lint,spec): validate the expression slots a node's configSchema declares (#4027) #4040).
Whichever is chosen, log/report what is deliberately designer-only or read-only, rather than leaving the exemption implicit.
Follow-up to #4027, which closed only the expression subset of that gap (#4040).
What #4040 fixed, and what it didn't
#4027 described two hand-written lists nobody reconciled: a node type's designer
configSchema, and what the rest of the platform does with the keys it declares. #4040 built a ledger + ratchet for the expression slots — everyxExpressionproperty a builtin declares is now validated and cannot silently go unchecked again.The other half is untouched. A
configSchemais written by hand next to an executor that readsconfigby hand, and nothing compares them. A property can be:visibleWhenshape, now covered for expressions only);The concrete instance found while doing #4040
notify's executor readscfg.sourceas a nested{ object, id }shape:Its
configSchemadeclaresrecipients, title, message, channels, topic, severity, sourceObject, sourceId, actorId, actionUrl, payload— nosource. So:sourceworks at run time, with no schema describing it and no test pinning it.cfg.sourceObject ?? src?.objectline is a consumer-side fallback of exactly the kind Prime Directive Add comprehensive test suite for Zod schema validation #12 calls debt — a second de-facto contract next to the declared one. Ifsourceis legacy, it belongs in the ADR-0087 D2 conversion layer (likeflow-node-notify-config-aliasesalready does forto/subject/body/url) so it is declared, tested and removable on a schedule. If it is current, it belongs in theconfigSchema.Either way the current state is the one #4027 was filed about: two lists, no reconciliation, drift invisible until someone trips on it.
Scope caveat — this is one instance, not an audit
I only checked the four executors whose config reads were easy to enumerate (
crud,screen,notify,http) while working on #4040.notify.sourceis what that turned up;crudandhttplooked consistent, and I did not checkconnector_action,loop,map,parallel,try_catch,subflow,waitorscript. The remaining node types have the same structure, so more drift is likely.Two non-findings worth recording so nobody re-chases them:
config.expandappears incrud-nodes.tsonly inside an error-message string (it is a start-node key, andstartis structural with no descriptor), andupdate_record/delete_recordneither declare nor readoutputVariable— consistent, not drift.Proposed
notify.source— conversion-layer alias, or declared property. Not something to guess at; it changes the designer form.configSchema(hand-maintained, but the ratchet keeps it honest — same shape as fix(automation,lint,spec): validate the expression slots a node'sconfigSchemadeclares (#4027) #4040 and feat(runtime): route ledger + conformance guard for the dispatcher↔client surface (#3563) #3569);cfg.<key>/ destructuring in each executor (fragile against indirection, but zero maintenance);configSchemafrom a Zod schema the executor itself parsesconfigwith, so the two cannot diverge by construction. Most correct, most invasive, and the only option that also gets the runtime the type/required/unknown-key enforcementconfigSchemacurrently does not provide (see the corrected TSDoc in fix(automation,lint,spec): validate the expression slots a node'sconfigSchemadeclares (#4027) #4040).log/report what is deliberately designer-only or read-only, rather than leaving the exemption implicit.Related
configSchemaand the executor's wire payload are two unchecked lists — nothing validates flow node config keys at author time #4027 / fix(automation,lint,spec): validate the expression slots a node'sconfigSchemadeclares (#4027) #4040 — the expression subset, closed