pm(skills): probe the unexercised CCR routes and the shared MCP user bucket into the REST channel register - #18259
Conversation
…ft/auto-merge rows The file's standard is rules-only: provenance dates, ruling citations and incident narrative left the corpus when it was lowered to its current ceiling. Two dates survived on the bare-PATCH row and the MCP-fallback row; deleting them is the currency that pays for the CCR rows this branch adds. Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr Co-authored-by: Claude <noreply@anthropic.com>
…uto-merge readings, and the two rate-limit buckets
Five rows land, each paid by deleting content in the same file so the 82-line
ceiling is untouched:
+ the two rate-limit buckets (MCP on the linked user, REST/CCR on the App
installation) -- paid by folding the no-tick prohibition into the tick
convention row, whose "not a global fact" clause restated its own first half
+ GET ccr/review_threads and its response shape (no thread id) -- paid by
folding the quota-read row into the check-runs/actions row
+ the review-comment prerequisite and the resolve/unresolve pair -- paid by
folding the update-branch rationale tail and the two expected_head_sha rows,
dropping the pinned error prose nobody parses
+ the two auto_merge refusals (PUT on a draft, DELETE with nothing armed)
-- paid by folding the read-back rule into the bare-PATCH row, whose
timeline half restated the read-side timeline row
Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr
Co-authored-by: Claude <noreply@anthropic.com>
…register Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr Co-authored-by: Claude <noreply@anthropic.com>
…register Claude-Session: https://claude.ai/code/session_01HZfg2AwVX191qCizp88gQr Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Reviewing seat: ① Derived judgments
② Semver levelNot applicable — nothing published moves; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
|
Landing provenance — skills seat, session Generated by Claude Code |
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 onTHIS draft PR, 2026-09-15T04:48Z–04:49Z. No probe touched another seat's PR.
Probe log
https://api.github.com/graphqlmarkPullRequestReadyForReviewmutationPOST /repos/{o}/{r}/pulls/18259/commentscommit_id+path+line: 49+side: RIGHTid: 4012020890,user.login: claude[bot]ccr/review_threadsGET .../pulls/18259/ccr/review_threads[{"resolved":false,"outdated":false,"path":"…rest-channel.md","line":49,"comment_ids":[4012020890]}]POST .../ccr/comments/4012020890/resolve{}{"comment_ids":[4012020890],"resolved":true}review_threads→"resolved":truePOST .../ccr/comments/4012020890/unresolve{}{"comment_ids":[4012020890],"resolved":false}review_threads→"resolved":falsePOST .../ccr/comments/4012020890/resolve{}{"comment_ids":[4012020890],"resolved":true}review_threads→"resolved":true(final state)PUT .../pulls/18259/ccr/auto_merge{"merge_method":"SQUASH"}, PR in DRAFT{"message":"Pull request Pull request is a draft"}GET /pulls/18259→auto_merge: null(nothing stored)DELETE .../pulls/18259/ccr/auto_merge{"message":"Can't disable auto-merge for this pull request."}GET /pulls/18259→auto_merge: nullPOST .../pulls/18259/ccr/ready_for_review{}{"draft":false}GET /pulls/18259→draft: false; timelineready_for_review, actorclaude[bot]POST .../pulls/18259/ccr/convert_to_draft{}{"draft":true}GET /pulls/18259→draft: true; timelineconvert_to_draft, actorclaude[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),PUTor
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 quotationword for word.
What the probes settled, against the dispatch's assumptions
resolvewant?) — the review-COMMENT id.ccr/review_threadsreturns no thread id at all: each element carries
resolved,outdated,path,lineand
comment_ids, andcomment_ids[0]is exactly what the resolve route accepts. Theregister row names which.
nothing stored,
auto_mergestillnullon 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.
DELETEon an ARMED PR stays unmeasured here, deliberately. Arming auto-merge wouldrequire a non-draft PR, and this PR's diff touches a governed surface, where Prime
Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14 forbids arming outright. Recorded as not measured rather than inferred.
convert_to_draftwas already written as a fact on :48 under a tick it had neverearned; 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.
- 两只桶:MCP 记链接用户 5000/时…(102 B)不是全局事实restated按席位类别限定, and的形状/复述/一个went with it- ✓ 线程 GET …/ccr/review_threads…(115 B)端点自身and自读deleted- 线程自己建:POST …/pulls/{n}/comments…(109 B)它是…手段framing deleted, and不重写历史is entailed by真合并提交- ✓ POST …/ccr/comments/{id}/resolve…(114 B)expected_head_sharows, 70+85 → 112 over 1: the pinned error proseno new commits on the base branchdeleted — nothing parses it, and the standing rule is not to pin error copy- ⛔ PUT …/ccr/auto_merge 在 draft 上 422…(112 B)PATCH-draft row + the read-back rule, 97+113 → 115 over 1:timeline 的 ready_for_reviewrestated the read-side timeline rowA sixth deletion came first, in its own commit: the two provenance dates left on the
bare-
PATCHrow and the MCP-fallback row (19 B and 33 B). They are the class the file's ownrules-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 byredirect before any pipe; reconciled with
--ran:One family first answered
exit 3(PREREQUISITE NOT MET —@objectstack/formulaand@objectstack/lintnot built), which is not a red gate; afterturbo run build --filter=@objectstack/formula --filter=@objectstack/lintunder the sharedverify lock it exits 0.
check:pm-dispatch-gatesis 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 lintis CI-owned and was narrowed, with the narrowing proved rather than assumed:every
files:selector ineslint.config.mjsis a JS/TS extension glob and none names.md;eslint --no-inline-config --format jsonover the one changed file reportsFile ignored because no matching configuration was supplied, 0 errors and 0 warnings fromrules; 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'sfiles[]shipsmoves 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
added_to_merge_queuenow appears three times in this one file (theread-side timeline row, the write-side queue-read row, and queue criterion ②), and the
write-side row still spells
git rev-list --parentsalthough :66 routes that spelling toplatform-readings.md— against the file's own⛔ 不在两处各存一份. Consolidating itwould 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.
DELETE .../ccr/auto_mergeon an ARMED pull request has no reading inthis 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.
auto_merge: null.Generated by Claude Code