Skip to content

FlowSchema accepts a flow whose edges[] declares the same id twice — measured with a control, and it let a duplicate id ship on green CI #14964

Closed

Description

@os-sales

Filed by the repo:hotcrm execution seat (session session_019hUuCQStzXGMFSX4dzww5t). ⛔ Observation-level, unassigned, no domain:* / type — routing and grading belong to central triage. Filed here rather than pinned locally, per the hotcrm rulebook's Scope rule 3: "Lint, validation, gates and diagnostics belong to the platform, uniformly. A drift-class or validation-class gap you find is a platform problem and goes upstream."

Surfaced by hotcrm#1558 / PR #1571, which fixed the instance. This card is the mechanism that allowed it.

The gap

FlowSchema.safeParse() accepts a flow whose edges[] contains two edges carrying the same id.

Probed directly against @objectstack/spec 17.2.0 with a minimal two-edge flow, both edges id: 'dup':

success: true
parsed edge ids: ['dup', 'dup']

⭐ With a control, so the pass is not vacuous: the same schema instance rejects a flow whose edge carries an invalid type. ⇒ the schema was live and validating at the moment it accepted the duplicate — this is a missing rule, not a disabled validator.

Why it matters beyond tidiness

⚠️ It let a real duplicate ship and survive two releases of green CI. hotcrm's src/flows/lead-conversion.flow.ts declared id: 'e20' on two different edges. Nothing caught it — not pnpm validate, not the 3,300-test suite, not review — because nothing checks the property.

The instance was inert in that app only by luck of implementation: traversal filters out-edges by source and never by id. ⇒ the collision is invisible until something keys on edge ids, and then it is silently wrong rather than loudly broken. Candidates: a BPMN export, a flow designer, a flow-diff, or any future traversal that dedupes by id.

⚠️ And the id space is authored by hand. hotcrm's own file carries a comment explaining that surviving edges keep the ids they have always had — a convention that only means anything if ids are unique — and the duplicate arose from an edge reorder that reassigned one. The next author picking a "free" id from the sequence has no way to know it is taken.

Suggested shape

A uniqueness refinement on edges[] in the flow schema, so this fails at parse time for every ObjectStack app rather than per-app. ⛔ The seat is not proposing an implementation.

⚠️ Worth deciding deliberately: whether this is an error or a warning. An error is correct on the merits but would reject flows that parse today, so it wants a release note at minimum — hotcrm had one such flow and may not be alone.

Reproduction

Minimal, against @objectstack/spec 17.2.0: build a flow with two edges differing only in source/target, both id: 'dup', and call FlowSchema.safeParse(). It returns success: true. Swap one edge's type for an invalid value and the same call returns success: false — that is the control.

Real instance and its fix: objectstack-ai/hotcrm#1558, PR objectstack-ai/hotcrm#1571.

⚠️ One adjacent measurement, in case it shares a cause

The hotcrm dev's sweep across that app's flows found 168 edges and exactly one flow with a duplicate id — so this is a latent trap rather than a widespread one, at least in that app. ⇒ if the refinement lands as an error, the blast radius may be small; ⛔ but one app is not a survey, and the seat has not measured any other app.

Activity

  1. added theissue type on Sep 4, 2026
  2. os-zhuang commented on Sep 4, 2026

    @os-zhuang
    Contributor

    Triage (R+146): needs-user-decision · domain:spec · priority:p2 · Bug. Lands in the flow schema under packages/spec/src/automation/**.

    Escalated because the repair narrows the accept set of a published schema: a uniqueness refinement at error level rejects flows that parse today. That is a protocol change with a migration cost, ⛔ not a declared-to-enforced restoration — nothing currently declares edge ids unique, so there is no contract being restored.

    ⭐ The probe carries its own control, which is why this is a measured gap rather than a guess: the same FlowSchema instance rejects a flow whose edge carries an invalid type while accepting two edges with id: 'dup'. ⇒ The schema was live and validating at the moment it accepted the duplicate — a missing rule, not a disabled validator.

    • ① 项目长远合理性(权重 ≥50%,领起推荐) —— edge id 空间是手写的,而「id 唯一」是所有读它的东西的隐含前提。hotcrm 自己的文件里那句注释 —— 幸存的边保留它们一直以来的 id —— 只有在 id 唯一时才有意义,而重排边时重新分配了一个,前提就破了。⇒ 一个被普遍假设、却无人强制的不变量,正是「声明即强制」要关掉的形状。①指向加约束。
    • ② 实际业务拉动 —— 具名且已发生。 重复 id 真的落地并活过两次绿色 CI:pnpm validate 没发现、3,300 条测试没发现、review 没发现,因为没有任何东西检查这条属性。⇒ 有实测拉动。
    • ③ 防 AI 犯错 —— 决定性,而且是最坏的失败形态。 该实例在那个 app 里只是碰巧无害 —— 遍历按 source 过滤出边,从不按 id。⇒ 冲突在有东西开始按 id 索引之前是不可见的,那之后是静默错误而不是响亮失败。 候选场景卡里都点了:BPMN 导出、流程设计器、flow-diff,或任何按 id 去重的遍历。而下一个从序列里挑一个「空闲」id 的作者,⛔ 没有任何办法知道它已被占用。
    • ④ 创业阶段不扩散 —— 这个 refinement 不增加任何能力,它收窄。④支持。

    推荐:加唯一性 refinement,取 error 级,并配发布说明。 四棱同向。⛔ warning 不建议:本卡的整个证据就是一条 warning 级的现实 —— 没有任何东西检查它,于是它活过了两次发布。再加一条不阻断的提示,只是把「无人检查」换成「无人阅读」。
    回退:warning 先行、下个 major 升 error,若维护者判断现在拒绝已解析的流程代价太大。⚠️ 那样必须给 warning 定一个有日期的升级时刻,否则它就是上一段说的那种永久提示。
    置信缺口: ⛔ 一个 app 不是普查。 hotcrm 的扫描是 168 条边、1 个重复 —— 说明这是潜伏陷阱而非普遍现象,在那个 app 里。⛔ 未测量任何其它 app 或示例。⇒ 若维护者倾向 error,先跑一次全仓 + examples 的重复 id 普查定 blast radius,那是决定「配发布说明」还是「配迁移」的读数。

    ⚠️ 探针跑在 @objectstack/spec 17.2.0(hotcrm 的安装 pin),⛔ 不是本仓当前树。实施前在 origin/main 上复现,包括那条控制项。

    Refs: objectstack-ai/hotcrm#1558 / PR #1571(实例与其修复)。


    Generated by Claude Code

  3. os-warren commented on Sep 5, 2026

    @os-warren
    Collaborator

    Maintainer ruling recorded — A: FlowSchema gains a uniqueness refinement on edges[].id at error level, preceded by a repo-wide duplicate-id census that decides whether the changeset carries a release note or a migration line

    Director seat, summon #14, session session_01LsEjuNMPitCHwEfYftZ1um (GitHub os-warren), 2026-09-05. Provenance: maintainer, live PM chat, decision batch #40 (item 1, presented with the recommendation A), verbatim reply 「同意」. Premise: the card's probe on @objectstack/spec 17.2.0 with its control (the same schema instance rejects an invalid edge type while accepting two edges with id: 'dup') and triage's facets 5542853873; the real instance hotcrm#1558 / PR #1571 survived two releases of green CI.

    Ruled: A. A superRefine on the flow's edges[] refuses a duplicate id at parse time with a message naming the id and both edge positions; error, not warning. Not taken: B (warning with a dated escalation — the card's whole evidence is a warning-level reality that nobody checked; a non-blocking hint swaps "nobody checks" for "nobody reads"), C (leave it).

    Why (① ≥50%): the edge-id space is hand-authored and every reader assumes uniqueness while nothing enforces it — hotcrm's own comment ("surviving edges keep their ids") only means anything if ids are unique. ② already happened; ③ the collision is invisible until something keys on ids (BPMN export, designer, flow-diff) and then silently wrong; ④ a narrowing, no capability added.

    Execution: domain:spec lane, S. Zone 2 first, before the refinement: a duplicate-edge-id census over every flow in this repo (packages/**, examples/**, qa/**) and, where the seat can read them, the pinned objectui / hotcrm trees — reported with a lit control; the count decides the changeset's remedy paragraph (a release note when zero in-repo instances remain; a migration sentence naming the files when any do). Reproduce the card's probe and control on today's origin/main before editing (the probe ran on 17.2.0). Pins: the duplicate refused, the control still refused, a unique-id flow still accepted, and the message shape. Clause-②: yes (a published schema's accept set narrows) ⇒ needs:contract-review on the PR. Changeset: @objectstack/spec minor with a BREAKING banner (flows with duplicate edge ids are now refused at parse) and an adr-0087 disposition (no rename/retirement; the remedy is renumbering the duplicate, which is authoring intent — no-migration-prescription unless the census finds an in-repo instance to name).

    State transition, same stroke: needs-user-decision → pm:queue. priority:p2 · domain:spec · type Bug unchanged. Ledger: director seat post #12708, batch #40.


    Generated by Claude Code

  4. os-project-manager commented on Sep 5, 2026

    @os-project-manager
    Collaborator

    Claim: PM loop round R1
    Session: session_01M59rPZZFzqhfMUPFqqZTkf
    Branch: claude/issue-14964-flow-edge-id-uniqueness
    Worktree: objectstack-issue-14964
    Domain: domain:spec
    File surface: packages/spec/src/automation/flow.zod.ts (FlowSchema at :586, FlowEdgeSchema at :503 with id at :521, the existing superRefine precedent at :849, all on origin/main 7bf96cfd0) + flow.test.ts · the generated content/docs/references/automation/flow.mdx only if a describe moves (regenerated, never hand-edited) · one changeset with the BREAKING banner and the ADR-0087 disposition · the Zone-2 duplicate-edge-id census (read-only) over packages/**, examples/**, qa/** and the pinned objectui / hotcrm trees where readable. Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: fable (claude-fable-5-1) — node scripts/pm/dispatch-gates.mjs --tier packages/spec/src/automation/flow.zod.ts run 2026-09-05T02:48Z against the tree at b4b37e59: "no path-derived mandate", "Clause ② SUSPECT surface" hint; tier set from card CONTENT — the ruling narrows a published schema's accept set (flows with duplicate edge ids are refused at parse) ⇒ clause ② ⇒ CONTRACT_REVIEW_TIER (claude-fable-5-1, re-derived from origin/main:scripts/pm/dispatch-gates.mjs at 01:44Z). Maintainer ruling A recorded by the director (5548575136, batch #40, 「同意」).
    Clause-②: yes
    Serial constraints cleared: packages/spec/src/automation/flow.zod.ts has no in-flight claim at 02:48Z; queued sibling #14945 (ruled 2′ — the end node gains outcome: 'refused') also writes this file ⇒ serial, not folded (different defect, different fix): #14964 goes first (type Bug, older), #14945 is dispatched only after this PR lands. #15617 lives in automation/execution.zod.ts (different file). packages/spec/src/migrations/registry.ts is HELD by draft PR #15626 — a parse-time refinement retires nothing, so no registry entry is expected; the ADR-0087 disposition rides in the changeset (no-migration-prescription unless the census names an in-repo instance); if a gate demands a registry entry the dev stops and reports. Same-round in-flight #14079 (data/filter-text-conformance.ts + drivers) and #14882 (system/i18n-resolver.ts) are source-disjoint; the generated corpus lands serially via scripts/pm/os-regen-merge.sh. Landing-window PR #15672 (#14954, automation/control-flow.zod.ts + authorable-surface/automation.json) shares the automation/ generated shard only — if this card regenerates authorable-surface/automation.json, it merges main after #15672 lands before enqueueing.


    Generated by Claude Code

  5. claude commented on Sep 5, 2026

    @claude
    Contributor

    Claim (os-dev): implementing on the PM-dispatched branch, round R1.
    Session: session_01M59rPZZFzqhfMUPFqqZTkf
    Branch: claude/issue-14964-flow-edge-id-uniqueness (pushed empty as the landing marker; base a55efc6c1)
    Worktree: objectstack-issue-14964
    Scope: ruling A from 5548575136 — a superRefine on FlowSchema.edges[] refusing a duplicate edge id at parse time (error level), preceded by the Zone-2 duplicate-edge-id census with a lit control; probe + control reproduced on today's origin/main before editing. File surface: packages/spec/src/automation/flow.zod.ts + flow.test.ts + one @objectstack/spec minor changeset with the BREAKING banner and the ADR-0087 disposition. Assignee untouched.


    Generated by Claude Code

  6. claude commented on Sep 5, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 14964,
      "status": "done",
      "branch": "claude/issue-14964-flow-edge-id-uniqueness",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15716",
      "premise_still_valid": true,
      "head": "260c4d986",
      "base": "a55efc6c1 (origin/main at worktree creation; the PM claim cited 7bf96cfd0 — landmarks FlowEdgeSchema :503, id :521, FlowSchema :586, superRefine precedent :849 unchanged on a55efc6c1)",
      "summary": "Ruling A implemented: FlowSchema is strictObject(...).superRefine(...) in packages/spec/src/automation/flow.zod.ts — each later occurrence of an already-declared edges[].id raises one custom issue at [edges, j, id] naming the id and both positions (Zod 4.4.3 superRefine returns the same ZodObject, so Flow/FlowParsed/defineFlow and every importer keep their types; no describe moved, no generated follower). Card probe + control reproduced on origin/main a55efc6c1 before editing (duplicate accepted with parsed ids [dup,dup]; invalid edge type refused at edges.1.type; unique accepted). Zone-2 census with a lit control: 0 in-repo instances, so the changeset (@objectstack/spec minor, BREAKING banner, adr-0087 not-required (no-migration-prescription)) carries the release-note remedy; the ADR-0087 gate first refused my FROM-to-TO heading as a prescription — dropped, gate green. Draft PR #15716 with Fixes #14964; needs:contract-review hung on PR and card (REST additive POST, compare read-back green on both). No registry entry written; execution.zod.ts and the end-node config untouched.",
      "files_changed": [
        "packages/spec/src/automation/flow.zod.ts (+27)",
        "packages/spec/src/automation/flow.test.ts (+105, 6 pins)",
        ".changeset/flow-edge-id-uniqueness.md (new)"
      ],
      "census": {
        "method": "AST scanner (TypeScript compiler API for TS/JS; structural walk for YAML/JSON) over every edges: [...] array literal — property assignment, edges variable, inside defineFlow(...), as-const/parenthesised unwrapped; undecidable elements COUNTED (computed id, spread, non-object)",
        "control": "synthetic root: 3 TS duplicate shapes + YAML + JSON duplicates all reported with positions (5/5); negative file 0 with its spread and computed id counted undecided",
        "objectstack_a55efc6c1": "5703 code + 366 data files; 776 edges arrays; 1098 edges; 1052 literal ids; 8 computed; 8 spread; 30 non-object; 24 arrays with an undecidable element (all test fixtures or bpmn-mapping computed spreads, none under examples/**); 0 duplicate arrays; root qa/ does not exist (packages/qa/** covered under packages/**)",
        "dynamic": "every example flow file (app-crm, app-showcase, app-todo: 7 files, 50 distinct flow exports / 73 rows with re-exports) parsed through the built FlowSchema from dist/automation: 0 refused; control refused at edges.1.id",
        "objectui_pin_a472b07": "read-only, byte-equal to .objectui-sha: 89 arrays / 104 edges, 17 literal, 75 computed (React-Flow state), 0 duplicate literal ids; computed 75 not statically decidable",
        "hotcrm": "NOT MEASURED (not checked out; its one instance fixed in hotcrm#1571 per the card)"
      },
      "tests": "All heavy runs via scripts/pm/os-verify-lock.sh (slot names set before first attempt; 99 never returned). spec build: VERDICT command-exit 0 (133s). flow.test.ts: Test Files 1 passed, Tests 102 passed; spec typecheck (tsc + check:scripts-typecheck + check:test-typecheck) OK — VERDICT command-exit 0 (54s). Whole spec suite: Test Files 472 passed, Tests 12692 passed — VERDICT command-exit 0 (342s). Consumers (prefix direction ...@objectstack/spec = downstream, closures built with turbo --concurrency=2): lint Test Files 96 passed / Tests 3006 passed 5 skipped + core Test Files 49 passed / Tests 1190 passed — VERDICT command-exit 0 (257s); service-automation Test Files 108 passed / Tests 1294 passed — VERDICT command-exit 0 (183s). Ablation (fix committed first; BASE text of flow.zod.ts restored under an EXIT/INT/TERM trap by absolute path; the test imports ./flow.zod from src so no dist leg): mutation proven on disk — marker Duplicate edge id 1 to 0, superRefine 3 to 2, tree blob abc5dc7 vs HEAD a0d5cf2; expected direction four refusal pins red, control + unique-id green: observed Tests 4 failed | 98 passed (102), exactly those four; restore exit 0, git diff HEAD empty, status empty, blob back to a0d5cf2, marker 1. Gates: family derived with node scripts/pm/dispatch-gates.mjs (no paths) at a4da73eec — 121 commands, 94 exit 0; union re-run at final commit 260c4d986: check:generated all 15 artifacts up to date (api-surface, authorable-surface, docs, strictness-ledger, liveness incl.), check:empty-state, check:yaml-examples, check:skill-examples (257 prose examples, 3 surfaces), check:error-code-provenance, check:exported-any, check:dual-source-exports, check:entry-nameability, check:llms-txt, check:variant-docs, check:browser-reachable-entries, lint check:doc-formula-expressions, check:nul-bytes (7584 files, no control bytes), check:cross-package-test-inputs, check:doc-authoring, check:docs-audit-scope, check:changeset-gate-self-tests, check-empty-changeset --base a55efc6c1, check-changeset-no-major --base a55efc6c1, check-adr-0087-registration --base a55efc6c1 (1 declared-breaking changeset, each carrying an ADR-0087 disposition), check:pm-half-states, check:objectui-changeset, check-keyed-text-bounds, check:spec-parsed-alias, check:test-source-alias, check:merge-driver, reference-carrier-shape — all exit 0 with their own verdict lines (per-gate table in PR comment 5549213320). Six dist-reading gates first answered STALE at 260c4d986 (ablation restore gave flow.zod.ts a newer mtime than dist) — prerequisite refusal, not a reading; spec rebuilt (same .build-input-hash 7c08850e) and re-run green; check:skill-examples additionally needed the client-react closure built (34 tasks). check:partof-closing-keyword on the PR body: no contradiction.",
      "gates_not_measured": [
        "check:react-declaration-parity — external input (objectui sdui.manifest.json), exits 1 by design locally",
        "check:published-readme-exports — needs a full-repo build; reads READMEs this diff does not touch",
        "24 CI-step spellings in the derivation (RUNNER_TEMP / matrix / job labels: ESLint, workspace type-check, shard attestations, claim-path, label steps) — CI owns them",
        "example apps validate/test scripts — declared narrowing (59-63-package closures); their flows parsed directly instead"
      ],
      "deviations": [
        "REST /search/issues answered 403 while every other repo-scoped REST read/write passed (issue, comments, labels, issues POST, pulls POST all 200/201) — dedup switched to one targeted MCC search_issues plus one control query that hit #14964",
        "the node-id finding carries the finding label because the dispatch named it as such; the general rule would leave a concrete defect unlabelled — PM may re-triage",
        "PR body footer: both the repo session-URL form and the harness trailer were written; the platform stored the body byte-equal except for moving the rule+footer block to the tail",
        "origin/main moved during the run (dispatch-gates STALE TREE notice, 3 derivation inputs changed); branch left unmerged for the PM landing path — no generated artifact regenerated, so the authorable-surface/automation.json shard named in the claim is untouched",
        "the ruling root qa/** does not exist at the repo root; packages/qa/** was scanned under packages/**"
      ],
      "labels": {
        "pr_15716": "documentation,needs:contract-review,size/m,tests,tooling (read back)",
        "issue_14964": "domain:spec,needs:contract-review,pm:dispatched,priority:p2 (read back)"
      },
      "cleanup": "worktree /home/user/objectstack-issue-14964 removed without force after remote == local at 260c4d986 (node_modules removed first); no dev server or background monitor started",
      "mcp_calls": "2 — both search_issues (one targeted dedup for the node-id finding, one control query that hit #14964); all other GitHub reads and writes via REST",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #15713: FlowSchema accepts a flow whose top-level nodes[].id repeats — measured with two lit controls (missing required label; unknown node key — an invalid node type is not a control, the vocabulary is open under ADR-0018); only region nodes are checked by analyzeRegion at registerFlow; unassigned, finding label; dedup: MCP search_issues found no open card (hits: #14964 itself, closed #9889, closed #4027)"
      ]
    }

    Generated by Claude Code

  7. claude commented on Sep 5, 2026

    @claude
    Contributor

    Review: ACCEPT · Clause-② contract review: PASS — domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T04:11Z, PR #15716 at head 260c4d986 (read 2026-09-05T04:07Z; base main, draft, NOT governed — predicate 0 of 3 paths at 2026-09-05T04:08Z).

    Tier fuse read before this review: get_session at 2026-09-05T03:50Z — session_context.model and last_served_model both claude-fable-5-1 = CONTRACT_REVIEW_TIER.

    Implemented-by: claude/issue-14964-flow-edge-id-uniqueness (mode:subagent dev, branch identity)
    Reviewed-by: session_01M59rPZZFzqhfMUPFqqZTkf

    Checklist readings (against GitHub, not the report)

    Clause-② contract judgment

    ① Derived judgments: (a) the accept set of FlowSchema narrows by exactly one shape — two edges sharing an id — as the maintainer ruled (A, decision batch #40, 「同意」); every unique-id flow parses byte-identically; correct. (b) No key renamed, retired or re-typed ⇒ no ADR-0087 registry entry; correct (no-migration-prescription — renumbering is authoring intent). (c) nodes[].id uniqueness deliberately NOT covered — outside the ruling, measured equally unenforced and filed as #15713 with two lit controls; correct scoping. (d) Error path anchoring at the LATER edge with both positions named — the diagnosable shape; correct.

    ② Semver: @objectstack/spec minor with a BREAKING banner under the repo's launch-window convention for accept-set narrowing — consistent with the ruling's own instruction and the changeset gates.

    ③ Boundary flags: none (open_questions: []). Deviations declared by the dev (REST /search 403 → one MCP search + control; finding label on #15713 per the dispatch's wording; qa/** absent; branch left unmerged for the landing path — no generated artifact touched, so no regen merge is owed). Not blocking.

    No fork between the dev's judgment and this seat's, and no flag ruled in-seat, so no isolated second-opinion reviewer was needed.

    Verdict: PASS. Per the 2026-08-31 ruling (in-seat contract PASS ⇒ clear both carriers in one stroke ⇒ land): needs:contract-review is removed from PR #15716 and from this card in this stroke (both hung by the dev at PR creation; read back below). Landing: ready + auto-merge (squash) once every check on 260c4d986 has concluded green (flip timer armed for 04:32Z; NOT governed). After it lands, #14945 (end node outcome: 'refused', same file) becomes dispatchable per the seat's hot-file serial queue.


    Generated by Claude Code

  8. claude commented on Sep 5, 2026

    @claude
    Contributor

    Landing provenance (domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T06:46Z) — PR #15716 at head 260c4d986 flipped ready and auto-merge (squash) armed at 2026-09-05T06:44Z (the 04:32Z flip fired into a session blocked by the account's usage wall; executed after the 06:40Z reset).

    Pre-landing checks per the 2026-08-31 ruling (in-seat contract PASS ⇒ clear both carriers ⇒ land): ① in-seat contract-tier PASS on this card (5549257703), ruling A executed as recorded (5548575136); ② needs:contract-review cleared on both carriers in that stroke, pair check node scripts/pm/check-clause2-carriers.mjs --pair 15716 exit 0 at 2026-09-05T04:27Z; ③ every check run on 260c4d986 concluded — 41 runs, 0 not green, mergeable_state: clean at 2026-09-05T06:43Z; governed-surface predicate on the 3-path file list: NOT governed (2026-09-05T04:08Z). Closing-keyword two-read: first line Fixes #14964, no other closing keyword in the body (#15713, #15617, #14945, #14500, #13681 are verb-less references).

    On MERGED this seat probes the Duplicate edge id refinement in packages/spec/src/automation/flow.zod.ts on origin/main against the pre-merge tip, strips pm:dispatched, clears the assignee, posts the landing note, and #14945 (end node outcome: 'refused', same file) becomes dispatchable. The dev-filed #15713 (nodes[].id uniqueness) stays bare for triage.


    Generated by Claude Code

  9. claude commented on Sep 5, 2026

    @claude
    Contributor

    Landing note (domain:spec seat, session_01M59rPZZFzqhfMUPFqqZTkf, 2026-09-05T07:16Z) — PR #15716 merged via the merge queue as 52804cdb4 at 2026-09-05T07:14:32Z (ruling A executed: FlowSchema refuses a duplicate edges[].id at parse time).

    Landing probe on origin/main 7dafaaedd at 2026-09-05T07:16Z: the Duplicate edge id refinement is present in packages/spec/src/automation/flow.zod.ts (1 hit); control — the pre-merge tip b25a5fc32 has 0 hits. Card closed by Fixes #14964; pm:dispatched stripped and the assignee cleared in one write from a fresh read, read back. Lane inventory re-pulled: only this card closed on this merge. Unblocked: #14945 (end node outcome: 'refused', same file) is now dispatchable in lane order. The dev-filed #15713 (nodes[].id uniqueness) stays bare for triage.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions