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
{{ message }}
Repository navigation
flows: lint a loop body with a fallible node and no containment, and a try_catch without catch; document loop { try_catch } as the per-iteration containment spelling (B-branch items 1–2 of #13681) #14394
Part of #13681 — the B-branch's lint and docs limbs, filed into the domain:devx queue by the domain:spec seat (session session_01GDA48PuRFrHyRfdkBz8m21) under the cross-seat path the retriage comment on that card prescribes (comment 5479171811: the lint limb is handed to its lane by a proper card, never privately). The visibility half (item 3, the run-summary contract) stays on #13681 and is in flight in the spec lane; this card does not depend on it — the lint rules and the docs spelling are authoring-time facts measured on origin/main today.
Reader: the domain:devx execution seat, at its next selection pass (this card is a plain pm:queue candidate; triage adds domain:* and type).
Ruling of record (do not re-decide)
Maintainer 2026-08-31, director decision batch #18, verbatim 「其他同意」 on the conditional ruling (issue comment 5478768627); branch selected by measurement (comment 5478879587): B — no new key (⛔ no loop.config.onIterationError), because loop { body: [ try_catch { try, catch } ] } measured as real per-iteration containment on the real AutomationEngine (5 elements, third fails, 5/5 iterations, elements 4–5 processed, run completes; measurement comment 5478851960).
Deliverables (from comment 5478879587 §B, items 1–2, and the retriage's three standing prohibitions in comment 5479171811)
Lint rule A — loop without containment: a loop whose body region contains a fallible node (any node that can return success: false or throw — at minimum every builtin action node, notify, connector_action, record writes) and no try_catch enclosing it ⇒ an authoring-time warning that names the loop node, the fallible node, and the prescribed spelling. Lands in packages/lint under the flow lint family.
Lint rule B — the near-miss shape, first target not an extra: a try_catch node whose catch region is absent gives zero containment and dies exactly like an unwrapped node (measured). Name it at authoring time; the fix text is the minimal catch spelling below.
Docs: write loop { try_catch { … } } into the flow docs as the orthography for per-iteration containment, carrying the measured minimal catch spelling verbatim (do not re-derive): catch cannot be empty — the region's nodes is .min(1), so catch: {} and catch: { nodes: [] } are both refused; the shortest usable catch is one bare assignment node with no config; edges may be omitted; errorVariable may be omitted.
Both lint rules ship with the positive control (a fixture that trips each rule) and the negative control (the documented spelling passes clean), and the docs example must type-check under check:skill-examples / check:yaml-examples where applicable.
Acceptance (executable)
pnpm --filter @objectstack/lint exec vitest run <the flow-lint test file> shows: the unwrapped-loop fixture → warning naming the loop and the node; the try_catch-without-catch fixture → warning; the documented loop { try_catch { try, catch: [assignment] } } fixture → no finding.
content/docs/automation/flows.mdx (or the page the devx seat judges canonical) documents the spelling with the minimal catch form above, and the example parses under FlowSchema.
File surface:packages/lint/src/lint-flow-patterns.ts (the two new rules + their FLOW_* rule-id constants, in the flow anti-pattern family), packages/lint/src/lint-flow-patterns.test.ts (positive + negative controls for both rules), packages/lint/src/index.ts (the two new rule-id constants on the barrel's existing FLOW_* export block only), content/docs/automation/flows.mdx (§"Structured control flow (ADR-0031)" — the loop { try_catch { … } } per-iteration containment spelling with the measured minimal catch verbatim), .changeset/*.md (@objectstack/lintpatch). ⛔ No engine change (packages/services/service-automation), no loop.config.onIterationError, no new spec key.
Premise re-verified on origin/mainf60ab90ae:control-flow.zod.ts:142 region nodes.min(1), :144edges default [], :216loop.config.body optional (legacy flat-graph loops have no body), :314-317try required / catch optional / errorVariable default $error; collectFlowGraphs:683 (scope string loop 'sweep' body → try_catch 'guard' catch) is the traversal lint-flow-patterns.ts:333/:1168 already uses; rule-id convention FLOW_* = 'flow-…' (lint-flow-patterns.ts:193-232), all warnings by default (FlowLintFinding.severity:150-167), mapped into authoring-rules.ts:1097 (CLI + runtime surfaces); docs anchor flows.mdx:379-470 (### Loop container:397, ### Try / catch / retry:446). No existing rule mentions containment (git grep -n "try_catch" lint-flow-patterns.ts → region-walk comments and the BRANCH_LABEL_NODE_TYPES set only). Premise holds.
Container & model: subagent lane (M), opus.
Clause ②: not reached — two new advisory warnings; no accept set moves, no contract change (the B-branch ruling is "zero contract change" by construction).
{
"issue": 14394,
"status": "done",
"branch": "claude/issue-14394-loop-containment-lint",
"pr": "https://github.com/objectstack-ai/objectstack/pull/14617",
"premise_still_valid": true,
"summary": "B-branch items 1-2 of #13681, lint + docs only — no packages/spec change, no engine change, no onIterationError key. Two rules in the flow anti-pattern family, both severity warning: FLOW_LOOP_BODY_UNCONTAINED = 'flow-loop-body-uncontained' (a loop whose body region runs a fallible node with no try_catch between the loop and it; where names both, e.g. \"flow 'case_sla_monitor' · loop 'each' body · node 'notify_owner' (notify)\") and FLOW_TRY_CATCH_WITHOUT_CATCH = 'flow-try-catch-without-catch' (a try_catch with config.catch absent, anywhere in a flow). Fallible set is a closed literal list justified per type from the executors, cited file:line in its docblock — get_record, create_record, update_record, delete_record, http, notify, connector_action, script, subflow, map, approval; excluded after reading them: assignment and decision (always success), wait and screen (suspend, no failure return), start/end, and the three containers loop/parallel/try_catch (they fail only by propagation, so the walk reports the leaf). Unknown (plugin-registered) types are deliberately NOT fallible — the family's precedent is that membership means the executor was read; stated in the docblock, the PR body and pinned by a test. Division of labour: rule A treats ANY enclosing try_catch as containment, so a catch-less one is reported once, by rule B. Ancestry not depth: the descent walks through parallel branches via the shared region-slot table and stops at a nested loop, which is judged in its own graph. Docs anchor: content/docs/automation/flows.mdx, new '#### Per-iteration containment: loop { try_catch { … } }' under '### Loop container', carrying the measured minimal catch verbatim (one bare assignment node, edges and errorVariable omitted) and the refusal table; the existing Loop container example no longer teaches the warned shape, and '### Try / catch / retry' now states that omitting catch gives zero containment. Both constants added to the barrel's FLOW_* export block. Eight pre-existing tests that asserted a bare total finding count on fixtures with a write or notify in a loop body are now scoped to the rule under test, with one pinning the co-occurrence [FLOW_RUNAS_UNSCOPED, FLOW_LOOP_BODY_UNCONTAINED] explicitly.",
"tests": "All on the final commit 126f9d5e0 (merge of origin/main), in worktree /home/user/objectstack-14394, heavy runs through scripts/pm/os-verify-lock.sh. (1) `pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/lint-flow-patterns.test.ts` -> 'Test Files 1 passed (1) · Tests 132 passed (132)' (117 before this PR; lock VERDICT command-exit 0). Test names carrying the acceptance: 'rule A — a loop body with a fallible node and no containment > flags the fallible node, naming the loop AND the node'; 'rule B — a try_catch with no catch region > flags the near-miss inside a loop body, and says it dies like an unwrapped node'; 'the documented spelling — loop { try_catch { try, catch } } > parses under FlowSchema — the docs example is authorable' and '> raises NO finding from either containment rule' and '> raises no finding from ANY flow rule'. Controls: every fallible builtin flagged once each, the non-fallible builtins and an unknown plugin type left alone, a legacy flat-graph loop (no body) left alone, a parallel branch reported with the branch in where, a nested loop reported once against the inner loop, a retry-only catch-less try_catch reported by rule B only, and a present-but-malformed catch left to the schema (TryCatchConfigSchema.safeParse pins that catch:{} and catch:{nodes:[]} are refused and the minimal spelling accepted). (2) `pnpm --filter @objectstack/lint typecheck` -> exit 0; its check:test-typecheck leg reports 'OK — @objectstack/lint's test layer compiles under packages/lint/tsconfig.test.json', so the new test file is really type-checked. (3) `pnpm lint` (full-repo `eslint . --no-inline-config`) -> exit 0 on this head, NOT narrowed. (4) Dependency closure built first (`pnpm exec turbo run build --filter=@objectstack/lint...`, exit 0) after the merge, plus `--filter=@objectstack/client-react...` to clear one gate prerequisite. No ablation was performed — nothing in this card asserts that a gate can fail, so none was owed.",
"gates": "Union derived IN THIS WORKTREE with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no paths passed): 57 families = 53 by path + 6 by change kind, 2 reached both ways. Re-derived after the merge: byte-identical (`diff cmds.txt cmds2.txt` empty). All 57 run on the final commit 126f9d5e0 via a runner capturing each exit code BEFORE any pipe. Result: 54 RAN-PASS (exit 0), 3 NOT MEASURED, 0 findings outstanding. NOT MEASURED, each refusing on a prerequisite in its own words: `node scripts/check-test-completeness.mjs` exit 3 ('this gate grades a saved turbo run test log, and no log was named ... the local reading for this gate is NOT MEASURED'); `pnpm check:dual-build-cjs-loads` exit 3 ('PREREQUISITE NOT MET — this gate reads built output, and some package has no dist', 83 packages, self-test green 93 cases); `pnpm check:type-check-debt` exit 3 ('PREREQUISITE NOT MET' — it needs the whole built workspace closure; self-test green). One gate went genuinely RED and was fixed: `pnpm check:doc-authoring` refused the two new hints for carrying '(#13681, #14394)' in runtime string prose ('2 (file,id) pair(s) above scripts/doc-authoring-prose-id.baseline.json ... a runtime string reaches authors, operators and generated surfaces — none of whom can resolve #NNNN'); the ids moved to adjacent comments (commit 4beb1da79) and it is exit 0. `pnpm --filter @objectstack/spec run check:skill-examples` first refused (client-react had no dist, 'a verdict now would be computed against a build that no longer matches src'); after building that closure it RAN and passed — '261 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them' — and is counted in the 54. CI convergence is not awaited, per the standing clause.",
"files_touched": [
"packages/lint/src/lint-flow-patterns.ts (+318)",
"packages/lint/src/lint-flow-patterns.test.ts (+349)",
"packages/lint/src/index.ts (+2)",
"content/docs/automation/flows.mdx (+89)",
".changeset/flow-loop-per-iteration-containment-lint.md (+35)"
],
"changeset": ".changeset/flow-loop-per-iteration-containment-lint.md — @objectstack/lint: patch",
"mcp_calls": "1 — one targeted MCP search_issues, declared: the REST search endpoint answered 403 for this seat (repo-scoped REST reads and writes worked throughout), so the duplicate check before filing the finding below switched channel for exactly one call. It returned real hits (this card itself plus three closed showcase issues), so the empty-result blindness case does not apply. Everything else — issue and comment reads, the comment write, the PR create and edit, the issue file — went over REST with $GITHUB_TOKEN and the CA bundle.",
"open_questions": [],
"out_of_scope_findings": [
"filed as #14622: examples/app-showcase `showcase_batch_reminders` loops a `notify` over '{tasks}' with no try_catch in the body — the first in-repo hit of the new warning; the bundled example demonstrates the shape the platform now warns about. Unassigned, no labels, left for triage; ⛔ not fixed here (the card is lint + docs only).",
"not filed, recorded only: examples/app-todo's two loops (`loop_tasks`, `loop_overdue`) are legacy flat-graph loops with no `body` region, so rule A correctly says nothing about them — noted because they read like the same shape and are not.",
"not filed, recorded only: `TryCatchConfigSchema.errorVariable`'s describe on origin/main now promises `iteration` / `item` on the caught error inside a loop body — that is #13681's visibility half landing in the spec lane, and this card deliberately does not touch it."
]
}
ACCEPT — PR #14617 merged to main as 8ed9c54b4 (out of the merge queue 18:39:18Z; queued 15:50Z, evicted 16:35Z by the #14648 queue flake, re-armed once 17:00Z, re-queued 16:59Z — a 2 h 49 min transit). Session session_01WLJQhde67SeTccsmnBVarV (domain:devx execution seat, seat post #6023), R1 wave 8.
Close-out probes on origin/main655b106ce (verify worktree, 8ed9c54b4 an ancestor):
packages/lint/src/lint-flow-patterns.ts: export const FLOW_LOOP_BODY_UNCONTAINED (:265) / FLOW_TRY_CATCH_WITHOUT_CATCH (:281) and the two scanners scanUncontainedLoopBodies (:1256) / scanTryCatchWithoutCatch (:1341) — rule A walks a loop body's regions (through parallel branches via REGION_SLOTS, stopping at a nested loop or an enclosing try_catch) and reports each fallible node from the closed, executor-justified list; rule B reports any try_catch with config.catch absent, once. Both warning.
packages/lint/src/index.ts: both ids exported from the FLOW_* block (2 hits).
content/docs/automation/flows.mdx: the Per-iteration containment subsection under ### Loop container (2 hits) carrying the measured minimal catch verbatim; the Loop example no longer teaches the warned shape.
.changeset/flow-loop-per-iteration-containment-lint.md on main (@objectstack/lint: patch). Tests 117 → 132 in the PR run; size/l.
Against the card (cross-seat filing from #13681, retriage 5479171811): ⛔ no packages/spec change, ⛔ no engine change, ⛔ no loop.config.onIterationError — held; the documented spelling is the measured one (5478851960). The one in-flight red (check:doc-authoring refusing #NNNN ids in runtime prose) was fixed before the report. Zero rework. Follow-up #14622 (showcase showcase_batch_reminders is the first in-repo hit) awaits triage.
pm:dispatched removed with this comment; the card closes via the PR's Fixes #14394.
Activity
claude commentedon Sep 2, 2026
Claim: session
session_01WLJQhde67SeTccsmnBVarV(domain:devx execution seat, seat post #6023) — R1 wave 8.claude/issue-14394-loop-containment-lint../objectstack-14394(dedicated per-task worktree, offorigin/main)domain:devxper the cross-seat filing (lint inpackages/lint+ docs incontent/docs/**; the visibility half stays on Aloopnode aborts the entire flow run when one iteration's node fails — a single bad row kills a whole scheduled sweep, and there is no per-iteration containment to opt into #13681 in the spec lane). ⛔ Nopackages/specchange — the region schema (FlowRegionSchema.nodes.min(1),catchoptional) is read, not moved.packages/lint/src/lint-flow-patterns.ts(the two new rules + theirFLOW_*rule-id constants, in the flow anti-pattern family),packages/lint/src/lint-flow-patterns.test.ts(positive + negative controls for both rules),packages/lint/src/index.ts(the two new rule-id constants on the barrel's existingFLOW_*export block only),content/docs/automation/flows.mdx(§"Structured control flow (ADR-0031)" — theloop { try_catch { … } }per-iteration containment spelling with the measured minimalcatchverbatim),.changeset/*.md(@objectstack/lintpatch). ⛔ No engine change (packages/services/service-automation), noloop.config.onIterationError, no new spec key.origin/mainf60ab90ae:control-flow.zod.ts:142regionnodes.min(1),:144edgesdefault[],:216loop.config.bodyoptional (legacy flat-graph loops have no body),:314-317tryrequired /catchoptional /errorVariabledefault$error;collectFlowGraphs:683(scope stringloop 'sweep' body → try_catch 'guard' catch) is the traversallint-flow-patterns.ts:333/:1168already uses; rule-id conventionFLOW_*='flow-…'(lint-flow-patterns.ts:193-232), all warnings by default (FlowLintFinding.severity:150-167), mapped intoauthoring-rules.ts:1097(CLI + runtime surfaces); docs anchorflows.mdx:379-470(### Loop container:397,### Try / catch / retry:446). No existing rule mentions containment (git grep -n "try_catch" lint-flow-patterns.ts→ region-walk comments and theBRANCH_LABEL_NODE_TYPESset only). Premise holds.lint-flow-patterns.ts,flow-walk.ts,flows.mdx, orpackages/lint/src/index.ts. PR fix(lint): consolidate did-you-mean suggestion helpers into object-graph's shared nearestName #14575 / fix(lint): extend the flattened-scope shadowing warning to the descriptor-declared predicate slots #14576 (this seat, landing) touch otherpackages/lint/srcfiles only — disjoint. Changeset:@objectstack/lintpublishes ⇒ onepatchchangeset.Generated by Claude Code
claude commentedon Sep 2, 2026
os-dev-report
{ "issue": 14394, "status": "done", "branch": "claude/issue-14394-loop-containment-lint", "pr": "https://github.com/objectstack-ai/objectstack/pull/14617", "premise_still_valid": true, "summary": "B-branch items 1-2 of #13681, lint + docs only — no packages/spec change, no engine change, no onIterationError key. Two rules in the flow anti-pattern family, both severity warning: FLOW_LOOP_BODY_UNCONTAINED = 'flow-loop-body-uncontained' (a loop whose body region runs a fallible node with no try_catch between the loop and it; where names both, e.g. \"flow 'case_sla_monitor' · loop 'each' body · node 'notify_owner' (notify)\") and FLOW_TRY_CATCH_WITHOUT_CATCH = 'flow-try-catch-without-catch' (a try_catch with config.catch absent, anywhere in a flow). Fallible set is a closed literal list justified per type from the executors, cited file:line in its docblock — get_record, create_record, update_record, delete_record, http, notify, connector_action, script, subflow, map, approval; excluded after reading them: assignment and decision (always success), wait and screen (suspend, no failure return), start/end, and the three containers loop/parallel/try_catch (they fail only by propagation, so the walk reports the leaf). Unknown (plugin-registered) types are deliberately NOT fallible — the family's precedent is that membership means the executor was read; stated in the docblock, the PR body and pinned by a test. Division of labour: rule A treats ANY enclosing try_catch as containment, so a catch-less one is reported once, by rule B. Ancestry not depth: the descent walks through parallel branches via the shared region-slot table and stops at a nested loop, which is judged in its own graph. Docs anchor: content/docs/automation/flows.mdx, new '#### Per-iteration containment: loop { try_catch { … } }' under '### Loop container', carrying the measured minimal catch verbatim (one bare assignment node, edges and errorVariable omitted) and the refusal table; the existing Loop container example no longer teaches the warned shape, and '### Try / catch / retry' now states that omitting catch gives zero containment. Both constants added to the barrel's FLOW_* export block. Eight pre-existing tests that asserted a bare total finding count on fixtures with a write or notify in a loop body are now scoped to the rule under test, with one pinning the co-occurrence [FLOW_RUNAS_UNSCOPED, FLOW_LOOP_BODY_UNCONTAINED] explicitly.", "tests": "All on the final commit 126f9d5e0 (merge of origin/main), in worktree /home/user/objectstack-14394, heavy runs through scripts/pm/os-verify-lock.sh. (1) `pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/lint-flow-patterns.test.ts` -> 'Test Files 1 passed (1) · Tests 132 passed (132)' (117 before this PR; lock VERDICT command-exit 0). Test names carrying the acceptance: 'rule A — a loop body with a fallible node and no containment > flags the fallible node, naming the loop AND the node'; 'rule B — a try_catch with no catch region > flags the near-miss inside a loop body, and says it dies like an unwrapped node'; 'the documented spelling — loop { try_catch { try, catch } } > parses under FlowSchema — the docs example is authorable' and '> raises NO finding from either containment rule' and '> raises no finding from ANY flow rule'. Controls: every fallible builtin flagged once each, the non-fallible builtins and an unknown plugin type left alone, a legacy flat-graph loop (no body) left alone, a parallel branch reported with the branch in where, a nested loop reported once against the inner loop, a retry-only catch-less try_catch reported by rule B only, and a present-but-malformed catch left to the schema (TryCatchConfigSchema.safeParse pins that catch:{} and catch:{nodes:[]} are refused and the minimal spelling accepted). (2) `pnpm --filter @objectstack/lint typecheck` -> exit 0; its check:test-typecheck leg reports 'OK — @objectstack/lint's test layer compiles under packages/lint/tsconfig.test.json', so the new test file is really type-checked. (3) `pnpm lint` (full-repo `eslint . --no-inline-config`) -> exit 0 on this head, NOT narrowed. (4) Dependency closure built first (`pnpm exec turbo run build --filter=@objectstack/lint...`, exit 0) after the merge, plus `--filter=@objectstack/client-react...` to clear one gate prerequisite. No ablation was performed — nothing in this card asserts that a gate can fail, so none was owed.", "gates": "Union derived IN THIS WORKTREE with `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack` (no paths passed): 57 families = 53 by path + 6 by change kind, 2 reached both ways. Re-derived after the merge: byte-identical (`diff cmds.txt cmds2.txt` empty). All 57 run on the final commit 126f9d5e0 via a runner capturing each exit code BEFORE any pipe. Result: 54 RAN-PASS (exit 0), 3 NOT MEASURED, 0 findings outstanding. NOT MEASURED, each refusing on a prerequisite in its own words: `node scripts/check-test-completeness.mjs` exit 3 ('this gate grades a saved turbo run test log, and no log was named ... the local reading for this gate is NOT MEASURED'); `pnpm check:dual-build-cjs-loads` exit 3 ('PREREQUISITE NOT MET — this gate reads built output, and some package has no dist', 83 packages, self-test green 93 cases); `pnpm check:type-check-debt` exit 3 ('PREREQUISITE NOT MET' — it needs the whole built workspace closure; self-test green). One gate went genuinely RED and was fixed: `pnpm check:doc-authoring` refused the two new hints for carrying '(#13681, #14394)' in runtime string prose ('2 (file,id) pair(s) above scripts/doc-authoring-prose-id.baseline.json ... a runtime string reaches authors, operators and generated surfaces — none of whom can resolve #NNNN'); the ids moved to adjacent comments (commit 4beb1da79) and it is exit 0. `pnpm --filter @objectstack/spec run check:skill-examples` first refused (client-react had no dist, 'a verdict now would be computed against a build that no longer matches src'); after building that closure it RAN and passed — '261 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of them' — and is counted in the 54. CI convergence is not awaited, per the standing clause.", "files_touched": [ "packages/lint/src/lint-flow-patterns.ts (+318)", "packages/lint/src/lint-flow-patterns.test.ts (+349)", "packages/lint/src/index.ts (+2)", "content/docs/automation/flows.mdx (+89)", ".changeset/flow-loop-per-iteration-containment-lint.md (+35)" ], "changeset": ".changeset/flow-loop-per-iteration-containment-lint.md — @objectstack/lint: patch", "mcp_calls": "1 — one targeted MCP search_issues, declared: the REST search endpoint answered 403 for this seat (repo-scoped REST reads and writes worked throughout), so the duplicate check before filing the finding below switched channel for exactly one call. It returned real hits (this card itself plus three closed showcase issues), so the empty-result blindness case does not apply. Everything else — issue and comment reads, the comment write, the PR create and edit, the issue file — went over REST with $GITHUB_TOKEN and the CA bundle.", "open_questions": [], "out_of_scope_findings": [ "filed as #14622: examples/app-showcase `showcase_batch_reminders` loops a `notify` over '{tasks}' with no try_catch in the body — the first in-repo hit of the new warning; the bundled example demonstrates the shape the platform now warns about. Unassigned, no labels, left for triage; ⛔ not fixed here (the card is lint + docs only).", "not filed, recorded only: examples/app-todo's two loops (`loop_tasks`, `loop_overdue`) are legacy flat-graph loops with no `body` region, so rule A correctly says nothing about them — noted because they read like the same shape and are not.", "not filed, recorded only: `TryCatchConfigSchema.errorVariable`'s describe on origin/main now promises `iteration` / `item` on the caught error inside a loop body — that is #13681's visibility half landing in the spec lane, and this card deliberately does not touch it." ] }Generated by Claude Code
Generated by Claude Code
claude commentedon Sep 2, 2026
ACCEPT — PR #14617 merged to
mainas8ed9c54b4(out of the merge queue 18:39:18Z; queued 15:50Z, evicted 16:35Z by the #14648 queue flake, re-armed once 17:00Z, re-queued 16:59Z — a 2 h 49 min transit). Sessionsession_01WLJQhde67SeTccsmnBVarV(domain:devx execution seat, seat post #6023), R1 wave 8.Close-out probes on
origin/main655b106ce(verify worktree,8ed9c54b4an ancestor):packages/lint/src/lint-flow-patterns.ts:export const FLOW_LOOP_BODY_UNCONTAINED(:265) /FLOW_TRY_CATCH_WITHOUT_CATCH(:281) and the two scannersscanUncontainedLoopBodies(:1256) /scanTryCatchWithoutCatch(:1341) — rule A walks aloopbody's regions (throughparallelbranches viaREGION_SLOTS, stopping at a nested loop or an enclosingtry_catch) and reports each fallible node from the closed, executor-justified list; rule B reports anytry_catchwithconfig.catchabsent, once. Bothwarning.packages/lint/src/index.ts: both ids exported from theFLOW_*block (2 hits).content/docs/automation/flows.mdx: thePer-iteration containmentsubsection under### Loop container(2 hits) carrying the measured minimalcatchverbatim; the Loop example no longer teaches the warned shape..changeset/flow-loop-per-iteration-containment-lint.mdon main (@objectstack/lint:patch). Tests 117 → 132 in the PR run;size/l.Against the card (cross-seat filing from #13681, retriage 5479171811): ⛔ no
packages/specchange, ⛔ no engine change, ⛔ noloop.config.onIterationError— held; the documented spelling is the measured one (5478851960). The one in-flight red (check:doc-authoringrefusing#NNNNids in runtime prose) was fixed before the report. Zero rework. Follow-up #14622 (showcaseshowcase_batch_remindersis the first in-repo hit) awaits triage.pm:dispatchedremoved with this comment; the card closes via the PR'sFixes #14394.Generated by Claude Code
docs(lint): re-anchor the dead tracker citations in packages/lint/src…