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
fix(lint): flow template rules reach a {record.FIELD} token outside a node filter (#16407)
* fix(lint): flow template rules reach a {record.FIELD} token outside a node filter
`flow-template-unknown-field` and `flow-template-lookup-traversal` each declare
a per-position severity — `error` inside a filter-guarded CRUD node's `filter`,
`warning` everywhere else — and the `warning` half never fired on the shape a
real hand-off flow has.
The cause is one key, and it is in the shared flow walk rather than in either
rule. `WalkedFlowNode.localConfig` is the region-stripped view a recursive
config scan must read or it reports every nested finding a second time against
the container; it was built by removing every key that holds a region on ANY
node type. `body` is `loop`'s region slot AND the canonical request-payload key
on an `http` node, so `config.body` was deleted from every node's view before
any rule saw it — and the http executor interpolates its raw config wholesale,
so a `{record.<typo>}` there renders an empty value into an outbound request on
every run.
`stripRegions` now takes the keys to remove; `walkFlowNodes` passes the slots
the node's own type declares, the same lookup that decides where the walk
descends. Nothing is double-reported and nothing that was never a region is
dropped. The flat-union view stays the default argument so the helper's other
caller keeps the behaviour it was written against.
Tests: the four measured injections as four pins on one hand-off fixture — the
two filter positions as negative controls that must stay `error`, the two
payload positions as the `warning` half — plus the both-positions dedupe, a
clean flow, and a payload nested in a loop body reported once on the node that
carries it. Every assertion reads the findings array; `warning` does not move
the exit code.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
* docs(changeset): state where the silent half was silent, at both ends
The clause read "at authoring time and at run time alike" against "renders as
an empty string", which puts the rendering at authoring time. The rendering is
a run-time event; what happens at BOTH ends is that nothing reports it — no
build-time finding, no run-time error — which is the property that makes the
failure survive to production.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
* docs(lint): name the sibling call site the union default still traps
The note read as if the flat-union default were correct for the caller that
still takes it. It is not: `lint-flow-patterns.ts` runs its own recursive
template scan over the union view, so it is blind to an `http` node's `body`
for exactly the reason this function's own doc gives one paragraph earlier —
the same defect, one call site over. The default is scope control for this
change, not a verdict, and the note now says which.
Also states the endgame, so the next reader does not have to rediscover it:
once that caller passes its own slots, `regionKeys` has no default-takers left
and must become required, or the shorter call keeps handing out the trap.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vbw3RPgdtqesx4azk9SbW8
---------
Co-authored-by: Claude <noreply@anthropic.com>
`flow-template-unknown-field` and `flow-template-lookup-traversal` now reach a `{record.<field>}` template that sits outside a node filter — the `warning` half both rules already declared, and never emitted.
6
+
7
+
A `{record.<field>}` token in a filter has always been reported as an `error`: an unresolved token there erases the condition and the CRUD node refuses to run. A token anywhere else — a message body, an http request payload, a created row's field values — is the quiet failure the rules were written for: it renders as an empty string on every run, and nothing reports it at either end — no build-time finding, no run-time error — so a hand-off payload naming a renamed field ships an empty value and the run is recorded as a success. That half was silent.
8
+
9
+
The cause was one key, in the shared flow walk rather than in either rule. A rule that scans a node's config recursively has to read a view of it with the nested regions removed, or it reports every finding inside a `loop` / `try_catch` / `parallel` a second time against the container. That view was built by removing every key that holds a region on *any* node type — and `body` is `loop`'s region slot **and** the canonical request-payload key on an `http` node. So `config.body` was deleted from every node's view before any rule read it, and the whole of an http payload was invisible. The view now removes only the slots the node's own type declares, which is exactly the set the walk descended into: nothing is double-reported, and nothing that was never a region is dropped.
10
+
11
+
Expect new `warning` findings on flows that publish clean today. Each one names a token that renders empty at run time; `warning` does not change `os validate`'s exit code, so a build that passed still passes.
0 commit comments