Skip to content

pm-dispatch: subscribe relay-opened PRs at collection; seats land through the allow-listed ccr pair; a landing denial stops and surfaces - #19997

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-19990-relay-prs-attach-and-land
Sep 24, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
claude/issue-19990-relay-prs-attach-and-land

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #19990
Clause-②: no

Rule text only, in three pm-dispatch references. This PR adds no allow row, no tool and no gate. .claude/settings.json, scripts/pm/**, SKILL.md and AGENTS.md are 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#1 seat's session, quoted on the card verbatim and in order:

「你的pr为什么没有挂在当前session上」
「写一个 skills 卡片,更新技能」
「包括你刚才为什么不能merge,我当前session设置的是auto」

The same words reached the domain:skills seat directly (claim comment 5817962037): 「你的pr应该挂在当前 session上,对应的卡片优先派发」.

What changed

file · line (after) bytes rule
execution-duties.md :149 (new) 118 Case 1. When a report names a PR, a session seat subscribes it at once (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 :147 87 → 116 The collection line now covers both modes itself ("(两种模式)", "评论与返回消息皆无"), replacing the deleted report-channel line (see Line budget).
landing-operations.md :49 82 → 117 (b). The landing executes the verdict of record (ACCEPT, or the contract-review PASS). It is not a self-approval.
landing-operations.md :51 65 → 115 (a). Ready and auto-merge go only through the two ccr commands that settings.json allow-lists (rest-channel.md :51 / :55).
landing-operations.md :54 (new) 120 (c). A classifier denial during landing means: stop, report to the maintainer, and record the command and the denial reason on the card. ⛔ Never respell the command or switch to the relay to get around it.
landing-operations.md :77 106 + 89 → 111 Case 1, landing side. Every PR in a session seat's window must be subscribed; subscribe any that is missing. The optional 「关键 PR」 wording is gone. The old :77 "not before the report" clause is folded in as 「⛔ 不早于报告」. Routine seats keep polling.
reading-discipline.md :23 82 → 120 (d). A timer text carries no verdict or landing write verb.

Wording 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.

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:

Whether that is enough for a seat landing a PR written by its own mode:subagent dev 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.md old :147 deleted. It read 「报告通道统一:GitHub 是两种模式共用的真相源;dev 终报先落 issue 评论、再作返回消息。」
    • The dev-side ordering lives in .claude/agents/os-dev.md :17–:18 (「报告交付两次,GitHub 优先:同一段 JSON 先作 issue 评论 … 再作为终报消息」).
    • "GitHub is authoritative in both modes" lives in os-dev.md :324 (「两种派发模式(mode:subagent 与 mode:cloud)下 GitHub 都是报告的权威源」). It also stays on the collection line as 「(两种模式)」.
  • landing-operations.md old :77, second clause, deleted. It read 「订阅是感知补充,⛔ 不替代 flip 定点」. The fact lives on:
    • :50: the flip timer is set at ACCEPT.
    • :52: 「CI success webhook 不可靠:⛔ 不坐等」.
    • platform-readings.md :40: 「订阅来的 check_suite.completed 是唤醒不是放行读数」.
    • Its first clause is kept on :77 as 「⛔ 不早于报告」.
  • landing-operations.md old :76 rewritten in place. It dates from 42af12fe7 (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_later is 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 in GOVERNED_APPROVERS (scripts/pm/check-governed-queue-guard.mjs :576). Three texts point the other way:

    • AGENTS.md: "Every GitHub write leaves through scripts/pm/, as objectstack-fleet[bot] … ⛔ Never a bare curl … 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 from node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack was run, with the exit code captured before any pipe. All exited 0: 17 derived commands, plus pnpm check:pm-governed-prose, node scripts/check-skills-token-ratchet.mjs and pnpm check:pm-settings-deny-roster. The reconciliation dispatch-gates --ran reports: "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-expressions first exited 3 (PREREQUISITE NOT MET, unbuilt @objectstack/formula / @objectstack/lint). It exited 0 after turbo run build for 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/main was not merged before opening. It moved by one commit (a docs(qa) change touching none of these files), and the queue rebuilds on current main.

维护者速读(草稿)

改了什么

  • dev 报告里点名了 PR,席位当场订阅这个 PR 的动态,并记进座位贴。规则里写明原因:经中继开出的 PR 永远不会自动挂到会话上。落地说明里原来"给关键 PR 挂订阅"是可选说法,现在改成"落地窗口里每个 PR 都要挂上,缺了就补"。
  • 落地(转 ready、挂 auto-merge)只走 .claude/settings.json 已放行的两条 ccr 命令。席位落地是在执行已记录的复核判决,不是自己批准自己。
  • 落地过程中如果被权限分类器拒绝:停手,报给您,在卡上记下命令和拒绝原因;不换写法,也不改走中继绕过去。
  • 定时提醒的文本里不再写"判决/落地"这类写操作,只写"到时重读什么、满足什么条件"。

为什么改

  • 您问了两个问题。
  • PR 为什么没挂在当前 session 上:中继开的 PR 不会自动挂上,而技能里只有可选的"关键 PR 挂订阅"。
  • auto 模式下为什么不能 merge:engine 席被拒了两次,一次是一条回读命令,一次是一条写着"发 ACCEPT 并落地"的定时器。它随后改走中继落地,而中继没有放行规则。放行的路本来就有:本席今天在 auto 模式下用它落地了 8 个 PR,一次都没被拒。

风险与代价(含回滚)

  • 只改三个技能参考文件的规则文本。行数不变,每行不超过 120 字节。回滚就是 revert 本 PR。
  • ccr 两条命令记在 os-zhuang 名下。而 AGENTS.md 写的是"所有 GitHub 写都经 scripts/pm,以 objectstack-fleet[bot] 身份,永不裸 curl 写",SKILL.md 也写"批准账号永不作席位的关联用户"。这个矛盾早就存在(SKILL.md 本来就写"ready/draft 走 ccr 路"),本 PR 没有新造,只是把它写得更明确。
  • 放行规则不保证分类器一定放行。send_later 在放行清单里,engine 席那条定时器还是按内容被拒了。所以新加了"被拒就停手上报"这一条。

席位意见

你要做的

  • 回一句话,确认下面两件事,或者指出要改哪一件:
    • ① AGENTS.md 第 14 条(Tier S 由所属席位在达档复核记录在案后落地)和 Multi-agent discipline 第 7 条(PR 全绿且已验收就挂 auto-merge),就是席位落地自己子代理所写 PR 的常设授权,不用另外记。
    • ② 用 ccr 两条命令落地,算 AGENTS.md「写只经 scripts/pm」这条规则的例外。是把这个例外写进 AGENTS.md,还是改走中继并加一条新的放行规则,都由您决定。

Generated by Claude Code

…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>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 04357257dbd0e1f2c43ad5faeab9162205f5aa53

Rendered in-seat by the domain:skills#1 seat at 2026-09-24T16:51Z on the diff of head 04357257d (3 files, +7/−7, line counts 183 / 101 / 37 unchanged, every line ≤ 120 bytes — measured on the head; check-governed-merges --pr 19997: GOVERNED, Tier S, .claude/** ×3), the card #19990 with the maintainer's three verbatim words, and the dev report 5818366169 (2026-09-24T16:49Z). Adversarial brief: does any line widen a seat's permissions, add an allow row, tool or gate, route a landing around a refusal, or delete a rule that has no other home?

① Derived judgments

  1. Case 1 — subscription at collection. execution-duties.md :149 「报告点名 PR ⇒ 会话席当即 subscribe_pr_activity 并记座位贴;中继开的 PR 永不自动挂会话」 states the act, the actor, the moment and the reason; landing-operations.md :77 「会话席窗口内 PR 须在挂 subscribe_pr_activity,缺即补;⛔ 不早于报告,Routine 座位轮询」 is the landing-side form, the optional 「关键 PR」 wording gone, the 「不早于报告」 bar kept. Correct — the maintainer's 「你的pr为什么没有挂在当前session上」 answered in rule text.
  2. Paid line in 〈收集〉. Old :147 (「报告通道统一:GitHub 是两种模式共用的真相源;dev 终报先落 issue 评论、再作返回消息」) is folded: the dev-side ordering lives in .claude/agents/os-dev.md :17–:18, 「两种模式下 GitHub 都是报告的权威源」 in os-dev.md :324, and the new :147 keeps 「(两种模式)」 and 「评论与返回消息皆无才进探活/判死」. Verified on the head by git show. No rule lost.
  3. Case 2 (a) — the landing route. :51 「绿即转 ready + 挂 auto-merge,只走 settings.json allow 行的 ccr 两命令」 names the route this seat used for eight landings this shift under auto mode (timeline actor os-zhuang, zero refusals) and SKILL.md :201 already prescribes (「ready/draft 走 ccr 路」). No allow row, tool or gate is added or changed. Correct; the card's ask (a) is answered by the existing allow-listed route, as the dispatch routed.
  4. Case 2 (b) — the authority. :49 「落地执行在案判决,非自批」: the seat's landing executes the review verdict of record (## Contract review + ACCEPT), the standing authorization being AGENTS.md Prime Directive feat: Comprehensive CRM example demonstrating all ObjectStack protocol features #14 and landing-operations.md :58. The dev's open question (b) is answered A — already recorded; the PR's 「你要做的」 ① lets the maintainer say otherwise. Correct.
  5. Case 2 (c) — a landing refusal. New :54 「落地中遭分类器拒 ⇒ 停手、报维护者、卡上记命令与拒因;⛔ 不换拼法或改走中继绕过」 — the harness's own instruction, now in the skill; it bars exactly what the engine seat did (a relay pr_ready / automerge_enable after a denial). Distinct from review-checklist.md :21–:22 (a dev's refused write applied on the seat's own review — a verdict, not a route-around). Correct.
  6. Paid line in §B. Old :76 + :77 folded into the new :77; the dropped clause 「订阅是感知补充,⛔ 不替代 flip 定点」 lives at :50 (the flip 定点) and :52 (⛔ 不坐等) and platform-readings.md :40 (a subscribed check_suite.completed is a wake, not a release reading). Verified on the head. No rule lost.
  7. Case 2 (d) — timer texts. reading-discipline.md :23 「…,⛔ 不带判决与落地类写动词」 (120 bytes): the denied timer carried both an ACCEPT and a landing verb, so 判决 is the right word beside 落地. Correct.
  8. Untouched on purpose: .claude/settings.json, scripts/pm/with-fleet.sh, fleet-write/ops.mjs, AGENTS.md, SKILL.md. Correct — a rule-text card, as claimed.
  9. Write identity (dev open question 0): the ccr pair writes as the seat's linked user (os-zhuang on the timeline), while AGENTS.md and SKILL.md :92 / :94 say every GitHub write leaves as objectstack-fleet[bot]. This diff does not create the tension (SKILL.md :201 and .claude/settings.json :61–:66 already carry the route; this seat's eight landings already show the actor); it names the route in one more place. The seat's answer is A — a named exception for the ccr landing pair in AGENTS.md, a Tier H edit that is the maintainer's; ⛔ not B (a new allow row and a new tool) on the seat's own reading. Carried to the maintainer in the round report and in the PR's 「你要做的」 ②. Not a defect of this diff.

② Semver level

No published package touched; skip-changeset is on the PR and correct; no content/docs/releases/ change. None owed.

③ Boundary flags

  • Dev deviations 1–5: 1 (authority on :49, route on :51 — two lines, since the joint form exceeded 120 bytes) accepted; 2 (old :77's second clause paid, homes verified) accepted; 3 (判决 vs 裁决; 「判决与落地类写动词」) accepted — the corpus's word for a maintainer ruling stays 裁决; 4 (the shared clone deepened with git fetch --shallow-since to trace provenance; no tree edit, the branch base 6bf7f1c0b is on origin/main) accepted — a fetch moves refs, not files; noted for the seat's checkouts, which fast-forward as usual; 5 (attribution per AGENTS.md, model-free) as required.
  • Open questions: 0 → A, (b) → A (①9, ①4).
  • Check-runs on 04357257d at this record: 7 in progress at the report's read; the ready flip waits for every check on the head to complete green with the rostered skips (check-expected-skips.mjs), ⛔ not on this record alone.
  • The PR is subscribed to this session at this collection, per the very rule it lands (:149).

Implemented-by: claude/issue-19990-relay-prs-attach-and-land
Reviewed-by: session_01A22sUB3mUWs6M36VgfijBq

VERDICT: PASS


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants