Skip to content

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

Description

@claude

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)

  1. 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.
  2. 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.
  3. 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.
  4. 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.

Out of scope here


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions