Skip to content

docs(pm): runbook step that pastes the decision frame into every dispatch prompt - #15057

Merged
os-zhuang merged 3 commits into
mainfrom
claude/issue-14869-runbook-frame-paste-step
Sep 4, 2026
Merged

docs(pm): runbook step that pastes the decision frame into every dispatch prompt#15057
os-zhuang merged 3 commits into
mainfrom
claude/issue-14869-runbook-frame-paste-step

Conversation

@os-steve

@os-steve os-steve commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Fixes #14869

The internal dispatch runbook constructed the dispatch prompt without ever naming the four-axis decision frame. After the batch-3 item-4 ruling (option B, recorded 2026-09-03 on #14685, comment 5520452691) the frame keeps two copies, both PM-side, and the dev definition expects it to arrive in the prompt from the PM's own copy — .claude/agents/os-dev.md:398-401, verbatim and untranslated:

升级分析的四轴决策框架由派发词携带 —— 派发的 PM 从自己那份副本填入(已发布模板里
rules/dev-template.md{decision_frame} 槽位):每个方案逐轴分析,推荐也按那
些轴给出理由;派发词没带,停下向 PM 索取,⛔ 不自拟一套轴。

That clause is unchanged by this PR — it is quoted here only because the new bullet is the PM-side half it was waiting for. Until now the runbook was an instruction surface promising a behaviour it no longer produced: the failure is loud rather than silent, but it costs one round-trip per dispatch.

The change — one bullet, one file, +4 lines, nothing else

.claude/skills/pm-dispatch/references/dispatch-runbook.md, § 派发词构造细则, inserted into the clause list immediately after the 两份读数 clause (the other "what every brief carries at dispatch time" entry) and before 文件面两句原文.

Conventions matched against the file it lands in: Chinese prose, English machine identifiers in backticks, ASCII (/)/:/,/; (the file uses ASCII 115/115/96/158/101 times against 9/9/0/0/0 full-width), the ideographic and , the bare U+26D4 no-entry glyph with no variation selector (44 occurrences, 0 VS16), and the (维护者 2026-0x-xx 裁) date-citation form its neighbour at :246 uses. No issue numbers — check:pm-skill-id-lint scans this directory with /#[0-9]{3,}/.

The bullet's current text, and the reason it was re-anchored after the first round, are in the Patch round section at the bottom.

The frame text is NOT copied — the bullet points at it

Anchor measurement, re-taken on this branch rather than trusted from the brief:

what reading
block .claude/skills/pm-dispatch/SKILL.md:868-885, inside its ## 升级与决策 section
block md5 sed -n 868,885p .claude/skills/pm-dispatch/SKILL.md | md5sum = b9a0de17880c39e412055e656a953222 (matches the brief's number; re-measured again on the merged tree, unchanged)

That blind spot is larger than this PR and out of scope here — filed separately and unassigned as #15056 (32 of 72 hand-written markdown files under the two scan roots were invisible, including all 12 published skill reference pages). PR #15060 has since acted on it, which is what forced this PR's patch round — see the bottom section.

Line ratchet — paid from existing headroom, no ceiling edit

lines ceiling headroom
origin/main d5b330dc (git show origin/main:… | wc -l) 276 280 4
this branch 280 280 0

Gate's own verdict line: ✓ check-skill-line-ratchet: .claude/skills/pm-dispatch/references/dispatch-runbook.md is 280 lines (ceiling 280; headroom 0).

No ceiling was edited, no other bullet was re-wrapped, and no cross-file move was declared or needed — the four lines fit the headroom exactly, and the patch round kept the bullet at exactly four lines.

Governed surface

.claude/** — governed, so a human merge is the review record. No seat flips it ready, enqueues it, or arms auto-merge. skip-changeset applies: nothing here publishes from any released package.

Patch round — re-anchored after the scanner's population widened

Why the queue kept ejecting an approved PR. check-skill-frame-sync reds on the merged tree, never on this PR's own build. PR #15060 (merged 2026-09-03T20:09Z, after head cce4a1eb was built) removed references/ from that scanner's skip set — acting on #15056, the finding this PR's first round filed. The scan therefore began reading dispatch-runbook.md, and the bullet's paste anchor quoted the frame's opening sentence, which carries a phrase in the scanner's FINGERPRINTS. Result: dispatch-runbook.md ... looks like ANOTHER copy of the decision frame (matched /固定评估轴/) but is not declared in COPIES. The PR's own checks were green because they ran before #15060 landed.

Merged origin/main c351a84d into the branch as merge commit ba86720d (no rebase, no force-push); the fix is ea53bae5.

The re-anchoring. The instruction is unchanged — paste the whole block verbatim from the internal PM copy, never retype, never a second in-repo copy, record the copy's commit and md5 in the brief, and the os-dev definition stops and asks when a brief arrives without it. What changed is only how the paste span is identified: by quotation before, structurally now.

Before (cce4a1eb):

- **决策框架整段现取现粘、逐单随派发词下发**(维护者 2026-09-03 裁):内部 PM 副本在
  `.claude/skills/pm-dispatch/SKILL.md`,自「每个方案必须沿四条固定评估轴分析…」
  至「推荐意见必须基于这四条轴给出理由…」逐字粘贴,⛔ 不重打、⛔ 不另立第三份副本
  (`check:skill-frame-sync` 拒);派发词记该副本的 commit 与 md5,os-dev 定义没带就停下索取。

After (ea53bae5):

- **四轴框架整段现取现粘、逐单随派发词下发**(维护者 2026-09-03 裁):内部 PM 副本 =
  `.claude/skills/pm-dispatch/SKILL.md` `## 升级与决策` 段的四轴框架块(黑体句起、推荐约束句止),
  整段逐字粘贴,⛔ 不重打、⛔ 不摘句;派发那刻现取,把该副本的 commit 与 md5 记进派发词。
  ⛔ 仓内任何文件不得另立第三份(`check:skill-frame-sync` 全树扫);os-dev 定义没带就停下索取。

The span is now named by file, by its enclosing section heading, and by the block's shape (bold lead sentence through the closing recommendation clause) — no quoted sentence at all, so nothing to fingerprint. The md5 the brief records stays the integrity check, which is what makes a structural anchor safe: a heading that moves is caught by the digest rather than by a stale quotation. The bullet also gained the rule the widened scan now enforces repo-wide — no second in-repo copy anywhere, not merely no third copy of the whole section — and dropped its excerpt allowance (⛔ 不摘句), because after #15060 an excerpt of the marker sentences is exactly what reds.

Checked against the detector itself, not by eye. All four FINGERPRINTS (/fixed axes/i, /固定评估轴/, /条评估轴/, /\b[A-Za-z]+-axis\s+(?:analysis|decision\s+frame|frame)/) and both MENTION_PATTERNS were run over the new bullet and over the whole file: zero hits in either.

Verdicts on the merged tree, at head ea53bae5 — exit codes captured by redirect before any pipe:

gate exit its own verdict line
node scripts/check-skill-frame-sync.mjs 0 ✓ check-skill-frame-sync: 2 copies of the decision frame are structurally isomorphic across 2 files · binding sentence present in all 2; 5 count mention(s) agree; 72 markdown files scanned for undeclared copies.
pnpm check:pm-skill-ratchet 0 ✓ check-skill-line-ratchet: … dispatch-runbook.md is 280 lines (ceiling 280; headroom 0).
node scripts/pm/check-skill-id-lint.mjs 0 ✓ check-skill-id-lint: 23 file(s) clean (pattern /#[0-9]{3,}/g).
node scripts/pm/check-governed-merges.mjs --test PATHS 3 ⛔ GOVERNED — a human merge is the review record for this PR · .claude/** ×1
pnpm check:nul-bytes 0 check-nul-bytes: OK (scanned 8259 text file(s) … no raw ASCII control bytes).

The scan population is the headline number: 72 markdown files now, against 40 before #15060 — the 32 files that finding named are being read, and the runbook is one of them, green.

Then the full re-derivation at the merged head, node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (no paths — the script takes the change set from the merge base, reporting 1 path(s) vs merge base c351a84da): 13 commands, one more than the previous round (check-closing-keyword-parity.mjs --self-test joined). All 13 run, all exit 0, including check:doc-formula-expressions after building its two named prerequisites (@objectstack/formula, @objectstack/lint) — that gate's exit 3 is PREREQUISITE NOT MET, which it states is not a measurement.

Two corrections to the patch brief, neither affecting the outcome: pnpm check:control-bytes does not exist in this tree — the control-byte gate is check:nul-bytes, which is in the derived list and ran green; and check-governed-merges.mjs --test requires the changed paths as arguments (it refuses an empty list rather than answering "not governed"), so they were derived with git diff --name-only $(git merge-base origin/main HEAD) HEAD.

Draft/ready, auto-merge and queue membership were not touched by this round — that state belongs to the seat that set it. That is also why the push arrived when it did: a branch with a PR in the merge queue is refused by the protected-branch hook (GH006 ... Branches that are queued for merging cannot be updated), and the only reliable way to release it is to dequeue the PR, which this seat does not do. The fix commit was therefore held locally and pushed the moment the 05:16:30Z queue entry ejected on the same frame-sync red, at 05:56:55Z — the enqueue at the old head is what the queue was still building, so no queue build was interrupted.

Generated by Claude Code — session session_019RfFHiRCSs3JXLK4cwcfox, recorded in prose because a body edit is measured to normalise the footer link below.

…atch prompt

The internal dispatch runbook constructed the dispatch prompt without ever
naming the four-axis decision frame. After the batch-3 item-4 ruling (option B,
2026-09-03) the dev definition expects the frame to arrive in the prompt from
the PM's own copy and stops and asks when it does not, so the runbook was an
instruction surface promising a behaviour it no longer produced -- one
round-trip per dispatch until the step is written down.

Adds one bullet to the clause list of the dispatch-prompt construction section,
beside the "two readings handed down at dispatch" clause it belongs with: the
internal-pm frame section is taken fresh and pasted verbatim per card, from
`.claude/skills/pm-dispatch/SKILL.md`, delimited by its two anchor sentences;
never retyped; the brief records the copy's commit and md5; the os-dev
definition stops and asks when the frame is missing.

The frame text itself is NOT copied -- the bullet points at the existing copy by
its anchors, so `check:skill-frame-sync` keeps watching exactly two copies.

Line ratchet: 276 -> 280 of the 280 ceiling; no ceiling edit, no re-wrap, no
cross-file move needed.

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 3, 2026
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Sep 3, 2026
@claude
claude Bot requested review from hotlong and os-zhuang September 3, 2026 19:16
@os-zhuang
os-zhuang marked this pull request as ready for review September 4, 2026 03:40
@os-zhuang
os-zhuang enabled auto-merge September 4, 2026 03:40
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 4, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 4, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 4, 2026
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 4, 2026
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Why this PR keeps falling out of the merge queue — skills seat (session session_019RfFHiRCSs3JXLK4cwcfox, os-steve), 2026-09-04T05:19Z, reproduced locally.

The approvals are not the blocker: the governed guard passed on every queue build. What reds is check-skill-frame-sync (job Type Check · source gates, step "Check the decision frame is in sync across its four copies") — on the queue build only. This PR's single bullet quotes the decision frame's opening words (每个方案必须沿四条固定评估轴分析…) as its paste anchor; PR #15060 (merged 2026-09-03T20:09Z, after this head cce4a1eb was built) took references/ out of that scanner's skip set, so the merged tree now reads dispatch-runbook.md as an undeclared copy of the frame (matched /固定评估轴/ … not declared in COPIES) and the queue removes the PR — 04:07:50Z and 05:14:16Z, and the 05:16Z enqueue will go the same way. The PR's own checks were green because they ran before #15060 landed.

Fix in flight (patch round to the card's dev, same branch): merge main, re-anchor the bullet without the frame's marker words (the paste instruction stays; the file's line ceiling is at 280/280 so the bullet keeps its four lines), check:skill-frame-sync green on the merged tree, push. The PR stays governed — one more approval after the push, then the queue.


Generated by Claude Code

…hrases

`check-skill-frame-sync` stopped skipping `references/` subtrees, so its
anti-dormancy scan now reads this file. The bullet's paste anchors quoted the
frame's opening and binding sentences verbatim, and the opening one carries a
phrase the scan's FINGERPRINTS match -- so the merged tree read the runbook as
an undeclared copy and the queue ejected the PR on every build.

Re-anchors the paste span structurally instead of by quotation: the internal PM
copy is named by file, by its enclosing section heading, and by the block's
shape (bold lead sentence through the closing recommendation clause), with the
dispatching seat recording that copy's commit and md5 in the brief. The
instruction is unchanged -- paste the whole block verbatim, never retype, never
excerpt, never a second in-repo copy, and the os-dev definition stops and asks
when a brief arrives without it.

Verified against all four FINGERPRINTS and both MENTION_PATTERNS: no hit
anywhere in the file. Still four lines, 108/118/119/119 bytes, so the ratchet
stays at 280 of its 280 ceiling.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox
@claude

claude Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Patch verified at the merged head — one fresh approval lands it — skills seat (session session_019RfFHiRCSs3JXLK4cwcfox), 2026-09-04T06:01Z, verified in a compare worktree at ea53bae5, not against the report.

Head ea53bae5 = merge of origin/main c351a84d (ba86720d, no rebase) + the re-anchored bullet. check-skill-frame-sync on this tree: green — 2 copies, 72 markdown files scanned, no undeclared copy (the very check that ejected the PR from the queue at 04:07Z, 05:14Z and 05:56Z); the bullet carries none of the scanner's marker phrases (the seat grepped all four fingerprints: 0 hits); the paste span is now identified structurally (file, section heading, block shape) and the instruction is unchanged; still four lines, dispatch-runbook.md 280 of 280 with no ceiling edit; check-skill-id-lint clean; merge-tree against origin/main 50d6c924 clean. CI at 06:01Z: 14 green + 9 skipped, 4 in progress, nothing red.

The existing approvals are pinned to the old head cce4a1eb, and until #15187 lands the queue guard reads only an approval on the current head — so this PR needs one more approval on ea53bae5 (review re-requested from os-zhuang), after which the queue build will pass. The dev's operational note is taken by the seat: a branch whose PR sits in the queue cannot be pushed (GH006), so the seat will not re-enqueue a red PR while a patch round is in flight.


Generated by Claude Code

@claude
claude Bot requested a review from os-zhuang September 4, 2026 06:01
@os-zhuang
os-zhuang enabled auto-merge September 4, 2026 06:03
@os-zhuang
os-zhuang added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 1bc3c09 Sep 4, 2026
29 checks passed
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants