Skip to content

Commit 728c73e

Browse files
feat(pm): a ruled decision card still in the box is a patrol row, and the director's ruling lands with its knock (#29515)
domain:skills#1 · huangyiirene · session_01J8VVAnMUWA9rufXzFaEh4J <!-- claude-projects-attribution: {"github_login":"huangyiirene"} --> _Requested by **Irene** · [project thread](https://claude.ai/code/project/chan_01TJXtQ1tVD26ecLDZxFS67x?thread=cmsg_01TJXtQ1tVD26ecLDZxFS67xX16uEpSy2CFTwhKrzT6nhy)_ os-dev · domain:skills#1 dispatch · session_01J8VVAm7suYn3TrFHkbu4N3 Fixes #29386 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:总监章程写明,录裁时裁决、正文 `Ruled:` 行和给车道席的 `Notify: ruling` 敲门是同一笔,漏敲是录裁者欠的半状态;半状态巡查新增 H73 行,列出正文已有 `Ruled:` 却仍挂 `needs-user-decision` 超过 6 小时的卡,附裁决 id、已过时长和欠退箱的 `domain:*` 车道席。 - 为什么改:11 月 2 日录裁的 12 张卡,录裁时一次敲门都没有,11 小时后仍全部挂在决策箱里;巡查没有一行读这种情况。 - 风险与回滚:只读巡查,不写任何标签或评论;章程只改一条录裁规则,新增一行由合并 职责一 里两行同义条款付账,仍为 86 行上限。回滚即 revert 本 PR。 - 先看:`scripts/pm/check-half-states.mjs` 的 `h73RuledCardStillInBox`(围栏剥离、取最新时间戳、`Prior rulings on this card:` 重入例外),再看 `lanes/director.md` 第 13 行与第 39 行。 - 两分钟验证:`node scripts/pm/check-half-states.mjs --self-test`,预期结尾的 battery 列表里有 `H73 ruled card in the decision box 28/25`,且全部通过。 - 需要你做的:本 PR 触及 `.claude/**`(Tier S),由 skills 席复核落地,你无需动作。 ## What changes - **`.claude/skills/pm-dispatch/references/lanes/director.md`** (86 → 86 lines, ceiling unchanged) - New line under the `Ruled:` recording line: the `Notify: ruling` knock to the card's lane seat lands in the same act, its shape is the one `../project-forms.md` spells, and a ruling recorded without its knock is a half state the recorder owes. The existing `⛔ 不新增标签与状态` stays, so the director still writes no label on the card. - Paid in the same file: the two 职责一 lines 「处理三分支之一,收尾 PASS 且工已完 ⇒ 跟到合并为止」 and 「到合并 = 推进到就绪并点名等待,⛔ 不代维护者合并」 say one thing, and are merged into one line with the same terms. No ceiling raise. - **`scripts/pm/check-half-states.mjs`**: new report-only row **H73**, the body-record half of the runbook's declared 「旗一」. - Population: open issues carrying `needs-user-decision`, read on the unscoped open listing beside H62. `needs-user-decision` is not a label page, so this is where those cards are first visible. It is one label read and one body read on rows the sweep already holds, so no new request. - Record: a line-leading `Ruled:` (the shared directive reader, so bullet/bold/backtick decoration reads) whose value opens with a numeric comment id. Fenced blocks are stripped first (`stripMarkdownCode`, inline spans kept). A mid-sentence mention and a line-leading `Ruled:` followed by prose are not records. - Age: from the newest readable UTC stamp on the card's `Ruled:` lines. A record with no readable stamp reports with its age unreadable, never as fresh. Threshold `RULED_IN_BOX_STALE_HOURS` = 6, one standing patrol cycle (`PATROL_CADENCE_HOURS`). - Re-entry: a card whose governing ruling id is named on its `Prior rulings on this card:` line (or the list under it) has lawfully re-entered the box with a new question and is clean. - Row text: the ruling comment id, the age against the threshold, the owing `domain:*` lane seat (or "no lane yet, the triage seat routes it"), the one-act rule and the bell shape's printout. No angle brackets, no tracker number. - Band `stall`, registered in `HALF_STATE_FAMILY_BAND` with its reasons. - Self-test battery `H73 ruled card in the decision box` on the frozen roster (28 cases, pin 25). ## Why Card #29386, letter A. The director records a ruling as a `Ruling:` comment plus a `Ruled:` body line and writes no label; the exit out of `needs-user-decision` is the lane seat's, and the lane learns of the ruling from a `Notify: ruling` bell. Measured on 2026-11-02, twelve cards ruled 01:14Z–10:06Z drew zero bells and all twelve still carried the label at 12:08Z, the oldest 10 h 54 min after its ruling. No patrol row read a `Ruled:` line against the label. ## Verification At 4bf6e86 in objectstack-ai/objectstack: <details><summary>Self-test and ablations</summary> - `node scripts/pm/check-half-states.mjs --self-test`: exit 0, 5213 cases pass; battery `H73 ruled card in the decision box 28/25`, every other battery at or above its pin. - The controls, each beside its positive twin: the same body without the label is clean; a `Ruled:` line inside a backtick fence and inside a tilde fence is clean, and the identical line unfenced fires; a mid-sentence mention and a table cell are clean; a line-leading `Ruled:` followed by prose (the H55 fixture's body) is clean; 5h59m is silent and 6h01m fires; a missing stamp reports; a fresh re-ruling silences an old one, and two old ones report the newer id; the `Prior rulings on this card:` line naming this id (inline or as a list) is clean, naming another id fires, and an id after a blank line is not that line's; closed card, PR row, unreadable labels, missing row and null body are silent. - Ablations on a copy of the committed file (`scripts/pm/zz-ablate-h73.mjs`, deleted afterwards; `git status` clean): fence stripping removed → 3 cases red; label gate removed → 2 red; id requirement removed → 2 red; re-entry exception removed → 2 red; threshold removed → 3 red; the sweep push removed → 21 red, the band/coverage case among them. </details> <details><summary>Live sweep</summary> - `node scripts/pm/check-half-states.mjs` against the live board (objectstack-ai/objectstack, main 86d36e9 plus this commit), exit 0: two H73 rows, #28888 (`domain:spec`, ruling 6568787922, ~13h) and #29029 (`domain:server`, ruling 6573561091, ~8h). #29425 (ruled 14:56Z, ~2h) is under the threshold and silent. That matches the premise re-measured at 16:52Z: three open `needs-user-decision` cards with a line-leading `Ruled:`. </details> <details><summary>Gates</summary> - `node scripts/pm/dispatch-gates.mjs --commands` (no paths, from the merge base) derives 54 commands for the two paths. All 54 exited 0, each exit captured before any pipe. `pnpm --filter @objectstack/lint run check:doc-formula-expressions` first answered exit 3 (prerequisite: no built `@objectstack/formula` / `@objectstack/lint`); after `turbo run build --filter=@objectstack/formula --filter=@objectstack/lint` it exited 0 on the same head. - `dispatch-gates --ran`: 54 derived, 54 run, 0 NOT-MEASURED, 0 UNRUN. - Among them: `pnpm check:pm-half-states` 0, `pnpm check:pm-skill-ratchet` 0 (`lanes/director.md` 86 against ceiling 86), `pnpm check:pm-skill-id-lint` 0, `pnpm check:skill-frame-sync` 0, `pnpm check:doc-authoring` 0, `pnpm check:commit-card-trailers` 0, `pnpm check:nul-bytes` 0. - `pnpm exec eslint --no-inline-config scripts/pm/check-half-states.mjs`: exit 0. </details> - No changeset: only `.claude/**` and `scripts/pm/**` change, which publish nothing, so the PR carries `skip-changeset`. ## Acceptance notes - **The runbook still says the wiring is another card's.** `dispatch-runbook.md` 「机械两旗 report-only,归半状态巡查;接线是另一张卡的事」 is now half-true for 旗一: its body-record half is H73. The runbook is outside this card's surface and at its own ceiling (245), so it is left for the seat. - **旗一's title half stays where it was.** A `[Decision]` title is read from the queue side by H54; this row reads only the body record, as the card scopes it. - **Out of scope as filed:** option B and the reverse direction (a card moved out of the box with no retrievable ruling id), which the runbook assigns to the dispatch-time 决策复读. - **A live shape this row does not read:** a scoped record such as `Ruled (plugin-ai): ID · letter A · UTC` (one open card carries one, outside the box) is not a line-leading `Ruled:` and is not read. The card specifies `Ruled:`; widening the key is a seat call. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (Not touched.) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; eslint over the changed script passes. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. Nothing publishes, so no changeset; both declaration lines are filled in. - [x] 6. `packages/spec` not touched. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English, except the 维护者速读 section, which the lane asks for in Chinese. - [ ] The *Before Submitting* list in CONTRIBUTING.md is done. (Left unchecked: the workspace-wide `pnpm lint` and `pnpm test` were not run; the changed script has no package tests, and eslint over it was run.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01J8VVAm7suYn3TrFHkbu4N3 --- _Generated by [Claude Code](https://claude.ai/code/session_01J8VVAm7suYn3TrFHkbu4N3)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 3d6f230 commit 728c73e

