Skip to content

Commit 6ef3312

Browse files
claude[bot]claude
andauthored
docs(pm): platform-readings retires the rows that still describe MCP update_pull_request as a live channel (#18307)
Fixes #18280 ## What `.claude/skills/pm-dispatch/references/platform-readings.md` carried four rows that prescribed or described MCP `update_pull_request` as a live channel. PR #18276 put `mcp__github__update_pull_request` into lock 1's `permissions.deny`, so no seat can call it — measured on this branch's base `53dd5aaa`: `grep -c mcp__github__update_pull_request .claude/settings.json` = 1. Those rows therefore pointed at a channel the harness refuses. One file, four rows, nothing else. 466 → 465 lines; every edited line ≤ 120 bytes. | base row | disposition | row on head | bytes | |---|---|---|---| | :43 — `update_pull_request` 不管传不传都发送 `draft` 位 ⇒ 任何调用必须显式带 `draft: true`。 | **retired** — folded into the re-keyed :44 | — | 109 → 0 | | :44 — reviewers/title/body/labels 的单字段调用同坑,曾把治理面 draft 发布进合并队列。 | **re-keyed**, absorbing :43's surviving mechanism | :43 — `update_pull_request` 单字段调用也发送 `draft` 位,曾把治理面 draft 发进队列 ⇒ 锁 1 已拒。 | 101 → 115 | | :46 — 它不碰 draft 位;门开席位优先走它,MCP-only 席才用 update 加显式 `draft: true`。 | **re-keyed** — true half kept, dead MCP-only branch dropped | :45 — 它不碰 draft 位 ⇒ 请审恒走它;MCP 兜底已拒。 | 99 → 61 | | :47 — undraft 两条通道:席位凭据走 `POST .../pulls/{n}/ccr/ready_for_review`,MCP 传 `draft: false`。 | **re-keyed** — the CCR route is now the only one | :46 — undraft 单通道:席位凭据走 `POST .../pulls/{n}/ccr/ready_for_review`;MCP 兜底已拒。 | 106 → 97 | | :345 — MCP `update_pull_request` 包装器删掉 PR 正文的页脚块。 | **re-keyed** as history of a denied channel, NOT deleted | :344 — MCP `update_pull_request` 包装器删掉 PR 正文的页脚块;该通道锁 1 已拒,读作历史。 | 68 → 103 | ### :44's status — asked by the card, answered here :44 is a reading about the past (an incident), not a prescription, so it survives as history. But it survives only by absorbing :43: its subject 「同坑」 dereferenced :43's pit, so deleting :43 alone would have left :44 pointing at nothing. The merged row carries all three surviving facts in one line — the mechanism (any single-field call still sends the `draft` bit), the incident it caused (a governed-surface draft went into the merge queue), and the current status (锁 1 已拒). That is what pays the ratchet: two rows about a denied tool become one. ### Why :345 is re-keyed and not deleted Deleting it would break rows this card may not touch: :347 hangs off :346 (the bare REST route), but :348 「同一 MCP 包装器上有反例」 and :349 「送无页脚正文经 MCP 编辑回读仍无页脚」 dereference :345's wrapper, and :355 names :345's observation as 「唯一不合此判据的观察」. The row keeps its measured content and is marked as a fact about a denied channel. ## Why this shape (four axes; the one design choice per row: delete vs. re-key as denied history) - **实际业务需求** — measured, not assumed: no code, gate or sibling file reads these row texts (`git grep` for 「同坑」, 「两条通道」, 「MCP-only」, 「包装器删掉」 across the tree outside `node_modules` finds no consumer but the file itself; the one other 「同坑」 hit, :316, is a different reading). The live routes the rows named — `POST /pulls/{n}/requested_reviewers` and `POST .../ccr/ready_for_review` — do have consumers, which is exactly the half kept in each re-keyed row. - **项目长远合理性** — one channel per action, no dialect. A prescription that routes a seat to a denied tool is a workaround written down; the register keeps the measured facts and drops the routes. - **防 AI 写代码犯错** — this is the axis that decided the deletions. A register line that says 「MCP-only 席才用 update 加显式 `draft: true`」 is a declaration the runtime does not honour: the seat that follows it finds the tool absent from its roster and, per :222 of this same file, must read that absence as the deny working. Removing the line removes the trap rather than asking the reader to tolerate it. - **创业阶段不扩散需求** — immediate retirement, no staged window and no dual spelling: the rows go with the deny that made them false, and no compatibility note is left behind for a channel nobody may use. The same axes said re-key, not delete, wherever a row still carries a measured fact with a live dereference (:44's incident, :46's 「它不碰 draft 位」, :47's CCR route, :345's antecedent for three rows below it). ## Gates Derived by `node scripts/pm/dispatch-gates.mjs --commands .claude/skills/pm-dispatch/references/platform-readings.md` — 16 commands, every one run, each exit captured by redirect before any pipe. The derivation is byte-identical when re-derived from the committed tree. | command | exit | |---|---| | `node scripts/check-closing-keyword-parity.mjs` | 0 | | `node scripts/check-closing-keyword-parity.mjs --self-test` | 0 | | `node scripts/check-comment-mask-corpus.mjs` | 0 | | `node scripts/pm/check-governed-queue-guard.mjs --self-test` | 0 | | `pnpm --filter @objectstack/lint run check:doc-formula-expressions` | 3 on the fresh worktree (PREREQUISITE NOT MET — `@objectstack/formula` and `@objectstack/lint` unbuilt; nothing was measured), then 0 after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under `scripts/pm/os-verify-lock.sh` (VERDICT command-exit 0, 4 tasks) | | `pnpm check:agent-test-spelling` | 0 | | `pnpm check:doc-authoring` | 0 | | `pnpm check:driver-memory-census` | 0 | | `pnpm check:nul-bytes` | 0 | | `pnpm check:pm-governed-merges` | 0 | | `pnpm check:pm-skill-id-lint` | 0 | | `pnpm check:pm-skill-ratchet` | 0 — 「platform-readings.md is 465 lines (ceiling 466; headroom 1)」, table-row pin 0/0, every 120-byte line cap held | | `pnpm check:refd-timer-probe` | 0 | | `pnpm check:required-contexts` | 0 | | `pnpm check:skill-frame-sync` | 0 | | `pnpm check:watch-hint-literal` | 0 | `node scripts/pm/dispatch-gates.mjs --ran ran.list` → exit 0: 「16 derived famil(ies) accounted for — 16 run, 0 NOT-MEASURED」. The battery `pnpm check:pm-dispatch-gates` is NOT derived for this path and was not run. Beyond the derivation: the control-byte sweep `grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'` over the edited file matches nothing (exit 1). ESLint is measured, not assumed: `pnpm exec eslint --format json` over the file reports 1 file, `errorCount` 0, message 「File ignored because no matching configuration was supplied」 — `eslint.config.mjs` populates only `**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}`, so Markdown is outside ESLint's population entirely and this diff cannot move the verdict on any untouched file (no type-aware rule can reach a file outside the population). Repo-wide `pnpm lint` is CI's run. No package `build`/`test`/`typecheck` is owed: the diff touches no package, no `exports` and no published `files[]` content. ## Reverse verification `grep -n update_pull_request` on the file: **3 hits before** (:43 the prescription, :66 `update_pull_request_branch` — a different tool, untouched, and :345 the wrapper) and **3 hits after** (:43 the merged history row, :65 `update_pull_request_branch`, :344 the re-keyed wrapper row). The card's expected count of 5 did not hold on the base: :46 and :47 name the tool as 「update」 and 「MCP」 without the identifier, so they never matched that grep — recorded as a premise check, not a deviation. Ablation, both legs hash-proved on the committed tree (HEAD blob `e863ac59`, base blob `d9bd0fda`): 1. Mutation leg — `git checkout 53dd5aa -- .../platform-readings.md` restored the four false rows; `git hash-object` on disk = `d9bd0fda` (equal to the base blob, so the mutation really landed), anchor greps 1/1/1 for the three retired texts and 0 for the new merged row, file at 466 lines. Reading: `pnpm check:pm-skill-ratchet` exit **0**, 「465」 becomes 「466 lines (ceiling 466; headroom 0)」. 2. Restore leg — `git checkout HEAD --` on the file by ABSOLUTE path; `git hash-object` = `e863ac59` (equal to the HEAD blob), `git diff HEAD` empty (0 lines), file back at 465. Re-reading: ratchet exit **0**, headroom 1. The script carried an EXIT/INT/TERM trap whose handler restores the file from HEAD by absolute path, and the restore is proved by the hash comparison plus the empty `git diff HEAD`, not by an exit code. **The observed direction is neither red-to-green nor a diagnostic count change, and is reported as measured:** no gate reads these row texts, so no ablation of them can turn one red by construction. What the two legs do establish is that the mutation reached disk and that the only gate that reads the file at all — the line ratchet — is green on both trees, at 466/466 and at 465/466. Recording that as a green ablation would be a fit, not a finding. ## Changeset `skip-changeset`: the whole diff is under `.claude/**`, the fast lane — nothing under any released package's `files[]` moves, so no `.changeset/*.md`. ## 维护者速读(草稿) **改了什么**:pm-dispatch 的平台读数表(`references/platform-readings.md`)里有四行仍把 MCP `update_pull_request` 当成能用的通道。本 PR 把其中的处方删掉、把仍成立的实测事实改写成「这个通道已被拒」的历史记录:两行合并成一行(:43+:44),另外三行原地改写(:46、:47、:345)。文件 466 → 465 行,只动这一个文件。 **为什么改**:PR #18276 已把该 MCP 工具加进 `.claude/settings.json` 的 deny 清单,席位根本调不到它。留着这些行等于让 AI 席位照着一条运行时必拒的路走——而同一张表的另一行又告诉它「工具从工具表消失就是 deny 生效」,两边打架。声明与强制对齐,一处说清楚就够。 **风险与代价(含回滚)**:纯文档面,无代码、无发布内容、无 changeset;风险是把某条仍有人引用的读数删过头,所以 :345 只改写不删除(下面三行还在引用它)。回滚 = revert 本 PR 的唯一提交。 **席位意见**: **你要做的**:这是 `references/` 层(受管面的 references 档),按分层规则由 skills 席位做 contract-tier 审查后落地;维护者无需操作。 ## Acceptance notes - noted, not filed: :348 「同一 MCP 包装器上有反例」 and :349 「送无页脚正文经 MCP 编辑回读仍无页脚」 still describe the same denied wrapper as a live edit channel, and :355 leans on :345's observation. They are outside this card's row surface and left byte-identical. 承接者:the skills seat's next register card on the PR-body footer block — the same block is already being worked at :350–:352. - noted, not filed: the card named :347 as one of the three rows citing the MCP wrapper. Read on the base, :347 「同路送无页脚正文存回恰一条」 dereferences :346 (裸 REST `PATCH /pulls`), not the MCP wrapper — the third MCP row in that block is :349. Nothing edited either way; recorded so the follow-up card names the right rows. 承接者:同上。 - noted, not filed: the ratchet now reports headroom 1 on this file (465 of ceiling 466). Lowering the ceiling is always legitimate and is how this map records a paydown, but the ceiling lives in `scripts/pm/check-skill-line-ratchet.mjs`, outside this card's declared single-file surface, so it was NOT touched. 承接者:the skills seat on its next touch of the ceiling map (the declared cross-file move into this file re-prices green either way: +11 against a net source decrease of 20 today, +10 at a 465 ceiling). - noted, not filed: the retired :46 clause was the only line telling a seat with no REST channel (an 「MCP-only 席」) what to do about a review request; under the deny such a seat has no channel at all. `rest-channel.md` :39 already spells the house answer for that shape (无通道 ⇒ 交有通道席位), so no new rule was invented here. 承接者:none. - This PR touches a governed surface (`.claude/**`), all of it under `.claude/skills/pm-dispatch/references/`: left DRAFT, no reviewer requested, no ccr route touched, no auto-merge armed. --- _Generated by [Claude Code](https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr)_ Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
1 parent 52c1a8c commit 6ef3312

1 file changed

Lines changed: 4 additions & 5 deletions

File tree

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@
4040
- 本仓转 draft 同时掉 auto-merge 与队列成员资格,不自动恢复,转正后重挂;姊妹仓曾保位照合。
4141
- 补救:转 draft 与 `disable_pr_auto_merge` 都做 —— 本仓 disable 单独不踢队。
4242
- 出队按队列 ref 阳性探针答不在队向,加未落地;ref 缺席只作旁证,⛔ 永不承载结论。
43-
- `update_pull_request` 不管传不传都发送 `draft` 位 ⇒ 任何调用必须显式带 `draft: true`
44-
- reviewers/title/body/labels 的单字段调用同坑,曾把治理面 draft 发布进合并队列。
43+
- `update_pull_request` 单字段调用也发送 `draft` 位,曾把治理面 draft 发进队列 ⇒ 锁 1 已拒。
4544
- 请审专用路 = REST `POST /pulls/{n}/requested_reviewers`,载荷只有 reviewers/team_reviewers。
46-
- 它不碰 draft 位;门开席位优先走它,MCP-only 席才用 update 加显式 `draft: true`
47-
- undraft 两条通道:席位凭据走 `POST .../pulls/{n}/ccr/ready_for_review`,MCP `draft: false`
45+
- 它不碰 draft 位 ⇒ 请审恒走它;MCP 兜底已拒
46+
- undraft 单通道:席位凭据走 `POST .../pulls/{n}/ccr/ready_for_review`;MCP 兜底已拒
4847
- 2026-09-12 两席实调:裸 GraphQL 会话内被拒,建议的 REST 正是 ccr 路 ⇒ 池 0 不再只能等重置。
4948
- ⛔ 裸 `PATCH /pulls/{n}``draft: false` 回 200 而无操作(2026-09-11);读回才作数:`GET /pulls/{n}`
5049
- `enable_pr_auto_merge` 恒显式传 `mergeMethod: "SQUASH"`;不传静默退回被禁的 merge-commit = 无操作。
@@ -342,7 +341,7 @@
342341
- ⇒ 失效既依拼写又依载体:评论里验过页脚对 PR 正文什么都没证明。
343342
- ⇒ PR 正文页脚不带前置横线,且写后回读正文 —— 那是唯一检测手段;评论两形皆可。
344343
- 署名页脚的写侧变异按通道与输入双重定域,⛔ 不是一条定律。
345-
- MCP `update_pull_request` 包装器删掉 PR 正文的页脚块。
344+
- MCP `update_pull_request` 包装器删掉 PR 正文的页脚块;该通道锁 1 已拒,读作历史
346345
- 裸 REST `PATCH /pulls` 追加一个裸页脚并保留既有 session-URL 页脚,差恰 58 字节。
347346
- 同路送无页脚正文存回恰一条(平台裸形)⇒ 该格处方是不送页脚,⛔ 不是不重送正文。
348347
- 同一 MCP 包装器上有反例:把已带页脚的正文整体重送,两条页脚均逐字节存活。

0 commit comments

Comments
 (0)