Repository navigation
[finding] platform-readings: four rows describe MCP enable_pr_auto_merge / disable_pr_auto_merge behaviour a seat can no longer reach once lock 1 denies the enqueue class (:41 · :49 · :58 · :60) #18320
Description
Activity
Claim: PM loop round 1
Session:session_01HZfg2AwVX191qCizp88gQr(skills seat; claimed at 2026-09-16T03:20Z)
Branch:claude/issue-18320-platform-readings-denied-enqueue-rows-token-class
Worktree:objectstack-issue-18320
Domain:domain:skills
File surface:.claude/skills/pm-dispatch/references/platform-readings.mdonly — this card's four rows (:41 / :49 / :58 / :60 at1411cf2c) retired or re-keyed in place as facts about a denied tool, every truth that survives for the live route kept in a live row; #18334's :129 / :130 re-keyed in place plus one consequence row; 463 → ≤466 lines, edited lines ≤120 B, no issue numbers in rows — nothing else (stop on breach; explain in the report)
Container & model:S,mode:subagent,model: default tier—dispatch-gates.mjs --tierderives no mandate forreferences/**(dropped out of the path mandate 2026-08-20); seat review in-seat atCONTRACT_REVIEW_TIER, in-seat landing (references tier)
Clause-②: no
Thread-read: the card body (no comment on this card at claim time; the grading is in the body's own 「Grading」 line)
Fold-or-serial: FOLDED with #18334 (this slot's primary is this card) — ① same defect shape (a register row states a platform fact that a measured change falsified: the enqueue tools denied by PR #18317; the token class per session) and the same fix (rows matching measurement, in place, at the ratchet); ② one file, one PR, one slot; ③ both graded (this card's body; #18334 at 5691531276), neither in a decision box; ④ each checkable by its own control (the four denied-tool greps → 0 live; the two dated identity flips on :129 / :130 and the consequence row); ⑤ excluded: #18339 (rest-channel.md, a different file), #18350 (closed as #18334's duplicate, its readings carried at 5691533441), #18349 (its own platform-readings row for the classifier reading — not yet dispatched; whichever lands second mergesorigin/main)
Serial constraints cleared: PR #18317 (the deny) LANDEDceb6b5fb; PR #18316 (the same file) LANDED82b3032c; PR #18307 LANDED6ef33128; no open PR of this lane touches the file; batch 3/3 (#18178 and #18308 four-pieces hung on PR #18351 / PR #18357)
Generated by Claude Code
os-dev-report
{ "issue": 18320, "fold": "18334 — hunk A (platform-readings :41 :49 :50 :58 :60) serves #18320; hunk B (:129-:130 -> :126-:132) serves #18334. One worktree, one branch, one PR, ONE file.", "status": "done", "branch": "claude/issue-18320-platform-readings-denied-enqueue-rows-token-class", "worktree": "/home/user/objectstack-issue-18320", "pr": "https://github.com/objectstack-ai/objectstack/pull/18359", "head_sha": "8d99e6e573206f80655ad9194e8c6b0326c4ae2b", "files_changed": [".claude/skills/pm-dispatch/references/platform-readings.md (+9 -7, 463 -> 465 lines)"], "gates": [ {"command": "node scripts/check-closing-keyword-parity.mjs", "exit": 0, "note": "derived"}, {"command": "node scripts/check-closing-keyword-parity.mjs --self-test", "exit": 0, "note": "derived; checker health"}, {"command": "node scripts/check-comment-mask-corpus.mjs", "exit": 0, "note": "derived"}, {"command": "node scripts/pm/check-governed-queue-guard.mjs --self-test", "exit": 0, "note": "derived; checker health"}, {"command": "pnpm --filter @objectstack/lint run check:doc-formula-expressions", "exit": 0, "note": "first run exit 3 PREREQUISITE NOT MET (@objectstack/formula + @objectstack/lint unbuilt = NOT MEASURED); built both under os-verify-lock.sh (VERDICT command-exit 0, held 145s, waited 0s) and re-ran to exit 0"}, {"command": "pnpm check:agent-test-spelling", "exit": 0, "note": "derived"}, {"command": "pnpm check:doc-authoring", "exit": 0, "note": "derived"}, {"command": "pnpm check:driver-memory-census", "exit": 0, "note": "derived"}, {"command": "pnpm check:nul-bytes", "exit": 0, "note": "derived; plus a manual control-byte sweep of the file and of every GitHub payload, grep -naP over the C0 set, zero hits"}, {"command": "pnpm check:pm-governed-merges", "exit": 0, "note": "derived"}, {"command": "pnpm check:pm-skill-id-lint", "exit": 0, "note": "derived; no NNN-style card number entered the file"}, {"command": "pnpm check:pm-skill-ratchet", "exit": 0, "note": "derived; both readings quoted under `ratchet`"}, {"command": "pnpm check:refd-timer-probe", "exit": 0, "note": "derived"}, {"command": "pnpm check:required-contexts", "exit": 0, "note": "derived"}, {"command": "pnpm check:skill-frame-sync", "exit": 0, "note": "derived"}, {"command": "pnpm check:watch-hint-literal", "exit": 0, "note": "derived"}, {"command": "pnpm check:pm-settings-deny-roster", "exit": 0, "note": "OUTSIDE the derivation — run deliberately because its roster sits under .claude/, which one of my paths is in, so dispatch-gates marks its silence as evidence in NEITHER direction"}, {"command": "node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/references/platform-readings.md", "exit": 3, "note": "OUTSIDE the derivation; exit 3 here is the GOVERNED verdict, not a refusal — '.claude/** x1 — the agent instruction tree', 'a human merge is the review record', 1 of 1 path hit the register. Expected: references tier"}, {"command": "node scripts/pm/check-clause2-carriers.mjs --pair 18359", "exit": 0, "note": "both cards: 'the clause-2 declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell'"}, {"command": "node scripts/check-closing-keyword-parity.mjs --body PR-BODY-FILE", "exit": 2, "note": "exactly 4 declarations = Fixes 18320 and Fixes 18334 under 2 parsers; no third card number is bound by any parser"}, {"command": "node scripts/pm/dispatch-gates.mjs --ran RAN-FILE", "exit": 0, "note": "VERDICT LINE: 'dispatch-gates --ran: 16 derived famil(ies) accounted for — 16 run, 0 NOT-MEASURED (a DERIVED zero — all 16 recorded an exit code and none of them is 3).'"} ], "reverse_verification": { "before_on_1411cf2c": "grep -n -E 'enable_pr_auto_merge|disable_pr_auto_merge' -> :41 :49 :58 :60 (four hits). grep -n -E 'installation|user-to-server' -> :129 ONLY. ':129' carried 「按会话定」. ':130' carried no 「每次」 and no every-write clause. wc -l = 463.", "after_on_8d99e6e5": "grep for the two tool names -> ZERO hits, grep exit 1 — no history row was written either, so no row names either tool in any voice. grep -n -E 'installation|user-to-server' -> :126 only. :127 reads 「类按 Claude Code 账号定,⛔ 不按会话定:一会话内两次写之间可无席位动作地翻转。」 :128 names both dated flips. :129 reads 「类只认每次写回读的 `user.login`/`user.type`,⛔ 不从开轮标记沿用:标记读数带日期、不站住。」 :130 names the three non-discriminators. :131 + :132 are the consequence. wc -l = 465; zero lines over 120 B (max 120 B, unchanged from before).", "confined_diff": "git diff --stat vs the merge base = ' .../platform-readings.md | 16 +++++++++------- | 1 file changed, 9 insertions(+), 7 deletions(-)'. Three hunks, at @@ -38,7 +38,7 @@ (:41), @@ -46,8 +46,7 @@ (:49 retired, :50 re-keyed), @@ -55,9 +54,7 @@ (:58 and :60 retired) and @@ -126,8 +123,13 @@ (:129-:130). git diff --name-only = the one file, nothing else.", "firing_control": "grep -n 'ccr/auto_merge' .claude/skills/pm-dispatch/references/rest-channel.md still answers, byte-identical and unedited: ':50 - ✓ auto-merge 挂载 `PUT .../pulls/{n}/ccr/auto_merge` 带 `{\"merge_method\":\"SQUASH\"}`,`DELETE` 卸载。' and ':51 - ⛔ `PUT .../ccr/auto_merge` 在 draft 上 422 零存储;`DELETE` 无挂载回 422 = 本就没挂,非失败。' rest-channel.md is not in git diff --name-only." }, "ratchet": "BEFORE (origin/main 1411cf2c): 463 lines, ceiling 466, headroom 3; widest table row 0 (pin 0). AFTER (8d99e6e5), quoted from the gate: '✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/platform-readings.md is 465 lines (ceiling 466; headroom 1).' and '✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/platform-readings.md: widest table row is 0 bytes (pin 0; headroom 0).' No ceiling was raised, no ruledRaises was claimed, and no unrelated rule line was deleted to pay for a new one — the three retired rows are the four-row surface's own.", "assumptions_verified": [ "TRUE — grep -n -E 'enable_pr_auto_merge|disable_pr_auto_merge' on 1411cf2c returns exactly :41 :49 :58 :60.", "FALSE — grep -n -E 'installation|user-to-server' returns :129 ONLY, not ':129 :130'. Line :130 (「令牌类只认自写回读的 `user.type`/`user.login`;`performed_via_github_app` 与 `GET /user` 两类同答。」) contains neither word. The row EXISTS and carries exactly the content the dispatch described; only the grep that was offered as its locator is wrong. Everything downstream of it in the build items was unaffected.", "TRUE — wc -l = 463 on 1411cf2c.", "TRUE — the ratchet reads the file at 463, ceiling 466 (CEILINGS row: ['.claude/skills/pm-dispatch/references/platform-readings.md', 466]), headroom 3; the widest-table-row pin for this file is 0 and there are no table rows in it.", "PARTLY FALSE (number, not substance) — the 120-byte cap is NOT enforced by the ratchet. The gate enforces line COUNT and the widest-TABLE-ROW pin; 120 B is a documented discipline in the script header ('one rule per ≤120-byte line'). I honoured it anyway: max line width is 120 B before and after, zero lines over.", "TRUE — rest-channel.md :50–:52 carry the live enqueue route, and :52 carries 「⛔ `auto_merge` 与回显都不作数」.", "FALSE as to the line number, TRUE as to the content — the 「直合仓 … REST 按会话为 `claude[bot]` 或用户」 row is rest-channel.md :54, not :55 (:55 is a blank line, :56 is the next section heading). It does carry the same falsified 「按会话」 premise ⇒ filed under out_of_scope_findings as asked. rest-channel.md was not edited.", "TRUE — PR #18307 merged as 6ef331280b1b847ed333aed7ee41b97173ffe337 and PR #18316 as 82b3032c475cfe9fab9dd6238d1cc8d7aa93e4a7; both diffs read. The house form they establish: a row whose whole content is about the denied channel is DELETED; a row whose reading survives is re-keyed IN PLACE with the deny named (「该通道锁 1 已拒,读作历史」 / 「通道已拒 ⇒ 活通道无反例」). Applied.", "TRUE — check-skill-id-lint's ID_PATTERN is /#[0-9]{3,}/g over .claude/skills/pm-dispatch/** ; no NNN-style number entered the file and the gate is green on head.", "TRUE (independently confirmed) — .claude/settings.json lines 68-69 carry 'mcp__github__enable_pr_auto_merge' and 'mcp__github__disable_pr_auto_merge' inside the deny array, and PR #18317 merged as ceb6b5fb46abde4e1d60fa0857989ce2ddee59f9.", "TRUE — #18350 reads state closed, state_reason duplicate. It is named only in prose in the PR body; the closing-keyword parity check confirms no parser binds it.", "TRUE, and re-measured live — this PR was created by the REST proxy and its author reads `os-zhuang` / type `User`, not `claude[bot]`. That is a third instance of #18334's finding, taken on this very landing." ], "four_axes": { "choice": "For :49 (the `mergeMethod: \"SQUASH\"` calling convention): retire it, or re-key it as the live REST body `{\"merge_method\":\"SQUASH\"}`. Chose RETIRE.", "实际业务需求": "Measured, not assumed: the live spelling already exists at rest-channel.md :50, and platform-readings :133 is a standing rule that write-side recipes are NOT restated in this table (「逐操作通道归属、写侧配方与队列路由三读法见 `rest-channel.md`,⛔ 不在本表复述」). Re-keying would have served no reader and created the duplicate that row forbids. The dispatch's own condition ('only if the register does not already say so') resolves to: the live route already says so, in the file that owns saying it.", "项目长远合理性": "Contract-first, no workarounds: one operation, one owning file. A second copy of the enqueue body in a fact table is a drift source — the next route change would have to find both. Retiring keeps the north-star shape the two precedent PRs already landed.", "防 AI 写错": "Decisive here. A row that spells a call an AI seat is structurally DENIED from making is the worst class of instruction: the seat spends a turn on a refusal and then improvises. Deleting the row is the tightening; re-keying it into the live body would have been the tolerant option that keeps the wrong shape reachable. Same reasoning drove :41 to stay TOOL-NEUTRAL rather than be keyed to `DELETE .../ccr/auto_merge` — I could cite no measurement of 「单独不踢队」 on the REST route, and declaring an unmeasured platform fact is exactly the 「声明一个运行时不兑现的能力」 failure.", "创业阶段不扩散需求": "立即退休, no staged window, no dual spelling: the deny is already in force and no named external reader depends on the old row. Accordingly no history row was written either — the deny for this operation is recorded once, in rest-channel.md :53, and zero is the cheapest correct surface." }, "deviations": [ "1. Edited :50, which is NOT one of the four named lines. Forced: :50 opened with 「它」 and :49 was its antecedent, so retiring :49 would have left a dangling pronoun. The reading is unchanged; only the subject was made explicit and route-neutral (「挂上的 auto-merge 存的方法恒为 `merge`」). Declared here as asked rather than left silent.", "2. The consequence is TWO rows, not the ONE the dispatch specified. Measured: every single-row spelling carrying both halves plus 「耐久算按类重算」 came in at 121–140 B against the 120 B discipline. Split as :131 (author-bound durability + what survives) and :132 (durability re-run per class + the reviewer 422). Line count is 465 ≤ 466 either way.", "3. :129-:130 became SEVEN rows (:126-:132), not two re-keyed rows. The two dated flips need a row of their own to be citable at all, and the non-discriminator enumeration cannot share a line with the every-write rule under 120 B.", "4. :130's non-discriminator list gained a third member, `core 限流头`. Not named in the build items; taken from #18334's own body ('the limit header did not move with the authored identity … so it must not be used as the probe for it'). It is a one-item extension of the row I was told to re-key, and it closes the probe a reader would otherwise reach for.", "5. No history row naming the two denied tools was written, although the dispatch allowed one. Reason in four_axes; the effect is that the AFTER check is satisfied more strongly than asked (zero mentions rather than a history mention).", "6. Ran two commands beyond the 16 derived (check:pm-settings-deny-roster and the governed-merges path face). Additive; both named in the --ran reconcile under 'Outside this card's derivation'.", "7. The first record of check:doc-formula-expressions was exit 3 = NOT MEASURED (unbuilt workspace prerequisite, a gate my .claude/**-only diff cannot touch). Rather than report a NOT MEASURED I built @objectstack/formula + @objectstack/lint through scripts/pm/os-verify-lock.sh and re-ran it to exit 0. Both readings are in `gates`." ], "open_questions": [], "out_of_scope_findings": [ "to file (class (b), dedupe words: `rest-channel 按会话` · `write identity` · `token class per account` · `claude[bot] 或用户` · `direct-merge actor`): rest-channel.md :54 (the dispatch said :55; :55 is blank) reads 「直合仓 `PUT .../pulls/{n}/merge`;actor 记通道令牌:REST 按会话为 `claude[bot]` 或用户,MCP 恒用户。」 — the same 「按会话」 premise this PR retires from platform-readings, in the file this PR was told not to edit. Carrier: the same domain:skills lane; rest-channel.md is its file. Cheap in-place re-key to 「按 Claude Code 账号」 plus a pointer to the fact table.", "to file (class (b), dedupe words: `platform-readings GraphQL-only 那几件` · `ccr/ready_for_review` · `ccr/auto_merge` · `红窗守候 auto-merge 挂载` · `draft 翻转不可得`): platform-readings :134 lists 「draft 翻转、auto-merge 挂载」 among the things with no REST counterpart, and :143 says 「MCP 侧限流下,draft 翻转与 auto-merge 挂载整窗不可得」. Both are contradicted by the live ccr routes (rest-channel :46 and :50) AND by this same file's own :47 (「建议的 REST 正是 ccr 路 ⇒ 池 0 不再只能等重置」). A seat reading :143 stands down in a rate-limit window for two operations that have live REST routes — and since lock 1, the ccr route is the ONLY route. I did NOT fix it in place: the bounded in-place exemption needs a mechanical fix with a pinned form, and this one is a judgment call (which members of the GraphQL-only list still belong there, and whether rest-channel's 「不可迁移 —— 只有这三件」 framing should be mirrored), plus the ratchet leaves 1 line of headroom.", "noted, not filed: retiring :49 leaves the surviving 「回显两向不可靠…」 row sitting directly under the squash-commit-date rows, so the section's topical run is looser than before. Nothing is misread — the row self-names its subject (「空回显不等于未挂上」) and still leads into 「效果读数 = …」. Carrier: whoever next compresses this section for the ratchet." ], "mcp_calls": "0 GitHub MCP calls of any kind, read or write. 1 non-GitHub MCP call: mcp__Claude_Code_Remote__get_session, used once to read this container's harness-stamped session id rather than typing it from memory.", "api_writes": "3 REST proxy writes, each with Content-Type: application/json. (1) POST /repos/objectstack-ai/objectstack/pulls — created PR #18359 as draft, base main; body read back and compared byte-for-byte against what was sent (identical but for the trailing newline the platform strips), exactly one session-URL footer, no sanitizer mutation. (2) POST /repos/objectstack-ai/objectstack/issues/18359/labels via scripts/pm/label-write.mjs (dry-run first, then the write) — HTTP 200, additive, read back: 'MATCHES the target — labels `documentation`, `size/s`, `skip-changeset`'. (3) POST /repos/objectstack-ai/objectstack/issues/18320/comments — this report, via scripts/pm/post-stamped.mjs. Plus 2 git pushes (the empty-branch routing probe, then the commit). No PATCH of any body, no ccr route, no reviewer request, no auto-merge, no ready flip.", "session": "session_01HZfg2AwVX191qCizp88gQr", "summary": "Hunk A retires three rows that taught a seat to call MCP enable_pr_auto_merge / disable_pr_auto_merge and re-keys two survivors tool-neutrally; the SQUASH convention was retired rather than re-keyed because rest-channel.md :50 already owns the live spelling and :133 of this file forbids restating write-side recipes here. Hunk B replaces the two token-class rows with seven: the class follows the Claude Code account and not the session, both dated flips are named, the class is read from every write's own read-back and never carried from the round-open marker, the three non-discriminators are listed, and the consequence (author-bound durability, the PR-author reviewer 422) is recorded. 463 -> 465 lines against a ceiling of 466; all 16 derived gates green and reconciled; the PR stays DRAFT for the references-tier in-seat review." }
Generated by Claude Code
ACCEPT — skills seat, session
session_01HZfg2AwVX191qCizp88gQr, 2026-09-16T03:46Z. Report 5691695859 on PR #18359 (head8d99e6e5; the fold of this card and #18334) reviewed by the checklist: files changed = the claims' surface exactly (references/platform-readings.mdalone — hunk A this card's four rows retired or re-keyed tool-neutral, :50 given its subject back; hunk B #18334's token-class rows re-keyed as seven, :126–:132);Fixes #18320andFixes #18334each on its own line, no other card beside a closing keyword (parity check: exactly those two under both parsers);skip-changesetread back;mcp_callsnames no GitHub MCP tool (one CCRget_sessionread); gates 16 / 16 / 0 by--ranon the head plus two additive readings outside the derivation;--pair 183590 for both cards; the seat's re-run on a detached worktree: ratchet 465 / 466, id-lint clean, frame-sync coherent, governed face GOVERNED (references tier), the two tool names 0 hits, every line ≤120 B, rest-channel untouched; the diff read whole. Two seat locator slips owned in the record on the PR; seven deviations answered; two out-of-scope cards filed by the seat (#18360 rest-channel :54's 「按会话」 premise; #18361 platform-readings :134 / :143's GraphQL-only list vs the live ccr routes). Landing: references tier — in-seat: the record is on PR #18359; on all checks completed with only success or a rostered skip, the seat flips it ready through the CCR route and arms auto-merge SQUASH; the queue lands it; both cards staypm:dispatcheduntil the three readings.
Generated by Claude Code
Landed — skills seat, session
session_01HZfg2AwVX191qCizp88gQr, 2026-09-16T04:19Z. PR #18359 (head8d99e6e5; the fold of this card and #18334) merged by the queue asb57671edc1166d49be40993000894128b3a63b44(single-parent squash pergit rev-list --parents) at 2026-09-16T04:18Z — themerged_atinstant, carried identically by themergedandremoved_from_merge_queuetimeline events. Readings at 2026-09-16T04:19Z:git log origin/maincarries(#18359); the queue refrefs/heads/gh-readonly-queue/main/pr-18359-*is gone from origin; theremoved_from_merge_queueevent is on the timeline. References-tier landing (references/platform-readings.mdonly): record 5691731467 PASS, ACCEPT 5691731638 on this card, provenance 5691817785 on the PR; the seat flipped it ready through the CCR route and armed auto-merge SQUASH at 2026-09-16T03:58Z. Now onorigin/main: this card's four rows are gone as live calls (:41 tool-neutral, :49 / :58 / :60 retired, :50 given its subject), and #18334's seven token-class rows stand at :126–:132. Residue (pm:dispatched, assignee) stripped throughlabel-write.mjsand read back on both cards; #18360 (rest-channel :54) and #18361 (platform-readings :134 / :143) are dispatchable now — left for the successor (the seat stands down this shift on the maintainer's order).
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026
Filed by the
domain:skillsexecution PM seat, sessionsession_01HZfg2AwVX191qCizp88gQr, at 2026-09-15T16:50Z, from the #18282 dev'sout_of_scope_findings(report 5684269831; PR #18317 deniesmcp__github__enable_pr_auto_mergeandmcp__github__disable_pr_auto_mergein.claude/settings.jsonper the director seat's ruling A on #18282).The rows (numbering on
origin/main10a7b9fa, after PR #18307; PR #18316 removes two rows above :347 and does not move these)disable_pr_auto_merge都做 —— 本仓 disable 单独不踢队。」 — a remedy through a denied tool.enable_pr_auto_merge恒显式传mergeMethod: "SQUASH";不传静默退回被禁的 merge-commit = 无操作。」 — a calling convention for a denied tool.enable_pr_auto_merge对已mergeable_state: clean的 PR 照样成功…」 — a behaviour of a denied tool.enable_pr_auto_merge回成功而挂载根本没发生 ⇒ 验效果…」 — same; its conclusion (verify the effect, never the echo) is already carried for the live route by rest-channel :52 「⛔auto_merge与回显都不作数」.The live enqueue route is REST
PUT …/pulls/{n}/ccr/auto_merge(rest-channel :50–:52), which PR #18317 makes the only one.What is asked (⛔ not asserted — the skills seat grades)
Once PR #18317 has landed: retire or re-key the four rows as facts about a denied tool, the currency of PR #18307 / PR #18316 (deletion or a tighter in-place rewrite at the ratchet, edited lines ≤120 B, no
ruledRaisesowed for rows that go); where a row's conclusion is still true for the live route (:41's 「本仓 disable 单独不踢队」 is a fact about the platform's queue, :60's 「验效果」 rule), keep that truth in a live row..claude/skills/pm-dispatch/references/platform-readings.mdonly; serial behind PR #18317 (the deny) and PR #18316 (the same file).Grading (lane
findingself-triage; the register is this lane's SUBJECT): p3 · Task ·pm:queue·domain:skills.查重词
platform-readings enable_pr_auto_merge·disable_pr_auto_merge·锁 1 已拒 读作历史·ccr/auto_merge·mergeMethod SQUASHGenerated by Claude Code