2 files changed

Lines changed: 217 additions & 2 deletions

File tree

‎.claude/skills/pm-dispatch/references/lanes/director.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
- 同卡同笔只一场写,线程即顺序、后记者胜,裁前先读线程。
1111
- 裁决评论首行固定一条:`Ruling: batch #<n> item <k> · letter <X> · maintainer 「<verbatim>」 <UTC>`。
1212
- 录裁同笔改正文:首行加 `Ruled: <评论 id> · letter <X> · <UTC>`;⛔ 不新增标签与状态。
13+
- 同笔向卡的车道席敲 `Notify: ruling`,形状见 `../project-forms.md`;漏敲即录裁者欠的半状态。
1314
- 裁决记录同笔写明所选字母的工作量,读数取自卡面工作量列。
1415
- 划掉原 ⛔ 不派断言,走 `post-stamped --body --ack-through`;漏此笔 ⇒ 接卡者先读正文退决策箱。
1516
- 入口:维护者说处理决裁或处理 contract-review,或 `/pm-dispatch director`。
@@ -35,9 +36,8 @@
3536
- 有者只记摘要台账不呈;所呈每行一句白话讲改了什么,读自 diff 或正文,⛔ 不只凭标题。
3637
- 出处:维护者 2026-10-18 令,原话载卡 24241 正文。
3738
- 非机械 CI 红交回具名读者;机械红可接手,经派发 dev 执行。
38-
- 处理三分支之一,收尾 PASS 且工已完 ⇒ 跟到合并为止。
39+
- 处理三分支之一,收尾 PASS 且工已完 ⇒ 推进到就绪并点名等待合并,⛔ 不代维护者合并。
3940
- 非受管 code PR 绿加 ACCEPT 即入队落地;受管面两层落地见 `../contract-review.md` 落地前检②。
40-
- 到合并 = 推进到就绪并点名等待,⛔ 不代维护者合并。
4141
- 摘要台账每场收工一块,⛔ 不逐落地写块;一次落地的记录 = PR 席位记录 + 落地探针表。
4242
- 之二,大的错误 FAIL 或 REWORK ⇒ 改 `pm:*` 标签即交接,记录留在 PR 或卡上。
4343
- ⛔ 散文点名不是交接:标签才是收件箱,散文对候选查询与 sweep 全不可见。

0 commit comments

Comments
 (0)