feat(scanners): a path written in prose is now resolved, not assumed (C3)
`import-resolver` follows @import targets; a path written in ordinary prose was checked by nothing. CA-CML-013 resolves those too — one finding per file, severity low, against both the CLAUDE.md's own directory and the scan root, because a nested file may legitimately write repo-root-relative paths. The design work here is the SILENCE list, and every entry on it was measured against 407 real CLAUDE.md files rather than argued for: - Bare filenames excluded: admitting them tripled the output (2350 vs 810), led by name-drops of tools that exist elsewhere on the machine. - Org/repo slugs, npm packages, pytest node ids and prose enumerations excluded: 111 fires, inspected, all false positives. - Bare folder names excluded on the same reasoning one level up: 183 of the remaining 699 fires (26%), led by `open/` — a Forgejo remote namespace prefix, not a directory. This one overturned a premise the fasit had asserted without measuring; the deviation is recorded rather than the prediction quietly edited. - Containment is checked against the scan root, not the file's own dir: a base a `..` chain can escape is not a base. Measured — without it, `../../../../etc/passwd` resolved to the real file and silenced its own finding, while a legitimate `../docs/x.md` still resolves. Rule ORDER is the reported reason (first match wins), so `npm test` is silenced as a command rather than as a bare token, and two silences with different causes keep their own fixtures. Twelve classes, pinned by name. Both load-bearing rules were seen RED against their own defect: deleting containment fails 1 test, deleting the slug rule fails 6. Dogfooded through the argv the command template itself constructs, which found a true positive in our own CLAUDE.md — `lib/humanizer.mjs` where the file is `scanners/lib/humanizer.mjs`. Fixed here. Suite 1662 -> 1701, 0 failing. Frozen v5.0.0 and default-output baselines: 0 changed files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HJbfM3N8zWQ1wA2voTrZxz
This commit is contained in:
parent
33bfd5ff5b
commit
dbb6a6a3cf
10 changed files with 478 additions and 3 deletions
23
README.md
23
README.md
|
|
@ -301,7 +301,7 @@ By default, `/config-audit` auto-detects scope from your git context. Override w
|
|||
|
||||
| Scanner | Prefix | What It Catches |
|
||||
|---------|--------|-----------------|
|
||||
| `claude-md-linter.mjs` | CML | Oversized files (line count **plus** a context-window-scaled char budget mirroring Claude Code's ~40.0k-char startup warning), missing sections, broken @imports, duplicates, stale TODOs |
|
||||
| `claude-md-linter.mjs` | CML | Oversized files (line count **plus** a context-window-scaled char budget mirroring Claude Code's ~40.0k-char startup warning), missing sections, broken @imports, duplicates, stale TODOs, and **dead prose references** (`CA-CML-013`) — backtick-quoted relative paths in prose that resolve to nothing, next to the file or from the scan root |
|
||||
| `settings-validator.mjs` | SET | Schema violations, unknown/deprecated keys, type mismatches, permission issues |
|
||||
| `hook-validator.mjs` | HKV | Invalid format, missing scripts, wrong event names, timeout risks, verbose-stdout scripts, and a low-precision **advisory** (info) when a hook injects un-grepped command output into `hookSpecificOutput.additionalContext` — that payload enters context on every fire (plain stdout does not) |
|
||||
| `rules-validator.mjs` | RUL | Bad glob patterns, orphaned rules, deprecated fields, unscoped rules |
|
||||
|
|
@ -318,6 +318,27 @@ By default, `/config-audit` auto-detects scope from your git context. Override w
|
|||
| `optimization-lens-scanner.mjs` | OPT | Optimization lens (mechanism-fit): a multi-step procedure in CLAUDE.md that would fit better as a skill (`CA-OPT-001`) — reads the machine-readable best-practices register, framed as an opportunity, not a failure. The deterministic half of the lens; prose-judgment cases (lifecycle→hook, unscoped path→rule, "never"→permission) are judged by the opus `optimization-lens-agent` via `/config-audit optimize` |
|
||||
| `agent-listing-scanner.mjs` | AGT | Always-loaded agent-listing budget: a per-agent description over the soft bloat cap (`CA-AGT-001`, advisory) and the summed active-agent name+description listing — re-sent every turn — exceeding the listing budget (`CA-AGT-002`). Both LOW and explicitly **inferred / upper-bound**: the agent-listing mechanism is undocumented, so the evidence discloses the estimate and heuristic budget rather than overstating certainty |
|
||||
|
||||
> **Dead prose references — a check designed around what it stays silent about.**
|
||||
> `import-resolver` follows `@import` targets; a path written in ordinary prose was
|
||||
> checked by nothing, so `CA-CML-013` (low) resolves those too. A reference has to be
|
||||
> unambiguously path-shaped to qualify: a separator, plus either a trailing `/` or a
|
||||
> known file extension, resolved both next to the CLAUDE.md and from the scan root —
|
||||
> a nested file may legitimately write repo-root-relative paths. One finding per file,
|
||||
> carrying the count and the first few paths.
|
||||
>
|
||||
> The design work is the silence list, and every entry on it was measured against 407
|
||||
> real CLAUDE.md files rather than argued for. Left alone: commands (`npm test`), URLs,
|
||||
> globs and placeholders (`CA-GAP-*`, `${CLAUDE_PLUGIN_ROOT}/…`), absolute and `~/`
|
||||
> paths, config keys and flags (`model:`, `--raw`), bare filenames (`README.md` — a
|
||||
> filename in prose is a concept, and admitting them tripled the output with name-drops
|
||||
> of tools that exist elsewhere), org/repo slugs and package names
|
||||
> (`ktg/some-repo`, `@anthropic-ai/claude-agent-sdk`), bare folder names (`docs/`,
|
||||
> `open/` — the same reasoning one level up), fenced code blocks, and anything resolving
|
||||
> outside the scanned tree. That last rule is not fussiness: without it a `../../../../etc/passwd`
|
||||
> resolved to the real file and silenced its own finding. A path carrying a trailing
|
||||
> `:54-56` locator is a known v1 miss — for a precision-first check, silence is the safe
|
||||
> failure direction.
|
||||
|
||||
> **Cross-scanner remediation — diagnosis meets the fix.** SKL diagnoses an over-budget
|
||||
> skill listing (`CA-SKL-002`); GAP prescribes the remedy. When the active skill listing
|
||||
> exceeds its ~2%-of-context budget and `disableBundledSkills` is not already set (in the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue