Skip to content

Commit a36914b

Browse files
huangyiireneclaude
andauthored
docs(adr): ADR-0090 D10 rule 4 — mark the run id undelivered, with its reopen condition (#19653)
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 (27197b6) 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](https://claude.ai/code)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 2ad2382 commit a36914b

1 file changed

Lines changed: 13 additions & 0 deletions

File tree

‎docs/adr/0090-permission-model-v2-concept-convergence.md‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,19 @@ alias tax on every API.
443443
>
444444
> Ruling: director seat, batch #139 item 1, maintainer 「同意」 2026-09-16 — letter **A**.
445445
446+
> **Status (2026-09-20, #18374) — rule 4's third part is NOT delivered.** `performed_by` and
447+
> `on_behalf_of` ship (#18371); no **run id** is stamped and none is pending — no agent-run
448+
> concept exists on the request path (the MCP door is explicitly stateless), so no
449+
> server-constructed identifier grouping one agent task exists to carry, and the two correlation
450+
> ids that do travel it (`traceId` from the client's `traceparent`, `requestId` preferring the
451+
> client's `X-Request-Id`) are caller-controlled, which this envelope refuses in writing:
452+
> 「Server-constructed only, never client-supplied」. **Reopens when** task-scoped, time-boxed
453+
> agent grants land (the `agent` bullet above): the **grant id is the run id**, and the successor
454+
> wires it as the `performedBy.runId` sibling key —
455+
> `packages/spec/src/kernel/execution-context.zod.ts#performedBy` is a one-key object precisely so
456+
> a sibling can be added without re-shaping a shipped field; it reserves the room, ⛔ not the name.
457+
> Ruling: director seat, batch #195 item 2, maintainer 「同意」 2026-09-20 — letter **C**.
458+
446459
### D11 — OWD gains an external dimension (`externalSharingModel`)
447460

448461
Portal and partner scenarios need the Salesforce insight: internal and external record baselines

0 commit comments

Comments
 (0)