Skip to content

pm-dispatch: an open PR names its owner — pr_create assigns the claim's Account, a hand-over re-assigns it, and H76 reports an unowned PR - #30796

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-jhzb1f
Nov 6, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-jhzb1f

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Elon · project thread

domain:skills#1 · os-elon-musk · session_016WV4d1MNyKiUFDBccFX8Cc

Fixes #29828

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:按裁决 A 落地「PR 挂处理人」。开发经中继 pr_create 开 PR 时就把处理人挂成认领评论里的 Account:(即卡的处理人);换手(兄弟席接管、释放、改派)与认领变更同笔改 PR 处理人;交棒请审时仍 ⛔ 不请席位自己的账号。半状态巡查新增 H76 行:开着的、非信箱 PR 没有处理人就列出来(只报告,不是门禁)。
  • 为什么改:原规则禁止 PR 挂处理人,实测今天开着的 52 个 PR 里 0 个有处理人,GitHub 列表上看不出谁负责,排查闲置 PR 只能逐个读评论。
  • 风险与回滚:只动 .claude/** 规则文本(Tier S)与 scripts/pm/ 巡查工具,不发布(skip-changeset)。中继本来就支持 pr_create 带 assignees,不改代码。H76 不写任何标签、处理人或评论,不挡合并。各规则文件行数不变、每行仍在 120 字节内,未抬任何上限。回滚即 revert。
  • 先看:① .claude/skills/pm-dispatch/references/execution-duties.md 认领节第 69 行(规则本体与换手同笔);② scripts/pm/check-half-states.mjs 的 h76OpenPrWithoutAssignee 与 sweep 里的接线;③ .claude/skills/pm-dispatch/SKILL.md 第 198–199 行(交棒请审只留「不请席位自身账号」)。
  • 两分钟验证:node scripts/pm/check-half-states.mjs --self-test,末行电池清单里应见 H76 unowned open PR 12/11,并以 0 退出。
  • 需要你做的:无,席位落地(Tier S,席位达档复核 PASS 且全绿后落地;存量 PR 的一次性补挂由席位在规则落地后经中继执行)。

What changes

Ruling record 6674390671 (letter A, maintainer 「按推荐裁」) on #29828, encoded in the three texts it names plus every restatement found under .claude/**:

  • .claude/agents/os-dev.md rule 2 (L38): the PR's assignee is the claim's Account:, carried by pr_create; a hand-over is the seat's. Was 「PR ⛔ 不带 assignees(中继虽收),席位交棒才派」.
  • .claude/agents/os-dev.md write budget (L62): pr_create carries labels and assignees. Was 「⛔ 无 assignees」.
  • .claude/skills/pm-dispatch/references/execution-duties.md 认领 (L69; L67 at 1371b9d8): the PR is assigned to the claim's account and a hand-over re-assigns it in the same stroke. Was 「PR ⛔ 不派席位账号」.
  • .claude/skills/pm-dispatch/SKILL.md hand-off step ③ (L198-199): 「⛔ 永不派/请席位自身账号」 keeps only the request half (the ruling replaces the assign half alone; a review request to the seat's own account stays forbidden); 「pr_create 不请不派」 becomes 「pr_create 派不请」.
  • .claude/skills/pm-dispatch/references/dispatch-runbook.md (L140): a card thread does not write the CARD's assignee — the PR's is now written by its pr_create.
  • scripts/pm/check-half-states.mjs: row H76, report-only, band state (H1's): an open PR with no assignee, a pm:mailbox PR excepted. The mailbox label is mailbox-open.mjs's MAILBOX_LABEL, imported lazily as H72 does; when it cannot be loaded every unowned PR fires UNJUDGED, never clean. Drafts are included. Free: it reads the open listing the sweep already holds. ⛔ No gate wiring.

Every file keeps its line count (each edit rewrites its own line in place) and every touched line stays within the 120-byte line budget; no ceiling moved.

Tests

  • node scripts/pm/check-half-states.mjs --self-test: new battery H76 unowned open PR (12 cases, pin 11): the firing, a ready PR firing like a draft, the assignee exemption (list field and legacy single field), the mailbox exemption beside its unlabelled twin, closed and missing rows, the unread-label UNJUDGED leg for null / undefined / empty, an assigned PR staying clean with the label unread, not-loud, band + emitted, the lazy-import wiring, the roster floor.
  • Live probe (read-only, offline predicate over a REST listing, 2026-11-06 ~03:05Z): 52 open PRs, 0 assigned, 13 unassigned pm:mailbox PRs exempt, 39 would fire H76.

Acceptance notes

Verification

Local subset, recorded as COMMAND :: exit CODE and reconciled with node scripts/pm/dispatch-gates.mjs --ran FILE --repo objectstack-ai/objectstack:

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (No schema touched.)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes.
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. (Publishes nothing: skip-changeset.)
  • 6. packages/spec touched: its generated artifacts are regenerated and committed. (Not touched.)
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…'s Account, a hand-over re-assigns it, and H76 reports an unowned PR

Ruling record 6674390671 (letter A) on #29828. The dev's pr_create now
carries the claim's Account as the PR's assignee (os-dev.md rule 2 and the
write budget), the 认领 line in execution-duties.md says a hand-over
re-assigns it in the same stroke as the claim change, SKILL.md's hand-off
step keeps only "never request the seat's own account", and the runbook's
thread rule names the card's assignee. check-half-states gains H76, a
report-only state row: an open non-mailbox PR with no assignee.

Claude-Session: https://claude.ai/code/session_016WV4d1MNyKiUFDBccFX8Cc
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 6, 2026
@github-actions github-actions Bot added the size/s label Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

Contract-review-claim: session_016WV4d1mkgEris4MHHLjtnk · head bcc6eae · 2026-11-06T03:29Z

@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Nov 6, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: bcc6eae49a5b2cc2f77bda6357918830f0210e67
Local-runs: probe — scratch worktree at the head sha ran node scripts/pm/check-half-states.mjs --self-test, check-skill-line-ratchet.mjs (self-test + run), check-governed-prose.mjs and check-skill-id-lint.mjs to verify the H76 battery pin and the ceilings offline; worktree removed afterwards
Scope: hits = .claude/agents/os-dev.md, .claude/skills/pm-dispatch/SKILL.md, .claude/skills/pm-dispatch/references/dispatch-runbook.md, .claude/skills/pm-dispatch/references/execution-duties.md, scripts/pm/check-half-states.mjs + cited = scripts/pm/mailbox-open.mjs, scripts/pm/check-skill-line-ratchet.mjs, scripts/pm/fleet-write/ops.mjs, AGENTS.md, .github/workflows/half-state-patrol.yml, .claude/skills/pm-dispatch/references/state-machine.md

① Derived judgments

  1. Assign at pr_create = the claim's Account — CORRECT. os-dev.md:38 「PR 派认领 Account:(pr_create 带)」 and os-dev.md:63 「pr_create(draft,含 labels 与 assignees)」 replace 「⛔ 不带 assignees」/「⛔ 无 assignees」; execution-duties.md:69 「PR 派认领账号」; SKILL.md:199 「pr_create 派不请」. The relay already accepts it: ops.mjs:2091 lists assignees as optional on pr_create, and the second-leg mechanism is ops.mjs:58-70.
  2. Hand-over re-assigns in the same stroke — CORRECT. execution-duties.md:69 「交棒同笔改」; os-dev.md:38 「交棒归席位」 (the dev's side: the hand-over is the seat's, not the dev's). The card hand-over step execution-duties.md:92 (② assignee 同笔换人) is unchanged and now covered by L69's PR clause.
  3. Reviewer request to the seat's own account still forbidden — CORRECT. SKILL.md:198 keeps 「⛔ 永不请席位自身账号」, dropping only the 派 half; the author-is-approver assign fallback stays.
  4. Tier S/H landing rules unchanged — CORRECT. SKILL.md:197 (③ 请审 = 席位交棒) and SKILL.md:203 (Tier S = .claude/**, 余皆 Tier H) are untouched; the diff touches only L198-199.
  5. "dev never writes the CARD assignee" preserved — CORRECT. os-dev.md:36-38 「卡 assignee 归 PM … 恒不写卡的 assignee」, execution-duties.md:69 「卡 assignee 归 PM,dev 恒不写」, dispatch-runbook.md:140 now says 「不写卡 assignee」 (narrowed from a bare 「不写 assignee」 that would have contradicted the ruling). SKILL.md:29/104-106, state-machine.md:41 card-assignee rules unchanged and consistent.
  6. No in-surface leftover — CORRECT. git grep of .claude/** at head for assignee|不派|派席位|不带 \assignees`|无 assignees|交棒才|席位自身finds no line saying a PR carries no assignee; every remainingassigneehit is a card/seat-post rule (e.g.SKILL.md:29,92-110, seat-post-protocol.md:11, platform-readings.md:170-171,236which are read-channel caveats, not the rule).dispatch-runbook.md:138(线程 ⛔ 不做 harness 开 PR 后指派/请审) forbids the harness's post-open assign, which the relay-carriedassignees` does not use — not a contradiction.
  7. Out-of-surface restatements still carry the old rule, as the PR declares: AGENTS.md:403-404 ("nor the PR's: pr_create carries none; the seat sets it at hand-over") and ops.mjs:103-105, ops.mjs:2093-2094 ("a dev's create carries no assignees"). Not edited here — carrier items, correctly left out of a Tier S diff.
  8. H76 report-only — CORRECT. check-half-states.mjs H76 predicate (the new block after h72OffTableMailboxLines) returns a string or null and writes nothing; the sweep wiring only does findings.push([pr, 'H76', unowned]) over seenPrs (populated from listOpenPullRequests at L23790, the REST /pulls?state=open listing at L21563, which carries assignees/assignee); band H76: 'state' (H1's band, L19617). half-state-patrol.yml:84: "Findings never fail anything. A completed sweep exits 0 whether it found 0 or 40"; lint.yml:1275 runs only --self-test. No gate reads it.
  9. Mailbox exemption — CORRECT: MAILBOX_LABEL = 'pm:mailbox' (mailbox-open.mjs:153) imported lazily the same way H72 does (L23811 vs L23853); unread label fires UNJUDGED_MARKER (L18073) rather than clean; an assigned PR is clean regardless.
  10. Battery meaningful — CORRECT: 12 cases, pin 11 (house "pin just under the count", as L25259-25375 neighbours), covering firing, draft/ready parity, both assignee fields, mailbox vs unlabelled twin, closed/missing rows, three unread-label UNJUDGED legs, not-loud, band + familyRegistryCoverage().emitted (L20038-20055 regex matches the push), lazy-import wiring, roster floor. Probe: ✓ check-half-states self-test: 5252 cases pass … H76 unowned open PR 12/11, exit 0.
  11. Ceilings/byte caps hold — CORRECT: line counts main→head os-dev 405→405, SKILL.md 319→319, dispatch-runbook 245→245, execution-duties 188→188 (zero headroom each, ratchet run ✓ exit 0); changed lines measure 117/105/116/116/120/119 bytes against MAX_LINE_BYTES = 120 inclusive (check-skill-line-ratchet.mjs:2714,2935). Governed-prose and skill-id-lint runs exit 0.
  12. Head delta: git patch-id of 561d532c4..7c76c755 equals the three-dot diff at head (66332495cd…), so the merge commit added nothing.

② Semver level

None — no package touched (paths are .claude/** and scripts/pm/**); skip-changeset label present, Check Changeset check-run success. Clause-②: no and Metadata-protocol: none re-derived as correct: no packages/spec/**, no published schema, no metadata protocol surface in the file list.

③ Boundary flags

④ Design judgment

  • .claude/agents/os-dev.md (L38, L63): the two dev-side lines encode arms 1 and 2 of the ruling in the dev's voice (what pr_create carries; the hand-over is not the dev's), keep the card-assignee prohibition, and stay inside the write budget line. Holds.
  • .claude/skills/pm-dispatch/SKILL.md (L198-199): the minimal edit — 「派/请」 → 「请」, 「不请不派」 → 「派不请」 — keeps the reviewer-request prohibition and the author-is-approver fallback intact, and reads with ③ (L197) unchanged. Holds.
  • .claude/skills/pm-dispatch/references/execution-duties.md (L69): the rule body — assign the claim's account, re-assign at hand-over in the same stroke — sits in the 认领 section beside L68's Account: derivation and L92's card hand-over step, so the PR re-assign is the same stroke as the claim change. Holds.
  • .claude/skills/pm-dispatch/references/dispatch-runbook.md (L140): narrowing 「不写 assignee」 to 「不写卡 assignee」 is required, since a thread's pr_create now writes the PR's. Holds.
  • scripts/pm/check-half-states.mjs: predicate, band, sweep wiring and battery follow the H72/H75 pattern (lazy import, UNJUDGED on unread input, not loud, no write, no exit effect); the row names WHO/HOW and the mailbox out-of-scope. Holds.

No must-fix. No should-fix.

Implemented-by: claude/project-thread-jhzb1f
Reviewed-by: session_016WV4d1mkgEris4MHHLjtnk

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:skills#1 · os-elon-musk · session_016WV4d1mkgEris4MHHLjtnk

维护者速读

  • 改了什么:按你裁的 [Decision] PR assignee: an open PR names its owner — assign it to the claiming seat's account at pr_create (os-dev.md L38/L62 and execution-duties.md L67 forbid it today)? #29828 A,开 PR 时就把处理人挂成认领席位的账号(卡上处理人那个账号),换手时同笔改处理人;请审仍永不请席位自身账号。规则改在 os-dev.md L38/L63、execution-duties.md L69、pm-dispatch/SKILL.md L198-199、dispatch-runbook.md L140。半态巡检新增只报告的 H76 行:开着的非信箱 PR 没有处理人就标出来,不拦合并。
  • 为什么改:你问「为什么很多pr都没有挂处理人」;今天开着的 52 个 PR 里 0 个有处理人,在 GitHub 列表里看不出谁负责。
  • 风险与回滚:4 个 .claude/** 文件只改规则句,行数都不变;check-half-states.mjs 加一行报告规则和 12 例电池。回滚即 revert 本 PR。
  • 先看:references/execution-duties.md L69 和 SKILL.md L198-199。
  • 两分钟验证:node scripts/pm/check-half-states.mjs --self-test,预期通过并含 H76 unowned open PR 12/11。
  • 需要你做的:无。.claude/** + scripts/pm/** 不需人批,复核 PASS(6676189587),席位直接入自动合并。合并后席位按卡线程列好的清单,经中继给现有 39 个开着的 PR 一次性补挂处理人。
  • 席位意见:可合。本 PR 自己已按新规挂了处理人。AGENTS.md L403-404 与中继 ops.mjs 的两处注释还写着旧规则,不在本卡范围,席位另立卡。

席位核对 — ACCEPT · head bcc6eae

  • 形态:5 文件,.claude/**(Tier S)+ scripts/pm/check-half-states.mjs(非受管),skip-changeset,Fixes #29828,作者 objectstack-fleet[bot],处理人 os-elon-musk,未请审。
  • 契约:Clause-② no,Metadata-protocol none,与认领 6675603411 一致。
  • 前提实测:dev 报告 6676350295;复核 grep 了 .claude/**,范围内已无「PR 不带处理人」的句子;「dev 永不写卡的处理人」保留;H76 只报告,信箱 PR 豁免。
  • 门禁 check-runs:head bcc6eae4 上 51 个,31 success,20 skipped(路径过滤预期 skip),0 红。
  • 接受的偏差:无。
  • 范围外去向:AGENTS.md L403-404(Tier H)、ops.mjs L103-105 与 L2093-2094 注释,由席位另立卡。
  • 落地条款:Tier S,席位经中继 pr_ready + automerge_enable;合并后核 [Decision] PR assignee: an open PR names its owner — assign it to the claiming seat's account at pr_create (os-dev.md L38/L62 and execution-duties.md L67 forbid it today)? #29828 已关、摘 pm:dispatched,并按清单补挂开着的 PR 的处理人。

Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 6, 2026 03:50
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge November 6, 2026 03:50
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 100303c Nov 6, 2026
52 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-jhzb1f branch November 6, 2026 04:10
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