docs(agents): the PR body is the dev's one body write — a later correction is the seat's PATCH, and the Clause-② line rides the create - #18659
Conversation
…ction is the seat's PATCH, and the Clause-② line rides the create The four-write budget stays four. What changes is where the two body-scoped demands are met: the `Clause-②:` line the `Check Changeset` gate reads out of the PR body is copied from the claim comment into the body at creation, so the one `POST /pulls` already in budget carries it; and any body correction needed afterwards — a gate remedy, a mid-task correction, a truncated body — is named in the report and written by the seat, never `PATCH`ed by the dev. A write that did cross the budget is listed in `api_writes` with its reason, never omitted. Line-neutral (403 / 403): the two added rules are paid by two deletions — the `立不成 ⇒ …` line (its only live clause, never drop a finding silently, is folded into the finding rule; the rest was dead once the dev stopped filing) and the comment-footer reading that duplicated AGENTS.md's issue-comment paragraph, which this file already routes the reader to. Claude-Session: https://claude.ai/code/session_01Gqi43smmqjJ5sUrhfoPeKu Co-authored-by: Claude <[email protected]>
维护者速读(终稿)skills 席 改了什么 — 只改 为什么改 — 预算禁止 dev PATCH 正文,而 风险与代价(含回滚) — 受管 agent 定义,只改规则文本;不加脚本、不加门禁、不扩 dev 写面(席位本来就持有 席位意见 — 荐合 B。四轴一致:零额外写就关掉了实测的案例;预算保持机械的四端点清单,而不是每轮争论「什么算修补」;dev 少一个分支而不是多一个(正文 PATCH 正是平台读数里页脚会被吃/追加的那条路);不扩能力面。 你要做的(一个动作) — 认可 B 即 Approve 本 PR(或直接人工合并);席位随后按裁定 C 落地。要 A(抬预算到五笔或列豁免)则 Request changes,本席另起。 Generated by Claude Code |
Fixes #18443
Clause-②: no
Governed surface (
.claude/**): draft,skip-changeset, the maintainer's approval lands it. File surface:.claude/agents/os-dev.mdonly. Head1344eb515, based6137fd6c. Line-neutral: 403 / 403.The gap, re-measured on
origin/maind6137fd6c预算外零写,⛔ 不 PATCH 正文.Check Changeset(pr-automation.ymlchangeset-check) runsscripts/check-changeset-no-major.mjs --base MERGE_BASE, which reads the declaration fromgithub.event.pull_request.bodythroughreadClause2Line(imported fromscripts/pm/check-clause2-carriers.mjs; line-initial key,yes/noonly). The red is CONDITIONAL, not unconditional as the card states: a missing line fails only asnot-measured-material(exit 1) — apatchchangeset on a package the diff grew, none of them raised tominor+; with no candidate offender it isnot-measured-moot(exit 0), and the whole job is exempt underskip-changeset. The remedy when it does fail is still exactly one act, a body write, and the job isedited-subscribed so that write re-fires it without a push.d6137fd6cthe pm-dispatch template names the claim comment as the only carrier (SKILL.md:473Branch:、Clause-②:各占一行且行首, :476, :809 template), no committed text tells anyone to put it in the PR body, andos-dev.mddid not contain the tokenClauseat all (grep: 0). The seat's own closure lives in its dispatch prompts (this card's order says putClause-②: noin the PR body AT CREATION), not in the tree. So onorigin/mainthe gap was still the whole class, not only the residual.edited-subscribed, each cleared only by a body write —Check Changeset(theClause-②:line),Duplicate Fix Guard(aFixesline naming a card another open PR claims),Part-of Closing-Keyword Guard(a closing keyword besidePart of). Plus the two non-gate cases the card names: a seat's mid-task correction and a sanitizer-truncated body (platform-readings: the PR-body write side eats a trailing rule line plus footer while the call reports success; bare RESTPATCH /pullsappends a bare footer beside an existing session-URL one, +58 B).translation-target-unknownreadsapps[].navigationonly, so every locale key for a CONTRIBUTED navigation item (navigationContributions) is a false positive whose advice deletes a translation the runtime honours #18203's report comment5696114759lists write (4)PATCH /repos/.../pulls/18433with the words the card quotes.Shape chosen: B, with the line carried at creation
The card offers (A) an allowance for a declaration-repair
PATCH(budget five, or the repair write uncounted) and (B) the remedy moved off the dev onto the seat. This PR proposes B plus one prevention line: the dev's PR body is written once, in thePOST /pullsalready in budget, and that one write carries theClause-②:line copied from the claim comment; any correction the body needs afterwards is named in the report and written by the seat. The budget stays four; the dev neverPATCHes a body. It is a variant of B, not a third shape — the rules decision (who writes the correction) is B's.Four-axis reasons (the framework as the dispatch pasted it):
POST /pulls), and the gate reads the body, so carrying the line at creation closes the case lint:translation-target-unknownreadsapps[].navigationonly, so every locale key for a CONTRIBUTED navigation item (navigationContributions) is a false positive whose advice deletes a translation the runtime honours #18203 actually hit at zero extra writes. The residual (three gates + two non-gate cases) is a post-creation PR-state correction, and post-creation PR-state writes are already the seat's: the contract-review carrier moved to the seat on 2026-09-15 (41ff021ca), the ready flip and auto-merge were never the dev's. Under A the dev would pay a write per correction; under B the seat pays only in the residual class, in the review it already performs on the PR before hanging the four-piece.repairis a word every out-of-budget write will be argued under, round after round); B keeps it mechanical: four named endpoints, and aPATCHinapi_writesis a refusal the seat can read without interpreting. B also keeps the write-identity design of docs(pm,agents,settings): write-identity locks 1–4 — deny MCP content writes, REST-only dev writes withapi_writes,batchdefault 2, user-account roles #18072 intact (REST-only dev writes, a ledger the seat verifies) instead of carving an exception into it.PATCHtraps the platform-readings measure (the appended footer, the eaten rule line, the ⛔ never re-send a body carrying an appended footer rule) on the rare path — precisely where an AI is least rehearsed. Contract-first: fix at the producer (the body as created), not by tolerating a wrong body downstream.PATCH .../issues/{n}body, ✓ inrest-channel.md) and deletes two lines of duplicated rule text. A widens the dev's write surface for a case prevention removes. No staged transition: the old sentence is gone, the new one is in force on landing.Cost stated plainly: under B a correction in the residual class still costs a seat round (dev reports, seat writes) — the same cost as today, minus the conflict the dev had to flag. 「flag it rather than bury it」 is kept as an explicit rule for every other out-of-budget write (the rewritten L57).
The diff — before / after with byte counts
Rule 3 block (indented list under 六条基本规则 3):
- 三类发现附查重词进报告交席位代立,dev 不 \POST /issues`;预算外零写,⛔ 不 `PATCH` 正文。`- 三类发现附查重词进报告交席位代立,dev 不 \POST /issues`、⛔ 不静默弃报;预算外零写。`- PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 \PATCH`;事后要改的报告点名改法,席位代写。`- 报告记 \api_writes`(次数 + 端点清单)与 `mcp_calls`(MCP GitHub 调用计数),席位对照预算核验。`- 报告记 \api_writes`(次数 + 端点清单)与 `mcp_calls`;越界真写了的照列注明缘由,⛔ 不漏记。`- 立不成 ⇒ 发现连同缘由写进报告交 PM 代立;⛔ 不查重硬立与静默弃报同为禁形。Definition of done block:
Draft PR 指向 mainline:- 正文行首照抄认领的 \Clause-②:` 行:`Check Changeset` 读正文不读卡,开 PR 那一笔就带上。`字节与 sanitizer 纪律 block:
- 评论通路 MCP 与 REST 同判:整块原样存活,缺规则线则不认、再落整块留两个。Whole file: 36842 B → 36858 B (+16 B), 403 → 403 lines, widest line 120 B before and after, zero lines over the ratchet's 120-byte cap.
Why the two deletions are content deletions, not re-wrap: old L58's conditional (
立不成 ⇒ …交 PM 代立) has been dead since the dev stopped filing (L55:dev 不 POST /issues, findings go to the seat unconditionally), and不查重硬立guards an act the dev no longer performs; its one live clause — never drop a finding silently — is folded into L55 as⛔ 不静默弃报. Old L402 restated AGENTS.md's issue-comment footer paragraph (「a bare footer UNDER the rule line is stored byte-identical, one footer; … NO rule line above it … leaving two」) which this file already routes the reader to twice (the归属条款是 AGENTS.md 的 GitHub mutates body BYTES 条line and完整读数住 AGENTS.md 同条), and AGENTS.md binds the dev by the file's own opening. TheMCP GitHub 调用计数parenthetical dropped from L58 is restated by the report template's ownmcp_callsfield description eight lines below the JSON fence.Rider not taken: the pending
tail --pidrider (the line names no pid source) sits in the 干净收尾 block, not in either block this PR touches, so it does not fit line-neutrally here and is left for the next os-dev.md PR.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackfrom the worktree at1344eb515(change set: 1 path vs merge based6137fd6c; the tool flagged STALE TREE —origin/mainmoved one commit to62d830e54,scripts/check-plugin-teardown-shape.mjs, which is not among the 18 families and does not touch this file). Every exit code captured redirect-then-$?:node scripts/check-closing-keyword-parity.mjs:: exit 0node scripts/check-closing-keyword-parity.mjs --self-test:: exit 0node scripts/check-comment-mask-corpus.mjs:: exit 0node scripts/pm/check-governed-queue-guard.mjs --self-test:: exit 0node scripts/pm/check-harness-current.mjs --self-test:: exit 0pnpm --filter @objectstack/lint run check:doc-formula-expressions:: first run exit 3 PREREQUISITE NOT MET (nodist/for formula + lint), prerequisite built underos-verify-lock.sh(VERDICT command-exit 0, held 1s, waited 0s, turbo cache hit), re-run :: exit 0 (22 record-scoped formula example(s) across 438 files / 1378 TS blocks judged clean)pnpm check:agent-model-declared:: exit 0pnpm check:agent-test-spelling:: exit 0pnpm check:commit-card-trailers:: exit 0pnpm check:doc-authoring:: exit 0pnpm check:driver-memory-census:: exit 0pnpm check:nul-bytes:: exit 0pnpm check:pm-governed-merges:: exit 0pnpm check:pm-skill-id-lint:: exit 0pnpm check:pm-skill-ratchet:: exit 0 —.claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0), same reading on the unedited treepnpm check:refd-timer-probe:: exit 0pnpm check:skill-frame-sync:: exit 0pnpm check:watch-hint-literal:: exit 0.claude:pnpm check:pm-settings-deny-roster:: exit 0node scripts/pm/check-governed-merges.mjs --test .claude/agents/os-dev.md:: exit 3 GOVERNED (.claude/** ×1 — the agent instruction tree), recorded as the expected answer, not a failure--ranreconciliation:18 derived famil(ies) accounted for — 18 run, 0 NOT-MEASURED (a DERIVED zero — all 18 recorded an exit code and none of them is 3). Pin checks: no script or doc outside this file pins any string rewritten or deleted here (grep overscripts/,.claude/,AGENTS.md,docs/: zero hits for each).skip-changeset:.claude/**is on the fast lane (nothing published moves);check-governed-merges --testanswered GOVERNED as above.维护者速读(草稿)
改了什么 — 只动
.claude/agents/os-dev.md,行数不变(403 / 403)。dev 的 GitHub 写预算仍是四笔;新增两条规则:① PR 正文 dev 只在开 PR 那一笔写,⛔ 不PATCH,事后要改的写进报告、由席位代写;② 开 PR 时把认领评论里的Clause-②:行照抄进正文行首,让Check Changeset一开就读得到。另把「越界真写了的照列注明缘由,⛔ 不漏记」写成明文。两行新增由两行删除付账:一条自 dev 不再立卡起就死掉的「立不成 ⇒ …」句(仅存的一句「不静默弃报」并入原句),一条与 AGENTS.md 逐字重复、本文件已两次指回 AGENTS.md 的评论页脚读数。为什么改 — 卡面测到的矛盾:
Check Changeset判红时唯一的补救是改 PR 正文,而 L55 明禁 devPATCH正文;dev 只能报冲突、烧一轮往返。复测发现根因更靠前:树里没有任何一处告诉 dev 把Clause-②:行放进 PR 正文(派发模板只写认领评论),所以线是在建 PR 时就漏掉的。把它放回建 PR 那一笔,常规情形零额外写;剩下的残余类(三个读正文的门禁、席位中途改令、被截正文)本来就是建 PR 之后的 PR 状态修正,归已经持有这类写(contract-review 标签、ready 翻转、auto-merge)的席位。没选「预算抬到五」:那会把预算从机械清单变成每轮都要争辩的「算不算修复」。风险与代价(含回滚) — 代价:残余类里的一次正文修正仍要一轮席位动作(dev 报、席位写),与今天相同,只是少了 dev 报冲突那一步。风险:席位写正文要走 REST
PATCH .../issues/{n},平台对 PR 正文的页脚/横线变异读数已在 platform-readings,席位照读回即可;dev 侧少一个分支,不多。两处删除若被判为内容损失,可单独恢复(各一行、字节已列)。回滚:revert 本 PR 即回到 L52/L55 原文,无其它文件牵连、无脚本、无 changeset。席位意见 — (留席位定稿)
你要做的 — 批准或退回本 PR:批准即接受「正文修正归席位、dev 零
PATCH」这一取舍;退回并注明「抬预算」即改走卡面的 A 形。Acceptance notes
Clause-②:carrier; after this PR the dev copies that line into the body, so the template needs no change to close the case. 承接者:thedomain:skillsseat, on the next pm-dispatch SKILL.md PR, if it wants the body carriage stated on both sides.Check Changesetreds a PR whose body carries no line-startClause-②:declaration」 is conditional in the gate (not-measured-materialonly); the remedy statement stands regardless. 承接者:无 — recorded here and in the report.tail --pidrider is left in place (different block, see above). 承接者:the next os-dev.md PR.origin/mainadvanced by62d830e54during this round; re-derivation after a fetch names the same 18 families (the changed file is not one of them). 承接者:无.Generated by Claude Code