pm-dispatch: subscribe relay-opened PRs at collection; seats land through the allow-listed ccr pair; a landing denial stops and surfaces - #19997
Conversation
…he allow-listed ccr pair; a landing denial stops - execution-duties 〈收集〉: a report that names a PR is subscribed by a session seat at once and listed on the seat post, because a PR the relay opens is never attached to the session automatically. The standalone report-channel line leaves; its dev-side half lives in os-dev.md. - landing-operations §B: the landing executes the verdict of record, not a self-approval; ready and auto-merge go only through the two ccr commands that settings.json allow-lists; a classifier denial during landing stops, goes to the maintainer and is recorded on the card, never routed around (no respelling, no switch to the relay); the optional "key PR" subscription line becomes the landing-side statement of the collection rule, with its not-before-the-report clause folded in. - reading-discipline: a timer text carries no verdict or landing write verb. Line counts unchanged (183 / 101 / 37); every line at or under 120 bytes. Claude-Session: https://claude.ai/code/session_01A22sUB3mUWs6M36VgfijBq Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Rendered in-seat by the ① Derived judgments
② Semver levelNo published package touched; ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #19990
Clause-②: no
Rule text only, in three
pm-dispatchreferences. This PR adds no allow row, no tool and no gate..claude/settings.json,scripts/pm/**,SKILL.mdandAGENTS.mdare untouched. Line counts are unchanged (183 / 101 / 37), and every edited line is at or under 120 bytes.The maintainer's words, in the
domain:engine#1seat's session, quoted on the card verbatim and in order:The same words reached the
domain:skillsseat directly (claim comment 5817962037): 「你的pr应该挂在当前 session上,对应的卡片优先派发」.What changed
execution-duties.md:149 (new)subscribe_pr_activity) and lists it on the seat post. Reason, stated once: a PR the relay opens is never attached to the session automatically.execution-duties.md:147landing-operations.md:49landing-operations.md:51settings.jsonallow-lists (rest-channel.md:51 / :55).landing-operations.md:54 (new)landing-operations.md:77reading-discipline.md:23Wording choices that differ from the dispatch text:
判决, not裁决, at :49. In this corpus裁决is a maintainer ruling, and判决is the review verdict (execution-duties.md:180–:183, 「判决 ACCEPT / REWORK / ESCALATE」).判决与落地类写动词, not only落地类写动词, at :23. The timer that was denied[Self-Approval]told the seat to post the ACCEPT as well as run the two landing ops.Why no new allow row is owed: case 2 (a)
The allow-listed landing route already exists. The skill already names it, and this PR only makes §B's landing step name it too.
.claude/settings.json:61–:66 allow-listscurl -sS -X POST …/pulls/*/ccr/ready_for_reviewandcurl -sS -X PUT …/pulls/*/ccr/auto_mergefor all three repos. The hotcrm pair was added on 2026-09-24 bye6a5ecb9. That commit also deliberately gavefleet-write/dispatch.mjsno row.git grep -n 'with-fleet' .claude/settings.jsongives 0 hits; the controlgit grep -n 'label-write' .claude/settings.jsongives 2.SKILL.md:201 says 「ready/draft 走 ccr 路」, andplatform-readings.md:48 says 「undraft 单通道:席位凭据走POST .../pulls/{n}/ccr/ready_for_review」.GET /issues/N/timeline, 2026-09-24T16:3xZ):domain:skillsseat under auto mode. Each hasready_for_reviewandadded_to_merge_queuewith actoros-zhuang(the ccr route, which writes as the seat's linked user).objectstack-fleet[bot](the relay route).Where the standing authorization is recorded: case 2 (b)
It is already recorded in the tree, so this PR adds only the one clause at :49:
AGENTS.mdPrime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14: Tier S lands "by the owning seat on a contract-tier review of record".AGENTS.mdMulti-agent discipline §7 and Post-Task Checklist step 2: arm auto-merge on a PR that is green and accepted.landing-operations.md:59 (Tier S).Whether that is enough for a seat landing a PR written by its own
mode:subagentdev is put to the maintainer below. This PR does not rule on it.Line budget: what left, and where each fact still lives
All three files stand at headroom 0. Each new line is paid for by deleting content, not by re-wrapping or raising a ceiling.
execution-duties.mdold :147 deleted. It read 「报告通道统一:GitHub 是两种模式共用的真相源;dev 终报先落 issue 评论、再作返回消息。」.claude/agents/os-dev.md:17–:18 (「报告交付两次,GitHub 优先:同一段 JSON 先作 issue 评论 … 再作为终报消息」).os-dev.md:324 (「两种派发模式(mode:subagent与mode:cloud)下 GitHub 都是报告的权威源」). It also stays on the collection line as 「(两种模式)」.landing-operations.mdold :77, second clause, deleted. It read 「订阅是感知补充,⛔ 不替代 flip 定点」. The fact lives on:platform-readings.md:40: 「订阅来的check_suite.completed是唤醒不是放行读数」.landing-operations.mdold :76 rewritten in place. It dates from42af12fe7(the 2026-08-07 ruling on subscribing key PRs). The newer maintainer words quoted above replace its optional scope.Measured risk that stays open
An allow row does not stop a denial based on content.
mcp__Claude_Code_Remote__send_lateris allow-listed (settings.json:23, present since before 2026-09-20), yet the engine seat's timer was denied[Self-Approval].platform-readings.md:435 records another content-based[Self-Approval]denial.Two explanations are possible: that session did not load this settings file, or the classifier judges content over an allow row. Which one holds was not measured. The eight ccr landings are the positive reading. The new :54 line covers the negative case.
Write identity, a tension this PR did not create. The ccr pair writes as the seat's linked user,
os-zhuang, which is inGOVERNED_APPROVERS(scripts/pm/check-governed-queue-guard.mjs:576). Three texts point the other way:AGENTS.md: "Every GitHub write leaves throughscripts/pm/, asobjectstack-fleet[bot]… ⛔ Never a barecurl… write".SKILL.md:92: 「批准账号永不跑席位或作其关联用户」.SKILL.md:94: 「写侧恒为objectstack-fleet[bot]」.SKILL.md:201 already routes ready/draft through ccr, so this tension predates this PR. The new :51 states the same route more plainly. The choice is the maintainer's; see the question below.Verification
At
04357257d, every command fromnode scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackwas run, with the exit code captured before any pipe. All exited 0: 17 derived commands, pluspnpm check:pm-governed-prose,node scripts/check-skills-token-ratchet.mjsandpnpm check:pm-settings-deny-roster. The reconciliationdispatch-gates --ranreports: "17 derived famil(ies) accounted for — 17 run, 0 NOT-MEASURED (a DERIVED zero …)".Verdict lines:
check:pm-skill-ratchet:execution-duties.md is 183 lines (ceiling 183; headroom 0)·landing-operations.md is 101 lines (ceiling 101; headroom 0)·reading-discipline.md is 37 lines (ceiling 37; headroom 0).check:pm-skill-id-lint:34 file(s) clean.check:skill-frame-sync:the one declared copy of the decision frame is internally coherent.check:nul-bytes:OK … no raw ASCII control bytes.check:doc-formula-expressionsfirst exited 3 (PREREQUISITE NOT MET, unbuilt@objectstack/formula/@objectstack/lint). It exited 0 afterturbo run buildfor those two packages under the verify lock. That first run measured nothing; it was not a failure.No build, test, reverse check or ablation applies to this change: it is rule text only, with no code path.
Acceptance notes
dispatch-runbook.md:128 has cloud cards subscribe as soon as the draft PR exists. The folded 「⛔ 不早于报告」 agrees with it only because a cloud dev reports at draft-PR time (runbook :135). No change is made.origin/mainwas not merged before opening. It moved by one commit (adocs(qa)change touching none of these files), and the queue rebuilds on currentmain.维护者速读(草稿)
改了什么
.claude/settings.json已放行的两条 ccr 命令。席位落地是在执行已记录的复核判决,不是自己批准自己。为什么改
风险与代价(含回滚)
send_later在放行清单里,engine 席那条定时器还是按内容被拒了。所以新加了"被拒就停手上报"这一条。席位意见
你要做的
Generated by Claude Code