skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21) - #14660

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split
Sep 2, 2026
Merged

skills(pm-dispatch): split the entry into SKILL.md + rules/ under #14296 items 1 and 4 (entry 9,708 tokens, package net −21)#14660
os-zhuang merged 2 commits into
mainfrom
claude/issue-14300-pm-dispatch-split

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#14300

Round 2 of the skills catalog optimization program #14292 member card for skills/objectstack-pm-dispatch (maintainer mandate 2026-09-02, verbatim: 「审核所有的 skills,进行全面的优化。」). Round 1 (PR #14444, merged 08:57Z) took the diet, 14,549 → 11,567 tokens. This PR is the entry + rules/ split plus the two deferrals the seat's ACCEPT on #14444 recorded (PMD-H-01, the #14229 two-delta sync). Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1 — branch claude/issue-14300-pm-dispatch-split, base ca48cf37, head fef3b449.

Rulings this PR runs on (one line each, verbatim and untranslated)

Files

skills/objectstack-pm-dispatch/SKILL.md (entry, hand-edited), skills/objectstack-pm-dispatch/rules/dev-template.md (new — text moved out of the entry), scripts/check-skills-token-ratchet.mjs (exactly two rows: the new file's row, the entry's re-lock). .claude/skills/pm-dispatch/**, .claude/agents/os-dev.md, CLAUDE.md read as the comparison oracle only; scripts/pm/check-skill-line-ratchet.mjs, generated files, content/docs/releases/** untouched; no other package. Frontmatter untouched ⇒ skills/README.md / content/docs/ai/skills-reference.mdx need no regeneration (check:skill-docs says "Skill docs in sync"). Clause-②: no — protocol text, no platform contract; clause ① applies (a tier-mandated surface) and the skill-face review is the seat's, in-seat. Governed skills/** ⇒ this PR stays DRAFT; review requests are the seat's step.

Token account (convention ceil(utf8 bytes / 4), node scripts/check-skills-token-ratchet.mjs)

filebefore (origin/main ca48cf37)after (fef3b449)ceiling row
SKILL.md (entry)11,5679,70814,549 → 9,708 (re-locked at the landed count; zero headroom)
rules/dev-template.md1,838new row, 1,838 (pinned at the landed count; zero headroom)
package (every file under skills/objectstack-pm-dispatch/; no generated file)11,56711,546−21

Per commit, each droppable on its own: the split commit da02d0c1 lands the package at 11,556 (−11); the sync commit fef3b449 at 11,546 (−10 more). Whole bundle: 157,662 → 157,641; ratcheted subtotal 141,214 / 165,532 → 141,193 / 162,529.

The three conditions, with numbers

Item 4: the entry ends ≤ 10,000 tokens — measured 9,708.

File map (old section → new file, tokens)

old (origin/main)newtokens
## The developer-agent operating template intro + the 4-backtick text fence (:626-799), minus the "When to STOP instead of coding" blockrules/dev-template.md — H1 + the same fence with {decision_frame} on the line the block occupied (rules/dev-template.md:99)1,838 after the sync commit (1,768 as moved)
the "When to STOP instead of coding" block inside that fence (:704-755) — the published-dev copy that check:skill-frame-sync pins to skills/objectstack-pm-dispatch/SKILL.md by file pathstays in the entry, in a text fence under the same heading (SKILL.md:620-660; anchors now at :633 "Analyze every option on four fixed axes:" and :654 "Justify your recommendation on all four axes")633, unchanged
**Report contract.** paragraphstays in the entry (SKILL.md:662-668) — it is the PM's reading of the report, not the dev's135, unchanged
everything elseunchanged in the entry

The frame fence — measured, and what the script would do

scripts/check-skill-frame-sync.mjsCOPIES binds published-pm (start "and analyze every option on the four fixed axes below.", binding "recommendation must be justified on … axes") and published-dev (start "Analyze every option on four fixed axes:", binding "Justify your recommendation on … axes") to skills/objectstack-pm-dispatch/SKILL.md by file path. Had the published-dev block moved into rules/ with the template, analyzeCopy() would have read the entry, matched the start anchor 0 times and recorded "could not extract the decision frame: the declaring sentence anchor matched 0 time(s), expected exactly 1" — a hard FAIL (exit 1), not a vacuous pass; the anti-dormancy scan (FINGERPRINTS over .claude and skills, rules/ included) would additionally have flagged rules/dev-template.md as an undeclared copy (/fixed axes/i). check:skill-frame-freshness imports the same COPIES and extractor and would have failed the same way. So both copies stay in the entry (:534 and :633), neither block is edited, and the rules file carries no fingerprint: the sync gate now reports "36 markdown files scanned for undeclared copies" (35 at base — the new file is scanned and clean). Both gates green on every commit.

Per-move / per-deletion 落点 | before | after (keyed by finding id)

id落点 before → afterbeforeafter
PMD-B-01 (split)SKILL.md:626-799rules/dev-template.md:1-130 + SKILL.md:620-668one 2,584-token template section paid in every sessionthe template is loaded when a dispatch is composed; the entry keeps the pointer, the gate-pinned block and the report contract
PMD-B-01 funding (split overhead +77 bytes: rules H1, placeholder line, entry fence, the pointer's link)SKILL.md:382 "- The issue is already claimed; do not touch its assignee." → deleted; SKILL.md:388 "Return ONLY the JSON report defined in the operating procedure." → deleted; template intro sentence "It is written to stand alone: an agent with no prior context and no custom agent type can follow it." → deletedthree restatements the dev read twice in one prompt (template rule 2; the template's top paragraph; step 5's "a general-purpose agent with the template is equivalent")the template's own sentences carry each rule once; split commit −11
#14229 delta 1 (verify-lock non-guarantee)rules/dev-template.md:44-50 (resource rule 1)"so memory peaks never stack. Queueing is normal…" — the guarantee list with no non-guarantee, the exact belief the oracle corrects"The lock does not promise an idle machine: it excludes only work routed through it (gate runs, installs and dev servers are not), so wall-clock readings taken under a hold are shared-box readings." (+45)
#14229 delta 2 (ratchet funding discipline)rules/dev-template.md:80-83, after the definition of doneno ratchet text in the published template"A size ratchet the project enforces (a line or token ceiling on a file) is paid only by deleting content: a re-wrap is not payment (densifying that adds no content is a repair, not a purchase), and a ceiling is raised only by the maintainer — nothing left to delete ⇒ report "blocked"." (+63)
sync fundingSKILL.md:381 "{conventions_file} in that repository is binding — read it before your first edit." → deleted; SKILL.md:383-385 the needs_decision bullet → deleted; :382 "Never merge anything." → deleted; rules/dev-template.md:7-8 "It is parsed mechanically, so the final message is the JSON and nothing else." → deleted; :128 "and HTML comments alike" → deleted; :57-58 "Leftover dependency trees exhaust the container's disk, which fails as confusingly as running out of memory." → deletedfive verbatim restatements (the template's binding-file paragraph, the "When to STOP" rule, rule 4, the report block's final-message and HTML-comment rules) and one published-only rationale sentence the oracle's rule 4 does not carrythe rule survives in each case; sync commit −10
PMD-H-01premise false (below)

Rule 4's remaining lines were re-flowed after the deletion (bytes unchanged, 7,352 before and after the re-flow — a re-wrap moves no tokens and pays nothing).

PMD-H-01 — disposition: no stub exists; nothing to delete, no row to drop

Evidence: git ls-tree -r --name-only origin/main -- skills/objectstack-pm-dispatch/ lists exactly SKILL.md; git grep -n "objectstack-pm-dispatch/evals" origin/main returns nothing; CEILINGS in scripts/check-skills-token-ratchet.mjs carries no evals/ row for this package (the audit's package-facts table said the same: "evals/ absent; 8 of 11 published packages have one"). The audit's PMD-H-01 proposed ADDING an evals/README.md (+300, new ceiling); #14296 item 2 = A deletes planned-eval stubs and adds none, which forecloses that addition. Neither a stub to delete (the PR #14585 / #14578 precedent does not apply) nor a real fixture to keep: premise_false: PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory.

#14229 sync — the two deltas and their oracle lines (.claude/agents/os-dev.md on origin/main, verbatim and untranslated)

  1. Resource rule 1, os-dev.md:85-88: 「同一张清单的非保证:它不保证机器空闲 —— 只排除经这个入口进来的工作,check:* 门禁、install、dev server 不走它,与持锁同核并跑(脚本每次获取与 VERDICT 行同述此界)⇒ 锁下墙钟绝对值一律是共享盒读数,不是安静机器承诺。」 → template resource rule 1 (rules/dev-template.md:47-50).
  2. Standard clauses, os-dev.md:323-327: 「付行数棘轮的唯一合法货币是删内容。 维护者 2026-08-17 裁「⛔ re-wrap(折行合并)不得用作筹行 —— 棘轮治理的是内容体量,行数只是机读代理,新增以删减付账;密度优化仅随净减内容的 PR 顺带」、2026-08-29 裁「筹行(为内容购买行数)⛔ vs 独立密度修复(无内容购买)允许」。分界只问折行有没有为新增内容买行 —— 门禁分不出两种 net-0;⛔ 不买内容的密度修复是修复,不要当筹行拒掉。删不出等量内容 ⇒ 报 blocked,⛔ 不抬 ceiling(人工地板)。」 → one template paragraph after the definition of done (rules/dev-template.md:80-83), carrying the rule without this repo's dates or quoted rulings (the 已发布 skill objectstack-pm-dispatch 仍是两轴决策框架 —— 与 .claude/ 内部三轴(#5130)分叉,且「创业聚焦」轴是否该泛化给第三方项目未定 #5451 route-B convention the published copy follows).

The other three hunks of #14229 (the model-pin comment shrunk to a pointer, the stash mechanism delegated to CLAUDE.md, the footer measurement delegated to AGENTS.md) are internal delegations with no published counterpart — the published template carries no model pin, already states the stash ban with its mechanism (round 1 F-03), and has no footer text — so nothing to sync there.

premise_false

  • PMD-H-01 — the deferral presumed an evals stub; the package has never had an evals/ directory (evidence above).
  • check:doc-links / check:published-readme-links verify the cross-file link — neither gate walks skills/**: check-published-readme-links.mjs sweeps published package READMEs and the spec prompt files; check-doc-anchors.mjs sweeps content/** plus the root README.md / ARCHITECTURE.md; no check:doc-links script exists. The one cross-file link (SKILL.md:622./rules/dev-template.md) was verified by hand: the target exists at that relative path, and the only intra-file anchor (#the-developer-agent-operating-template, SKILL.md:354) still resolves because the heading stays in the entry.
  • check:skill-examples marks travel with their fences — the package has zero os:check marks and zero TypeScript fences (audit package facts), so nothing travelled; the gate is not in this PR's derived family.
  • check:skill-identifier-liveness Leg 2 — re-measured: BINDINGS has no row for this file (8 registered sections, none in skills/objectstack-pm-dispatch/**); the three Leg 1 exemptions (backlogRepo, conventionsFile, routingLabelPrefix) are in the Configuration table, which did not move, and still resolve.
  • check:role-word — 0 occurrences of the word in both files before and after (grep -c = 0; the file is not in the baseline), so the count could not move.

Gates — head fef3b449 (union re-derived AFTER the last move: node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, no paths, "gate list derived from the tree of 'objectstack-ai/objectstack' at commit fef3b44"; 25 commands; every exit code captured by redirect before any pipe)

gateexitthe gate's own verdict line
node scripts/check-skills-token-ratchet.mjs (+ --self-test)0"✓ check-skills-token-ratchet: 32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratcheted." — rows skills/objectstack-pm-dispatch/SKILL.md 9708 / 9708 (+0), skills/objectstack-pm-dispatch/rules/dev-template.md 1838 / 1838 (+0); self-test "64 cases pass"
pnpm check:skill-frame-sync0"✓ check-skill-frame-sync: 4 copies of the decision frame are structurally isomorphic across 3 files · 4 axes: business-need → long-term-soundness → ai-authoring-safety → startup-scope-discipline · binding sentence present in all 4; 4 count mention(s) agree; 36 markdown files scanned for undeclared copies."
pnpm check:skill-frame-freshness (dispatch-named, not in the derived family)0"✓ check-skill-frame-freshness: the decision frame in this tree is current with origin/main (fetched just now)."
pnpm check:skill-identifier-liveness0"check-skill-identifier-liveness OK — Leg 1: 465 citation(s) over 42 published file(s) checked against 93441 implementation word tokens (3 ledgered exemption(s)); Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)."
pnpm check:skill-compatibility0"✓ check-skill-compatibility-version: 11 SKILL.md file(s) reconciled against 79 workspace packages"
pnpm --filter @objectstack/spec run check:skill-docs0"✅ Skill docs in sync"
pnpm check:role-word0"check-role-word: OK, no new occurrences of the reserved word."
pnpm check:corpus-claim-drift0"check-corpus-claim-drift: OK, no new claim sites beside a pinned spelling."
pnpm check:doc-authoring0"✓ doc authoring guard: sibling-package prose ids hold the baseline — 831 pinned site(s) across 231 file(s) …"
pnpm --filter @objectstack/lint run check:doc-formula-expressions0first pass exit 3 "PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built"; after pnpm --filter '@objectstack/lint...' --filter '@objectstack/formula...' run build under scripts/pm/os-verify-lock.sh (OS_VERIFY_LOCK_SLOT=issue-14300-r2; "VERDICT command-exit 0 · held the lock 130s · waited 406s"): "✓ check:doc-formula-expressions: 22 record-scoped formula example(s) across 422 files / 1364 TS blocks judged clean by @objectstack/formula."
pnpm check:pm-governed-merges0"✓ check-governed-merges --self-test: 243 assertions …" + "live: the real generator declared 9 output(s) and certified this tree"
pnpm check:pm-dispatch-gates0"✓ dispatch-gates self-test: 1240 cases pass."
pnpm check:ratchet-remedy-authority0"OK check-ratchet-remedy-authority: 184 scripts swept … 12 mark the expanding remedy ⛔ MAINTAINER-ONLY …"
pnpm check:watch-hint-literal0"✓ check-watch-hint-literal: 45 declaration(s) across 4 rostered name(s) …"
node scripts/check-ci-filter-parity.mjs0"OK: all 130 declared cross-package glob(s) (92 unique) are covered …"
node scripts/check-cross-package-test-inputs.mjs / pnpm check:cross-package-test-inputs0 / 0"OK: 25 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob."
node scripts/check-shard-attestation.mjs0"✓ check-shard-attestation: 2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)."
node scripts/pm/bare-root-worklist.mjs --self-test0"OK self-test: 57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s) …"
pnpm check:agent-test-spelling · pnpm check:bash32-floor · pnpm check:cli-command-ids · pnpm check:entry-guard · pnpm check:parse-guard · pnpm check:pnpm-filter-targets0 eachbash32-floor "✓ … 26 tracked shell file(s) … name no bash 4+ construct …"; cli-command-ids "✓ … 315 command-id literal(s) across 112 file(s) … all resolve"; entry-guard "✓ check:entry-guard: 199 scripts/ file(s) …"; parse-guard "✓ check:parse-guard: 198 scripts/ file(s) …"; pnpm-filter-targets "✓ check:pnpm-filter-targets: 142/181 --filter occurrence(s) … resolve"
pnpm check:nul-bytes (any edit)0"check-nul-bytes: OK (scanned 7996 text file(s) — 7996 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes)."
node scripts/check-empty-changeset.mjs --base origin/main0"✓ No empty-frontmatter changeset introduced by this diff (0 declaring changeset(s) added)."

NOT MEASURED:node scripts/check-test-completeness.mjs — exit 3, "PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named" (CI tees the log; by design not measurable here). The derivation printed its stale-tree notice ("1 commit(s) behind origin/main, 1 file(s) it derives from CHANGED") — origin/main moved by one unrelated commit (20b88391) after the branch was cut; neither scripts/check-skills-token-ratchet.mjs nor skills/objectstack-pm-dispatch/** moved on main (git log HEAD..origin/main -- … empty before both pushes), so no merge was needed.

Baseline on the untouched worktree at ca48cf37, before the first move: ratchet "skills/objectstack-pm-dispatch/SKILL.md 11567 / 14549 (-2982)", frame-sync "35 markdown files scanned", liveness "41 published file(s)".

Changeset

skip-changeset: nothing is released by any package — the diff touches skills/** and one root gate script's ceiling rows; scripts/check-empty-changeset.mjs's route for a PR that releases nothing is this label, and it confirms no changeset is added.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1


Generated by Claude Code

…rules/dev-template.md; the gate-pinned decision frame stays in the entry
#14296 item 1 (A) + item 4 (A), under the #14568 = A reading. The
template fence moves verbatim into rules/dev-template.md; the "When to
STOP" block — the published-dev copy that check:skill-frame-sync pins to
SKILL.md by file path — stays in the entry as a fenced block the PM
inserts at the template's {decision_frame} line. Entry 11,567 -> 9,788
tokens; package 11,567 -> 11,556 (-11): the split's structural overhead
(the rules H1, the placeholder line, the entry fence, the pointer's link)
is funded by two dispatch-prompt bullets that restated template rule 2
and the template's top paragraph verbatim, and by the template intro's
stand-alone sentence, which step 5 already states. Ratchet rows: the new
file pinned at 1,768 (its landed count); the entry re-locked at 9,788.
No other row changes.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ent template — the verify-lock non-guarantee and the ratchet funding discipline
The follow-up sync PR #14444 recorded, from .claude/agents/os-dev.md on
origin/main: (1) resource rule 1 now states the lock's non-guarantee —
it does not promise an idle machine, only excludes work routed through it,
so wall-clock readings under a hold are shared-box readings; (2) a size
ratchet is paid only by deleting content — a re-wrap is not payment, a
densification that adds nothing is a repair, a ceiling is raised only by
the maintainer, nothing left to delete means "blocked". Additions +108
tokens, funded in the same package: three dispatch-prompt non-negotiables
that restated the template's binding-file paragraph, the "When to STOP"
rule and rule 4 verbatim; the template's top-paragraph restatement of the
final-message rule; the sanitizer trap's HTML-comment clause (stated at
the report block); and rule 4's published-only rationale sentence about
disk exhaustion, which the oracle does not carry. Package 11,556 ->
11,546 (-10 for this commit, -21 against main). Ratchet rows re-pinned at
the landed counts: entry 9,708, rules/dev-template.md 1,838.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants

@os-litant@os-zhuang@claude