Skip to content

Three pre-existing flow-lint fixtures bind the loop item with itemVar, a key LoopConfigSchema rejects — the nested-region tests describe a loop no author can write #5700

Closed

Description

@os-zhuang

Found while implementing #5633. Filed unassigned, observation-class (finding, no pm:queue): no shipped behaviour is wrong — this is test fixtures describing a container the schema rejects, so the coverage they advertise is weaker than it reads.

What

packages/lint/src/lint-flow-patterns.test.ts binds the loop item with itemVar in three pre-existing fixtures:

LoopConfigSchema (packages/spec/src/automation/control-flow.zod.ts) is a strictObject, and the declared key is iteratorVariable. itemVar is neither declared nor aliased, so it is reported as an unrecognized_key rather than dropped (#4001):

REJECTED  itemVar             unrecognized_keys=[["itemVar"]]     (the only issue)
PARSES    iteratorVariable    unrecognized_keys=[]
REJECTED  itemVariable        unrecognized_keys=[["itemVariable"]]  (declared alias -> guidance)

(itemVariable is deliberately registered as an alias so the edit-distance suggester cannot send an author to indexVariable — see the comment above LoopConfigSchema's aliases. itemVar is not in that set.)

Why the tests do not notice

Region collection reads config.body. collectFlowGraphs / regionSlotsOf never look at the item-binding key, so a fixture spelling itemVar descends and gets scanned exactly like a correct one — every assertion in those cases passes for the right reason about the rule, while the fixture describes a loop an author cannot write. Nothing in the suite parses these fixtures, so nothing goes red.

That is the same shape this very file already documents for a trigger descriptor — the #4966 note above the time-relative case, which added expect(TimeRelativeTriggerSchema.safeParse(...).success).toBe(true) precisely because "a fixture the runtime would refuse teaches the wrong shape to every reader of this file". This is that finding one container down.

Scope, and what is already fixed

Fixtures added by #5633 (PR #5695) are already correct: re-spelled to iteratorVariable, given the label that FlowNodeSchema requires on the body nodes, and pinned against LoopConfigSchema in both directions (fixture parses green; the near-miss spelling really is rejected, so the pin has teeth). That PR deliberately did not touch the three pre-existing fixtures — they are not exposed by its change, and re-spelling someone else's fixtures is scope creep on a build-gating PR.

So what remains is exactly those three call sites.

Fix

Mechanical: itemVar to iteratorVariable at the three sites, plus the label the body nodes need if the fixture is to parse fully, plus a LoopConfigSchema pin on the shared loopBodyFlow helper so the whole family cannot rot back. Worth checking in the same pass whether other container fixtures in the flow-lint tests spell undeclared keys on parallel branches or try_catch regions — the audit is one safeParse per fixture and is the durable half of the fix.

Note the flow-level label requirement is a separate and much broader convention in this file: essentially none of its fixtures are full-FlowSchema-green (FlowSchema requires label on the flow and on every node), because the suite passes hand-written raw literals rather than parsed stacks. Bringing the whole file to full-flow-parse-green is a different, larger decision and is not proposed here — the narrow claim is that a key a fixture writes should be a key the schema accepts.

Related

Activity

  1. added
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    and removed
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    on Aug 6, 2026
  2. os-zhuang commented on Aug 6, 2026

    @os-zhuang
    ContributorAuthor

    发现分诊(finding 轮):晋级 —— 摘 finding,入 pm:queue,域 domain:devx。

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  3. self-assigned this
    on Aug 7, 2026
  4. hotlong commented on Aug 7, 2026

    @hotlong
    Contributor

    ⛔ 认领(claim)

    派 1 名 os-dev 落地;test-only 走 skip-changeset。


    Generated by Claude Code

  5. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Aug 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:devxDomain lane — seat card indexed by label:pm:seatpm:dispatchedDispatched to a dev agent by /pm-dispatch

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions