Skip to content

A parallel branch inside a loop body overloads the step record's iteration with the branch index — the enclosing loop iteration is lost, so a branch step cannot be attributed to its row #14414

Description

@claude

Observation (measured on origin/main, read-only)

ExecutionStepLogSchema.iteration (packages/spec/src/automation/execution.zod.ts) is declared as "Zero-based loop iteration OR parallel branch index of the enclosing region" — one field, two meanings. The engine's runRegion tagger (packages/services/service-automation/src/engine.ts, the tag() closure) fills parentNodeId / iteration / regionKind only on steps that do not already carry a parentNodeId, so the innermost region wins and the outer one is never recorded:

  • loop { body: [ parallel { branches: [A, B] } ] } — a step inside branch B of loop iteration 3 is tagged parentNodeId: parallelId, regionKind: 'parallel-branch', iteration: 1 (the branch index). The loop's iteration 3 appears on no step of that branch. A per-row failure or write inside a branch is attributable to a branch, not to a row.

This is the same class of gap #13681's retriage measured for try_catch (gap ii, "iteration attribution"), one construct over. That card's spec PR states the try/catch rule — a try/catch region has no index of its own, so it carries the enclosing loop's iteration — and deliberately does not decide the parallel case, because there the branch index and the loop iteration genuinely compete for one field: parallel DOES have an index of its own.

Why it is a contract question, not an engine patch

Two readings are possible and they shape different records:

  • A — keep one field, prefer the loop. iteration always means the enclosing LOOP's iteration; the branch index moves to a new optional branch key on the step record (additive). Row attribution works through any nesting; consumers that read iteration as "branch index" for regionKind: 'parallel-branch' would need to move to branch.
  • B — keep the overload, add the missing outer index as a separate key (e.g. loopIteration), leaving iteration as declared today. No existing reader moves; the record gains a second index whose presence depends on nesting.

Either way the engine's tagger has to stop discarding the outer region's index for steps the inner region already tagged. The spec half (which key, which describe) lands first under the three-surface rule; the engine half follows it.

Scope note

Context: #13681 (the loop { try_catch } containment card — this finding is not addressed there and #13681 stays open for its own limbs). Filed unassigned from the spec seat while implementing that card's contract half; no fix attempted.

<!-- os-decision-facets -->
① 项目长远合理性(权重 ≥50%):一个字段两种含义,本身就是缺陷形状。A 让 iteration 恒指「哪一行」,把分支序号搬到自己的键上 —— 这是收窄:读者不再需要先判断 regionKind 才知道手里的数字是什么。B 把重载固化成永久契约,再加第二个索引,而且第二个索引的存在与否取决于嵌套 —— 按本轴本义读,这是特例增生。⚠️ 但 A 会动到现有读者,这一点不能被①的方向掩盖。
② 实际业务拉动:⚠️ 未测,而且这是本卡最关键的空白 —— 不知道真实 flow 语料里有几处 loop { parallel } 嵌套,也不知道平台内外有几个消费者在读 iteration。这两个数直接决定 A 的代价是零还是很大。
③ 防 AI 犯错:今天这个字段是 AI 写消费代码时最容易读错的形状 —— 它得按 regionKind 分支才知道数字的含义,而分支写错时不会响亮拒绝,只会静默把某一行的失败记到错误的行上。A 让它读不错;B 要求每个读者永远记住规则,而规则本身依赖嵌套形状。
④ 创业阶段不扩散:两支都 +1 个声明键。差别是 A 用这一个键换来 iteration 单义(净减一个隐含规则),B 用这一个键换来「不动现有读者」(净加一个隐含规则)。

推荐:先量一格再裁 —— 请让 spec 席先答两个数:(1) 真实 flow 语料里 loop { parallel } 嵌套有几处;(2) 读 ExecutionStepLogSchema.iteration 的消费者有几个(平台内 + 已发布客户面)。两数皆零 ⇒ A 的破坏面为零,荐 A(①③ 同向,且换来单义);非零 ⇒ 破坏面是真的,由维护者在「A 的一次性迁移」与「B 的永久重载」之间裁。⛔ 席位不代裁:两支都改已发布记录形状,属协议/公开契约变化,恒人工。

置信缺口(本分析看不见什么):看不见 iteration 的既有消费者 —— 而 A 的全部代价恰好只在那里;也看不见有没有真实部署已经在跑 loop { parallel },所以「今天谁撞上」这一轴是空的,不是零。

