You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(tooling): fail check-doc-authoring by name when a declared ROOT is dead (#4916) (#4934)
`collectFiles()` walked each root inside `try { walk(r, files); } catch {}`.
Rename, move or delete any one of `.claude` / `skills` / `content` and its
ENOENT was swallowed in place: the scan finished the remaining roots and
printed `✓ doc authoring guard: N files clean`, exit 0. Measured on this tree
with `.claude/` renamed away, the old code reports 215 files clean, exit 0,
where the honest answer is 219 — "all three roots are clean" and "one root was
never opened" are the same green line with a smaller N, and nobody reads N.
`assertRootsResolvable()` now runs before any walking and throws a
`DeadRootError` naming every root that is missing, unreadable, or not a
directory; `main()` renders that as a red gate pointing at the dead root. No
whitelist and no `optional` flag: all three roots are git-tracked directories
with tracked files, so no checkout that can run this gate at the repo root is
legitimately missing one, and an optional marker would be a supported way to
silence the failure instead of following the rename — the empty catch, spelled
politely. The inner try is gone too: an error during the walk also means the
corpus was only partly read.
The proof is bidirectional and permanent. `--self-test` (#4913) already walked
a real temporary tree with the real walker; it now renames one root away
mid-run and requires red naming that root and not the survivors, replaces
another root with a file and requires the `not a directory` verdict, then
restores both and requires green again. This closes what #4913's self-test
could not: it stayed green with the repo's real `.claude/` renamed away,
because it asserts over its own temp tree.
Same discipline as #4690 / #4804 / #4835 / #4851 / #4868 / #4890.
Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
Co-authored-by: Claude <noreply@anthropic.com>
Tooling-only: `scripts/check-doc-authoring.mjs` now fails, by name, when one of its declared `ROOTS` cannot be resolved (#4916). Releases nothing — no package changes.
5
+
6
+
The walk was `for (const r of ROOTS) { try { walk(r, files); } catch {} }`. Rename, move or delete any one root and its ENOENT was swallowed in place: the scan finished the *remaining* roots and printed `✓ doc authoring guard: N files clean`, exit 0. Measured on this tree — with `.claude/` renamed away, the old code reported **215 files clean, exit 0** where the honest answer is 219. From outside, "all three roots are clean" and "one root was never opened" are the same green line with a smaller N, and nobody reads N. That is the sixth instance this week of one shape: a check that runs, is green, and structurally cannot reach part of its subject (#4690 / #4804 / #4835 / #4868 / #4890 / #4851).
7
+
8
+
`assertRootsResolvable()` now runs before any walking and throws a `DeadRootError` naming every root that is missing, unreadable, or not a directory; `main()` turns that into a red gate that says which root died and tells the author to follow the rename in `ROOTS` rather than restore a tolerant skip. **No whitelist and no `optional: true` flag**, deliberately: `.claude`, `skills` and `content` are all git-tracked directories with tracked files, so no checkout that can run this gate at the repo root is legitimately missing one. An optional marker added "just in case" would be a supported way to silence the failure instead of fixing the rename — the empty `catch {}`, spelled politely. Should a root ever become legitimately absent, that is a decision to record with its condition and a test, not a check to relax. The inner `try` is gone too: an error *during* the walk also means the corpus was only partly read, which must not print as a clean scan.
9
+
10
+
The proof is bidirectional and permanent, not a one-off in the PR description. `--self-test` (#4913) already walked a real temporary tree with the real walker; it now also renames one root away mid-run and requires red naming that root and *not* the survivors, replaces another root with a file and requires the `not a directory` verdict, then restores both and requires green again. Observing green proves nothing about a gate whose failure mode is scanning less — so the self-test observes red first, every run. Note what this closes that #4913's self-test could not: the old self-test stayed green with the repo's real `.claude/` renamed away, because it asserts over its own temp tree.
console.log('✓ check-doc-authoring self-test: scope wiring (.claude in, .claude/worktrees out)and detection both hold.');
258
+
console.log('✓ check-doc-authoring self-test: scope wiring (.claude in, .claude/worktrees out), detection, and the dead-root hard error (red when a ROOT is renamed, green when restored) all hold.');
0 commit comments