Skip to content

Commit c053f74

Browse files
claude[bot]claude
andauthored
pm(skills): probe the unexercised CCR routes and the shared MCP user bucket into the REST channel register (#18259)
Fixes #18130 Measurement-first register work on `.claude/skills/pm-dispatch/references/rest-channel.md`. The card's readings 2 and 3 (`ccr/ready_for_review`, `PUT ccr/auto_merge`) were already on :48 / :51 and are not re-recorded. What this branch owes is one probe per UNEXERCISED CCR route named by the session proxy's own 403 body, plus the shared per-user MCP bucket fact. Every route below earned its row by being invoked once; nothing here is written from the card's text. Session: `session_01HZfg2AwVX191qCizp88gQr` (skills seat, dev subagent). All probes ran on THIS draft PR, 2026-09-15T04:48Z–04:49Z. No probe touched another seat's PR. ## Probe log | # | Route | Method / body sent | Status | Body stored / returned | Read-back | |---|---|---|---|---|---| | P1 | `https://api.github.com/graphql` | POST, `markPullRequestReadyForReview` mutation | **403** | proxy's own body, 629 B, naming the five CCR routes verbatim | n/a — refused before GitHub sees it | | P2a | `POST /repos/{o}/{r}/pulls/18259/comments` | `commit_id` + `path` + `line: 49` + `side: RIGHT` | **201** | review comment `id: 4012020890`, `user.login: claude[bot]` | thread appears in `ccr/review_threads` | | P2b | `GET .../pulls/18259/ccr/review_threads` | GET | **200** | `[{"resolved":false,"outdated":false,"path":"…rest-channel.md","line":49,"comment_ids":[4012020890]}]` | — | | P2c | `POST .../ccr/comments/4012020890/resolve` | POST `{}` | **200** | `{"comment_ids":[4012020890],"resolved":true}` | `review_threads` → `"resolved":true` | | P2d | `POST .../ccr/comments/4012020890/unresolve` | POST `{}` | **200** | `{"comment_ids":[4012020890],"resolved":false}` | `review_threads` → `"resolved":false` | | P2e | `POST .../ccr/comments/4012020890/resolve` | POST `{}` | **200** | `{"comment_ids":[4012020890],"resolved":true}` | `review_threads` → `"resolved":true` (final state) | | P3a | `PUT .../pulls/18259/ccr/auto_merge` | PUT `{"merge_method":"SQUASH"}`, PR in DRAFT | **422** | `{"message":"Pull request Pull request is a draft"}` | `GET /pulls/18259` → `auto_merge: null` (nothing stored) | | P3b | `DELETE .../pulls/18259/ccr/auto_merge` | DELETE, nothing armed | **422** | `{"message":"Can't disable auto-merge for this pull request."}` | `GET /pulls/18259` → `auto_merge: null` | | P4a | `POST .../pulls/18259/ccr/ready_for_review` | POST `{}` | **200** | `{"draft":false}` | `GET /pulls/18259` → `draft: false`; timeline `ready_for_review`, actor `claude[bot]` | | P4b | `POST .../pulls/18259/ccr/convert_to_draft` | POST `{}` | **200** | `{"draft":true}` | `GET /pulls/18259` → `draft: true`; timeline `convert_to_draft`, actor `claude[bot]` | P1's route list, quoted from the 403 body itself rather than from the card: `GET /repos/{owner}/{repo}/pulls/{n}/ccr/review_threads`, `POST /repos/{owner}/{repo}/pulls/{n}/ccr/comments/{comment_id}/resolve` (or `/unresolve`), `PUT` or `DELETE /repos/{owner}/{repo}/pulls/{n}/ccr/auto_merge`, `POST /repos/{owner}/{repo}/pulls/{n}/ccr/ready_for_review`, `POST /repos/{owner}/{repo}/pulls/{n}/ccr/convert_to_draft`. It matches the card's quotation word for word. ### What the probes settled, against the dispatch's assumptions - **P2 (which id does `resolve` want?)** — the review-COMMENT id. `ccr/review_threads` returns no thread id at all: each element carries `resolved`, `outdated`, `path`, `line` and `comment_ids`, and `comment_ids[0]` is exactly what the resolve route accepts. The register row names which. - **P3 (auto-merge on a draft)** — the PUT is REFUSED, and the refusal is the reading: 422, nothing stored, `auto_merge` still `null` on read-back. The DELETE then also answers 422 ("Can't disable auto-merge for this pull request") because nothing was armed — so a 422 from DELETE is not evidence of a failed disarm, and the read-back is what decides. - **`DELETE` on an ARMED PR stays unmeasured here, deliberately.** Arming auto-merge would require a non-draft PR, and this PR's diff touches a governed surface, where Prime Directive #14 forbids arming outright. Recorded as not measured rather than inferred. - **`convert_to_draft`** was already written as a fact on :48 under a tick it had never earned; the probe makes the tick true. No new row is owed for it, so none is added. ## Rows landed — five, and what paid for each The file is at its 82-line ceiling with no standing raise exception, so the currency is deleted content, never a re-wrap. Line count 82 → 82; bytes 6,738 → 6,965. | Row added (bytes) | Paid by | |---|---| | `- 两只桶:MCP 记链接用户 5000/时…` (102 B) | tick-convention row + the no-tick prohibition, 108+56 B over 2 lines → 114 B over 1: `不是全局事实` restated `按席位类别限定`, and `的形状` / `复述` / `一个` went with it | | `- ✓ 线程 GET …/ccr/review_threads…` (115 B) | check-runs/actions row + quota-read row, 88+61 → 120 over 1: `端点自身` and `自读` deleted | | `- 线程自己建:POST …/pulls/{n}/comments…` (109 B) | update-branch row + its rationale tail, 91+81 → 114 over 1: the `它是…手段` framing deleted, and `不重写历史` is entailed by `真合并提交` | | `- ✓ POST …/ccr/comments/{id}/resolve…` (114 B) | the two `expected_head_sha` rows, 70+85 → 112 over 1: the pinned error prose `no new commits on the base branch` deleted — nothing parses it, and the standing rule is not to pin error copy | | `- ⛔ PUT …/ccr/auto_merge 在 draft 上 422…` (112 B) | bare-`PATCH`-draft row + the read-back rule, 97+113 → 115 over 1: `timeline 的 ready_for_review` restated the read-side timeline row | A sixth deletion came first, in its own commit: the two provenance dates left on the bare-`PATCH` row and the MCP-fallback row (19 B and 33 B). They are the class the file's own rules-only lowering removed; deleting them is what let the rows above fit. No rule was dropped. Every merged row keeps both of its rules; what left the file is restatement, framing, an entailment and one pinned error string. ## Gates `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, no paths, derived 15 families on head `95065f36`; all 15 run in the foreground with `$?` captured by redirect before any pipe; reconciled with `--ran`: ``` Run reconciliation — 15 derived, 15 run, 0 NOT-MEASURED, 0 UNRUN. ✓ dispatch-gates --ran: 15 derived famil(ies) accounted for — 15 run, 0 NOT-MEASURED (a DERIVED zero — all 15 recorded an exit code and none of them is 3). ``` One family first answered `exit 3` (PREREQUISITE NOT MET — `@objectstack/formula` and `@objectstack/lint` not built), which is not a red gate; after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` under the shared verify lock it exits 0. `check:pm-dispatch-gates` is not in this card's derivation. Reverse verification on the head: - `wc -l` → **82**, equal to the ceiling. - `awk 'length($0)>120'` → prints nothing, for touched and untouched lines alike. - `pnpm check:pm-skill-ratchet` → 0 · `pnpm check:pm-skill-id-lint` → 0 (27 files clean, pattern `/#[0-9]{3,}/g`) · `pnpm check:pm-governed-prose` → 0. `pnpm lint` is CI-owned and was narrowed, with the narrowing proved rather than assumed: every `files:` selector in `eslint.config.mjs` is a JS/TS extension glob and none names `.md`; `eslint --no-inline-config --format json` over the one changed file reports `File ignored because no matching configuration was supplied`, 0 errors and 0 warnings from rules; and since the diff is a single markdown file outside that population, no untouched file's verdict can move. `skip-changeset`: `.claude/**` is on the fast track — nothing any package's `files[]` ships moves here. ## 维护者速读(草稿) **改了什么** —— PM 席位的 REST 通道对照表新增五条读数:评审线程的三条 CCR 路由(取线程、 解决、取消解决)、auto-merge 在 draft 上的两个拒绝,以及 MCP 与 REST 分属两只限流桶这一事实。 **为什么改** —— 会话代理自己的 403 报文点名了这批路由,但表里此前只有其中两条被实调过。 未实调的路由写进表里就是「未带 ✓ 的形状当已验证事实」,而这正是该表第一节明令禁止的。 这一轮每条路由都在本 PR 自己的 draft 上跑过一次才落行。两只桶那条解决的是另一件事: 席位的 MCP 状态动作会被同一 GitHub 用户下别的会话的读耗光,而 CCR 路由走的是另一只桶, 所以「换通道」在这里是合法退路,不是违规续写。 **风险与代价(含回滚)** —— 只改一个 markdown 参考表,不改任何运行时代码,发布面零变化。 文件行数仍是 82(天花板),字节数 +227。回滚 = revert 本 PR,无迁移、无残留状态。 探针在本 PR 上留下一条评审评论线程(已 resolved)与两次 draft 翻转,PR 终态是 draft、 auto-merge 未挂载。 **席位意见** —— **你要做的** —— 无需维护者动作:本 PR 的受管路径全部落在 `references/**`,按分层裁定 走席位 contract-tier 复审后进队列。 ## Acceptance notes - noted, not filed: `added_to_merge_queue` now appears three times in this one file (the read-side timeline row, the write-side queue-read row, and queue criterion ②), and the write-side row still spells `git rev-list --parents` although :66 routes that spelling to `platform-readings.md` — against the file's own `⛔ 不在两处各存一份`. Consolidating it would free two more lines. Carrier: the next PR that pays density on this file — the rules-layer change already queued behind this one touches :53 in the same block. - noted, not filed: `DELETE .../ccr/auto_merge` on an ARMED pull request has no reading in this repo yet, and cannot get one from a governed-surface PR. It needs a non-governed card that legitimately arms auto-merge and disarms it again. Carrier: none today. - The probe thread on this PR is left RESOLVED. The PR ends draft, `auto_merge: null`. --- _Generated by [Claude Code](https://claude.ai/code)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent b722547 commit c053f74

1 file changed

Lines changed: 11 additions & 11 deletions

File tree

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

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
## 通道边界
66

77
- 出口代理按设计只放 repo-scoped 路径(`/repos/{o}/{r}/...`)加 `/rate_limit`;org 级端点未实测。
8-
- ✓ 按席位类别限定,不是全局事实:每个 ✓ = 在一个会话门开着的席位实调通过。
8+
- ✓ 按席位类别限定:每个 ✓ = 会话门开着的席位实调通过,⛔ 无 ✓ 不当已验证事实。
99
- 会话门关着的席位本表两侧整表不可达:repo-scoped 读写全 403、`gh` 缺席,而 MCP 与 git 正常。
1010
- ⇒ 先跑一条 repo-scoped 探针再选通道。
1111
- 403 后 `/rate_limit` 判凭据形态:15000/时 = 凭据活被 repo-scoping 拒;60/时或 auth 错 = 无凭据。
12+
- 两只桶:MCP 记链接用户 5000/时,兄弟会话共享同桶;REST/CCR 记 App 安装 15000/时。
1213
- 限流拒绝绑定被拒身份(报文 user ID):同身份各写通道一并耗尽,⛔ 换通道续写与重试同罪。
1314
- 他侧只在身份不同时是退路:凭据 `GET /user` ≠ 被拒 user ID 才换;席内 PM 与 dev 同一身份。
14-
- ⛔ 未带 ✓ 的形状不当已验证事实复述。
1515

1616
## 读侧 —— 全部可迁移
1717

@@ -26,10 +26,10 @@
2626
- ✓ 整条评论线 `GET .../issues/{n}/comments?per_page=100`。
2727
- ✓ Timeline 事件 `GET .../issues/{n}/timeline`:cross-ref、`added_to_merge_queue`、ready_for_review。
2828
- ✓ PR diff `GET .../pulls/{n}` 带 Accept `application/vnd.github.diff`;文件清单 `.../pulls/{n}/files`。
29+
- ✓ 线程 `GET .../pulls/{n}/ccr/review_threads` 回 `{resolved,outdated,path,line,comment_ids}`,无线程 id。
2930
- ✓ 取某 ref 上的文件 `GET .../contents/{path}?ref=...`,raw accept。
3031
- ✓ 祖先与对比 `GET .../compare/{base}...{head}` —— 浅检出上本地祖先判据不可信时的正解。
31-
- ✓ 门禁与 workflow `GET .../commits/{sha}/check-runs` · `GET .../actions/runs`。
32-
- ✓ 配额自读 `GET /rate_limit`,端点自身零计费。
32+
- ✓ `GET .../commits/{sha}/check-runs` 门禁、`GET .../actions/runs` workflow、`GET /rate_limit` 配额零计费。
3333

3434
## 写侧 —— 全部可迁移
3535

@@ -41,16 +41,16 @@
4141
- 请求体走文件(`-d @file`)或引号定界 heredoc(`<<'EOF'`),⛔ 永不内联双引号串。
4242
- 双引号内 shell 先展开反引号、`$(...)`、`$VAR`,请求尚未成形;只标题坏而正文完好即此形。
4343
- ✓ 请求复审 `POST .../pulls/{n}/requested_reviewers` · 开 PR `POST .../pulls` 带 `draft=true`。
44-
- ✓ 把 `origin/main` 合进 PR head:`PUT .../pulls/{n}/update-branch`,PM 席位可用。
45-
- 它是零文件写的合 main 手段,产出真合并提交、不重写历史。
46-
- `expected_head_sha` 必须是完整 40 字符 SHA,短 SHA 回 422。
47-
- base 未动回 422 no new commits on the base branch = 无事可做,不是失败。
44+
- ✓ `origin/main` 合进 PR head:`PUT .../pulls/{n}/update-branch`,PM 席位、零文件写、真合并提交。
45+
- `expected_head_sha` 须完整 40 字符 SHA(短 SHA 回 422);base 未动回 422 = 无事可做,不是失败。
4846
- ✓ draft 转 ready `POST .../pulls/{n}/ccr/ready_for_review`,反向 `.../ccr/convert_to_draft`。
49-
- ⛔ 裸 `PATCH /pulls/{n}` 带 `{"draft": false}` 回 200 且什么都没改(2026-09-11 实调),读回仍 draft。
50-
- ⇒ 状态码不作数,读回才作数:`GET /pulls/{n}` 的 `draft: false`、timeline 的 `ready_for_review`。
47+
- ⛔ 裸 `PATCH /pulls/{n}` 带 `{"draft": false}` 回 200 零改;状态码不作数,`GET /pulls/{n}` 才作数。
48+
- 线程自己建:`POST .../pulls/{n}/comments` 带 `commit_id`·`path`·`line`,回读看 `review_threads`。
49+
- ✓ `POST .../ccr/comments/{id}/resolve` · `/unresolve`;`{id}` 是评审评论 id,⛔ 只在自己 PR 上探。
5150
- ✓ auto-merge 挂载 `PUT .../pulls/{n}/ccr/auto_merge` 带 `{"merge_method":"SQUASH"}`,`DELETE` 卸载。
51+
- ⛔ `PUT .../ccr/auto_merge` 在 draft 上 422 零存储;`DELETE` 无挂载回 422 = 本就没挂,非失败。
5252
- 入队读 timeline `added_to_merge_queue`,落地读 `git rev-list --parents`;⛔ `auto_merge` 与回显都不作数。
53-
- 两条 2026-09-12 两席实调;备用通道 MCP `update_pull_request` 与 `enable_pr_auto_merge`。
53+
- 备用通道 MCP `update_pull_request` 与 `enable_pr_auto_merge`。
5454
- 直合仓 `PUT .../pulls/{n}/merge`;actor 记通道令牌:REST 按会话为 `claude[bot]` 或用户,MCP 恒用户。
5555

5656
## 不可迁移 —— 只有这三件,围着它们排计划;红窗守候规则住 `platform-readings.md` 配额段

0 commit comments

Comments
 (0)