Skip to content

Commit 23cf11a

Browse files
docs(pm-dispatch): point every PR-body rewrite at the issue_patch door (#31058)
<!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xRZfRWwVbM1oLGd4rdqg3kL)_ Fixes #31050 Clause-②: no Metadata-protocol: none `dispatch-gates --tier` reads a MANDATORY model tier, from clause ① (`.claude/agents/os-dev.md`, the dev-agent definition). This card ran on the project's default model: that mandate is waived by the maintainer's standing order in this project (2026-11-03), and the dispatching seat runs the contract review. ## 维护者速读 - 改了什么:席位改写 PR 正文的其余三处(`rest-channel.md`、`platform-readings.md` 的 flake 记因、`os-dev.md` 的席位代写)都指向 `seat-post-protocol.md` 的 PR 正文行;中继改 PR 正文不追加页脚这一读数补进 `platform-readings.md`;`check-handover.mjs` 头注分别点名交回规则的两处去处。 - 为什么改:#31049 只在两处教了 PR 正文门;`rest-channel.md` 仍写「直调 `dispatch.mjs` 仅落地」,与 ACCEPT 前改正文相抵,另两处改正文不点门。 - 风险与回滚:只改内部 agent 规程文字与一行脚本注释,不发包(`skip-changeset`),四个文件行数不变;回滚即 revert。 - 先看:`rest-channel.md` L16–17(新例外行);`platform-readings.md` L343(新页脚读数,排在 L337–342 的裸 REST 改侧格之后)。 - 两分钟验证:`node scripts/pm/check-skill-line-ratchet.mjs`,预期退出 0,`rest-channel.md` 82 行、`platform-readings.md` 458 行、`os-dev.md` 405 行,各等于上限。 - 需要你做的:无,席位落地。 ## What changes **Item 1, `.claude/skills/pm-dispatch/references/rest-channel.md` L16.** The line said a direct `dispatch.mjs` call is for landing only, but a seat rewrites a PR body before ACCEPT. It is split in two: - L16 keeps the op table, the read side and the batch rule: `闭合 op 表住 fleet-write/ops.mjs;读侧不走中继;批量恒走逐 op 工具。` - New L17 names the exception and points to the door, with no second spelling of it: `直调 dispatch.mjs 仅落地,与 PR 正文单笔 issue_patch(seat-post-protocol.md 正文行,不送页脚)。` **Item 2, `scripts/pm/check-handover.mjs` L33–34 (header comment only, no code).** PR #31049 deleted the old home (`seat-post-protocol.md`, 收班), and its two facts now live in two places, so the header names both: - the refusal inside (a), a `needs_decision` card handed to the decision box and never back to `pm:queue` → `seat-post-protocol.md` 交接收尾清单 step 2 (L47, `needs_decision 进决策箱`); - the stay-behind narrowing → `seat-lifecycle.md` 离任留守 (L44, 离任留守只写点名的已 ACCEPT 待队列或待人批 PR). The comment now reads: `The sign-off hand-back rule (seat-post-protocol.md, 交接收尾清单 step 2) names one refusal inside (a); seat-lifecycle.md 离任留守 narrows (a)'s stay-behind (section below):`. **Item 3, the two rewrites that named no door.** - `references/platform-readings.md` L290 (new, under the `Check Changeset` flake line): `⇒ 该正文改走 seat-post-protocol.md 的 PR 正文行,不送页脚。` - `.claude/agents/os-dev.md` L66, rewritten in place: `PR 正文 dev 只在 pr_create 写,⛔ 不 PATCH;改法报告点名,席位经 seat-post-protocol.md 代写。` The meaning is the old line's (the dev writes the body once, at the create; the report names the change; the seat writes it), and it now names where the seat's rewrite goes. **Item 4, the footer reading (`platform-readings.md` L336–341).** Settled from code and stored bodies only; no test write was made. - How the relay reads back: after a `success` run, `sendFleetWrite` reads every action that sent a `body` (`READ_BACK_LOCATORS.issue_patch` = `GET /repos/{repo}/issues/{issue}`) and judges it with post-stamped's `classifyReadBack` (`judgeStoredBody`, `scripts/pm/fleet-write/dispatch.mjs` L1081). The class `identical` is `stored === sent` (`declaredNormalisation`, `scripts/pm/post-stamped.mjs` L2843). Nothing is stripped before that comparison, and `storedBytes` is the raw stored length. A stored body with the bare footer appended would print `footer-appended`, not `identical`. - What it read: PR #31049's body, 8149 bytes sent and 8149 stored, `identical`. PR #29225's edit was read back `identical` too (its landing comment on #29145). - What the stored bodies show today (one `GET /repos/objectstack-ai/objectstack/issues/{n}` each, read only): #31049 is 8149 bytes and #29225 is 6785 bytes, and both end with the `<!-- signed: … -->` trailer and a newline. Neither carries a `_Generated by …_` footer. - So the relay `issue_patch` appends no footer, while main L338–341 measured the raw-REST `PATCH` cell (+58). Per AGENTS.md, the cells differ by channel and are not generalised. Main L341 (now L340) stays as it is. New L343 records the relay cell after the whole raw-REST edit-side band (L337–342), so the strip-both-spellings and attribution lines still read with their own cell: `中继 issue_patch 不在此列:dispatch.mjs 读回 PR 正文存 = 送(identical),无追加。` - `seat-post-protocol.md` L31 is unchanged. Adding 不送页脚 there does not fit at 120 B (the shortest spelling measured is 125 B), and the file has no restatement to delete to pay for a second line. For now the no-footer word rides on the pointers: `rest-channel.md` L17 and `platform-readings.md` L290 carry it, and `SKILL.md` L313 already did. `os-dev.md` L66 is at exactly 120 B and carries the pointer only. Giving the rule its one home at L31 (and dropping the pointers' copies) is left to #31059. ### Deleted restatements (deletion only; each fact's surviving home) | File | Deleted line (main) | Surviving home | |---|---|---| | `rest-channel.md` | L42 `⛔ post-stamped/label-write 永不接进管道再 &&:拒收读成 0;看尾先落文件或 set -o pipefail。` | `scripts/pm/post-stamped.mjs` header, 〈⛔ Never pipe this tool, then `&&` the write that follows〉 (L112–127: redirect then capture, or `set -o pipefail`; "it covers every writer beside it — `label-write.mjs` included"); `scripts/pm/label-write.mjs` header, 〈Exit codes — capture them BEFORE any pipe〉 (L156) | | `platform-readings.md` | L36 `⛔ 永不用 -c merge.os-regen.driver= 覆盖:驱动不是被关掉而是跑失败,路由路径全报冲突。` | AGENTS.md, Multi-agent discipline §11, corollary ("⛔ Never with `-c merge.os-regen.driver=` … git runs the configured program, it fails, and every routed path is reported conflicted"); `scripts/pm/os-regen-merge.sh` header L303–304 | | `platform-readings.md` | L313 `否则 repair-first 被正确地应用到完好的卡上,重写毁掉的是正确内容。` | AGENTS.md, 〈GitHub mutates body BYTES〉 ("⛔ A body reading short only through the API is probably intact — check the rendered page before "repairing" it; a rewrite destroys a correct card"); the prescription it followed, L312 (now L311), stays | ## Tests None: the diff is instruction text and one comment line, with no runtime behaviour to test. The gates below are the checks. ## Acceptance notes ### Line budget (`scripts/pm/check-skill-line-ratchet.mjs`, exit 0) | File | Lines (main → head) | Ceiling | Bytes (main → head) | |---|---|---|---| | `references/rest-channel.md` | 82 → 82 | 82 | 7,772 → 7,739 | | `references/platform-readings.md` | 458 → 458 | 458 | 47,066 → 47,039 | | `.claude/agents/os-dev.md` | 405 → 405 | 405 | 38,411 → 38,414 | | `scripts/pm/check-handover.mjs` (not ratcheted) | 891 → 891 | — | 65,299 → 65,301 | Every touched line: `rest-channel.md` L16 120 → 88 B, new L17 118 B; `platform-readings.md` new L290 78 B, new L343 102 B; `os-dev.md` L66 117 → 120 B; `check-handover.mjs` L33 111 → 113 B and L34 31 → 78 B. No new section; no fence line touched. ### Not changed here (found while reading) - `scripts/pm/fleet-write/dispatch.mjs` header (〈A pull request's body …〉, L454–456 on `main`) still says "an edit of a pull's body gets the bare footer block appended after the trailer (`platform-readings.md`, the edit side), so send no footer of your own". The relay read-backs above show no append on that path. The advice (send no footer) still holds: a footer after the trailer would be the body's last non-empty line, and the door would refuse the body as unsigned. Only the stated reason is stale. This is outside the card's file surface; it is filed as #31059 and not changed here. ## Verification <details><summary>Local gates on 3ac6083: 41 derived, 41 run with exit 0, 0 NOT MEASURED (`dispatch-gates --ran`)</summary> - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived the same 41 commands for the 4 changed paths as on round 1 (33bac6a). Each ran under a 900 s timeout, its exit code captured before any pipe; all 41 exited 0 on the first run (the `@objectstack/formula`, `@objectstack/lint` and `@objectstack/objectql` builds from round 1 were in place). - They include `check:pm-skill-ratchet`, `check:pm-skill-id-lint`, `check:pm-governed-prose`, `check:pm-governed-merges`, `check:pm-half-states`, `check:pm-post-stamped`, `check:doc-authoring`, `check:skill-frame-sync`, `check:commit-card-trailers`, `check-comment-mask-corpus.mjs`, and the self-tests of `check-governed-queue-guard.mjs` and `check-harness-current.mjs`. - `--ran` printed: `41 derived famil(ies) accounted for — 41 run, 0 NOT-MEASURED (a DERIVED zero — all 41 recorded an exit code and none of them is 3)`. - Round 1 (33bac6a): 41 of 41 exit 0, the formula gate after the same builds. </details> - `node scripts/pm/check-governed-merges.mjs --branch claude/project-thread-0ili91`: GOVERNED, Tier S (席内达档复核落地): `.claude/**` ×3; `scripts/pm/check-handover.mjs` is not on the register; 14 changed lines (+7 / −7), under 3000. - `node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD`: exit 0 before every push. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (No schema touched.) - [x] 2. Every name I added uses the casing for its kind. (No names added.) - [x] 3. No formatter ran. (Markdown and one comment line; no lintable source changed.) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. Nothing publishes (`.claude/**` and a `scripts/pm/**` comment), so the PR takes `skip-changeset`. Both declaration lines are filled in above. - [x] 6. `packages/spec` not touched; nothing to regenerate. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. (The 维护者速读 section is Chinese, per the lane template.) - [x] The *Before Submitting* list in CONTRIBUTING.md is done. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAkpKySQ5xGrSjjjnVw <!-- signed: domain:skills#3 · huangyiirene · session_01J8VVAj7CvjkGXvgXzd6RZ7 --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b5fd350 commit 23cf11a

4 files changed

Lines changed: 7 additions & 7 deletions

File tree

‎.claude/agents/os-dev.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ model: opus
6363
- 写预算三笔:`git push`、`pr_create`(draft,含 labels 与 assignees)、`os-dev-report` 评论。
6464
- 卡与线程只走 payload 档(公开仓单卡网页内嵌 JSON,拼写住 platform-readings)或单卡 REST 读。
6565
- 三类发现进报告交席位代立,不 `POST /issues`、⛔ 不静默弃报;PM 去重读数当既有事实用。
66-
- PR 正文 dev 只写一次,在开 PR 那一笔,⛔ 不 `PATCH`;事后要改的报告点名改法,席位代写。
66+
- PR 正文 dev 只在 `pr_create` 写,⛔ 不 `PATCH`;改法报告点名,席位经 `seat-post-protocol.md` 代写。
6767
- 报告记 `api_writes`(次数 + 端点清单)与 `mcp_calls`;越界真写了的照列注明缘由,⛔ 不漏记。
6868
- 归挂不散落:落在已排队 issue 范围内的发现,报告点名为它的 sub-issue(自动进派发池)。
6969
- 只是依赖它的,报告点名独立单带 `Blocked-by:` 行;立在修复落地的仓,带回链;席位代立。

‎.claude/skills/pm-dispatch/references/platform-readings.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
- 注册按克隆(`pnpm install` 的 prepare),服务端一个驱动都不跑 ⇒ 两侧答的不是同一个问题。
3434
- 驱动接手的路径上 exit 0 只说内容判断被推迟,⛔ 不是无冲突:它对内容什么都没说。
3535
- ⇒ 冲突证明探无驱动裸克隆,配方与读法见 `scripts/pm/os-regen-merge.sh`:exit 1 无树 id = 缺对象
36-
- ⛔ 永不用 `-c merge.os-regen.driver=` 覆盖:驱动不是被关掉而是跑失败,路由路径全报冲突。
3736
- 入队决策点才整对象 `get` 一次;挂了 flip 定点到点读,⛔ 不又查又等。
3837
- 状态核验用最小字段(search/list 加 `fields`)或等事件。
3938
- 聚合读数(`blocked`/`dirty`)只作阴性筛查再定位;放行按名定向读单条 job,⛔ 不拉全表。
@@ -288,6 +287,7 @@
288287
- 经 `rerun-failed.mjs` 重跑 PR `ci.yml` 失败 job 仅一次,先在 PR 或卡写明 flake 理由;二败即真红。
289288
- `run_rerun_failed` 只收 `ci.yml`;他 workflow 的 flake 走下两条,⛔ 永不空提交、永不关了重开。
290289
- `pr-automation.yml`(`Check Changeset` 取消无后继):席位改正文记下 flake 理由,其 `edited` 即重跑。
290+
- ⇒ 该正文改走 `seat-post-protocol.md` 的 PR 正文行,不送页脚。
291291
- `lint.yml`(检出超时):`main` 前进后中继 `pr_update_branch` 出真新 head 整套重跑;齐平即空操作。
292292
- 同一 head 上轻量兄弟 workflow `success` 加重量级载体 `cancelled` 是普通取代的预期签名。
293293
- 同名 `failure` 也会被带另一诊断的后一次 `failure` 取代 ⇒ 任何判定前先按名取最新一次。
@@ -310,7 +310,6 @@
310310
- doctype 开标记与 object 标签形状同触发;网页全文完好,⛔ 不修复只在 API 读短的卡。
311311
- 同坑第三条读路径:MCP `issue_read` 与 PR 读路径把行内反引号里的尖括号片段整个吃掉。
312312
- GitHub 存储字节完好、raw REST 一字不差 ⇒ ⛔ 不单凭 MCP 读判截断,先取 raw 或渲染页核对。
313-
- 否则 repair-first 被正确地应用到完好的卡上,重写毁掉的是正确内容。
314313
- 唤醒中继渲染会把 `{` `}` `<` 转义 ⇒ 判已发布产物按 `GET` 取存储体,⛔ 永不按中继正文。
315314
- 判据 = 数空的行内代码跨度:一个空跨度恰是短尖括号片段被吃掉的签名。
316315
- 判据是尖括号不是反引号:有的正文本来就把标识符不带尖括号写。
@@ -341,6 +340,7 @@
341340
- 该追加按面不按路由:`PATCH /issues/{n}` 打在 PR 上同样 +58 追加裸页脚,而 draft 位不动。
342341
- 页脚两拼写:裸版与 session-URL 版都要剥,漏剥的卡在正文中段,而 58 字节差照常。
343342
- ⇒ 代价是归属:裸形无 session id,按此剥净的 PR 正文不载明哪个会话写的;另置见 AGENTS.md。
343+
- 中继 `issue_patch` 不在此列:`dispatch.mjs` 读回 PR 正文存 = 送(`identical`),无追加。
344344
- 第四形:建 PR 两通道同判 —— 送出体尾部不是 `---` 加页脚块时,追加一条同形页脚。
345345
- 该追加是横线加一条 session-URL 形页脚,送出体是存储体的严格前缀;字节数非常量(90/91)。
346346
- 尾部已是该块则一字不追加,两通道各实测两向 ⇒ 建侧通道不是变量,判据是送出体尾部。

‎.claude/skills/pm-dispatch/references/rest-channel.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
- ⛔ 它、赋值与 `cd … &&` 前缀都落分类器;多仓云会话首调单独裸 `cd /home/user/objectstack`。
1414
- 活着 = 工作流文件在 `main` 且 Actions 状态 `active`;维护者在 Actions UI 停用即整队回 `direct`。
1515
- dispatch 带会话令牌发往 objectstack;run 在 runner 上以逐次铸造、窄到目标仓的 App 令牌执行。
16-
- 闭合 op 表住 `fleet-write/ops.mjs`;读侧不走中继;批量恒走逐 op 工具,直调 `dispatch.mjs` 仅落地。
16+
- 闭合 op 表住 `fleet-write/ops.mjs`;读侧不走中继;批量恒走逐 op 工具。
17+
- 直调 `dispatch.mjs` 仅落地,与 PR 正文单笔 `issue_patch`(`seat-post-protocol.md` 正文行,不送页脚)。
1718
- 正文超 60,000 字节的那一笔 `post-stamped` 写走 `direct` 并印一行,身份是席位自己的用户。
1819
- run 失败记 5(post-stamped 4,close-cards 有步落地或读不回 4),UNCONFIRMED 6:只读,⛔ 永不重试。
1920

@@ -39,7 +40,6 @@
3940

4041
- ✓ 评论 `POST .../issues/{n}/comments`;改评论 `PATCH .../issues/comments/{id}`。
4142
- ✓ 标签加法 `POST .../issues/{n}/labels`,定向删 `DELETE .../issues/{n}/labels/{name}`;加法优先。
42-
- ⛔ `post-stamped`/`label-write` 永不接进管道再 `&&`:拒收读成 0;看尾先落文件或 `set -o pipefail`。
4343
- ⛔ 永不 MCP `issue_write`(锁 1 已拒);会话分类器拒改动 ⇒ 无通道,交有通道席位立卡。
4444
- ✓ 建卡带标签 `POST .../issues` · 改正文 `PATCH .../issues/{n}` · 认领 `POST .../issues/{n}/assignees`。
4545
- ✓ 该 `PATCH` 带 `state` 关卡/重开,`state_reason` 交付 `completed`、撤单 `not_planned`,走裸 REST。

‎scripts/pm/check-handover.mjs‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@
3030
* newer than it, and whose state labels (`PM_EXCLUSIVE_STATE_LABELS`, the six
3131
* mutually exclusive states of `SKILL.md`) are anything but `needs-user-decision` alone.
3232
*
33-
* The sign-off hand-back rule (`seat-post-protocol.md`, 收班) names one refusal inside (a) and narrows (a)'s
34-
* stay-behind (section below):
33+
* The sign-off hand-back rule (`seat-post-protocol.md`, 交接收尾清单 step 2) names one refusal inside (a);
34+
* `seat-lifecycle.md` 离任留守 narrows (a)'s stay-behind (section below):
3535
*
3636
* (a′) NEEDS_DECISION a card (a) holds whose NEWEST `os-dev-report` (`latestDevReport`, the patrol's newest-of
3737
* HELD reading) is newer than the claim and declares `"status": "needs_decision"`, while the card

0 commit comments

Comments
 (0)