Skip to content

docs(adr): ADR-0090 D10 rule 4 — mark the run id undelivered, with its reopen condition - #19653

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-18374-adr-0090-d10-run-id-status-line
Sep 22, 2026
Merged

hotlong merged 1 commit into
mainfrom
claude/issue-18374-adr-0090-d10-run-id-status-line

Conversation

@huangyiirene

@huangyiirene huangyiirene commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #18374

维护者速读(草稿)

改了什么 —— ADR-0090 D10 的 agent 规则 4 要求每次 agent 写入记三样:谁干的、代谁干的、哪一次运行。前两样已在产,第三样没有。本 PR 在该决策自己的注记尾部(规则 4 已经指过去的那处)加一条带日期的状态行 —— 13 行、一个文件 —— 写明「运行 id 未交付」、为什么、以及它什么时候该回来:任务级 agent 授权落地时,授权 id 就是运行 id。⛔ 规则 4 自己那句话一个字没动。

为什么改 —— 执行裁决评论 5749155184(总监席 batch #195 item 2,letter C,维护者「同意」2026-09-20)。一条声明了却发不出来的契约,比一条写明「暂缓」的契约更糟;ADR-0049 的诚实状态那一档要求把它标成未交付,而不是随手铸一个「叫运行 id 的请求 id」。

风险与代价(含回滚) —— 纯文档:零运行时、零 spec、零发布面。回滚 = revert 这一个提交。真正的代价是未来读者会看到一条明写「未交付」的规则 —— 这正是目的,而不是副作用。

席位意见 —— 技能席 1(session_01Wnstp2kTth7sGXfr8fXypc)已按 GitHub 与拉取的 head 495929b 复核:13 行与裁决 5749155184 的五项内容逐一对应(已交付对、run id 未交付、两条 why、reopen 条件、裁决引用),规则 4 原句一字未动,注记落在规则 4 自己指向的注记尾部;check-adr-symbol-anchors、check-adr-links、check:adr-anchors 在本席自己的 worktree 复跑均 exit 0,check-governed-merges --pr 19653 读 GOVERNED Tier H(13 行)。两处对派发词的修正本席认可:docblock 只留位、未命名 runId,注记如实写「留位不留名」;+13 行超出派发词的 ≤ +5 系派发词自相矛盾(内容清单与行数上限在 100 列换行下不可能同时成立),内容优先。建议合并;Fixes #18374 合入即关卡,pm:dispatched 由本席在合入时摘。

你要做的(一个动作) —— 读那 13 行,认可就手工合并。docs/adr/** 是 Tier H 受管面,本 PR 保持 draft,⛔ 没有 AI 席位可以代你合、代你入队或给它挂 auto-merge。

Clause-②: no

What landed

One dated status note in docs/adr/0090-permission-model-v2-concept-convergence.md — 13 lines added, 0 removed, 1 file. It sits in the decision's own note tail, immediately after the 2026-09-16 note that rule 4's own sentence already points readers at ("see the 2026-09-16 note at the end of this decision"), so both amendments to rule 4 now live in one place, in date order. Rule 4's sentence is byte-unchanged.

The note states, in the ruling's order: performed_by and on_behalf_of ship (#18371); no run id is stamped and none is pending; why (no agent-run concept on the request path — the MCP door is explicitly stateless — so no server-constructed identifier grouping one agent task exists to carry, and the two correlation ids that do travel that path, traceId from the client's traceparent and requestId preferring the client's X-Request-Id, are caller-controlled, which the envelope refuses in writing); the reopen condition (task-scoped, time-boxed agent grants land ⇒ the grant id is the run id ⇒ a successor wires performedBy.runId); and the ruling reference in the file's own Ruling: form.

Two measured corrections to the dispatch's premises

The shipped docblock reserves the ROOM, not the NAME. packages/spec/src/kernel/execution-context.zod.ts#performedBy reads verbatim: "A one-key object rather than a bare string so the API-key door (#18335, blocked on this carrier) can name its own identifier as a sibling key if it is ruled an agent, without re-shaping a field that already shipped." It reserves a sibling-key extension point and names the API-key door as the motivating case; it never names runId. The status note is worded to match what is actually reserved and says so explicitly ("it reserves the room, ⛔ not the name") — writing it any other way would have put a fresh declared-but-absent key into an ADR whose whole point is that class of defect.

The line budget could not hold the enumerated content. The dispatch's suggested route asked for net ≤ +5 physical lines and enumerated five required contents; at this file's 100-column wrap those two cannot both hold (the content is ~1,150 characters ≈ 12 wrapped lines). Content won, lines were minimised: 13 added lines, every one of them ≤ 100 columns, no line removed, nothing else in the tree touched.

Gates

Derived mechanically, not recalled: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths — the script took its own change set from the merge base), 19 families. All 19 run, all exit 0, reconciled with --ran:

✓ dispatch-gates --ran: 19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero — all 19 recorded an exit code and none of them is 3).

Named readings from that set:

  • node scripts/check-adr-symbol-anchors.mjs :: exit 0 — ✅ check-adr-symbol-anchors: 2121 anchors across 140 records resolve
  • pnpm check:doc-authoring :: exit 0
  • pnpm check:adr-anchors :: exit 0
  • pnpm check:pm-governed-merges :: exit 0
  • pnpm check:nul-bytes :: exit 0 (plus a hand scan of the inserted text for control bytes: no match)

One family needed a prerequisite: pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 — its own text says "Nothing was measured: this gate exited before running a single check", naming two unbuilt workspace packages. After pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint (through scripts/pm/os-verify-lock.sh, VERDICT command-exit 0) it re-ran at exit 0. The exit-3 reading is recorded as NOT MEASURED, ⛔ not as a failure.

Repo-wide scans (pnpm lint and the rest) are CI's run, not this PR's; the type-check lanes and the path-scheduled CI job the derivation printed as NOT MEASURED are CI's too.

Reverse verification — the new citation is actually checked

The note cites packages/spec/src/kernel/execution-context.zod.ts#performedBy, and check-adr-symbol-anchors resolves that spelling. A green gate over a corpus of 2121 anchors says nothing about this one, so it was ablated: node scripts/ablation-replace.mjs swapped the symbol for ablationProbeNoSuchSymbol (anchor hit 1 → 0, blob 27197b6cd90d → 978fa39ca89f, both verified on disk by the tool, not by an exit code), then re-ran the gate.

Predicted direction: turns red naming this line. Observed:

❌ check-adr-symbol-anchors: 1 finding(s) across 140 records.
  [unresolved-symbol] docs/adr/0090-permission-model-v2-concept-convergence.md:455  `packages/spec/src/kernel/execution-context.zod.ts#ablationProbeNoSuchSymbol`
      `ablationProbeNoSuchSymbol` has no declaration site or string-literal token in `packages/spec/src/kernel/execution-context.zod.ts`

Restore leg: ablation-replace: ok restored: blob == HEAD (27197b6cd90d) and 'git diff HEAD' is empty. Both legs ran from the committed state; no probe file survives. (A first attempt was refused by the tool because the replacement text still contained the anchor as a substring, so the anchor count did not drop — recorded here because that attempt measured nothing.)

Changeset — skip-changeset, measured

docs/adr/** publishes nothing. Measured rather than assumed: of 83 tracked package.json files, 70 declare files[] and none of them ships docs/; the 13 that declare no files[] are all private: true. The single files[] entry a docs|adr|** probe matched is packages/spec shipping src/**/*.zod.ts, which is not a docs path.

Landing posture — Tier H, stays draft

docs/adr/** is Tier H (人合) on the GOVERNED_SURFACES register in scripts/pm/check-governed-merges.mjs. This PR is opened draft and stays draft: the maintainer merges it by hand. ⛔ No AI seat merges it, queues it, arms auto-merge on it, flips it out of draft, or submits an approving review on it.

Acceptance notes

  • The zero-commit remote branch claude/issue-18374-run-id-entry-carrier (564ac2f170, the domain:spec seat's write-path probe) is still on the remote. It is a stale marker, not in-flight work. Comment 5753761987 measured both delete channels refused (git push --delete hung up, REST DELETE /git/refs/... answered 403), so this run did ⛔ not re-attempt the delete.
  • Observation only, ⛔ no card filed: the 2026-07 status blockquote at the top of D10 tracks "the agent audit-provenance gap" as a follow-up with no tracker number beside it, unlike the #2849 in the same sentence. The status note this PR adds is that follow-up's record, but the 2026-07 line was left untouched — amending it is outside this card's declared file surface, and it is not a defect, a contract violation or a metadata-authoring trap.
  • Concurrency re-checked at this branch's base: all 18 open PRs' file lists read; none touches docs/adr/0090-permission-model-v2-concept-convergence.md. origin/main had not moved from 80ca0b1c88, so no merge was owed.

Generated by Claude Code

…s reopen condition

Rule 4 declares `performed_by` + `on_behalf_of` + run id. The first two ship; the
run id has no carrier, and the ruling is to say so rather than mint one.

One dated status note in the decision's own note tail, beside the 2026-09-16 note
rule 4 already points at: the run id is not delivered, why (no agent-run concept on
the request path, no server-constructed identifier grouping one agent task, and the
two correlation ids that do travel it are caller-controlled, which the envelope
refuses in writing), and the reopen condition (task-scoped agent grants land ⇒ the
grant id is the run id ⇒ a successor wires `performedBy.runId`).

Rule 4's own sentence is unchanged. No spec or runtime change: the `performedBy`
docblock reserves the room for a sibling key, not the name, and nothing declares
`runId` today.

Claude-Session: https://claude.ai/code/session_01Wnstp2kTth7sGXfr8fXypc
Co-authored-by: Claude <noreply@anthropic.com>
@hotlong
hotlong marked this pull request as ready for review September 22, 2026 06:41
@hotlong
hotlong added this pull request to the merge queue Sep 22, 2026
Merged via the queue into main with commit a36914b Sep 22, 2026
44 checks passed
@hotlong
hotlong deleted the claude/issue-18374-adr-0090-d10-run-id-status-line branch September 22, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants