Skip to content

pm-dispatch: pm:epic marks every card an epic reserves — never with pm:queue - #15696

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-15666-epic-reservation-label-on-children
Sep 5, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-15666-epic-reservation-label-on-children

Conversation

@claude

@claude claude Bot commented Sep 5, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15666

Governed surface (.claude/**) — draft PR, human merge. No seat flips it ready, enqueues it, arms auto-merge, or approves it. skip-changeset: the diff publishes nothing from any released package (.claude/** + scripts/pm/**).

What changes, and why only this

The maintainer's rulings stay verbatim on the card (no dates, quotations or card numbers enter the file): the reservation an epic holds must be visible on every reserved card in the list page, and reusing pm:epic on the sub-issues instead of a new label was accepted. This PR writes that meaning into exactly the three surfaces the card names:

  1. .claude/skills/pm-dispatch/SKILL.md — section「Epic 子树车道」: the five rules, one line each, paid inside the section (811 of 811 lines; ceiling untouched; every line ≤120 bytes).
  2. .claude/skills/pm-dispatch/SKILL.md — the pm:epic row of the label table.
  3. scripts/pm/ensure-pm-labels.sh — the pm:epic description only (98 characters against the 100 cap). Repo list untouched — the loop already seeds all five repos including cloud; no credentials logic.

Deliberately untouched, per the rulings: references/core-rules.md (the digest carries no epic line today), references/state-machine.md, scripts/pm/check-half-states.mjs (the two patrol rows are the sibling card #15667, filed in the same act), every other SKILL.md section, every ratchet row and pin.

Before → after

Section「Epic 子树车道」(SKILL.md lines 298–311; the angle-bracket placeholder in the epic: argument is spelled N here and is unchanged in the file)

Before — 14 rule lines:

- 大开发(父单 + sub-issue 树)整体委托一个专职 PM 会话:`/pm-dispatch epic:#N`。   (97 B)
- 队列 = 子树 open 未认领 sub-issue,每轮重读不缓存。   (67 B)
- 委托信号成对落地:父单打 `pm:epic` + 正文写会话 ID 与声明的文件领地。   (95 B)
- 其它 PM 的候选获取跳过整棵子树。   (48 B)
- 域座位批次选择时读一次 `label:pm:epic` 索引,避开领地相交。   (80 B)
- epic PM 不同时持有 `domain:*` 座位;认领纪律全套照做。   (71 B)
- 触 `packages/spec` 的 sub-issue 照旧转 spec 座位。   (60 B)
- 衍生问题三分法,判据:不修它,epic 验收过不过得去。   (70 B)
- in-scope ⇒ 挂父单 sub-issue 下轮自动入队。   (56 B)
- 触 spec/公共契约 ⇒ 转 spec 座位队列,epic 侧写 `Blocked-by:`。   (78 B)
- 顺带发现 ⇒ 独立立单进修复落地仓 backlog,查重先行。   (73 B)
- ⛔ 不借 sub-issue 通道把未分诊的卡塞进池子。   (62 B)
- 每次分流留一行审计评论;父单维护 checklist 汇总评论,决策仍锚在具体 sub-issue。   (106 B)
- 收尾四步、僵尸回收与领地防撞细则见 `references/seat-post-protocol.md`。   (91 B)

After — 14 rule lines:

- 大开发(父单 + sub-issue 树)整体委托一个专职 PM 会话:`/pm-dispatch epic:#N`。   (97 B)
- 委托信号成对落地:父单打 `pm:epic` + 正文写会话 ID 与声明的文件领地。   (95 B)
- epic 立卡挂父单、打 `pm:epic`,⛔ 永不 `pm:queue`;`label:pm:epic` 即父子保留全集,域座位不取。   (117 B)
- 队列 = 子树 open 未认领 sub-issue,每轮重读不缓存;其它 PM 候选获取跳过整棵子树。   (108 B)
- 域座位批次选择读一次 `label:pm:epic` 索引,避开领地相交;epic PM 不兼任 `domain:*` 座位。   (113 B)
- 认领纪律全套照做:先写标签、再 `Claim:`、再全线程重读;认领后 `pm:epic` 留在卡上。   (111 B)
- 离开子树(交车道或转 spec 座位)同一笔标签写摘 `pm:epic` 加 `pm:queue`。   (92 B)
- `pm:epic` + `pm:queue` 同卡 = 半状态(保留兼移交);后者即已移交,取回走全套认领协议含重读。   (119 B)
- 单车道仓(无 `domain:*`)开卡即认领合法;多车道仓域标签前置照旧,子树标记即保留。   (110 B)
- 衍生问题三分,判据:不修它 epic 验收过不过得去;in-scope ⇒ 挂父单 sub-issue 下轮自动入队。   (119 B)
- 触 `packages/spec`/公共契约(sub-issue 或衍生)⇒ 照旧转 spec 座位队列,epic 侧写 `Blocked-by:`。   (115 B)
- 顺带发现 ⇒ 独立立单进修复落地仓,查重先行;⛔ 不借 sub-issue 通道塞未分诊卡进池子。   (117 B)
- 每次分流留一行审计评论;父单维护 checklist 汇总评论,决策仍锚在具体 sub-issue。   (106 B)
- 收尾四步、僵尸回收与领地防撞细则见 `references/seat-post-protocol.md`。   (91 B)

Label-table row (SKILL.md line 118)

  • Before: | `pm:epic`(父单) | 子树已委托 epic PM;其它 PM 不把其 sub-issue 当候选 | — 87 bytes
  • After: | `pm:epic`(父单或 sub-issue) | 已由 epic PM 保留;其它 PM 永不取;⛔ 永不与 `pm:queue` 同挂 | — 110 bytes (the file's widest row stays the domain:engine row at 342, pin unchanged)

Label description (scripts/pm/ensure-pm-labels.sh, the pm:epic line)

  • Before: Parent delegated to a dedicated epic PM — other PMs never dispatch into its subtree — 83 characters
  • After: Reserved by a dedicated epic PM, parent or sub-issue; other PMs never take it; never with pm:queue — 98 characters (cap 100, measured in code points as the gate does)

Rule inventory — one row per surviving line (E1–E14 = the 14 pre-existing rules in file order; N1–N5 = the card's five)

after bytes carries merged / changed
1 97 E1 verbatim
2 95 E3 verbatim (moved up one slot so the delegation pair reads together)
3 117 N1 new: cards hang under the parent and carry pm:epic, ⛔ never pm:queue; label:pm:epic is the whole reserved set, parents and children; domain seats never take one
4 108 E2 + E4 queue definition + other PMs skip the whole subtree; only the particle 的 dropped
5 113 E5 + E6 (first clause) batch selection reads the label:pm:epic index + epic PM holds no domain:* seat; 选择时→选择, 不同时持有→不兼任
6 111 N2 + E6 (second clause) E6's 认领纪律全套照做 kept verbatim as the head; then the pair as written: label write, Claim:, full-thread re-read; pm:epic stays after the claim
7 92 N3 new: leaving the subtree (to a lane, or to the spec seat) removes pm:epic and adds pm:queue in one label write
8 119 N4 new: pm:epic + pm:queue on one card is a half-state (reserved and handed over at once); pm:queue means handed over; taking back = full claim protocol incl. the re-read
9 110 N5 new: single-lane repos (no domain:*) may open-and-claim in one act; multi-lane repos keep the domain-label prerequisite, the subtree marker is the reservation
10 119 E8 + E9 trichotomy criterion + in-scope ⇒ sub-issue under the parent, auto-enqueued next round; 三分法→三分, one comma dropped
11 115 E7 + E10 the two spec lines were one rule twice: sub-issues or derived work touching packages/spec/public contract go to the spec seat queue, epic side writes Blocked-by:; now one ⇒ branch of the trichotomy
12 117 E11 + E12 incidental findings ⇒ separate card in the fix-landing repo, dedupe first + ⛔ never push untriaged cards into the pool through the sub-issue channel; 「backlog」and two particles dropped
13 106 E13 verbatim
14 91 E14 verbatim (the pointer to references/seat-post-protocol.md)

All 14 pre-existing rules survive; the section's one pre-existing ⛔ (E12) survives; two ⛔ are added (line 3, the table row). Five lines paid by six joins (E6 is split across lines 5 and 6), net 0 lines in the file.

Gates — all run on the merged head edc6d1226 after the final commit; exit codes captured before any pipe; each gate's own verdict line quoted

  • pnpm check:pm-skill-ratchet — exit 0 — ✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md is 811 lines (ceiling 811; headroom 0). and ✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/SKILL.md: widest table row is 342 bytes (pin 342; headroom 0).
  • pnpm check:skill-frame-sync — exit 0 — ✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 files (none of the frame's fingerprint phrases appear in the new lines)
  • pnpm check:pm-governed-prose — exit 0 — ✓ check-governed-prose: 2 instruction surface(s) name all 5 registered governed surfaces (docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md) and claim no others.
  • pnpm check:pm-skill-id-lint — exit 0 — ✓ check-skill-id-lint: 24 file(s) clean (pattern /#[0-9]{3,}/g).
  • pnpm check:pm-label-desc-cap — exit 0 — ✓ check:pm-label-desc-cap: 23 label descriptions in scripts/pm/ensure-pm-labels.sh, all ≤100 characters (longest: 100, repo:objectui).
  • pnpm check:nul-bytes — exit 0 — check-nul-bytes: OK (scanned 7583 text file(s) -- 7583 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).
  • node scripts/pm/check-governed-merges.mjs --test .claude/skills/pm-dispatch/SKILL.md scripts/pm/ensure-pm-labels.sh — exit 3 (expected) — ⛔ GOVERNED — a human merge is the review record for this PR, .claude/** ×1; paths not on the register: scripts/pm/ensure-pm-labels.sh
  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack ⇒ 32 commands; every one executed and recorded byte-for-byte; node scripts/pm/dispatch-gates.mjs --ran — exit 0 — ✓ dispatch-gates --ran: 32 derived famil(ies) accounted for — 32 run, 0 NOT-MEASURED. 31 of the 32 exit 0 (each gate's own verdict line is in the run log); the one non-zero is below.
  • pnpm lint (eslint . --no-inline-config, whole tree — no narrowing to declare) through scripts/pm/os-verify-lock.sh — VERDICT command-exit 0 · held the lock 110s on edc6d1226 (and command-exit 0, held 120s, on the pre-merge commit 718c718a5); shared-box seconds, not idle-box figures.
  • Model tier read from the file surface with dispatch-gates.mjs --tier: MANDATORY (clause ①, the PM skill main file).

Not measured locally (honest gaps, CI owns them)

  • pnpm --filter @objectstack/lint run check:doc-formula-expressions — exit 3, PREREQUISITE NOT MET — the workspace package `@objectstack/formula` is not built; after building @objectstack/formula through the lock (VERDICT command-exit 0, held 236s) the next prerequisite is @objectstack/lint's own dist. A whole-tree family over content/docs formula expressions, which this diff does not touch.
  • The derivation's 3 families that take a value from the workflow (check-cross-package-test-inputs --union-into, check-shard-attestation, check-test-completeness) and 1 CI-measured-only family, as it prints them.

Serial notes

🤖 Generated with Claude Code

https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox


Generated by Claude Code


Generated by Claude Code

…`pm:queue`

SKILL.md 「Epic 子树车道」 gains the five reservation rules (children carry
`pm:epic`, claim protocol as written, one-write hand-over, the half-state,
single- vs multi-lane repos), paid inside the section by merging adjacent
single-rule lines; the `pm:epic` label-table row and the label description in
`scripts/pm/ensure-pm-labels.sh` carry the same meaning. Ceiling untouched
(811/811, table pin 342).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 5, 2026
@claude
claude Bot requested review from hotlong and os-zhuang September 5, 2026 03:17
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Sep 5, 2026
@os-zhuang
os-zhuang marked this pull request as ready for review September 5, 2026 03:23
@os-zhuang
os-zhuang enabled auto-merge September 5, 2026 03:24
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 5, 2026

os-steve commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

ACCEPT — governed in-seat review of PR #15696, head edc6d1226 (skills seat, 2026-09-05T03:3xZ). Posted after os-zhuang's approval (03:23Z) and enqueue (03:33Z); the review record is owed regardless and changes nothing on the PR.

Implemented-by: claude/issue-15666-epic-reservation-label-on-children (os-dev subagent, contract-review tier)
Reviewed-by: session_019RfFHiRCSs3JXLK4cwcfox (skills seat)

Verified in a detached compare worktree at the PR head against merge-base a55efc6c1, not from the report: two files. .claude/skills/pm-dispatch/SKILL.md, +11 / −11 inside the「Epic 子树车道」section and the pm:epic row of the label table: the maintainer's four rulings of 2026-09-05 are now five rules, one line each — an epic's cards hang under the parent and carry pm:epic, ⛔ never pm:queue, and label:pm:epic is the whole reserved set that domain seats never take; the claim atomic pair as written with pm:epic staying after the claim; leaving the subtree swaps pm:epic for pm:queue in one label write; pm:epic + pm:queue is a half-state and pm:queue means handed over (take-back is the full claim protocol, re-read included); single-lane repos may open-and-claim while multi-lane repos keep the domain-label prerequisite — paid inside the section by six joins of adjacent single-rule lines with all fourteen pre-existing rules and the one pre-existing ⛔ intact; the label row now reads「已由 epic PM 保留;其它 PM 永不取;⛔ 永不与 pm:queue 同挂」. scripts/pm/ensure-pm-labels.sh: the pm:epic description carries the new meaning (98 of the 100-character cap); the repo list still seeds all five repos, cloud included. Seat runs on the head: check-skill-line-ratchet 811 of 811 and the widest table row 342 of 342, check-skill-frame-sync isomorphic, check-skill-id-lint 24 files clean, check-governed-merges --test exit 3 (GOVERNED, .claude/** ×1); every section line ≤119 bytes; no dates, quotations, card numbers, ⚠/⭐, fingerprints or model names in the added text. The dev's family: 32 derived commands, 31 exit 0 and one NOT MEASURED (a formula-docs gate needing two package builds), check:pm-governed-prose and check:pm-label-desc-cap green, whole-repo lint through the lock. CI on edc6d1226: 38 check runs, none non-green.

Landing regime: governed (.claude/**); the human step has been taken by an approver. Closes #15666; #15404 dispatches on the same file once this lands.


Generated by Claude Code

Merged via the queue into main with commit c43ed91 Sep 5, 2026
39 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-15666-epic-reservation-label-on-children branch September 5, 2026 04:24
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

3 participants