Skip to content

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

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-18443-os-dev-budget-body-patch
Sep 17, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-18443-os-dev-budget-body-patch

Conversation

@os-justin

Copy link
Copy Markdown
Collaborator

Fixes #18443

Clause-②: no

Governed surface (.claude/**): draft, skip-changeset, the maintainer's approval lands it. File surface: .claude/agents/os-dev.md only. Head 1344eb515, base d6137fd6c. Line-neutral: 403 / 403.

The gap, re-measured on origin/main d6137fd6c

  • L52 and L55 read exactly as the card quotes them (117 B and 118 B): the four-write budget, and 预算外零写,⛔ 不 PATCH 正文.
  • How the body line is demanded today: Check Changeset (pr-automation.yml changeset-check) runs scripts/check-changeset-no-major.mjs --base MERGE_BASE, which reads the declaration from github.event.pull_request.body through readClause2Line (imported from scripts/pm/check-clause2-carriers.mjs; line-initial key, yes / no only). The red is CONDITIONAL, not unconditional as the card states: a missing line fails only as not-measured-material (exit 1) — a patch changeset on a package the diff grew, none of them raised to minor+; with no candidate offender it is not-measured-moot (exit 0), and the whole job is exempt under skip-changeset. The remedy when it does fail is still exactly one act, a body write, and the job is edited-subscribed so that write re-fires it without a push.
  • Whether the seat's committed orders now supply the line: no. On d6137fd6c the pm-dispatch template names the claim comment as the only carrier (SKILL.md :473 Branch:Clause-②: 各占一行且行首, :476, :809 template), no committed text tells anyone to put it in the PR body, and os-dev.md did not contain the token Clause at all (grep: 0). The seat's own closure lives in its dispatch prompts (this card's order says put Clause-②: no in the PR body AT CREATION), not in the tree. So on origin/main the gap was still the whole class, not only the residual.
  • The residual class is measurable: three PR-body-scoped gates, all edited-subscribed, each cleared only by a body write — Check Changeset (the Clause-②: line), Duplicate Fix Guard (a Fixes line naming a card another open PR claims), Part-of Closing-Keyword Guard (a closing keyword beside Part 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 REST PATCH /pulls appends a bare footer beside an existing session-URL one, +58 B).
  • Provenance holds: lint: translation-target-unknown reads apps[].navigation only, 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 comment 5696114759 lists write (4) PATCH /repos/.../pulls/18433 with 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 the POST /pulls already in budget, and that one write carries the Clause-②: 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 never PATCHes 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):

  • 实际业务需求 — measured, not read-as-useful: the only body author at creation is the dev (POST /pulls), and the gate reads the body, so carrying the line at creation closes the case lint: translation-target-unknown reads apps[].navigation only, 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.
  • 项目长远合理性 — A makes the budget a judgement (repair is a word every out-of-budget write will be argued under, round after round); B keeps it mechanical: four named endpoints, and a PATCH in api_writes is 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 with api_writes, batch default 2, user-account roles #18072 intact (REST-only dev writes, a ledger the seat verifies) instead of carving an exception into it.
  • 防 AI 写错 — B gives the dev one branch fewer, not one more: write the body right once (a fixed line copied verbatim from the claim, so the two carriers agree by construction), never rewrite it. A would hand the dev the PR-body PATCH traps 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.
  • 创业阶段不扩散需求 — B adds no capability, script or gate and widens nothing: it reallocates one existing seat write (PATCH .../issues/{n} body, ✓ in rest-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):

  • L55 before (118 B): - 三类发现附查重词进报告交席位代立,dev 不 \POST /issues`;预算外零写,⛔ 不 `PATCH` 正文。`
  • L55 after (117 B): - 三类发现附查重词进报告交席位代立,dev 不 \POST /issues`、⛔ 不静默弃报;预算外零写。`
  • L56 new (117 B): - PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 \PATCH`;事后要改的报告点名改法,席位代写。`
  • L58 (was L57) before (118 B): - 报告记 \api_writes`(次数 + 端点清单)与 `mcp_calls`(MCP GitHub 调用计数),席位对照预算核验。`
  • L58 after (119 B): - 报告记 \api_writes`(次数 + 端点清单)与 `mcp_calls`;越界真写了的照列注明缘由,⛔ 不漏记。`
  • old L58 deleted (112 B): - 立不成 ⇒ 发现连同缘由写进报告交 PM 代立;⛔ 不查重硬立与静默弃报同为禁形。
  • L52 unchanged (117 B): the four-write budget stands as written.

Definition of done block:

  • L279 new (113 B), directly under the Draft PR 指向 main line: - 正文行首照抄认领的 \Clause-②:` 行:`Check Changeset` 读正文不读卡,开 PR 那一笔就带上。`

字节与 sanitizer 纪律 block:

  • old L402 deleted (102 B): - 评论通路 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. The MCP GitHub 调用计数 parenthetical dropped from L58 is restated by the report template's own mcp_calls field description eight lines below the JSON fence.

Rider not taken: the pending tail --pid rider (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/objectstack from the worktree at 1344eb515 (change set: 1 path vs merge base d6137fd6c; the tool flagged STALE TREE — origin/main moved one commit to 62d830e54, 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 0
  • node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
  • node scripts/check-comment-mask-corpus.mjs :: exit 0
  • node scripts/pm/check-governed-queue-guard.mjs --self-test :: exit 0
  • node scripts/pm/check-harness-current.mjs --self-test :: exit 0
  • pnpm --filter @objectstack/lint run check:doc-formula-expressions :: first run exit 3 PREREQUISITE NOT MET (no dist/ for formula + lint), prerequisite built under os-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 0
  • pnpm check:agent-test-spelling :: exit 0
  • pnpm check:commit-card-trailers :: exit 0
  • pnpm check:doc-authoring :: exit 0
  • pnpm check:driver-memory-census :: exit 0
  • pnpm check:nul-bytes :: exit 0
  • pnpm check:pm-governed-merges :: exit 0
  • pnpm check:pm-skill-id-lint :: exit 0
  • pnpm check:pm-skill-ratchet :: exit 0 — .claude/agents/os-dev.md is 403 lines (ceiling 403; headroom 0), same reading on the unedited tree
  • pnpm check:refd-timer-probe :: exit 0
  • pnpm check:skill-frame-sync :: exit 0
  • pnpm check:watch-hint-literal :: exit 0
  • extra, the roster the derivation marks ⛔ under .claude: pnpm check:pm-settings-deny-roster :: exit 0
  • node 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

--ran reconciliation: 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 over scripts/, .claude/, AGENTS.md, docs/: zero hits for each).

skip-changeset: .claude/** is on the fast lane (nothing published moves); check-governed-merges --test answered 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 明禁 dev PATCH 正文;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

  • noted, not filed: the committed pm-dispatch template still names the claim comment as the only Clause-②: carrier; after this PR the dev copies that line into the body, so the template needs no change to close the case. 承接者:the domain:skills seat, on the next pm-dispatch SKILL.md PR, if it wants the body carriage stated on both sides.
  • noted, not filed: the card's sentence 「Check Changeset reds a PR whose body carries no line-start Clause-②: declaration」 is conditional in the gate (not-measured-material only); the remedy statement stands regardless. 承接者:无 — recorded here and in the report.
  • noted, not filed: the tail --pid rider is left in place (different block, see above). 承接者:the next os-dev.md PR.
  • The dispatch-gates STALE TREE flag: origin/main advanced by 62d830e54 during this round; re-derivation after a fetch names the same 18 families (the changed file is not one of them). 承接者:无.

Generated by Claude Code

…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]>

Copy link
Copy Markdown
Collaborator Author

维护者速读(终稿)

skills 席 session_01Gqi43smmqjJ5sUrhfoPeKu,2026-09-17T13:19Z。对照本席自己读的 diff 校正 dev 草稿;席位意见已填。

改了什么 — 只改 .claude/agents/os-dev.md(+4 / −4,403 → 403 行,预算四笔不变)。写预算那段(L55–L58)由「预算外零写,⛔ 不 PATCH 正文」改成三条明确规则:PR 正文 dev 只写一次,就是开 PR 那一笔,⛔ 不 PATCH;事后要改的,报告里点名改法,席位代写;越界真写了的照列注明缘由,⛔ 不漏记(把「先报告不埋掉」写成明文)。PR 段新增一行:正文行首照抄认领评论的 Clause-②:,因为 Check Changeset 读的是正文不是卡。为保持行数,删掉两行重复文本(「立不成 ⇒ …」的活句并入 L55;评论页脚那行与 AGENTS.md 同条重复)。

为什么改 — 预算禁止 dev PATCH 正文,而 Check Changeset 判红时唯一的补救恰是 PATCH 正文:dev 按字面必须拒绝,照做就越界。#18203 那轮真的撞上了(dev 写了「WRITE (4) IS OUT OF BUDGET AND I AM FLAGGING IT」),白跑一轮。卡上给了两个方向:A 抬预算 / 列豁免;B 把修正挪给席位,并让 Clause-②: 行在开 PR 时就带上,常见情形根本不需要修正。本 PR 做的是 B

风险与代价(含回滚) — 受管 agent 定义,只改规则文本;不加脚本、不加门禁、不扩 dev 写面(席位本来就持有 PATCH /issues/{n})。剩余类(中途修正、被 sanitizer 截断的正文)仍要一个席位回合,与今天一样,少的是 dev 的冲突报告那一步。本 PR 自己就是证据:正文开 PR 时带了 Clause-②: no,全程零 PATCH。回滚 = revert 一个提交。

席位意见 — 荐合 B。四轴一致:零额外写就关掉了实测的案例;预算保持机械的四端点清单,而不是每轮争论「什么算修补」;dev 少一个分支而不是多一个(正文 PATCH 正是平台读数里页脚会被吃/追加的那条路);不扩能力面。

你要做的(一个动作) — 认可 B 即 Approve 本 PR(或直接人工合并);席位随后按裁定 C 落地。要 A(抬预算到五笔或列豁免)则 Request changes,本席另起。


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review September 17, 2026 14:38
@os-zhuang
os-zhuang enabled auto-merge September 17, 2026 14:38
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 17, 2026
Merged via the queue into main with commit 0111212 Sep 17, 2026
39 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-18443-os-dev-budget-body-patch branch September 17, 2026 15:01
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] the os-dev write budget forbids the only act that clears a Check Changeset red — PATCH of the PR body has no compliant path

3 participants