Skip to content

docs(pm-dispatch): a seat reads requested_reviewers itself before a Tier H handoff; the per-author request rule is spelled out - #25784

Queued
objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-jsx6o1
Queued

objectstack-fleet[bot] wants to merge 2 commits into
mainfrom
claude/project-thread-jsx6o1

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Sam · project thread

Refs #25782 (not Fixes yet: the card has no claim. The domain:skills seat that claims it names this branch in its Claim: and switches this line to Fixes.)

Clause-②: no
Metadata-protocol: none

What changes

.claude/skills/pm-dispatch/SKILL.md, section 〈路径分叉〉, rule ③ (lines 198–201 on origin/main f0cf3383). Four lines rewritten in place, net 0 lines.

Before:

- ③ 请审是中继 op:`pr_create`/`pr_ready` 命中 Tier H 即向 `GOVERNED_APPROVERS` 全员请审。
- 已请审/已指派/已评审者跳过(零写);PR 作者即其一时请审必 422,op 改为 assign 该账户替代。
- 席位只核对 run 摘要 governed review 行,缺口才手补(免碰 draft 位 REST 路)并在轮次报告点名。
- ready/draft 走中继 op;MCP 兜底已拒;端点见 rest-channel。

After:

- ③ 中继 `pr_create`/`pr_ready` 命中 Tier H 即向 `GOVERNED_APPROVERS` 中未请/派/审者请审。
- 作者是审批人 ⇒ 指派它、请其余(请它必 422),否则请全员;速读只点非作者审批人去批。
- 脱中继开的 PR 无 run 行:交速读前席位恒自读 `requested_reviewers`/`assignees`,⛔ 不只看 run 行。
- 缺口经中继 `pr_request_reviewers`/`assign` 补,⛔ 不碰 draft 位;ACCEPT 与轮报点名脱中继作者。
  • Card item 1 (backstop). The seat reads the PR's own requested_reviewers and assignees before the speed-read, instead of only the run row; a PR opened outside the relay has no run row by construction. Gaps are filled with the relay ops pr_request_reviewers (a missing request) and assign (an approver-author missing its assignment; added on the contract review's note), and the off-relay author is named in the ACCEPT and the round report. This extends contract-review.md's 「另记作者」 note from contract reviews to every Tier H handoff.
  • Card item 2 (per-author rule). Stated in role words, exactly what governedReviewPlan (scripts/pm/fleet-write/execute.mjs:430) computes: covered = requested ∪ assigned ∪ submitted-review; toRequest = uncovered approvers minus the author; toAssign = the author when it is an uncovered approver; a non-approver author (the fleet bot, any other login) gets every uncovered approver requested. Its self-test rows at execute.mjs:1387–1390 pin the same cases.
  • Card item 3 (speed-read). 「你要做的」 names only a non-author approver, because GitHub refuses a self-approval.

Deviation: prose, not the card's table

