From 021dfbcbb1ed447593fe9b69db5f8b44a16a34e7 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 10:24:20 +0000 Subject: [PATCH] docs(pm): state the skill line-ratchet's coverage boundary in its header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CEILINGS map covers 18 files — the .claude/ instruction surfaces plus root AGENTS.md — and zero files under the published skills/ catalog, while the header read as though the ceiling covered the instruction surface as a category. A reader could not see the published root was outside it without diffing the map against the filesystem. State the covered set as an enumeration, state the published root as deliberately outside with the two reasons (the ratchet prices per-seat/ per-Routine full-file reads, which the published catalog is not on; and the published catalog is already a governed human-merge-only surface), and name coverage extension as a policy change needing its own card and a maintainer. Pin the boundary in the self-test: enforcement cannot hold it, because a ceiling on a real published SKILL.md would run green like any other row. No CEILINGS entry added; no enforcement behaviour changed. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01AeA3nU1B5Q2pgxqxgUrexd --- scripts/pm/check-skill-line-ratchet.mjs | 39 +++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/scripts/pm/check-skill-line-ratchet.mjs b/scripts/pm/check-skill-line-ratchet.mjs index a79dc0337a..d0ded1b522 100644 --- a/scripts/pm/check-skill-line-ratchet.mjs +++ b/scripts/pm/check-skill-line-ratchet.mjs @@ -25,6 +25,39 @@ * see check-skill-id-lint.mjs). Without a gate that intent erodes one * well-meaning paragraph at a time. * + * ## What is covered — and the published catalog, which deliberately is not + * + * "The whole surface" above means the CEILINGS map below, which is an + * ENUMERATION, never a root glob: the pm-dispatch surface (SKILL.md, its + * references/, the per-lane job descriptions), the four other + * `.claude/skills/` playbook SKILL.md files, the dev-agent definition + * `.claude/agents/os-dev.md`, and the root `AGENTS.md`. Read a file's absence + * from the map as a fact to check, not an oversight to infer — `.claude/hooks/`, + * `.claude/settings.json` and `CLAUDE.md` carry no ceiling either. + * + * The **published** `skills/` catalog — the one that ships to customer projects + * — is deliberately OUTSIDE the ceiling. It is the omission worth stating + * because it is by far the larger surface: eleven published SKILL.md totalling + * ~10,400 lines, against ~3,700 covered here. Two reasons, both about the cost + * curve the ratchet prices rather than about size (#9923): + * + * - What the ratchet prices is a full-file token read paid PER SEAT SESSION + * and PER ROUTINE FIRE, which is what every covered file above costs. The + * published catalog is read by customer projects, not by this repo's seats + * — a different cost curve, and not the one this gate was built against. + * - The published catalog is already a governed, human-merge-only surface + * (Prime Directive #14), so growth there passes a human eye by + * construction — a control a ratchet would merely duplicate. Note this + * reason does not separate the two roots by itself: the covered files are + * governed at merge too. What no reviewer prices THERE is the recurring + * per-session read of reason one, which is why they still carry ceilings + * and the published catalog does not. + * + * Extending coverage to the published root is therefore a POLICY CHANGE, not a + * maintenance edit: it needs its own card and a maintainer's ruling, not a + * CEILINGS row added in passing. The self-test pins this boundary, because + * enforcement cannot — a published-root entry would run perfectly green. + * * ## The ratchet discipline (shrink-only, per file) * * - A ceiling may be LOWERED by any PR that shrinks its file — lowering is @@ -142,6 +175,12 @@ function selfTest() { ['all six lane job descriptions are covered', ['engine', 'services', 'cli', 'devx', 'skills', 'spec'].every((n) => CEILINGS.has(`.claude/skills/pm-dispatch/references/lanes/${n}.md`)), true], ['the other four skills are covered (#9473)', ['checklist-test', 'checklist-author', 'dogfood-verification', 'spec-property-retirement'].every((n) => CEILINGS.has(`.claude/skills/${n}/SKILL.md`)), true], ['root AGENTS.md is covered (#9792)', CEILINGS.has('AGENTS.md'), true], + // The boundary the header states, pinned (#9923). Enforcement cannot hold + // it: a ceiling on a real published SKILL.md runs green like any other row, + // so without this case the header paragraph could drift from the map + // silently. Extending coverage to the published catalog is a policy change + // — it lands with a maintainer ruling that also deletes this case. + ['the published skills/ catalog is deliberately uncovered', [...CEILINGS.keys()].some((k) => k.startsWith('skills/')), false], ]; let failed = 0; for (const [name, actual, expected] of cases) {