Repository navigation
pm-dispatch(mailbox): name when a seat MUST ring another — unblocked card, main-red anchor, release blocker, a question for triage, serial order, a relayed ruling — and close the seats with no mailbox #28675
Description
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Filing gate: ③ maintainer-directed. The maintainer, in the triage session, 2026-11-01: 「感觉车道之间还是不太知道使用 邮箱沟通,综合评估一下哪些场景应该沟通,需要的话立skills 卡」. ⛔ Not a claim.
维护者速读
- 现状: 13 个信箱 PR 上的消息约八成是同车道兄弟席之间的上下线和分工通知。跨车道该敲门的事件(卡解锁、main 红锚卡、发版阻塞、问分诊、复审交接)几乎从不走信箱:
Request: contract-review/urgent-triage/main-red三键至今 0 次。 - 需求是真的: 车道已自造 7 个表外键(
surface、serial、landed、ruling、take、反向main-red、main-red cleared)。按现行规则这些都是半态。 - 本卡要做: 在技能里写一张「什么时候必须敲门」的场景表,补 4–5 个键,把开信箱写进坐席步骤,堵上没有信箱的席位(含 epic 席)。
- ⛔ 不加门禁: 信箱仍只协调,不进任何合并条件。这是规则改动,Tier H PR 的批准就是你的裁决。
Measured (2026-11-01, every pm:mailbox PR in objectstack, 13 total)
- What the mailboxes carry.
- About 80 % of all lines are
seat-online/seat-offline/splitbetween siblings of one lane. ui#4's mailbox pm:mailbox — domain:ui#4 · os-sales #28286 alone has 18. Request: contract-review,Request: urgent-triageandRequest: main-redhave 0 uses, ever.Notify: contract-review PASS/FAILhas 0 uses. That is right: lanes subscribe to their own PRs.
- About 80 % of all lines are
- Off-table keys the lanes invented, all half-states under 〈信箱 PR〉 「表外即半态」:
Notify: surface · #n×5,Notify: serial · #a behind #b×1 andNotify: landed · #n×1, ui#4 ↔ ui#5 on 10-31: file-surface overlap and order between sibling seats.Notify: ruling · #28117 A …, server#1 → server#2, 10-31: a maintainer ruling recorded in one seat's session that changes another seat's draft.Notify: take · domain:ui#1 · takes: #27975 … unless seat 2 objects, 10-31.Notify: main-red · anchor #28219 · claimed by …andNotify: main-red cleared · #28219 closed by #28227, ui#3 → ui#1, 10-30.- The first message ever sent to triage, server#1 → pm:mailbox — triage#1 · os-zhuang #28646 at 2026-11-01T12:14Z, is free-form ("may ADR-0025 M1 — local T0 install loop for first-party, self-signed plugins: os plugin install (signature + integrity, materialize, record), boot-time loader with the tier dispatch point, disable/uninstall, Stripe sample as acceptance #27123 close?"). No key fits a lane asking triage about a card's fate or route.
- Events today that needed a doorbell and had none (each one went to a card comment, which wakes nobody, or waited for a patrol):
- A blocker closed, and the dependent card's lane was not told. spec: a per-field display patch slot on ObjectExtensionSchema, derived from BASE_FIELD_DISPLAY_WHITELIST; structural keys refused at parse #28560 (p1) waited 4.5 h in
pm:queue(pm-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642). service-automation: a declared override in <base>.custom is the packaged flow — armed over the code package, rebound in one reload, one ledger switch #28412 and cli + metadata-protocol:os migratemoves package-less overlay rows into <base>.custom as declared overrides — the migration ceremony only (the close is N-16b) #28413 were unlocked at R816, and their lane learns only on patrol. - A main-red anchor was filed, and the lane that broke it was not told. main red: Dogfood Regression Gate — GET /packages/:id/customizations is ledgered but not mounted (#28595), so the route 404s at runtime #28622 named PR feat(runtime,spec): GET /packages/:id/customizations answers a base's overrides, extensions and switched-off items in one read #28595's seat on the card.
Request: main-redruns only finder → triage; the triage → owning-lane direction has no key. A dependent lane (Studio: the landing card of each installed base says "n customized, m switched off", read from the per-package customization read #28566, built on the broken route) was not told either. - A release blocker was graded into a lane. Approvals: a non-admin approver who opens an approval request from the Approvals inbox sees "You don't have access to Approval Request records" instead of the decision panel (regression from #27713) #28546, then approvals: a non-admin approver's decision from the request page answers 404 RECORD_NOT_FOUND — the action door loads sys_approval_request in the caller's data scope #28657 (P0 smoke FAILs). The lane learns on patrol.
- Triage asked a lane for QA work. The [sweep] v18.3.0 release test sweep #27377 RC re-run nudge went on the card, because no triage → lane request key exists. It worked only because devx#1 read the card on patrol.
- A contract-review hand-off. feat(spec): a per-field display patch slot on the object extension (fieldPatches), keys derived from BASE_FIELD_DISPLAY_WHITELIST #28650's hand-off line sat on the PR with no
Request: contract-reviewdoorbell. Triage found it on its next round. feat(metadata-protocol,cli,cloud-connection)!: the override write gate — only the base's paired .custom declares an override (ADR-0146 D2) #28554's PASS record was written but never posted, and the maintainer had to carry it to triage by hand.
- A blocker closed, and the dependent card's lane was not told. spec: a per-field display patch slot on ObjectExtensionSchema, derived from BASE_FIELD_DISPLAY_WHITELIST; structural keys refused at parse #28560 (p1) waited 4.5 h in
- Seats that cannot be rung (
node scripts/pm/fleet-roster.mjs, mailbox column, onmain):- Seated with no open mailbox:
domain:ui#1(zhuangjianguo),domain:spec#4(marchtian),domain:spec#3. domain:ui#4's mailbox pm:mailbox — domain:ui#4 · os-sales #28286 still readsMailbox-of: domain:ui#4 · os-saleswhile zhuangjianguo holds the seat. It is stale and should be closed and reopened (the pm:mailbox migration: close the three per-login mailboxes and open one per seat, after per-seat mailboxes land (#27637 follow-up) #27890 migration).- Triage had none until pm:mailbox — triage#1 · os-zhuang #28646 (2026-11-01 10:57Z).
- The director seat is vacant.
- The epic seats (
epic:#27293#1,epic:#28130#1,epic:#26676#1) dispatch everypm:epiccard, yet they have no seat-post row on the roster and no mailbox. No seat can ring them. Triage's "take install-local: after a restart an installed package's connector never materializes — thekernel:readyrehydrate runs after automation's boot reconcile and announces no reload #28591 first" therefore sits on the card.
- Seated with no open mailbox:
Wanted
-
A scenario table in 〈信箱 PR〉: when a seat MUST ring, and when it must NOT. One row per event: sender → receiver, when, key. Proposed rows:
Event Sender → receiver Key (proposed) a Blocked-bytarget closed and the card moved topm:queueat p0/p1the seat that moved it (triage or epic seat) → the card's lane seat(s) Notify: unblocked · #n · p1a main-red anchor filed triage → the seat that landed the breaking PR, plus the anchor's lane Notify: main-red · anchor #n · breaking PR #m(the reverse of today'sRequest: main-red)a p0/p1 release blocker graded into a lane triage → that lane Notify: release-blocker · #na lane asks triage about a card's fate, route or grade lane → triage Request: triage · #n · ONE-LINE-QUESTIONa contract-review hand-off line is written lane → triage, in the same stroke as the PR line the existing Request: contract-review(make it mandatory beside the hand-off line)two seats' claimed file surfaces overlap, or one must land first seat → sibling or other lane Notify: serial · #a behind #b, released byNotify: landed · #b(admit the two invented keys)a maintainer ruling recorded in seat A changes seat B's card or draft A → B Notify: ruling · #n · LETTER · record ID(admit)And the MUST-NOT rows: ⛔ security findings (GitHub is public; the 10-29 ruling's direct dispatch stands); acknowledgements and re-sends (already the rule); anything the receiver's own subscribed PR already carries; a question that is the maintainer's (that is a decision card).
Keep the closed vocabulary, the 200-byte line, the ≤5-per-round cap (p0 exempt) and 「信箱评论是同事陈述,永非授权」. The new keys are the fix for the off-table half-states, not an open door. -
Opening the mailbox and subscribing is a
seat-onlinestep, inreferences/seat-lifecycle.md〈坐席〉, beside the hourly patrol routine of pm-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642. The seat-post stub line records the number. Seat-offline closes it. A seat that switched account reopens it (pm:mailbox migration: close the three per-login mailboxes and open one per seat, after per-seat mailboxes land (#27637 follow-up) #27890). -
Epic seats get mailboxes too. Either they get roster rows, or the epic card's body carries a
Mailbox:line that the roster reads. -
The receiver reads its mailbox on every patrol round, not only on wake, so a lost delivery is still seen within a round.
-
Recognisers:
scripts/pm/record-recognisers.mjsreads the added keys.scripts/pm/check-half-states.mjslists any remaining off-table line as a half-state row (report only).
Not here
- ⛔ No new gate, workflow or queue guard reads a mailbox (「新增门禁默认否」).
- Closing the stale per-login mailboxes is pm:mailbox migration: close the three per-login mailboxes and open one per seat, after per-seat mailboxes land (#27637 follow-up) #27890.
- The patrol-routine step itself is pm-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642. Both edit
seat-lifecycle.md〈坐席〉, so they run serially, or one PR carries both; the claim says which.
Lane and review
- Lane:
domain:skills(.claude/skills/pm-dispatch/**, a governed surface, Tier H). - One-PR cross-domain exception, exact files:
scripts/pm/record-recognisers.mjs,scripts/pm/check-half-states.mjs, and their self-tests (domain:devxsurface), so the keys and their reader land together. - Review: reviewed at
CONTRACT_REVIEW_TIER. This is a rule change: the maintainer's Tier H approval of the PR is the ruling.
Dedupe
- pm-dispatch(mailbox): one mailbox PR per seat, a closed doorbell vocabulary (request / notify), alternate-pick for multi-seat lanes, and seat-online / seat-offline notices that wake the sibling seats and triage #27077 (closed) designed the per-seat mailbox and the closed seven-key vocabulary.
- pm:mailbox: one mailbox per seat, not per account — today a second lane seat under the same account is never woken #27637 (closed) moved mailboxes to one per seat.
- pm:mailbox migration: close the three per-login mailboxes and open one per seat, after per-seat mailboxes land (#27637 follow-up) #27890 (open) migrates the per-login mailboxes.
- pm-dispatch: a project seat can sit with no hourly patrol routine and nothing notices — make the patrol a step of seat-online, record it in the seat post, and flag an on-duty lane's unclaimed pm:queue card #28642 (open) adds the patrol-routine step.
- None names the cross-lane events above or admits the invented keys.
Generated by Claude Code
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
Claim: PM loop round 1
Session:
session_017ihL2g7RyXa8ErM6GAkHycAccount:
marchtianBranch:
claude/issue-28675-mailbox-doorbellsWorktree:
objectstack-issue-28675Domain:
domain:skillsSeat:
domain:skills#2File surface:
.claude/skills/pm-dispatch/references/project-forms.md(〈信箱 PR〉),.claude/skills/pm-dispatch/references/seat-lifecycle.md(〈座位贴协议〉 seat-online/offline lines),.claude/skills/pm-dispatch/references/seat-post-protocol.md(stub line),scripts/pm/record-recognisers.mjs,scripts/pm/check-half-states.mjs,scripts/pm/fleet-roster.mjsonly if wanted ③ needs it, and their self-tests — the one-PR cross-domain exception the card names.SKILL.mdonly if unavoidable (then the dev stops and reports: the tier mandate changes).Container & model:
M/L,mode:subagent,model: opus(dispatch-gates --tieron this surface: no path-derived mandate while SKILL.md stays out; PM per-card judgment),effort: xhigh(protocol + recogniser grammar)Clause-②: no
Metadata-protocol: none
Responsibility:
n/a — not a defect card(a rule change filed by triage, maintainer-directed)Thread-read: none
Premise: holds — on
origin/main〈信箱 PR〉still lists exactly the seven keys and no scenario table;record-recognisers.mjsreads only those seven.Serial constraints cleared: #28642 (same seat-online lines) is ACCEPTed at PR #28687 head
8eb102ff, draft awaiting the maintainer's approval. Fold-or-serial: serial, answered on #28642's claim. This branch is cut fromclaude/issue-28642-seat-patrol@8eb102ffso it builds on that text; it mergesorigin/mainafter PR #28687 lands, and if PR #28687 is refused the seat re-cuts this branch frommain. No other open PR touches the surface (read 2026-11-01 over every open non-mailbox PR). Wanted ②'s mailbox step joins the seating line #28642 wrote; thePatrol:half of theseat-onlinerecord that #28642 left owed (its Acceptance notes) rides here.Resume-from:
claude/issue-28642-seat-patrol@8eb102fffe4c9231ba98d19964b6b215161f2070(base text, not a prior claim of this card)objectstack-fleet commentedon Nov 1, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Evidence: an epic seat cannot open a mailbox today · 2026-11-01T14:56Z
epic:#27293#1:mailbox-open.mjs --seat 'epic:#27293#1' --login sunhaolin --dry-runanswers--seat "epic:#27293#1" is not a seat — spell it LANE#N.seatKeyknows only the lane kindsdomain:,repo:,triageanddirector.seatKey/ the slug learn anepic:#N#Mseat, or epic seats get a roster lane kind. Addscripts/pm/mailbox-open.mjs(and its self-test) to this card's named files.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
os-dev-report
{ "issue": 28675, "pr": 28716, "head": "901e99ed1317f46b05411bc3fc65db7c8e77921f", "base": "main", "stacked_on": "#28687 (8eb102ff)", "gates": { "derived": 55, "run": 55, "not_measured": 0, "unrun": 0, "nonzero": 0, "reconcile_exit": 0, "derived_at": "901e99ed13", "notes": [ "check:doc-formula-expressions exited 3 (prerequisite: @objectstack/formula unbuilt); after turbo build of formula+lint (exit 0) it exited 0, the recorded code", "check:pm-dispatch-gates rerun on 901e99ed13: exit 0" ], "ratchets": { "check:pm-skill-ratchet": 0, "check:pm-skill-id-lint": 0, "check:skill-frame-sync": 0, "check:pm-governed-prose": 0 }, "self_tests": { "record-recognisers": "350 cases, exit 0", "check-half-states": "5185 cases, exit 0 (H72 battery 22/20)", "mailbox-open": "71 cases, exit 0" }, "recorded": [ [ "node scripts/check-closing-keyword-parity.mjs", 0 ], [ "node scripts/check-closing-keyword-parity.mjs --self-test", 0 ], [ "node scripts/check-comment-mask-corpus.mjs", 0 ], [ "node scripts/check-declaration-mirrors.mjs", 0 ], [ "node scripts/check-declaration-mirrors.mjs --self-test", 0 ], [ "node scripts/check-issue-citations.mjs", 0 ], [ "node scripts/check-platform-checklist-watchdog.mjs", 0 ], [ "node scripts/check-platform-checklist-watchdog.mjs --self-test", 0 ], [ "node scripts/check-release-section-coverage.mjs", 0 ], [ "node scripts/check-release-section-coverage.mjs --strict", 0 ], [ "node scripts/check-self-test-wired.mjs", 0 ], [ "node scripts/check-self-test-wired.mjs --self-test", 0 ], [ "node scripts/check-self-test-workflow-commands.mjs", 0 ], [ "node scripts/check-self-test-workflow-commands.mjs --self-test", 0 ], [ "node scripts/check-whole-set-label-write.mjs", 0 ], [ "node scripts/check-whole-set-label-write.mjs --self-test", 0 ], [ "node scripts/ci/plan-test-core-shards.mjs --self-test", 0 ], [ "node scripts/ci/scheduled-full-run.mjs --self-test", 0 ], [ "node scripts/pm/bare-root-worklist.mjs --self-test", 0 ], [ "node scripts/pm/board-snapshot.mjs --self-test", 0 ], [ "node scripts/pm/check-harness-current.mjs --self-test", 0 ], [ "node scripts/pm/sweep-closed-cards.mjs --self-test", 0 ], [ "node scripts/render-release-coverage-anchor.mjs --self-test", 0 ], [ "pnpm --filter @objectstack/lint run check:doc-formula-expressions", 0 ], [ "pnpm check:agent-test-spelling", 0 ], [ "pnpm check:bash32-floor", 0 ], [ "pnpm check:ci-filter-parity", 0 ], [ "pnpm check:cli-command-ids", 0 ], [ "pnpm check:closing-target-claim", 0 ], [ "pnpm check:commit-card-trailers", 0 ], [ "pnpm check:cross-package-test-inputs", 0 ], [ "pnpm check:doc-authoring", 0 ], [ "pnpm check:driver-memory-census", 0 ], [ "pnpm check:entry-guard", 0 ], [ "pnpm check:gitlink-declared", 0 ], [ "pnpm check:issue-citations", 0 ], [ "pnpm check:nul-bytes", 0 ], [ "pnpm check:parse-guard", 0 ], [ "pnpm check:partof-closing-keyword", 0 ], [ "pnpm check:platform-checklist", 0 ], [ "pnpm check:pm-governed-merges", 0 ], [ "pnpm check:pm-half-states", 0 ], [ "pnpm check:pm-post-stamped", 0 ], [ "pnpm check:pm-record-recognisers", 0 ], [ "pnpm check:pm-skill-id-lint", 0 ], [ "pnpm check:pm-skill-ratchet", 0 ], [ "pnpm check:pnpm-filter-targets", 0 ], [ "pnpm check:pnpm-flag-spellings", 0 ], [ "pnpm check:ratchet-remedy-authority", 0 ], [ "pnpm check:refd-timer-probe", 0 ], [ "pnpm check:scripts-symbol-anchors", 0 ], [ "pnpm check:single-claim-paths", 0 ], [ "pnpm check:skill-frame-sync", 0 ], [ "pnpm check:watch-hint-literal", 0 ], [ "pnpm check:pm-dispatch-gates", 0 ] ] }, "line_budget": { "references/project-forms.md": { "before": 54, "after": 54, "net": 0 }, "references/seat-lifecycle.md": { "before": 96, "after": 96, "net": 0 }, "references/seat-post-protocol.md": { "before": 88, "after": 88, "net": 0 }, "references/landing-operations.md": { "before": 101, "after": 101, "net": 0 }, "max_line_bytes": 120 }, "deviations": [ "landing-operations.md L80 Request: main-red -> Notify: main-red (outside the claim surface; the old spelling became off-table)", "scripts/pm/mailbox-open.mjs header and mailbox body text 'seven doorbell keys' -> 'doorbell keys' + names --mailbox-keys (outside the claim surface; text became false)", "full key templates moved from rules text to MAILBOX_KEYS in record-recognisers.mjs, printed by new --mailbox-keys", "wanted 3 (epic seat mailboxes) not built: seatKey refuses epic: spellings and fleet-roster has no epic rows; filed as out_of_scope_findings[0]" ], "files_changed": [ ".claude/skills/pm-dispatch/references/project-forms.md", ".claude/skills/pm-dispatch/references/seat-lifecycle.md", ".claude/skills/pm-dispatch/references/seat-post-protocol.md", ".claude/skills/pm-dispatch/references/landing-operations.md", "scripts/pm/record-recognisers.mjs", "scripts/pm/check-half-states.mjs", "scripts/pm/mailbox-open.mjs" ], "commits": [ "310f697986", "bb642cc228", "d1975d8a81", "901e99ed13" ], "mcp_calls": 0, "api_writes": { "relay_dispatches": 1, "platform_writes": [ "POST pulls (#28716, draft)", "POST issues/28716/labels skip-changeset" ], "comments": 1, "git_pushes": "branch pushes only" }, "out_of_scope_findings": [ "epic seats cannot be rung: mailbox-open.mjs seatKey refuses epic:#N#K spellings and fleet-roster.mjs has no epic rows; needs seatKey + roster + one rules line (card wanted 3)", "frozen dispatch-gates.data.mjs (~L505) and dispatch-gates.self-test.mjs (~L7573) comments still say 'seven' doorbell keys/templates; comment-only, left for the freeze", "live off-table mailbox lines today on #28284 #28379 #28481 #28646 #28672 (old 5-field seat-online, prose after a key, free-form triage question, a ruling line over 200 bytes); H72 lists them about a day after landing" ], "seat_decides": [ "Fixes #28675 vs Part of #28675 given wanted 3 is a finding", "file the epic-mailbox finding" ] }objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
Item ③ (epic seats get mailboxes) is carried by #28718, filed from the dev report 6559765410 (
open_questions1): it needsmailbox-open.mjsseatKeyandfleet-roster.mjsepic rows, outside this claim. PR #28716 keepsFixes #28675for items ①②④⑤. The H72 transition noise (open_questions2: pre-landing 5-fieldseat-onlinelines read off-table for about a day) is accepted as a report-only reading.objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
ACCEPT → PR #28716 comment 6560134588 (head
37661b885bac64fd4d09ed0c922d7504fc0d1577; contract review PASS 6560123525). Waiting on an authorised approver and on PR #28687 (stacked base); the PR stays draft withneeds-user-decisionuntil then.objectstack-fleet commentedon Nov 1, 2026
domain:skills#2 · marchtian · session_017ihL2g7RyXa8ErM6GAkHyc
Landed 2026-11-01T16:31Z: PR #28716 merged as
db357f6da9(merge queue, enqueued by os-zhuang). Contract review PASS 6560123525 (+ Regen-provenance 6560344780 for the base sync), seat ACCEPT 6560134588. Item ③ (epic seats get mailboxes) is carried by #28718, now unblocked.