Found while implementing #15230 (the runRegion tagger half of #14414). Filed unassigned; domain:*, type and priority are triage's.
What is missing
examples/app-showcase declares each ADR-0031 structured construct as its own top-level flow and nests none of them in another:
git grep -n "type: 'loop'" -- examples/ apps/
examples/app-showcase/src/automation/flows/index.ts:868 (BatchRemindersFlow, body = one notify node)
examples/app-todo/src/flows/task.flow.ts:29
examples/app-todo/src/flows/task.flow.ts:83
The per-node-type map the checklist already records says the same thing explicitly — automation.flow-node-type-matrix, fixtures.requires:
loop=showcase_batch_reminders · parallel+http=showcase_fan_out_notify · try_catch=showcase_resilient_sync
Three separate flows. showcase_batch_reminders loops a single notify; showcase_fan_out_notify fans out at top level; ProjectEscalationFlow composes decision with parallel and try_catch but sits under no loop.
Why it blocks something concrete
PR for #15230 adds a loop { parallel } acceptance clause to automation.flow-run-step-nesting (item revision 3). That clause exists because the maintainer ruling of 2026-09-03 made iteration single-valued and gave the parallel branch index its own branch key, and a step inside a parallel branch that is itself inside a loop body is the only shape where both index keys are populated on one record. A run of that clause today scores blocked(fixture): there is no flow to trigger.
The clause was written anyway rather than deferred — an absent clause is exactly what let the iteration overload sit unmeasured — and the item's fixtures.requires records the gap in the open. This card is the other half.
What would close it
A showcase flow whose loop body holds a two-branch parallel, exported and added to the flow list in examples/app-showcase/src/automation/flows/index.ts, with at least two rows so the clause's (iteration, branch) pair check has something to distinguish. No gate script enumerates showcase flows by path, so the cost looks like the defineFlow plus its array entry.
Worth deciding as part of it: whether the nested-composition gap is wider than this one clause. loop { try_catch } is documented as the per-iteration containment spelling (#13681, #14394) and is the shape #14456 taught the engine to attribute to a row, and showcase demonstrates that nesting nowhere either — so a reader of the examples app cannot see the containment spelling the docs recommend.
Refs: #15230 (the engine change that makes the clause writable) · #14414 / PR #15227 (the contract half) · #14622 (the neighbouring observation that showcase_batch_reminders loops a fallible node with no containment) — none of those is addressed here.
Found while implementing #15230 (the
runRegiontagger half of #14414). Filed unassigned;domain:*, type and priority are triage's.What is missing
examples/app-showcasedeclares each ADR-0031 structured construct as its own top-level flow and nests none of them in another:The per-node-type map the checklist already records says the same thing explicitly —
automation.flow-node-type-matrix,fixtures.requires:Three separate flows.
showcase_batch_remindersloops a singlenotify;showcase_fan_out_notifyfans out at top level;ProjectEscalationFlowcomposesdecisionwithparallelandtry_catchbut sits under no loop.Why it blocks something concrete
PR for #15230 adds a
loop { parallel }acceptance clause toautomation.flow-run-step-nesting(item revision 3). That clause exists because the maintainer ruling of 2026-09-03 madeiterationsingle-valued and gave the parallel branch index its ownbranchkey, and a step inside a parallel branch that is itself inside a loop body is the only shape where both index keys are populated on one record. A run of that clause today scoresblocked(fixture): there is no flow to trigger.The clause was written anyway rather than deferred — an absent clause is exactly what let the
iterationoverload sit unmeasured — and the item'sfixtures.requiresrecords the gap in the open. This card is the other half.What would close it
A showcase flow whose
loopbody holds a two-branchparallel, exported and added to the flow list inexamples/app-showcase/src/automation/flows/index.ts, with at least two rows so the clause's(iteration, branch)pair check has something to distinguish. No gate script enumerates showcase flows by path, so the cost looks like thedefineFlowplus its array entry.Worth deciding as part of it: whether the nested-composition gap is wider than this one clause.
loop { try_catch }is documented as the per-iteration containment spelling (#13681, #14394) and is the shape #14456 taught the engine to attribute to a row, and showcase demonstrates that nesting nowhere either — so a reader of the examples app cannot see the containment spelling the docs recommend.Refs: #15230 (the engine change that makes the clause writable) · #14414 / PR #15227 (the contract half) · #14622 (the neighbouring observation that
showcase_batch_remindersloops a fallible node with no containment) — none of those is addressed here.