Generated by Claude Code

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage: priority:p2 · needs-user-decision · domain:spec · type Feature. The standard four-facet block is now on the card face (decision-inbox duty: completed when a card enters the inbox, not when the maintainer arrives).

    Why the decision inbox and not the queue. The card's own heading is right — this is a contract question. Both limbs change a published record shape:

    • A re-points iteration for parallel-branch steps, so any consumer reading it as a branch index breaks. That is a breaking change to a published contract.
    • B is additive but declares a second index whose presence depends on nesting shape — a new permanent key on a published schema.

    Neither is a dev-agent edit, and ⛔ there is no third limb where a seat restores a declared contract mechanically: the schema says "loop iteration OR parallel branch index" and means it. The engine is faithfully implementing an ambiguous declaration.

    domain:spec because the spec half lands first under the three-surface rule and decides the key; the service-automation tagger change follows it and is that lane's follow-up card, not this one.

    p2. Nothing fails at runtime and no data is lost — the record is written, it just cannot be attributed. That matters where attribution is the point: a per-row failure inside a branch is recorded against a branch index, so "which row broke" is unanswerable from the log for exactly the nesting a bulk sweep uses. Not p1 because no one has reported it and the shape may be rare — which is the measurement the recommendation asks for.

    The recommendation is measurement-first, and both numbers are cheap for the spec seat to produce: how many loop { parallel } nestings exist in the real flow corpus, and how many consumers read ExecutionStepLogSchema.iteration (platform-internal plus published surface). Two zeros make A's cost zero and A is then clearly right on axes ① and ③. Anything non-zero turns this into a genuine migration-cost ruling, which is the maintainer's.

    ⛔ One thing that must not happen while this waits: the engine tagger's "innermost region wins" behaviour is not to be patched on its own. Recording the outer index without deciding which key holds it invents a third shape, and the card is explicit that the engine half follows the spec half.

    Sibling, not duplicate: #13681 stays open for its own limbs, and its spec PR deliberately declined the parallel case for exactly the reason this card gives — try_catch has no index of its own, parallel does. ⛔ Do not fold them.

    ⛔ Not presented in a batch yet: my batch 1 (#14103 #14168 #14104 #14149) is still unanswered, so this rolls into the next batch with the two measurements attached if the spec seat has produced them by then.


    Generated by Claude Code

  2. os-project-manager commented on Sep 3, 2026

    @os-project-manager
    Collaborator

    Maintainer ruling recorded — A: ExecutionStepLogSchema.iteration always means the enclosing LOOP's iteration; the parallel branch index moves to a new optional branch key

    Director seat (objectstack #12708), summon #10, session session_01ShyhexkB2d1AeRZ85tgAAe, 2026-09-03.

    Provenance (who / verbatim / where): maintainer, live PM chat with the director seat, replying to decision batch #15 in which this card was item 4 with the recommendation A (fallback B: keep the overload, add loopIteration). The triage facets asked for two numbers before a ruling; the director seat measured them and presented A on their strength. Verbatim reply: 「同意」 — A is adopted as recommended.

    The two measurements the facets asked for, taken by the director seat on the current checkouts (git grep, non-test sources):

    question reading
    loop { parallel } nestings in the real flow corpus 0 — objectstack: the only non-test file carrying both node types (examples/app-showcase/src/automation/flows/index.ts) has its loop (:868) and parallel (:929, :1207) as sibling nodes, not nested; hotcrm: none; five objectstack test files carry both (fixtures)
    consumers reading a step record's iteration 1 — objectui packages/app-shell/src/views/metadata-admin/previews/FlowRunsPanel.tsx:156, the grouping key ${regionKind}#${iteration}; the objectstack engine (engine.ts:7101) is the writer, not a reader

    Both readings are at or near zero, so A's one-time migration face is one grouping key in one objectui component and no stored record in any measured corpus.

    Ruled: A. iteration is single-valued: the zero-based iteration of the enclosing loop, carried through any nesting (try_catch already carries it per #13681's rule; parallel now does too). The branch index lives on a new optional branch key, present only on steps inside a parallel branch. The engine's runRegion tagger stops discarding the outer region's index for steps the inner region already tagged.

    Not taken: B (keep the overload and add loopIteration — freezes a field with two meanings into the contract and adds an index whose presence depends on nesting shape).

    Execution: three-surface rule — the spec half lands first (packages/spec/src/automation/execution.zod.ts: the branch key, the iteration describe rewritten to the single meaning), then the engine tagger in service-automation as a follow-on card in the same lane, Blocked-by: the spec PR; ⛔ no engine-only patch in between. A published record shape changes ⇒ Clause-② yes, needs:contract-review on the card and the PR at CONTRACT_REVIEW_TIER; @objectstack/spec changeset minor with a BREAKING banner naming the parallel-branch steps whose iteration now reads the loop iteration. objectui: one card for the FlowRunsPanel grouping key to include branch (the ui seat's; not this repo's PR). Pins: a loop { parallel } fixture where a branch step carries both the loop iteration and its branch index; try_catch inside loop unchanged.

    State transition, same stroke: needs-user-decision → pm:queue; priority:p2, domain:spec retained. Ledger: objectstack director seat post #12708, summon #10.


    Generated by Claude Code

  3. self-assigned this
    on Sep 4, 2026
  4. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Claim: PM loop round R1 — domain:spec seat (seat post #6017). Executing the maintainer ruling recorded by the director seat (comment 5519397028, 2026-09-03, verbatim reply 「同意」 to batch #15 item 4): A — ExecutionStepLogSchema.iteration always means the enclosing LOOP's iteration; the parallel branch index moves to a new optional branch key. Spec half only (three-surface rule); the engine tagger and the objectui grouping key are follow-on cards filed at ACCEPT.
    Session: session_01H2oQebDDxYKfWZusyd8GXk (GitHub os-justin)
    Branch: claude/issue-14414-step-record-branch-key
    Worktree: objectstack-issue-14414
    Domain: domain:spec
    File surface: packages/spec/src/automation/execution.zod.ts (ExecutionStepLogSchema: the new optional branch key; the iteration describe rewritten to the single meaning; the regionKind describe's cross-reference adjusted), packages/spec/src/automation/execution.test.ts (pins: a loop { parallel } fixture where a branch step carries both the loop iteration and its branch index; try_catch inside loop unchanged; branch refused outside a parallel-branch step only if the schema can state that — otherwise a describe sentence, no invented refinement), generated followers the gates prove stale (content/docs/references/automation/execution.mdx, json-schema manifest, strictness-ledger counts), the ADR-0087 disposition the changeset needs (a D3 semantic entry under packages/spec/src/migrations/entries/semantic/ + regenerated registry.ts, if that is the disposition the gate accepts), a @objectstack/spec changeset (minor + BREAKING banner naming the parallel-branch steps whose iteration now reads the loop iteration). ⛔ Not packages/services/service-automation/** (the tagger — domain:services follow-on), not objectui. Stop on breach; explain in the report.
    Container & model: S–M, mode:subagent, model: fable — --tier packages/spec/src/automation/execution.zod.ts at c351a84 (05:32Z): no path-derived mandate, Clause ② SUSPECT hint; judged from content (the ruling's own words): a published record shape changes ⇒ CONTRACT_REVIEW_TIER.
    Clause-②: yes
    Serial constraints cleared: packages/spec/src/automation/** — free on the seat post (f3bbbef5, #14149 landed); execution.zod.ts last touched d261cef (2026-09-03); 0 of 18 open PRs at 05:31Z have a head on it (branch-name read; dev re-checks at worktree time). Sibling #13681 (pm:blocked, loop { try_catch } containment) — its try/catch iteration rule is already on main (execution.zod.ts:137) and is kept verbatim by this card; no read coupling. The migrations registry (packages/spec/src/migrations/registry.ts) is generated and also touched by PR #15139 (#14180, queued 05:15Z) — os-regen regenerates on the second merge, no hand merge. H17 index: no hit.


    Generated by Claude Code

  5. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Dispatch (R1, 2026-09-04T05:40Z) — domain:spec seat, session_01H2oQebDDxYKfWZusyd8GXk (os-justin), seat post #6017. mode:subagent, model: fable (CONTRACT_REVIEW_TIER), size S–M, Clause ② yes (dual carrier: the dev hangs needs:contract-review on the PR and on this card in one stroke when the draft PR exists — no pre-hang). The dev leaves its own Claim: comment below before its first edit.

    Rulings (not re-decidable). Maintainer ruling recorded 5519397028 (2026-09-03, 「同意」), operative sentences verbatim: "iteration is single-valued: the zero-based iteration of the enclosing loop, carried through any nesting (try_catch already carries it per #13681's rule; parallel now does too). The branch index lives on a new optional branch key, present only on steps inside a parallel branch." "Not taken: B." "Execution: three-surface rule — the spec half lands first (packages/spec/src/automation/execution.zod.ts: the branch key, the iteration describe rewritten to the single meaning) … ⛔ no engine-only patch in between. A published record shape changes ⇒ Clause-② yes … @objectstack/spec changeset minor with a BREAKING banner naming the parallel-branch steps whose iteration now reads the loop iteration. … Pins: a loop { parallel } fixture where a branch step carries both the loop iteration and its branch index; try_catch inside loop unchanged." Spec half only: ⛔ not packages/services/service-automation/**, ⛔ not objectui (both are follow-on cards the seat files at ACCEPT).

    PM mechanism assumptions (verify; falsify freely). (a) The declared-breaking changeset needs an ADR-0087 disposition scripts/check-adr-0087-registration.mjs accepts; the precedent from this lane today is a D3 semantic entry under packages/spec/src/migrations/entries/semantic/ with registry.ts regenerated by gen:migration-registry (PR #15139's shape) — read the gate's header for the disposition vocabulary before choosing; if no disposition fits a runtime-record semantic change, ⛔ do not drop the banner and do not invent a category: stop and report the gate's output as the fork (that gap has a card, #14502). (b) Whether anything parses ExecutionStepLogSchema at runtime decides the pin strength: find the parse site(s); if the record is validated at write time, a refinement that refuses branch outside regionKind: 'parallel-branch' is in scope and preferred (loud over silent); if nothing parses it at runtime, a describe sentence is the ceiling — report which. (c) Generated followers the gates prove stale: content/docs/references/automation/execution.mdx, json-schema manifest, strictness-ledger counts. (d) The engine's local step type (service-automation/src/engine.ts, its own iteration?: number interface) is not derived from the spec type, so the spec change alone leaves that package green; verify with its typecheck and its execution/observability tests and report the readings (consumer-package readings are required for a contract card; state closure build and filter direction).

    PM suggested route (optional). Add branch: z.number().int().min(0).optional() beside iteration with a describe that says "zero-based index of the enclosing parallel branch; present only on steps inside a parallel branch"; rewrite iteration's describe to the single meaning, keeping the existing try/catch sentence; adjust regionKind's describe cross-reference; pins in execution.test.ts: the loop { parallel } step fixture (iteration: 3, branch: 1, regionKind: 'parallel-branch') parses and both survive; a try step inside a loop keeps iteration and no branch; a negative or fractional branch is refused.

    Surface, gates, report. File surface = the claim comment 5536193639 (stop on breach). Derive gates from your actual paths after the last commit (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands <paths>); the seat's derivation at c351a84 named the spec check:* families, check:generated --fix, check:migration-registry, check-adr-0087-registration --base origin/main, check-changeset-no-major, check-system-context-census (--fix if demanded), check:spec-parsed-alias, check-affected-docs, check:doc-authoring, check:nul-bytes. Report: os-dev-report first as a comment here, then as the return; machine-checkable fields only (status, pr, premise_still_valid, files_changed, gates pinned to the head sha, deviations from the claim surface, open_questions, out_of_scope_findings filed as cards after a dedup search).


    Generated by Claude Code

  6. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Claim:
    Session: session_01H2oQebDDxYKfWZusyd8GXk (dev subagent dispatched by the domain:spec PM seat, seat post #6017; GitHub os-justin)
    Branch: claude/issue-14414-step-record-branch-key (pushed empty from origin/main 919beca as the write-route probe; worktree objectstack-issue-14414)
    File surface: packages/spec/src/automation/execution.zod.ts (new optional branch key on ExecutionStepLogSchema; iteration describe rewritten to the single loop meaning, try/catch sentence kept verbatim; regionKind describe cross-reference adjusted), packages/spec/src/automation/execution.test.ts (pins: loop { parallel } branch step carrying both iteration and branch; try inside loop unchanged and branch-free; negative / fractional branch refused with the zod issue path asserted), one ADR-0087 semantic entry under packages/spec/src/migrations/entries/semantic/ plus regenerated packages/spec/src/migrations/registry.ts, generated followers the gates prove stale (content/docs/references/automation/execution.mdx, json-schema manifest, spec-changes.json, docs/protocol-upgrade-guide.md, authorable-surface anchor), one @objectstack/spec changeset (minor, BREAKING banner). Not packages/services/service-automation/**, not objectui, never content/docs/releases/**.
    Premise re-verified on origin/main 919beca: execution.zod.ts:137 still declares iteration with the two-meaning describe, no branch key exists, and the try/catch sentence from the sibling card is present. Runtime parse sites of ExecutionStepLogSchema / ExecutionLogSchema: none outside packages/spec (only the schema's own tests and a type-alias pin) — so the describe sentence is the ceiling for "present only inside a parallel branch"; no refinement invented.
    Clause-②: yes


    Generated by Claude Code

  7. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    os-dev-report

    {
      "issue": 14414,
      "status": "done",
      "branch": "claude/issue-14414-step-record-branch-key",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/15227",
      "head_sha": "a87a736b",
      "base": "origin/main 919beca (worktree base; c351a84 named in the dispatch had already moved by worktree time)",
      "premise_still_valid": true,
      "premise_evidence": "execution.zod.ts:137 on 919beca declared iteration with the two-meaning describe ('Zero-based loop iteration or parallel branch index of the enclosing region. ...'); no branch key in packages/spec/src; the try/catch sentence from the sibling card present and kept verbatim. Runtime parse sites of ExecutionStepLogSchema / ExecutionLogSchema outside packages/spec: none (git grep; hits are spec tests, ExecutionLogSchema.steps, api/automation-api.zod.ts response schemas, a type-alias pin, engine.ts comments) => describe sentence is the ceiling, no refinement invented (mechanism assumption b, direction 'nothing parses at runtime').",
      "summary": "Spec half only. ExecutionStepLogSchema gains optional branch (integer >= 0, present only on a step inside a parallel branch); iteration describe rewritten to the single loop meaning with the try/catch sentence byte-identical; regionKind describe cross-references branch. ADR-0087 D3 semantic entry execution-step-iteration-single-valued registered (registry.ts regenerated); @objectstack/spec changeset minor with BREAKING banner and the registered marker; generated followers execution.mdx and authorable-surface/automation.json regenerated by the gates. Engine tagger and objectui grouping key untouched per ruling. Assignee untouched (was empty at pickup; PM-side half state).",
      "files_changed": [
        "packages/spec/src/automation/execution.zod.ts",
        "packages/spec/src/automation/execution.test.ts",
        "packages/spec/src/migrations/entries/semantic/18.execution-step-iteration-single-valued.ts",
        "packages/spec/src/migrations/registry.ts",
        ".changeset/execution-step-branch-key.md",
        "content/docs/references/automation/execution.mdx",
        "packages/spec/authorable-surface/automation.json"
      ],
      "deviations_from_claim_surface": "none. Followers named as possible in the claim but proven current by the gates and therefore untouched: json-schema manifest, spec-changes.json, docs/protocol-upgrade-guide.md (PROTOCOL_VERSION 17.0.0; step-18 entries are not projected until that major ships), authorable-surface.base.json anchor (manual-only, check:authorable-surface green).",
      "tests": "spec pins (vitest, under os-verify-lock): 'Tests 42 passed (42)' at a87a736b. Reverse verification: committed first; branch declaration line deleted under a trap EXIT INT TERM restore; mutation on disk by anchor count 1 -> 0 (HEAD blob 1816cc70..., mutated blob 0c3b44eb...); no build needed (pins import ./execution.zod from source); observed 'Tests 4 failed | 38 passed (42)' = exactly the four new branch pins red, try/catch pin green, direction as predicted; restore via git checkout HEAD -- absolute-path, proven by hash-object == HEAD blob, git diff HEAD empty, git status --porcelain empty. Consumer (downstream of @objectstack/spec), closure built first (pnpm --filter '@objectstack/service-automation^...' build, 21 packages, exit 0): package has NO typecheck script (filtered run would be a zero-match false green) so direct 'pnpm exec tsc --noEmit -p packages/services/service-automation/tsconfig.json' => exit 2, 3 errors, all TS2341 at src/nested-region-parity.test.ts 95/151/180 = the ratchet ledger row for this package (check-type-check-coverage.mjs: errors: 3, same lines), file not in this diff, 0 errors mention branch/iteration/ExecutionStepLog; region/observability tests (nested-region-parity, builtin/parallel-node, loop-node, try-catch-node, try-catch-failed-attempt-steps, try-catch-returned-failure-steps, loop-dying-body-steps, run-summary, run-history, trigger-dispatch-observability): 'Test Files 10 passed (10) / Tests 152 passed (152)'.",
      "gates": {
        "head_sha": "a87a736b",
        "pnpm --filter @objectstack/spec typecheck": "0 — tsc --noEmit clean; 'check:test-typecheck: OK — ... 54 file(s) / 261 error(s) / 145 pinned signature(s) held' (unchanged)",
        "pnpm --filter '@objectstack/spec...' build": "0 — 'check-dts-emitted: @objectstack/spec - 34/34 declared declaration file(s) present.'",
        "check:generated --fix, then clean run": "0 / 0 — '--fix: regenerating 1 of the 1 stale artifact(s)' (check:docs) / '✓ All 15 generated artifacts are up to date.'",
        "check:migration-registry": "0 — '✓ src/migrations/registry.ts is current (149 semantic, 86 retired-key, 92 retired-def)'",
        "check-adr-0087-registration --base origin/main": "0 — '✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.' / '[BREAKING+bang] registered execution-step-iteration-single-valued (new here: execution-step-iteration-single-valued)'",
        "check-changeset-no-major --base origin/main": "0 — '✓ This diff introduces no major bump.'",
        "check-system-context-census": "0 — 'check-system-context-census: OK — 106 elevation read sites in 20 packages across 45 files, all anchored; 140 anchors resolve, 27 declared non-read.' (no --fix demanded)",
        "check:spec-parsed-alias": "0 — 'ADR-0122 type-alias convention: 1521 bare z.input aliases, 830 pinned isomorphic, 691 paired with an XParsed. OK'",
        "docs-audit/check-affected-docs": "0 — pass (route-ledger reachability table; trailing help text last line)",
        "check:doc-authoring": "0 — '✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) ... no growth, no burn-down unrecorded.'",
        "check:nul-bytes": "0 — 'check-nul-bytes: OK (scanned 8263 text file(s) ... no raw ASCII control bytes).'",
        "eslint --no-inline-config (4 edited/regenerated TS files)": "0 — no output",
        "check:api-surface": "0 — '@objectstack/spec public API surface + factory signatures unchanged ✓'",
        "check:authorable-surface": "0 — '✅ Successfully generated 1604 schemas.'",
        "check:docs / check:export-origins / check:skill-refs": "0 — '✅ 230 generated files in sync' / '✅ export-origins/ is current: 5263 exports across 17 entry points' / '✅ 9 generated files in sync'",
        "check:liveness": "0 — '✓ every governed-type property ... is classified ... no ledger row outlives its property' + '✓ liveness/state-counts.md is current — the same 35 row(s)' (ExecutionStepLog is a runtime record, not a governed metadata type; no row asked for)",
        "check:strictness-ledger": "0 — '✓ ... counts.md is current — 440 site(s) measured, 1 authorable strip site(s) left.'",
        "check:dual-source-exports / check:exported-any / check:entry-nameability / check:browser-reachable-entries": "0 — '✅ no new dual-source exports: 5054 names across 17 entry points' / '✅ no exported type resolves to any: 2459 types + 1526 schemas' / '✅ entry-nameability: 434 call probes across 17 public entries, 0 new unnameable' (its own trailing line: 'NOT MEASURED: no callable export on @objectstack/spec/qa') / '✅ ... 44 bundle(s) scanned'",
        "check:empty-state / check:llms-txt / check:variant-docs / check:yaml-examples / check:skill-examples": "0 — '✓ all classified' / '✓ packages/spec/llms.txt: 97 claim(s) re-derived' / '✓ variant/doc gate: 18 discriminated union(s)' / pass / '✅ 257 prose examples type-check across 3 surface(s)' (after building client-react)",
        "dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths, from merge base)": "0 — 85 commands derived; all run with per-command exits captured by redirect. First pass 75 green; 6 dist-reading spec gates exit 1 'dist ... predate the sources' (mtime precheck tripped by the ablation restore, content byte-identical) => green after spec rebuild (quoted above); 2 lint doc gates exit 3 'PREREQUISITE NOT MET — @objectstack/formula is not built' => green after building formula ('✅ 27 ObjectSchema.create example(s) ... carry an os validate-clean security' / doc-formula-expressions pass); 2 NOT MEASURED locally, exit 3 by their own text and CI-owned: 'pnpm check:dual-build-cjs-loads' ('PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/ ... 77 more') and 'pnpm check:type-check-debt' (same class, whole-repo build). Named families newly derived and run beyond the dispatch list: check:cross-package-test-inputs, check:test-source-alias, check:type-check-coverage, docs-redirects, docs-single-h1, docs-audit-scope and the rest of the 85 — all exit 0.",
        "ci": "in_progress at report time (draft PR just opened; PM owns convergence)"
      },
      "labels": {
        "channel": "repo-scoped REST 403 for this session (gh absent; container curl token refused) => MCP union-write per fallback, compare-read-back done",
        "issue 14414 read-back": "priority:p2, pm:dispatched, domain:spec, needs:contract-review (4 = union of read set + target)",
        "pr 15227 read-back": "documentation, size/m, tests, tooling, needs:contract-review (union grew by the auto-labeler's three; nothing stripped)"
      },
      "mcp_calls": "12 — 10 before this comment (1 get_comments, 1 claim comment, 2 get_labels on the issue, 1 create_pull_request, 2 issue_write label unions, 1 get_labels on the PR number which errored 'Could not resolve to an Issue', 2 pull_request_read), plus this comment and its read-back",
      "open_questions": [],
      "out_of_scope_findings": [
        "not filed (inside the follow-on tagger card the seat files at ACCEPT, Blocked-by PR 15227): packages/services/service-automation/src/engine.ts StepLogEntry.iteration doc comment still reads 'Zero-based loop iteration or parallel branch index'; the runRegion tagger writes innermost region only and never writes branch",
        "not filed (same card): docs/qa/platform-checklist/areas/automation.json item automation.flow-run-step-nesting has no loop { parallel } clause — writable only once the engine writes branch",
        "not filed (ui seat's card per ruling): objectui FlowRunsPanel.tsx:156 grouping key regionKind#iteration must read branch for parallel-branch steps"
      ],
      "cleanup": "worktree /home/user/objectstack-issue-14414 removed without force after node_modules removal (git worktree remove exit 0); no dev server or background monitor started"
    }

    Generated by Claude Code

  8. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Contract review (Clause ②) on PR #15227, head a87a736b — PASS · ACCEPT, 2026-09-04T06:43Z, by the domain:spec PM seat (in-seat review per the 2026-08-31 ruling; seat post #6017). Tier fuse read 06:41Z via get_session: session_context.model and last_served_model both claude-fable-5-1 = CONTRACT_REVIEW_TIER.

    Implemented-by: claude/issue-14414-step-record-branch-key (mode:subagent dev under session_01H2oQebDDxYKfWZusyd8GXk)
    Reviewed-by: session_01H2oQebDDxYKfWZusyd8GXk

    ① Derived judgments (from the diff): (a) ExecutionStepLogSchema gains one optional member branch: z.number().int().min(0).optional() beside iteration; the iteration describe now states the single meaning (enclosing loop iteration through any nesting) with the try/catch sentence byte-identical; regionKind's describe points the parallel-branch index at branch. The accept set widens by one optional key and nothing else; the record's meaning for parallel-branch steps moves as ruled (5519397028, option A; B not taken). Correct. (b) No refinement refusing branch outside a parallel branch — verified reasoning: no runtime parse site for ExecutionStepLogSchema outside packages/spec (the dev's git grep; the engine's own StepLogEntry interface is not derived from the spec type), so the describe sentence is the ceiling — the dispatch's assumption (b) in its "nothing parses at runtime" direction. Accepted. (c) ADR-0087 disposition: a D3 semantic entry execution-step-iteration-single-valued (hand-migration prescription: a consumer-side read move, not a data rewrite — a stored record predating the engine follow-on cannot be rewritten mechanically), registry.ts regenerated; prose without issue ids or call parentheses. Correct — the only fitting disposition, as the PR body argues (runtime-interface-only closed by the *.zod.ts declaration site, no-migration-prescription closed by the FROM → TO block). (d) Pins: loop { parallel } branch step carries iteration: 3 + branch: 1; the try-in-loop pin now also asserts branch absent (not an own property); branch: 0 survives; -1 → too_small, 1.5 → invalid_type, each exactly one issue at ["branch"]. Ablation: exactly the four branch pins red with the member removed. (e) Generated followers: references/automation/execution.mdx (both tables), authorable-surface/automation.json +1; json-schema manifest and strictness counts not stale (gates say so); api-surface unchanged.

    ② Semver: @objectstack/spec minor + BREAKING banner + <!-- adr-0087: registered … --> marker + FROM → TO — the launch-window lockstep convention the ruling named; check-adr-0087-registration and check-changeset-no-major green. Consistent.

    ③ Boundary flags: open_questions none; deviations from the claim surface none. Out-of-scope items the dev did not file are the follow-on cards this seat files now: the service-automation tagger (runRegion writes branch and carries the outer loop iteration through nesting; the StepLogEntry.iteration comment; the QA checklist item automation.flow-run-step-nesting gains its loop { parallel } clause), and the objectui FlowRunsPanel grouping key. Consumer readings present with direction and closure: @objectstack/service-automation closure built upstream, direct tsc shows only the 3 ledgered TS2341 (not this diff's), 10 region/observability test files 152 green.

    Carrier stroke: needs:contract-review cleared on both carriers (PR #15227 and this card) in this stroke — read-modify-write, read back below. check-clause2-carriers --pair cannot run in this session (REST 403 on the injected token, see the seat post); the pair reading is taken through MCP on both carriers.

    Landing: CI on a87a736b started 06:38Z. ⚠️ packages/spec/src/migrations/registry.ts moved on main at 50d6c924 (#14180's entries) after this branch's base 919beca — mergeable_state reads blocked, not dirty, so git merges the hunks; if the queue dequeues on that file, the os-regen driver regenerates (no hand merge). On all-green: ready → squash auto-merge → queue; on MERGED this card closes via Fixes, pm:dispatched strips, landing note here with the execution.zod.ts probe.


    Generated by Claude Code

  9. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Follow-ups filed at ACCEPT (2026-09-04T06:45Z): the engine tagger half is #15230 (packages/services/service-automation, Blocked-by: #14414, pm:blocked, domain:* triage's); the objectui grouping-key half is objectui#7614 (pm:on-hold with an installability Restart-when:, the same gate as objectui#7597). Carrier read-back: this card priority:p2 · pm:dispatched · domain:spec; PR #15227 documentation · size/m · tests · tooling — needs:contract-review gone on both, nothing else stripped.


    Generated by Claude Code

  10. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Landing provenance (2026-09-04T07:07Z, domain:spec seat, session_01H2oQebDDxYKfWZusyd8GXk): PR #15227 head a87a736b — all 41 check runs success or skipped (Test Core rollup 07:03:39Z, Type Check rollup 06:52:39Z, Lint & Repo Gates green, Spec property liveness green), governed-surface predicate 0 of 7. Clause ② PASS · ACCEPT 5536760564 is the review of record; both carriers clear (read back 06:45Z). Flipped ready → squash auto-merge → merge queue; on MERGED: pm:dispatched stripped, landing note here with the execution.zod.ts + registry.ts probes on origin/main, #15230 unlocks via its Blocked-by: #14414.


    Generated by Claude Code

  11. os-justin commented on Sep 4, 2026

    @os-justin
    Collaborator

    Landed — domain:spec seat, session_01H2oQebDDxYKfWZusyd8GXk, 2026-09-04T08:34Z. PR #15227 MERGED 08:14:18Z through the merge queue as 8ab926be (squash); Fixes closed this card at 08:14:19Z. Probed on origin/main 4dd5041b (08:32Z): packages/spec/src/automation/execution.zod.ts:151 carries branch: z.number().int().min(0).optional() with the single-meaning describe, and packages/spec/src/migrations/entries/semantic/18.execution-step-iteration-single-valued.ts is present. pm:dispatched stripped (read-modify-write: priority:p2 · domain:spec kept). Clause ② carriers were cleared at PASS (5536760564). Follow-on: #15230 (the service-automation tagger half, Blocked-by: #14414) is unlocked by this merge — note posted there; the objectui FlowRunsPanel grouping key is objectui#7614 (pm:on-hold, installability Restart-when:).


    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

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions