Skip to content

pm-dispatch: an unruled decision behind Blocked-by refuses the dispatch; measure-then-decide sends a reading-only dev - #23414

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23379-unruled-decision-no-building-dev
Oct 14, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23379-unruled-decision-no-building-dev

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #23379
Clause-②: no

Text-only charter change on three protocol faces, under the maintainer's 「同意」 (2026-10-14) on the director seat's proposal, quoted from the card verbatim: 「先裁再派。派发门加一条:卡上有未裁的 Blocked-by: 决策 或派发令写「先测量再决定」的,只派「只读读数」的 dev(不建闭包、不跑测试),或根本不派、等裁。」 and 「立卡你决定,不需要我同意」. Second leg of the serial relay behind #23378 (its draft PR #23405 at head 63496bd46c edits os-dev.md, dispatch-runbook.md and AGENTS.md); this PR is based on origin/main 5656c5638a, not on that branch, and touches none of its hunks (proof below). Draft; the landing tier is whatever node scripts/pm/check-governed-merges.mjs --pr N reads for .claude/**.

What changes (text only), before / after

1. Dispatch gate — .claude/skills/pm-dispatch/SKILL.md, 状态模型 table, the pm:blocked row (L108), amended in place

Before (159 bytes):

| `pm:blocked` + 正文行 `Blocked-by: #N` | 等上游:选择期跳过,#N 关闭时由解锁扫描放回;工已完、PR 被外部门禁卡住的同用本态 |

After (295 bytes; the file's widest-row pin is 342, so the row stays inside it, and a table row is structurally exempt from the 120-byte line cap):

| `pm:blocked` + 正文行 `Blocked-by: #N` | 等上游:选择期跳过,#N 关闭时由解锁扫描放回;工已完、PR 被外部门禁卡住的同用本态;正文或线程行首 `Blocked-by:` 指向无 `Ruled:` 的 open `needs-user-decision` 卡 ⇒ ⛔ 不派发,挂本态直至其 `Ruled:` |

The gate sentence: a line-head Blocked-by: in the card's body or thread that names an open needs-user-decision card carrying no Ruled: means the card is not dispatched and hangs pm:blocked until that card carries Ruled:. It sits where pm:blocked + Blocked-by: semantics already live (the selection skip, the unlock scan), beside the needs-user-decision row (L106, 永不派发) and the red line at L29. Ruled: is the marker references/lanes/director.md L12 writes on the decision card's first body line when a ruling is recorded.

2. Reading-only dev — .claude/skills/pm-dispatch/references/dispatch-runbook.md, 〈派发词构造细则〉

Before (L235, 112 bytes):

- 测量先行卡(修复由测量结果有条件授权)⇒ 派发令写明 ⛔ 测量存在之前不写修复。

After (L235 amended in place, 118 bytes; L236 new, 108 bytes):

- 测量先行卡(修复由测量结果有条件授权)⇒ 只派只读读数 dev 或不派等裁;建设 dev 待裁。
- 只读读数 dev 不建闭包、不跑测试、不开 PR;只读树与记录,读数贴决策卡或立卡。

A measure-first card (a dispatch whose first act is "measure, then decide") dispatches a 只读读数 (reading-only) dev — no worktree closure, no build, no test run, no PR; it reads the tree and the record and posts the reading on the decision card or files one — or is not dispatched at all and waits for the ruling; the building dev follows the ruling. The old clause 「⛔ 测量存在之前不写修复」 is subsumed: a dev that opens no PR writes no fix.

Paid by one deletion in the same file. Deleted L206 (87 bytes):

- 内部 PM 副本 = `.claude/skills/pm-dispatch/SKILL.md` 升级与决策 节的四轴框架块。

It restates .claude/agents/os-dev.md L355 「框架唯一副本在 pm-dispatch SKILL.md 〈升级与决策〉;派发词逐字粘贴,dev ⛔ 不留副本。」, and the one fact it carried for the PM side (where the block lives) is folded into its neighbour L205, amended in place: 「四轴框架整段现取现粘、逐单随派发词下发。」 becomes 「四轴框架块(SKILL.md 升级与决策 节)整段现取现粘、逐单随派发词下发。」 (95 bytes).

3. The mode's one line — .claude/agents/os-dev.md, 〈何时停手不写码〉 and the report template

New L354 (116 bytes), the sibling of the needs_decision line:

- 派发词标只读读数 ⇒ 不建闭包、不跑测试、不开 PR;报 `status: "reading"`,读数贴决策卡。

Report template enum (L364), amended in place:

  "status": "done | rework | blocked | needs_decision",

becomes

  "status": "done | rework | blocked | needs_decision | reading",

Paid by one deletion in the same file. Deleted old L354 (84 bytes):

- 升级分析的四轴决策框架由派发词携带,PM 从自己那份副本填入。

It restates its two siblings: L355 「…派发词逐字粘贴,dev ⛔ 不留副本。」 (the frame arrives via the dispatch order, from the single copy) and L356 「…派发词没带,停下向 PM 索取…」, and dispatch-runbook.md L205 「…逐单随派发词下发」 carries the PM side.

Line budget (ceilings on main: 319 / 241 / 402 — every added line paid in the same file, no ceiling moved)

file before after lines added lines deleted (named above) lines amended in place
.claude/skills/pm-dispatch/SKILL.md 319 319 0 none L108 row (159 → 295 B)
.claude/skills/pm-dispatch/references/dispatch-runbook.md 241 241 1 (L236, 108 B) L206 (frame-copy pointer) L205 (95 B), L235 (118 B)
.claude/agents/os-dev.md 402 402 1 (L354, 116 B) old L354 (frame carried by the dispatch order) L364 enum (65 B)

Every added or amended non-table line is at or under 120 bytes (measured with Buffer.byteLength): 116, 65, 95, 118, 108; the SKILL.md row is a table row (exempt class table in scripts/pm/check-skill-line-ratchet.mjs) at 295 B against the file's row pin of 342 B. No re-wrap funds any line. No issue number enters a skill file; no model identifier enters any file. The maintainer's term 「只读读数」 is the one spelling in all three files; "reading-only" is its English face here.

Dry run — the new sentences applied to #23267's claim as it stood at comment 6156257682 (2026-10-13T22:09Z, posted 22:10:28Z)

What the record shows for the card at that instant:

So the Blocked-by: leg does not refuse the building dispatch as of 22:09Z: neither card the body names was an open needs-user-decision card without Ruled:. It would have refused only a dispatch read before 14:44Z.

The measure-then-decide leg does refuse it. The claim's File surface reads "the dev measures which door is the record's and declares it in the report and PR body … whichever the measurement shows ADR-0138 D3 item 5 names as the administrator's path", so the dispatch's first act was a measurement whose result selected the route, and the card's own body lists the dev's options as (A) a new door, (B) a new spec key, (C) amend the record — a decision shape. Under runbook L235–236 as amended, that dispatch sends a 只读读数 dev (or nobody, waiting for the ruling): the reading goes on the decision card, no closure is built, no suite runs, no PR opens. What happened instead is the card's own measurement: a building dev built the plugin-security closure under the verify lock and ran two pin suites, returned status: needs_decision at 22:28:30Z (comment 6156571003), the card entered needs-user-decision at 22:31:36Z, the ruling landed at 02:06:29Z (comment 6159279205, Ruled: first line written on the body), and the building dev was dispatched at 02:11Z.

Acceptance item read against the record: one of the two legs refuses (measure-then-decide), the other does not fire at 22:09Z; the card's premise that the Blocked-by: leg would have caught this claim is corrected here rather than forced.

Boundary proof against PR #23405 (head 63496bd46c, merge-base e4ec6ec1a5)

Gates (local subset = the families node scripts/pm/dispatch-gates.mjs --commands derives for this diff at 5656c5638a; exit codes captured before any pipe; the farm — pnpm lint, pnpm test, full builds — is CI's, read off this PR's check-runs)

22 families derived, 22 run, all exit 0, --ran reconciliation: 「✓ dispatch-gates --ran: 22 derived famil(ies) accounted for — 22 run, 0 NOT-MEASURED (a DERIVED zero — all 22 recorded an exit code and none of them is 3)」.

  • pnpm check:pm-skill-ratchet exit 0 — verdict lines: 「SKILL.md is 319 lines (ceiling 319; headroom 0)」, 「SKILL.md: widest table row is 342 bytes (pin 342; headroom 0)」, 「dispatch-runbook.md is 241 lines (ceiling 241; headroom 0)」, 「os-dev.md is 402 lines (ceiling 402; headroom 0)」.
  • pnpm check:pm-skill-id-lint exit 0 · pnpm check:pm-governed-prose exit 0 · pnpm check:skill-frame-sync exit 0 · pnpm check:agent-model-declared exit 0 · pnpm check:nul-bytes exit 0.
  • The other sixteen derived families (check-closing-keyword-parity + its self-test, check-comment-mask-corpus, check-governed-queue-guard --self-test, check-harness-current --self-test, check:agent-test-spelling, check:commit-card-trailers, check:cross-package-test-inputs, check:doc-authoring, check:driver-memory-census, check:gitlink-declared, check:pm-expected-skips, check:pm-governed-merges, check:refd-timer-probe, check:watch-hint-literal, @objectstack/lint check:doc-formula-expressions) all exit 0.
  • One declared deviation from the dispatch's "no build locally": check:doc-formula-expressions first answered exit 3 PREREQUISITE NOT MET (@objectstack/formula and @objectstack/lint unbuilt — nothing measured), so a targeted two-package build ran under the verify lock (os-verify-lock.sh -c 'pnpm exec turbo run build --filter=@objectstack/formula --filter=@objectstack/lint --concurrency=2' → 「VERDICT command-exit 0 · held the lock 112s · waited 0s」), after which the gate re-ran to exit 0 (「9 @example(s) judged clean … 15 predicate(s) … judged clean」). The build left git status clean — no generated artifact moved.
  • Raw control-byte self-scan of the three files: zero hits. No ablation: text-only change, nothing tested pins it.

Acceptance notes (observations, not cards)

维护者速读(草稿)

  • 改了什么:三份协议文本各加一句,行数不变(319/241/402)。状态模型表的 pm:blocked 行多一条:卡上行首 Blocked-by: 指向一张还没 Ruled: 的 open 决策卡,就不派发,挂 pm:blocked 等裁。派发细则里「测量先行卡」改为只派「只读读数」dev(不建闭包、不跑测试、不开 PR,读数贴决策卡或立卡)或干脆不派等裁,建设 dev 待裁后再派。os-dev 契约加一行只读读数模式(报 status: "reading"),报告枚举多一个 reading。新增的行以删掉两句重复表述支付。
  • 为什么改:你 2026-10-14 「同意」的「先裁再派」。security: no door can bind a permission set to the guest anchor — ADR-0138 D3 item 5 has no enforcer (PUT /meta/position/guest answers 403 NOT_OVERRIDABLE; guest suggestions are refused) #23267 那种卡决策没裁就派了建设 dev,结果是一次 271 秒的闭包构建、两套 pin 测试和一份八千字的 needs_decision 报告,零代码。门加在派发前:读数由便宜的只读 dev 产出,建设在裁决之后。
  • 风险与代价(含回滚):纯文本,不碰脚本、门禁与 workflow;唯一风险是口径 —— 只认行首 Blocked-by: 与决策卡上的 Ruled: 标记,散文里提到决策卡不触发,这是既有正典标记规则的延续。回滚 = revert 这一个 commit,无数据与状态迁移。
  • 席位意见:
  • 你要做的:落地档位由 check-governed-merges --pr 读(.claude/** 按登记是 Tier S,席位按契约复核落地);若它读为 Tier H,需要你的一次批准。PR 保持 draft。

Generated by Claude Code

…dispatch; measure-then-decide sends a reading-only dev

SKILL.md state-model row: a line-head Blocked-by: naming an open
needs-user-decision card without Ruled: is not dispatched and hangs
pm:blocked until that card is ruled. dispatch-runbook 派发词构造细则: a
measure-first card dispatches a 只读读数 dev (no closure, no tests, no PR;
the reading goes on the decision card or into a new card) or waits for the
ruling; the building dev follows the ruling. os-dev.md: the reading-only
mode's one line under 何时停手不写码 and `reading` in the status enum.

Ceilings held at 319/241/402: the runbook pays with its frame-copy pointer
folded into the neighbouring line, os-dev with a line its sibling restates.

Claude-Session: https://claude.ai/code/session_013zGKMG1cRedVzWtqGGGZW9
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Oct 14, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 14, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 54dbbd5636c154de97122fa55cf8320d70903115
Local-runs: none

Reviewed in seat by the dispatching skills seat (served tier read from get_session last_served_model this fire, equal to the constant's value), on the PR diff (three files, +6/−6, one commit on 5656c5638a; check-governed-merges --pr 23414: .claude/** ×3, Tier S, 12 changed lines), card #23379 (the maintainer's 「同意」 on 方案 3, 2026-10-14, quoted in the card and the PR body), the dev's report 6162769119, PR #23405's head 63496bd46c and this head's check-runs. The governed faces are the PM status model, the dispatch-word construction rules and the dev contract; the judgment is whether each sentence says what the card's authority says, and whether each deletion removes nothing the files do not still say. Written 2026-10-14T07:03Z.

① Derived judgments

② Semver level

None owed: .claude/** ships in no package; skip-changeset on the PR is correct.

③ Boundary flags

Implemented-by: claude/issue-23379-unruled-decision-no-building-dev
Reviewed-by: session_013zGKMG1cRedVzWtqGGGZW9

VERDICT: PASS


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 14, 2026 07:05
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 14, 2026 07:05
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit b5b1bf7 Oct 14, 2026
39 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23379-unruled-decision-no-building-dev branch October 14, 2026 07:12
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