Repository navigation
Commit 5d0904c
feat(pm):
Fixes #29745
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:新增 PR 专用标签 `pm:awaiting-merge`(等您审核并合并的 PR 挂它,永不挂
issue);`needs-user-decision` 只留给决策卡(issue)。SKILL.md 复核 ②
与状态表改读法;总监呈批、分诊轮次记录、轮次报告健康指标、车队总表都把「决策卡 N」与「待您审合 PR M」分开计。巡查 H48 与交接检查
`acceptedPullWait` 改读新标签。
- **为什么改**:您的裁决「同意 pm:awaiting-merge」(A):一个标签两种意思,决策箱计数把等您回一个字的卡和等您点合并的
PR 混在一起,呈批分不开。
- **风险与回滚**:不新增门禁、不改六态互斥。风险只在过渡期:本 PR 落地后,巡查 H48 会把仍挂旧标签的受管 PR(现有一张,见
Acceptance notes)报为「缺 `pm:awaiting-merge`」,席位换标即清。回滚 = revert 本
PR;GitHub 上的标签对象留着无害。
- **先看**:① `scripts/pm/check-half-states.mjs`:新常量
`GOVERNED_PR_AWAITING_MERGE_LABEL` 与 `DECISION_INBOX_LABEL`,及 H48 读标签的
hunk(唯一改行为的 hunk);② `.claude/skills/pm-dispatch/SKILL.md`:复核 ② 行与状态表
`needs-user-decision` 行;③ `scripts/pm/ensure-pm-labels.sh`:新标签行与改写的
`needs-user-decision` 描述。
- **两分钟验证**:`node scripts/pm/fleet-roster.mjs --self-test`,预期末行 `✓
fleet-roster self-test: 115 cases in 9 batteries pass.`;再 `pnpm
check:pm-skill-ratchet`,预期 SKILL.md 仍 319 行、五个 references 行数不变。
- **需要你做的**:无,席位落地(落地时席位跑 `bash scripts/pm/ensure-pm-labels.sh
--reconcile` 建标签,并给仍挂旧标签的 PR 换标)。
## What changes
The maintainer's ruling on the card (verbatim: 「同意 pm:awaiting-merge」,
option A). One label, two inboxes: a PR that waits on the maintainer's
own review and merge used to carry `needs-user-decision`, the same label
as a decision card, so the decision count mixed "a letter owed" with "a
review and a click owed".
1. **The label** — `scripts/pm/ensure-pm-labels.sh` gains
`pm:awaiting-merge` ("PR only: landing waits on the maintainer's own
review and merge (SKILL.md 复核 ②); never on an issue", in the per-repo
loop, 100-char cap respected) with its named readers in the comment.
`needs-user-decision`'s description now says "decision cards only, never
on a PR". Kept as is: `pm:awaiting-maintainer` (an issue, a human act
outside GitHub). No new gate.
2. **SKILL.md** (net 0 lines, every edited line ≤120 bytes): 复核 ② now
says 「同笔挂 `pm:awaiting-merge`」; the next clause says it is PR-only and
outside the six states; the state-table row says `needs-user-decision` =
decision cards (issues) only, never a PR; the preamble names the
maintainer's three entry points.
3. **Readers** list the two inboxes apart — 「决策卡 N」 and 「待您审合 PR M」:
- `references/lanes/director.md` (the director's batch and daily
digest), `references/triage-duties.md` (triage round records;
`needs-user-decision` = issues only), `references/seat-lifecycle.md`
(the round report's health metric), `references/state-machine.md` (the
six states are all issue states). Each reference that grew a line paid
for it inside the same file by deleting a duplicated line (details under
Acceptance notes); the others were rewritten in place.
- `scripts/pm/check-half-states.mjs`: H48 (a governed PR with an ACCEPT
verdict must carry the label) now reads
`GOVERNED_PR_AWAITING_MERGE_LABEL` = `pm:awaiting-merge`. The card
readers that had been reusing the PR constant (H52, H62, H73, the ④
dependents index and its renderer) read `DECISION_INBOX_LABEL` =
`needs-user-decision`. Pinned: the old shape (`needs-user-decision` on a
PR) no longer satisfies H48's label half; the new label is not one of
`PM_EXCLUSIVE_STATE_LABELS`.
- `scripts/pm/check-handover.mjs`: `acceptedPullWait` reads the new
label on the stay-behind pull; pinned that the old shape is no longer a
wait.
- `scripts/pm/fleet-roster.mjs`: a new "awaiting merge" column (pulls
carrying the label that close an in-flight card of the seat, attributed
like "awaiting landing"; no new read — labels ride on the open-pulls
listing) and an inbox line under the table: 「决策卡 N · 待您审合 PR M」, counted
apart and never summed. `--json` carries the same `inboxes` totals.
Fixture: pull 25427 carries the label.
- The 终局四件套 prose in `dispatch-gates.mjs`, `check-governed-merges.mjs`
and `check-governed-queue-guard.mjs` names the new label on the PR.
4. **The open PRs in the old shape** — ruling item 4 named PR #29698,
which merged on 2026-11-03 (moot). The search `org:objectstack-ai is:pr
is:open label:needs-user-decision` at dispatch time returned four:
objectstack#30263 (the ADR-0148 docs PR) and three outside the label
loop (duly#157, duly#142, www.objectos.ai#327). Relabelling is a label
write and belongs to the landing seat, not to this PR's write budget.
## Tests
Self-tests of every touched script, run on the final head (readings
under Verification):
- `node scripts/pm/fleet-roster.mjs --self-test` — 115 cases in 9
batteries pass (110 on `origin/main`; 5 new: the column, the retired
shape counts nowhere, `inboxTotals`, the inbox line, no inbox line
without totals; the import pin now also asserts no second spelling of
the label).
- `node scripts/pm/check-handover.mjs --self-test` — 67 cases pass (66
on `origin/main`; 1 new: the retired shape is no longer a wait).
- `pnpm check:pm-half-states` (`check-half-states.mjs --self-test`) —
5224 cases pass (2 new: the old shape no longer satisfies H48's label
half; the PR constant is `pm:awaiting-merge` and not one of the six card
states), with H48's existing cases re-pinned on the new label.
- `pnpm check:pm-label-desc-cap` — 45 descriptions ≤100 chars (longest
100, the pre-existing `tooling`).
- `pnpm check:pm-skill-ratchet` — SKILL.md 319/319, state-machine 41/41,
triage-duties 100/100, seat-lifecycle 98/98, director 86/86; no edited
line over 120 bytes.
- `pnpm check:pm-skill-id-lint`, `pnpm check:skill-frame-sync` — green.
No ablation: the behaviour change is label-name plumbing pinned by the
self-tests above; nothing under `packages/*` moved.
## Acceptance notes
- **Paying the line ratchets** (every ceilinged file at headroom 0; the
currency is deleted content, never a re-wrap):
- `lanes/director.md`: +1 line (待您审合箱 and the two-count rule) paid by
deleting 「本席任何形态都纯召唤制,⛔ 无任何 routine;分诊席默认同项目召唤,职责见 `triage.md`」 — its
first half repeats line 7 (「授权面 = 人工召唤 … 直连 ⛔ 无 Routine/cron」), its
second half repeats `lanes/triage.md` line 4 (「由维护者一句召唤到任一项目,默认同总监席项目」).
- `triage-duties.md`: +1 line (round records split the two counts) paid
by deleting 「Backlog sweep 是常设职责,每 fire 扫任一析取命中的卡」, which line 19
(「首触定级与五析取 sweep 每 fire 跑到清空 …」) subsumes.
- `seat-lifecycle.md`, `state-machine.md`, `SKILL.md`: rewritten in
place, net 0.
- **The GitHub label object is not created by this PR**: no relay op
creates labels, so creation stays a landing step — `bash
scripts/pm/ensure-pm-labels.sh --reconcile` on the loop's repos, which
also rewrites `needs-user-decision`'s live description (the create-only
default would leave the old text). `pm:awaiting-merge` answered 404 on
this repo at dispatch time.
- **Carrier: the landing seat** — relabel objectstack#30263
(`needs-user-decision` → `pm:awaiting-merge`); the three PRs in `duly`
and `www.objectos.ai` sit in repos outside `ensure-pm-labels.sh`'s loop,
so their shape is a seat decision, noted and not filed.
- **Boundary, not filed** (ruling: no new gate): nothing patrols
`pm:awaiting-merge` on an ISSUE, and `label-write.mjs` cannot tell an
issue from a PR without a read; the rule lives in SKILL.md and the
label's description.
- **Untouched on purpose**: `board-snapshot.mjs`,
`references/landing-operations.md`, `references/contract-review.md`
(named as clues) do not read the label; `fleet-roster.mjs`'s "awaiting
ruling" already excluded pulls; the six-state mutex and
`PM_EXCLUSIVE_STATE_LABELS` are unchanged.
- **skip-changeset**: `.claude/**` and `scripts/pm/**` publish nothing
from any released package.
## Verification
Final head `0cf500af` (every reading below was taken on this tree; base
`fdd06415` on `origin/main`). No package is touched, so no ①
dependency-closure build and no ② package test is owed; `test:repo` and
the farm-wide scans are CI's.
**Derived families.** `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` derived 63 commands from the 13
changed files. Every one ran in the worktree with its exit code captured
before any pipe (`bash -c CMD >> log 2>&1; EXIT=$?`). Reconciliation,
`dispatch-gates --ran` over the recorded `command :: exit code` lines:
「63 derived famil(ies) accounted for — 63 run, 0 NOT-MEASURED (a DERIVED
zero — all 63 recorded an exit code and none of them is 3)」.
- One command, `pnpm --filter @objectstack/lint run
check:doc-formula-expressions`, first exited 3 — PREREQUISITE NOT MET
(`@objectstack/formula` and `@objectstack/lint` unbuilt; by the gate's
own text「Nothing was measured … NOT a finding」). After `pnpm exec turbo
run build --filter=@objectstack/formula --filter=@objectstack/lint`
under `os-verify-lock.sh` (VERDICT command-exit 0 · held the lock 2s ·
waited 0s) it exits 0; the reconciliation above is the post-rerun one.
- Local-only families (`check:dev-prereqs`,
`check:skill-frame-freshness`) are not named by the derivation: neither
`packages/spec` nor the four-axis frame files moved.
- CI: the same families run in `Lint & Repo Gates`; the report comment
cites the PR's check-runs by name once they exist, not a local re-run.
<details><summary>63 commands, all exit 0 at head 0cf500a (summary line
of each, where the gate prints one)</summary>
```text
exit 0 node scripts/check-closing-keyword-parity.mjs
exit 0 node scripts/check-closing-keyword-parity.mjs --self-test 40 assertions, 5 mutations each driven to red
exit 0 node scripts/check-comment-mask-corpus.mjs 20780 files, 0 disagree, 0 unparseable
exit 0 node scripts/check-declaration-mirrors.mjs
exit 0 node scripts/check-declaration-mirrors.mjs --self-test 29 cases
exit 0 node scripts/check-issue-citations.mjs
exit 0 node scripts/check-platform-checklist-watchdog.mjs
exit 0 node scripts/check-platform-checklist-watchdog.mjs --self-test
exit 0 node scripts/check-release-section-coverage.mjs
exit 0 node scripts/check-release-section-coverage.mjs --strict
exit 0 node scripts/check-self-test-wired.mjs 249 scripts CI runs, every self-test wired
exit 0 node scripts/check-self-test-wired.mjs --self-test
exit 0 node scripts/check-self-test-workflow-commands.mjs
exit 0 node scripts/check-self-test-workflow-commands.mjs --self-test
exit 0 node scripts/check-skills-token-ratchet.mjs 57 authored bundle files within ceilings
exit 0 node scripts/check-skills-token-ratchet.mjs --self-test 97 cases
exit 0 node scripts/check-whole-set-label-write.mjs
exit 0 node scripts/check-whole-set-label-write.mjs --self-test 24 fixture trees + 5 refusals + 1 hatch
exit 0 node scripts/ci/plan-test-core-shards.mjs --self-test 23 cases
exit 0 node scripts/ci/scheduled-full-run.mjs --self-test
exit 0 node scripts/pm/bare-root-worklist.mjs --self-test
exit 0 node scripts/pm/board-snapshot.mjs --self-test 200 cases across 14 batteries
exit 0 node scripts/pm/check-governed-queue-guard.mjs --self-test 403 cases
exit 0 node scripts/pm/check-harness-current.mjs --self-test 26 cases
exit 0 node scripts/pm/sweep-closed-cards.mjs --self-test 87 cases across 9 batteries
exit 0 node scripts/render-release-coverage-anchor.mjs --self-test 17 assertions
exit 0 pnpm --filter @objectstack/lint run check:doc-formula-expressions (exit 3 PREREQUISITE before the build, 0 after)
exit 0 pnpm check:agent-test-spelling 0 violations, 661 files
exit 0 pnpm check:bash32-floor 31 shell files
exit 0 pnpm check:ci-filter-parity 139 assertions
exit 0 pnpm check:cli-command-ids 89 modules
exit 0 pnpm check:closing-target-claim 121 cases
exit 0 pnpm check:commit-card-trailers 81 cases
exit 0 pnpm check:cross-package-test-inputs 261 cases
exit 0 pnpm check:declared-population-live 251 of 312 families reach the tree
exit 0 pnpm check:doc-authoring baseline held, 125895 strings read
exit 0 pnpm check:driver-memory-census
exit 0 pnpm check:entry-guard 294 scripts files
exit 0 pnpm check:gitlink-declared 36 assertions
exit 0 pnpm check:issue-citations
exit 0 pnpm check:nul-bytes 75 assertions
exit 0 pnpm check:parse-guard 293 scripts files
exit 0 pnpm check:partof-closing-keyword 45 cases
exit 0 pnpm check:platform-checklist 265 assertions
exit 0 pnpm check:pm-dispatch-gates 1945 cases (fast tier), 7 slow sections deferred
exit 0 pnpm check:pm-expected-skips 206 cases
exit 0 pnpm check:pm-governed-merges 537 assertions
exit 0 pnpm check:pm-governed-prose 2 surfaces name all 13 governed surfaces
exit 0 pnpm check:pm-half-states 5224 cases
exit 0 pnpm check:pm-label-desc-cap 45 descriptions, all ≤100 (longest 100, tooling)
exit 0 pnpm check:pm-label-write 136 cases across 11 batteries
exit 0 pnpm check:pm-post-stamped 753 cases across 26 batteries
exit 0 pnpm check:pm-record-recognisers (also runs fleet-roster: 115 cases in 9 batteries)
exit 0 pnpm check:pm-skill-id-lint 110 files clean
exit 0 pnpm check:pm-skill-ratchet every ceiling held; cross-file moves: 3
exit 0 pnpm check:pnpm-filter-targets 212/284 filter occurrences resolve
exit 0 pnpm check:pnpm-flag-spellings 645 files
exit 0 pnpm check:ratchet-remedy-authority
exit 0 pnpm check:refd-timer-probe 11 cases
exit 0 pnpm check:scripts-symbol-anchors
exit 0 pnpm check:single-claim-paths 93 cases
exit 0 pnpm check:skill-frame-sync the one declared frame copy is coherent
exit 0 pnpm check:watch-hint-literal 76 declarations across 4 rostered names
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_012MmDsR4AZoJZyzKQcBEESh)_
---------
Co-authored-by: Claude <noreply@anthropic.com>pm:awaiting-merge — a PR awaiting the maintainer's review and merge no longer shares needs-user-decision with decision cards (#30445)1 parent ede9e6b commit 5d0904c
13 files changed
Lines changed: 163 additions & 85 deletions
File tree
- .claude/skills/pm-dispatch
- references
- lanes
- scripts/pm
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
20 | | - | |
| 20 | + | |
21 | 21 | | |
22 | 22 | | |
23 | 23 | | |
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
107 | | - | |
| 107 | + | |
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| |||
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
189 | | - | |
| 189 | + | |
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
193 | 193 | | |
194 | | - | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
25 | | - | |
26 | 25 | | |
27 | 26 | | |
28 | 27 | | |
| |||
51 | 50 | | |
52 | 51 | | |
53 | 52 | | |
54 | | - | |
| 53 | + | |
| 54 | + | |
55 | 55 | | |
56 | 56 | | |
57 | 57 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
75 | | - | |
| 74 | + | |
| 75 | + | |
76 | 76 | | |
77 | 77 | | |
78 | 78 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
7 | | - | |
| 7 | + | |
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
11 | 12 | | |
12 | | - | |
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
| |||
40 | 40 | | |
41 | 41 | | |
42 | 42 | | |
43 | | - | |
| 43 | + | |
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
218 | 218 | | |
219 | 219 | | |
220 | 220 | | |
221 | | - | |
| 221 | + | |
222 | 222 | | |
223 | 223 | | |
224 | 224 | | |
| |||
1943 | 1943 | | |
1944 | 1944 | | |
1945 | 1945 | | |
1946 | | - | |
| 1946 | + | |
1947 | 1947 | | |
1948 | 1948 | | |
1949 | 1949 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
450 | 450 | | |
451 | 451 | | |
452 | 452 | | |
453 | | - | |
| 453 | + | |
454 | 454 | | |
455 | 455 | | |
456 | 456 | | |
| |||
2324 | 2324 | | |
2325 | 2325 | | |
2326 | 2326 | | |
2327 | | - | |
| 2327 | + | |
2328 | 2328 | | |
2329 | 2329 | | |
2330 | 2330 | | |
| |||
0 commit comments