The card asks for the rule "as a table". It is written as one prose line instead, because:

  • SKILL.md is at its 319-line ceiling (check-skill-line-ratchet.mjs), and a four-row table costs six lines. A raise needs a ruling of record that orders the text; none exists for this card.
  • Every references/*.md that could host it carries a MAX_TABLE_ROW_BYTES pin of 0, which also needs a maintainer ruling to raise.
  • project-forms.md keeps rules in role words and logins out of rules text; the rule in role words covers all four of the card's rows. For reference, with today's GOVERNED_APPROVERS (os-zhuang, hotlong) it reads:
PR author requested assigned can approve
objectstack-fleet[bot] os-zhuang, hotlong — either
os-zhuang hotlong os-zhuang hotlong
hotlong os-zhuang hotlong os-zhuang
any other login os-zhuang, hotlong — either

A direct human merge stays open in every row (rule ②).

Survival of the dropped clauses

The old line 201 is gone; each clause still has a home:

  • 「ready/draft 走中继 op」 and 「MCP 兜底已拒」: references/platform-readings.md:47–48 (「请审恒走它;MCP 兜底已拒」, 「undraft 与挂载走中继 op … MCP 兜底已拒」), and SKILL.md 全体座位的不变量 「内容写只走 REST 代理,⛔ 无 MCP 写」.
  • 「端点见 rest-channel」: references/rest-channel.md spells pr_ready/pr_draft, and landing-operations.md B points there (「拼写见 rest-channel.md」).
  • 「(零写)」 and 「免碰 draft 位」: carried as 「未请/派/审者」 and 「⛔ 不碰 draft 位」 in the new lines.

Not changed: the Writes: line

The dispatch order's Writes: line (PR only through relay pr_create) is already mandatory at references/execution-duties.md:129 (「派发令恒带 Writes: 行」) and references/dispatch-runbook.md:140. The cloud-side miss behind this card was a seat not following that line; no text change is owed.

The maintainer's words (2026-10-25, Claude Code project "cloud", verbatim, as quoted in the card):

等我手工合并的,为什么没有按照 pm-dispatch 技能请求审核

我说的需要更新 github 上的项目吗

这个还识别账户的吗?hotlong 开发的会自动请审吗?

维护者速读(草稿)

  • 改了什么:pm-dispatch 的 Tier H 请审规则改两点。一是席位在交速读前自己读 PR 的 requested_reviewers/assignees,有缺口就经中继补请审,不再只看中继的 run 行。二是把按作者请审的规则写明:作者是审批人就指派他本人、请另一位;其他作者两位都请;速读只请非作者那位批。
  • 为什么改:直接用账户开的 Tier H PR(不经中继)没有自动请审,也没有 run 行可核,cloud 上两张 PR 因此一直没人被请审。
  • 风险与代价(含回滚):只改技能文本,行数不变,删掉的一行在 platform-readings 和 rest-channel 里都还有。回滚即还原这四行。
  • 席位意见:
  • 你要做的:PR 是受管面(.claude/**,Tier S),达档复核在案后由 skills 车道席位落地。

Acceptance notes

Gates (local)

On head c79e2346 (the one-line assign delta): pnpm check:pm-skill-ratchet, check:pm-skill-id-lint, check:pm-governed-prose, check:skill-frame-sync, each exit 0.

On head bc491118: Derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 20 commands, every one exit 0 after pnpm install. pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 (prerequisite: @objectstack/formula / @objectstack/lint unbuilt) and exited 0 after turbo run build of those two. 20 derived, 20 run, each with its exit code recorded before any pipe.

Session: session_01FiwXn7nJjWeZrtvzYraPVj

🤖 Generated with Claude Code

https://claude.ai/code/session_01FiwXn7nJjWeZrtvzYraPVj

…ier H handoff; the per-author request rule is spelled out

The relay requests the governed approvers only on its own pr_create /
pr_ready. A Tier H PR opened directly by an account has no run row,
so a seat that checks only that row never sees the gap. The seat now
reads requested_reviewers / assignees on every Tier H PR before the
speed-read and fills any gap with the relay's pr_request_reviewers.

The per-author rule governedReviewPlan performs is stated: an author
who is an approver is assigned and the others are requested; any
other author gets every approver; the speed-read asks only a
non-author approver to approve.

Net 0 lines (ceiling 319). The dropped line's three clauses survive
in platform-readings.md (undraft through the relay op, MCP fallback
refused) and rest-channel.md (op spellings).

Refs #25782

Claude-Session: https://claude.ai/code/session_01FiwXn7nJjWeZrtvzYraPVj
Co-authored-by: Claude <noreply@anthropic.com>
…sign op

The contract review of this PR noted that an approver-authored PR opened
outside the relay may also lack the author's assignment, which
pr_request_reviewers cannot write. Line 201 names the relay op assign
beside it. 116 bytes, net 0 lines.

Refs #25782

Claude-Session: https://claude.ai/code/session_01FiwXn7nJjWeZrtvzYraPVj
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: c79e23467c2e83a2be82da15a981ad066f40352b
Local-runs: none
Scope: .claude/skills/pm-dispatch/SKILL.md + scripts/pm/fleet-write/execute.mjs (governedReviewPlan :430, governedReviewText, requestGovernedReview :815–860, self-test rows :1387–1392), scripts/pm/fleet-write/ops.mjs (assign :823, unassign :829, pr_create :861, pr_request_reviewers :875, pr_ready :899, pr_draft :907, governedReviewRequests :980), scripts/pm/check-governed-queue-guard.mjs (GOVERNED_APPROVERS :621), scripts/pm/check-governed-merges.mjs (GOVERNED_SURFACES, .claude/** Tier S on objectstack), .claude/skills/pm-dispatch/references/platform-readings.md :44–50, references/rest-channel.md :44 :47 :55–56, references/landing-operations.md :51 :62, references/contract-review.md :29, references/execution-duties.md :59 :129, references/dispatch-runbook.md :140 :143, references/project-forms.md :12, scripts/pm/check-skill-line-ratchet.mjs (CEILINGS :399 SKILL.md 319, MAX_TABLE_ROW_BYTES :2181–2215, MAX_LINE_BYTES :2461 = 120), scripts/pm/check-governed-prose.mjs :166

Inputs read: card #25782 body and its one comment (the implementation offer at 10:42:57, ⛔ not a claim; no rulings, no earlier records), PR #25784 body as it stands at 10:48:33, its file list (one file, +4 −4, two commits), the net diff of c79e2346 against origin/main (5612dd9) read with git diff origin/main... after a fetch (no checkout), the one-line delta bc491118..c79e2346, and the 23 check-runs on the new head as of 10:48–10:49 UTC. This record supersedes the one rendered on bc491118; the finding that head's record raised (the assign leg of an off-relay gap) is what this head answers.

① Derived judgments

The net diff against main is still four lines for four lines at SKILL.md :198–201 (〈路径分叉〉 rule ③). The delta from the previous head is :201 alone: 「缺口经中继 pr_request_reviewers 补」 → 「缺口经中继 pr_request_reviewers/assign 补」. Lines :198–200 are byte-identical to the previous head, and the judgments on them stand; they are restated here so this record reads whole.

  1. :198 「中继 pr_create/pr_ready 命中 Tier H 即向 GOVERNED_APPROVERS 中未请/派/审者请审」 — RIGHT. GOVERNED_REVIEW_OPS is derived from the rows carrying governedReview: true, exactly pr_create and pr_ready (ops.mjs :867, :904; the self-test pins the pair). governedReviewPlan sends only on tier === GOVERNED_TIER_H; covered = requested ∪ assigned ∪ submitted-review (reviewedLogins excludes PENDING), so 「未请/派/审者」 = missing. A Tier S diff (the .claude/** row alone, this PR) sends nothing.
  2. :199 「作者是审批人 ⇒ 指派它、请其余(请它必 422),否则请全员」 — RIGHT in substance. toAssign = missing.filter(isAuthor), toRequest = missing.filter(not author); a non-approver author (the fleet bot, any other login) gets every uncovered approver requested. Precision notes, neither a rule the code does not perform: 「指派它」 and 「请全员」 apply to UNCOVERED approvers, scoped by :198 (an author already assigned by pr_create's assignees leg, execution-duties.md :59, gets nothing sent). 「请它必 422」 matches the plan's own doc comment. 「它」 = 作者, antecedent clear within the clause; the same pronoun for a non-person stands at platform-readings.md :47.
  3. :199 「速读只点非作者审批人去批」 — RIGHT as a seat duty (card item 3), not claimed as relay behaviour. Approver author ⇒ the other approver is named; non-approver author ⇒ either qualifies. A direct human merge stays open by rule ② (:189), so nothing narrows.
  4. :200 「脱中继开的 PR 无 run 行:交速读前席位恒自读 requested_reviewers/assignees,⛔ 不只看 run 行」 — RIGHT. The governed review: row is pushed only inside the relay run (execute.mjs :835–850), so a PR not opened by the App has none by construction. The seat's hand read omits submitted reviews, which the relay counts as covered; the worst case is a harmless re-request of an approver who COMMENTED, and an APPROVED state is rule ②'s landing case. The card asked for exactly these two fields.
  5. :201 「缺口经中继 pr_request_reviewers/assign 补,⛔ 不碰 draft 位;ACCEPT 与轮报点名脱中继作者」 — RIGHT, and now complete against the per-author rule. pr_request_reviewers (ops.mjs :875) is POST /pulls/{n}/requested_reviewers, body reviewers/team_reviewers only. assign (ops.mjs :823) is permission: issues, required issue + assignees, ONE POST /issues/{n}/assignees — the same endpoint and body shape governedReviewRequests (:980) sends for the relay's own toAssign leg, and a pull's number is its issue number, so the seat passes the PR number as issue. Neither path carries the draft field, so 「⛔ 不碰 draft 位」 holds for both (platform-readings.md :45–47 is the measured reading that update_pull_request-shaped writes are the ones that do). The two ops together cover both legs of the plan: request the uncovered non-author approvers, assign an uncovered approver-author. The ACCEPT and round-report naming extends contract-review.md :29 「另记作者」 to every Tier H handoff, as the card asked. No rule here that the relay cannot perform; the only thing the seat does that the relay does not is read the fields by hand, which is the card's point.

Survival of the four removed lines (the ratchet's 「砍点逐条核幸存」), clause by clause — unchanged from the previous head:

  • old :198 「请审是中继 op」 → SKILL.md :94 「内容写只走 REST 代理,⛔ 无 MCP 写」, rest-channel.md :47 「(Tier H 归中继 op)」, platform-readings.md :47 「请审恒走它;MCP 兜底已拒」, new :201. Carried.
  • old :199 「已请审/已指派/已评审者跳过(零写)」 → new :198 「未请/派/审者」; 「PR 作者即其一时请审必 422,op 改为 assign 该账户替代」 → new :199, and the op is now named at :201. Carried.
  • old :200 「席位只核对 run 摘要 governed review 行,缺口才手补(免碰 draft 位 REST 路)并在轮次报告点名」 → new :200–201. Carried and strengthened; this is the card's change.
  • old :201 「ready/draft 走中继 op」 → platform-readings.md :48, landing-operations.md :51 (「经中继 op pr_ready + automerge_enable 落地,拼写见 rest-channel.md」), rest-channel.md :55 (pr_ready, reverse pr_draft); 「MCP 兜底已拒」 → platform-readings.md :47–48, SKILL.md :94; 「端点见 rest-channel」 → landing-operations.md :51. Carried, with the same honest cost: SKILL.md itself now names rest-channel.md nowhere; the reader reaches it via the 阶段细则索引 row for landing-operations.md (:88). Acceptable at a 319/319 ceiling.

Card acceptance: the backstop (:200–201), the per-author rule (:199) and the speed-read naming a non-author approver (:199) are present; the per-author rule is exactly governedReviewPlan's computation, and the remedy ops are the relay's own. The declared deviation (prose, not the card's table) is TRUE and accepted: CEILINGS pins SKILL.md at 319 and the tree at this head is 319 lines; every plausible references/*.md host carries a MAX_TABLE_ROW_BYTES pin of 0 (compile-surfaces.md at 352 is not a host); project-forms.md :12 keeps logins out of rules text, so role-word prose is the register's own form; the login table lives in the PR body. The maintainer's verbatim words ask for the behaviour, not the form.

Ambiguities a seat could misread, none blocking: 「它」 (2), 「未请/派/审者」 (a compression of 未请审/未指派/未评审者, recoverable from the old text and the code's covered), 「请全员」 (every uncovered approver). The assign-leg gap of the previous record is closed by this head.

Measures read off the tree, not run: SKILL.md at c79e2346 is 319 lines; :198–201 are 107, 117, 119 and 115 bytes against MAX_LINE_BYTES 120 (the commit message says 116; the measured byte count of the committed line is 115 — immaterial, both under budget). check-governed-prose.mjs :166 reads SKILL.md for the governed-glob enumeration at :182–183, untouched.

PR body versus tree: the body's "After:" block still shows :201 WITHOUT /assign, its "Line ceiling" note says "at most 119 bytes", and its "Gates (local, head bc491118)" paragraph names the previous head. The body is a claim, not the governed text, and the diff governs; but the seat should have the body's "After:" block and gates paragraph refreshed to this head (relay issue_patch) before the maintainer reads the speed-read, so the body does not misquote the committed rule. Not a FAIL of the text under review.

Check-runs on the head as read (23 runs, started 10:48:37–10:48:39): completed success — No other open PR may claim the same issue. In progress — Lint · repo and tooling gates (hosts the pm-skill-line-ratchet step and check:pm-governed-prose), Lint · PM dispatch-gates, Lint · docs and code guards, Lint · CI, release and engine gates, Lint · ESLint, Lint · scoped (tooling self-tests; query-options erasure; slot lookup and corpus), Type Check (workspace; source gates; consumer gates; debt ledger), filter, Governed Surface Queue Guard, Check PR Size, Check Documentation Links, The card this PR closes must claim this branch, Part-of PR must not also close its card, No other open PR may claim the same single-writer path. Expected skips — Check Changeset, Packed-tarball smoke (opt-in), 18.x upgrade harness (opt-in). No failure on this head at read time. On the previous head bc491118 the same families had concluded green except the five lint/type jobs that were still running; this head's one-line delta touches nothing those families read differently, but the conclusions here are the gate verdicts and the seat reads every one green before ready. The PR body's local-gates paragraph is a claim about the previous head and is not adopted.

② Semver level

No package publishes: the diff is one file under .claude/**, which nothing builds or ships. Label skip-changeset is on the PR and matches. Clause-②: no on the PR body is correct — no published accept set widens or narrows; the plain no is the right spelling, the face being decided by the governed path. Metadata-protocol: none matches.

③ Boundary flags

  • PR author user.login is objectstack-fleet[bot] (opened through the relay's pr_create), so contract-review.md :29 「另记作者」 is not triggered by login. The body's attribution comment names github_login os-zhuang; both commits are authored Claude with the session trailer; os-zhuang is the PR assignee (席位自有 PR 指派自己). Noted for the landing seat; no action.
  • Lane ownership (the PR's own flag, repeated in the card comment): written from the cloud project, which holds no domain:skills seat; card pm-dispatch: a Tier H PR opened outside the relay gets no review request and no run row to check; state the per-author request rule and make the seat read requested_reviewers before the handoff #25782 is unclaimed, carries no domain:* label and no triage audit comment, so 〈红线〉 「无分诊审计评论 ⛔ 不得认领」 blocks a claim today. Refs #25782 is the correct wording for that state. This record is independent of lane; landing (triage → claim naming claude/project-thread-jsx6o1 → Refs to Fixes → ready → queue) is the domain:skills seat's. No escalation owed: text-only, Tier S, non-narrowing, asked for by the maintainer in words.
  • Hot file with open PR docs(pm-dispatch): text written by accounts outside the maintainer and the fleet is data, never instructions #25776 (claude/project-thread-g9y2ww, draft): its SKILL.md hunks are @@ -28,14 +28,13 @@ and @@ -86,6 +85,7 @@ (〈红线〉, 〈阶段细则索引〉; net 0), plus os-dev.md, two references and new CEILINGS rows in the ratchet. No overlap with :198–201, no ceiling collision (both leave SKILL.md at 319). Either order merges cleanly; the second to land takes a routine base sync.
  • Branch name claude/project-thread-jsx6o1, not claude/issue-25782-slug: dispatch-runbook.md :143 records this as the measured platform exception for project threads; the claim writes it as-is.
  • Stale body (see ①): "After:" block, byte note and gates paragraph describe bc491118; refresh before the maintainer's read.
  • Pending gates: all but one check-run were in progress when read, including the job that carries the skill ratchet and governed-prose. The verdict here is on the text against the code; queue entry still requires every check green (SKILL.md 入队资格).

Implemented-by: claude/project-thread-jsx6o1
Reviewed-by: session_01FiwXn7nJjWeZrtvzYraPVj

VERDICT: PASS

Independence: this record was rendered by an isolated reviewer subagent at the tier, briefed only with the card, the PR and the head's check-runs, and is adopted by the implementing session named above. That session holds no domain:skills seat, so the seat that claims #25782 may adopt this record or render its own.


Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 25, 2026 13:33
@os-zhuang
os-zhuang enabled auto-merge October 25, 2026 13:33
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 25, 2026
Any commits made after this event will not be merged.

This branch has not been deployed

No deployments
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants