Uh oh!
There was an error while loading. Please reload this page.
chore(scripts): check-skills-paths scans .claude/skills too — 27 to 88 stated paths under the gate, the #7251 pins restored (#7358) - #7407
Merged
Conversation
…#7358) SCAN_ROOT was one string, `skills`. objectui#7251 moved the two contributor-only guides into `.claude/skills/objectui-contributor/` and 55 of 93 stated paths, 59%, left the checked surface in one commit with nothing turning red — the gate simply stopped looking. Make it a list, `['skills', '.claude/skills']`, and thread it through `scan()` (a `perRoot` breakdown beside the totals), the OK line, the `--list` footer and the empty-verdict trap. That trap is now judged PER ROOT, which is the lesson the miss itself taught: summed over roots, "one root reads nothing" is invisible — a whole-surface floor stayed comfortably green on the 16 files still under `skills` while a second tree of 55 assertions sat unscanned. Measured, before -> after: 16 -> 20 files, 27 -> 88 stated paths checked (console-development.md 49, no-touch-zones.md 6, objectui-contributor's SKILL.md 5, verify/SKILL.md 1). The widened surface brings exactly one red, cleared in the next commit. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…de (objectui#7358)
The widened surface brought exactly one red, and it is not rot: the
deliberate negative sentence in `console-development.md`'s Key contexts
section, "there is no `apps/console/src/context/` directory at all",
written to correct the recurring wrong guess that the five contexts live
in the console app. The other 60 coordinates in the two moved guides all
resolved on arrival.
This is the entry objectui#7251 was forced to delete: the baseline is
keyed by guide file, so the move retired it through the ratchet's second
direction ("1 baseline entry the scan never met ... Delete the entry").
Widening the root makes the scan meet the same sentence again, so the
entry comes back under the new key.
Granted against the gate's own prescription, quoted in the entry's
reason: "If the path is deliberately named as NOT existing -- a sentence
whose whole point is 'there is no such directory' -- add it to
scripts/skills-path-baseline.json with a reason, and expect the gate to
go red again the day that path appears on disk."
Nothing was corrected at source because nothing was stale; `ls` confirms
`apps/console/src/context/` still does not exist, which is what the
sentence says.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1…ken (objectui#7358) Three restorations and one deletion, all of them named in advance by the comments objectui#7251 left beside the weakened forms. The `checked` floor goes back to 50, the value it dropped to 20 to survive the move, with the arithmetic restored: 88 checked today, of which the two moved guides carry 55. If `.claude/skills` ever falls out of SCAN_ROOTS the reading drops to 33 and this floor is red. Beside it, a per-root floor. A total cannot see one root go quiet: 27 under `skills` alone clears a floor of 20, which is exactly how the 55 left unnoticed. The objectui#3713 / #3730 block asserts `result.missing` through `scan(repoRoot)` again, on the guide's current path, and carries its exemption pin again. The "is NOT covered by the gate today" assertion is DELETED, as it was written to be. Its replacement is the inverse claim rather than nothing, because `inGuide(result.missing)` is empty both when the guide is clean and when nothing scans it: the guide's own density is now tied to its root's checked count, so the two are no longer confusable. Five fixture cases cover the two-root surface: the declared roots, a dead path found under `.claude/skills`, the `perRoot` breakdown, a root that reads nothing showing as a zero row, and a baseline entry keyed to a file under the second root. 31 -> 37 test cases, all passing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
os-litant
commented
Sep 2, 2026
CollaboratorAuthor
Landing provenance (skills lane seat, session Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes#7358
SCAN_ROOTwas one string,skills. #7251 moved the two contributor-only guides into.claude/skills/objectui-contributor/and 55 of 93 stated paths left the checked surface in one commit with nothing turning red — the gate simply stopped looking. This makes it a list,['skills', '.claude/skills'], clears the red the wider surface brings, and restores the pins #7251 had to weaken.Head:
471589f. Every number below was measured on that commit unless it names another.The measurement the docblock asks for
The script's own header requires this: "Widen it on purpose, with the measurement re-run, not as a rider." Re-run, before and after, with
node scripts/check-skills-paths.mjsand--list:0614b6df1)471589f)console-development.mdno-touch-zones.mdobjectui-contributor/SKILL.mdverify/SKILL.mdPer root, which the gate now prints on every green run:
The card's headline number is 93, and the honest re-measurement is 88. Both the card's own figures cannot hold at once: it records 18 to 16 files and 93 to 27 assertions, a loss of 66, while the two moved guides carry 55 between them. The missing 11 are assertions #7251 also removed when it rewrote the published guides it kept. So widening restores 61 assertions under the new root — the 55 that left, plus 6 in two files that were never under
skillsat all — for 88, not 93. The PR title carries the measured number rather than the card's.The red the widened surface brought: exactly one, and it is not rot
Coordinates corrected at source: zero. Not for want of looking — the other 60 in the two moved guides all resolved on arrival. They were maintained by hand through #3713 and #3730 and had not yet gone stale, which is the case for gating them, not against.
The one non-resolver is the deliberate negative sentence in the Key contexts section, which exists to correct the recurring wrong guess that the five contexts live in the console app:
Evidence it is a true statement and not a stale coordinate:
This is the entry #7251 was forced to delete. The baseline is keyed by guide file, so the move retired it through the ratchet's second direction — the gate demanded it in its own words, "1 baseline entry the scan never met ... Delete the entry". Widening the root makes the scan meet the same sentence again, so the entry returns under the new key, granted against the gate's own prescription, quoted verbatim in the entry's
reason:Dated
objectui#3735 (re-keyed under the moved guide path by objectui#7358, 2026-09-02). It is the only entry in the file, as it was before the move: one exemption for 88 assertions.The lesson the miss itself taught: emptiness is judged per root
The empty-verdict trap in
main()used to ask whether the whole surface read zero. That question could not have caught #7251: 16 files and 27 assertions still underskillsis a healthy-looking total while a second tree of 55 sits unscanned. It now asks per root, and a root that judges nothing is named and red — either a move nobody threaded through, or a root that should be deleted fromSCAN_ROOTS, and both are decisions rather than a pass.scan()returns aperRootrow per root to make that answerable at all.The pins #7251 left to be reversed
All three were named in advance by the comments beside them.
checkedfloor, 20 back to 50. With the arithmetic restored, as Skills optimization flight — skills/objectui: RESTRUCTURE (≈ −21,600 tok of 64,022, −34%) — ~19% of the package is addressed at a contributor to this repo (console-development.md, no-touch-zones.md, half of architecture.md), one rule stated up to four times, 11 vestigial guide frontmatters, and three evals that fail correct answers #7251 left it: 88 checked today, of which the two moved guides carry 55 (49 + 6). If.claude/skillsever falls out ofSCAN_ROOTSthe reading drops to 33 and the floor is red — the assertion Skills optimization flight — skills/objectui: RESTRUCTURE (≈ −21,600 tok of 64,022, −34%) — ~19% of the package is addressed at a contributor to this repo (console-development.md, no-touch-zones.md, half of architecture.md), one rule stated up to four times, 11 vestigial guide frontmatters, and three evals that fail correct answers #7251 could not make.skillsalone clears a floor of 20, which is exactly how the 55 left unnoticed.result.missingthroughscan(repoRoot)again, on the guide's current path, and carries its exemption pin again.inGuide(result.missing)is empty both when the guide is clean and when nothing scans it, so the guide's own stated-path density is now tied to its root'scheckedcount and the two stop being confusable.Five fixture cases cover the two-root surface: the declared roots, a dead path found under
.claude/skills, theperRootbreakdown, a root that reads nothing showing as a zero row rather than an absence, and a baseline entry keyed under the second root. 31 to 37 cases.Ablation — the widened root really is checked
One coordinate in the newly covered guide, mutated on the committed tree and restored, both legs proved on disk. No build or
distis involved: the gate is anodescript reading markdown, so there is no artifact between the edit and the reading.Mutation landed (
packages/app-shell/src/layout/UnifiedSidebar.tsxto...SidebarGONE.tsx, injected-token count 1, original-token count 0, on-disk hash0cd9febagainst HEAD blob27e5f46), gate exit 1:Restore proved, not assumed —
git checkout HEAD -- ABSOLUTE_PATHunder atrap ... EXIT INT TERM, then on-disk hash27e5f46equal to the HEAD blob,git diff HEAD --name-onlyempty, injected-token count 0, original-token count 1. Gate exit 0:Premises that did not hold
premise_false: the gate has a --self-test mode— the dispatch expectednode scripts/check-skills-paths.mjsto run "self-test + live". It has no such flag;grep -n 'self-test\|selfTest'over the script returns nothing, and its only mode besides the live run is--list. The self-test is the vitest suite, and that is where the two-root cases were added.premise_false: 93 stated paths come back under the gate— 88, for the arithmetic given above.premise_false: the queue guard returns exit 3 GOVERNED— it does so when.claude/skills/**is in the diff, and nothing there needed correcting, so the diff is three files underscripts/. Its own verdict:✅ NOT GOVERNED — 3 path(s) checked against 5 governed surface(s); none matched.Draft and human-merged either way, as the dispatch asks.premise_false: the widened surface brings stale coordinates to correct at source— 60 of 61 resolve; the single non-resolver is the deliberate negative sentence.Gates, at
471589fExit codes captured by redirecting first (
cmd > file 2>&1; EXIT=$?), never read across a pipe. Each row quotes the gate's own verdict line.node scripts/check-skills-paths.mjs✅ check-skills-paths: OK (87/88 stated path(s) resolve across 20 guide file(s); 1 baselined).pnpm exec vitest run scripts/__tests__/check-skills-paths.test.tsTest Files 1 passed (1)/Tests 37 passed (37)pnpm type-check:scriptstsc -p tsconfig.scripts.json, silentnode scripts/check-doc-links.mjsLinks are valid across 17 scan roots.node scripts/check-control-bytes.mjs✅ check-control-bytes: OK (scanned 6103 tracked text file(s); skipped 85 binary).node scripts/check-shell-escape-residue.mjs✅ check-shell-escape-residue: OK (4/4 root(s) resolved ...)node scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.node scripts/check-governed-queue-guard.mjs --self-testOK check-governed-queue-guard self-test: 132 cases passnode scripts/check-governed-queue-guard.mjs --test(3 changed paths)✅ NOT GOVERNED — 3 path(s) checked against 5 governed surface(s); none matched.pnpm exec eslint(changed files)No changeset, on the gate's own verdict, not on judgement:
3 file(s) changed, 0 of them published source of a package the release covers. Noskip-changesetlabel, which this repo does not use as a mechanism, and no empty-frontmatter changeset either — the gate says none is owed.type-check:scriptsgenuinely covers the edited test file, rather than excluding it and reporting a clean run about other files:tsc -p tsconfig.scripts.json --listFileslists bothscripts/check-skills-paths.mjsandscripts/__tests__/check-skills-paths.test.ts, one occurrence each.eslint was narrowed, and the narrowing is measured rather than assumed. Population, read from
eslint.config.jsand not guessed: every rule block is scopedfiles: ['**/*.{ts,tsx}'], and no block declares an.mjs,.cjsor.jsonglob — so of the three changed files only the.tstest is inside the linted population at all. File count read from--format json: 1 result object,errorCount0,warningCount0. Invariance: the config declares neitherparserOptions.projectnorprojectService, so linting is not type-aware and nothing in this diff can move the verdict on a file it did not touch. The full-repopnpm lintis CI's run.Scope
Three files, all under
scripts/. Nothing underskills/objectui/**, nothing underpackages/**, no other gate touched, and — because nothing needed correcting — nothing under.claude/skills/**either.Two findings of the same class were filed unassigned rather than ridden in here; neither is addressed by this PR:
skillsroot does not reach.claude/skills#7403 —check-shell-escape-residue'sskillsdirectory root lost the same two files in the same move: 18 fenced blocks off its surface, invisible to itsminFiles: 5floor because 16 files still satisfy it.skills-paths.yml's header states the gate's scan surface asskills/**over 18 files — both halves are stale #7404 — this gate's own workflow header still states the surface asskills/**over 18 files. Prose only; the workflow has no path filter and still runs correctly.🤖 Generated with Claude Code
https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Generated by Claude Code