Skip to content

Commit 7e40d1d

Browse files
fix(devx): check the published skill fence against the scaffold emission policy (#19210)
Part of #16767 — the `--check` leg only. The `gen:` write-back leg named on the card stays open and unaddressed here; it needs its own ruling, so no closing keyword. ## The gap `check:scaffold-emission-policy` pinned `SCAFFOLD_TYPESCRIPT_RANGE` on **one** of its two hand-written restatements — the bundled template `packages/create-objectstack/src/templates/blank/package.json`. The other restatement, the "Complete Working Example" `package.json` fence in `skills/objectstack-platform/SKILL.md`, had no reader at all, and it is the one that drifted longest (to a retired major). Measured on `origin/main` at `6e4024c76` before the change: ``` scripts/sync-scaffold-emission-policy.mjs:116 constant: 'SCAFFOLD_TYPESCRIPT_RANGE', occurrences of `objectstack-platform` in that gate: 0 (it cannot reach the fence) firing control, same grep for a term it DOES contain: 5 (SCAFFOLD_PNPM_RANGE) ``` ## What this adds A **check-only** second carrier: - `PUBLISHED_RESTATEMENTS` — a hand-kept table of (file, fence, keys). One row today: the skill's fence, checking `devDependencies.typescript`. - `readRestatementFence()` — locates the fence by **content** (heading, then the label line inside that section, then the first fence, whose language tag must match), never by line number: this carrier's line number is already measured moving (608 the day the gap was filed, 613 on the card). Every step demands exactly one match and throws otherwise, so a renamed section reds instead of degrading into "nothing found, all green". - `checkRestatement()` — parses the fence and compares against the same `SCAFFOLD_*` constants. A fence that drops a checked key is a hard failure naming the path, matching the templates' contract. ## What this deliberately does NOT do - **No `gen:` write-back.** `skills/**` is a governed surface (Prime Directive #14) and a generator writing into a governed published file needs its own ruling. The restatement pass runs under `--check` only; the write run — the one `packages/create-objectstack`'s `build` invokes — neither reads nor writes the carrier, which also keeps the on-ramp's build free of a dependency on a published skill file. - **No byte under `skills/**` is touched.** Reading a governed file is not governing it, so this stays an ordinary devx PR. `check-skills-token-ratchet` is green and the skill's token count is unmoved. - **No prose pointer in the skill.** Already measured dead: that file sits at 12980 tokens against a 12984 ceiling and the shortest conforming sentence is 85 bytes, 17 tokens over. - The failure text for a drifted restatement **refuses to point at `pnpm gen:scaffold-emission-policy`** — it says so explicitly, because that command does not and must not fix this carrier. ## Verification — both directions driven **GREEN**, after the change, on the real tree: ``` packages/create-objectstack/src/templates/blank/package.json already emits the shared policy skills/objectstack-platform/SKILL.md (## Complete Working Example) already restates the shared policy ✓ check:scaffold-emission-policy: 2 carrier(s) emit the shared policy — 1 bundled template(s) + 1 published restatement(s) (SCAFFOLD_PNPM_RANGE=>=10.15, SCAFFOLD_TYPESCRIPT_RANGE=^5.3.0). ``` Before the change the same line read `1 bundled template(s) emit the shared policy`. **RED**, by ablation in the worktree (never committed). Landing proof read BEFORE any verdict — a substitution whose anchor matched nothing exits 0, leaves the blob unchanged and reads exactly like "the gate did not notice": ``` LANDING-PROOF BEFORE: head_blob=713cb7503e2a9cd6f884fd94a3b74617e275ee3f working_hash=713cb7503e2a9cd6f884fd94a3b74617e275ee3f grep(^5.3.0)=1 grep(^4.4.4)=0 LANDING-PROOF AFTER: working_hash=9eaa632e945f513f2e53384ff145dcf3c1cc18d0 grep(^5.3.0)=0 grep(^4.4.4)=1 ✗ a published restatement of the shared emission policy has drifted. Policy source: packages/cli/src/commands/init.ts (SCAFFOLD_PNPM_RANGE=>=10.15, SCAFFOLD_TYPESCRIPT_RANGE=^5.3.0) skills/objectstack-platform/SKILL.md — the `## Complete Working Example` **`package.json`**: fence: devDependencies.typescript is "^4.4.4" but SCAFFOLD_TYPESCRIPT_RANGE declares "^5.3.0" MUTATED_CHECK_EXIT=1 ``` The write run was driven under the same mutation and stayed green with the carrier byte-identical — the check-only contract, observed rather than asserted: ``` WRITE_EXIT=0 carrier_hash_unchanged=yes ``` **RESTORE**, byte-identical: ``` LANDING-PROOF RESTORE: working_hash=713cb7503e2a9cd6f884fd94a3b74617e275ee3f head_blob=713cb7503e2a9cd6f884fd94a3b74617e275ee3f equal=yes grep(^5.3.0)=1 grep(^4.4.4)=0 DIFF_EMPTY=yes RESTORED_CHECK_EXIT=0 ``` The ablation is also permanent as fixture-driven self-test batteries `H` (16 assertions) and `I` (4), so the leg cannot go mute again without a red: the carrier is observed counted in the verdict, reddening on fence drift and naming that fence, refusing a dropped key and a renamed heading, and left byte-identical and unreached by the write run. `--self-test` now reaches 49 assertions. ## Gates `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` derived 29 commands from the committed change set; all 29 ran green (`check:pm-dispatch-gates` timed separately — it is a band, not a point). Additionally run, because their rosters live under `scripts/` where this diff is: `check-skills-token-ratchet` (green, skill token count unmoved), `check-published-list-mirrors`, `check:console-injection`, `check:engine-double-contract`, `check:i18n-stale-fill`, `check:pm-governed-prose` — all green. `check:dts-closure` and `check:published-readme-exports` returned exit **3 = PREREQUISITE NOT MET** (no package `dist/` in this worktree); their subject is built `.d.ts` output, which this diff does not touch. Recorded as NOT MEASURED locally, left to CI, not as a pass. Lint: the repo-wide `eslint . --no-inline-config` run completed here over **6906** files with 0 errors and 0 warnings, so no narrowing was needed. Type-check lane: not applicable. The only changed file is a root-level `.mjs` with no TypeScript; no package `tsconfig` reaches `scripts/` at the repo root, and `turbo run typecheck` is per-package. ## Changeset None — `skip-changeset`. Nothing already published moves: the sole changed path is `scripts/sync-scaffold-emission-policy.mjs`, the root package is private, and no published package's `files[]` ships anything under `scripts/` (scanned every non-private workspace manifest; zero hits). ## Acceptance notes Noted, not filed: - The same fence restates four `@objectstack/*` ranges by hand. The card and triage both ruled these out for now: this gate does not know the release range, and introducing one here would create the second version authority that causes this whole defect family. Carrier for that: whoever next touches `sync-template-versions.mjs`, which already owns `@objectstack/*` ranges for the bundled templates. - The `gen:` write-back half of the card remains genuinely open and is what keeps this PR from closing #16767. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk --- _Generated by [Claude Code](https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6e4024c commit 7e40d1d

1 file changed

Lines changed: 352 additions & 5 deletions

File tree

0 commit comments

Comments
 (0)