fix(acr): feature-gap scopes presence checks to authored config + reads settings cascade (M-BUG-13)
The GAP scanner's 25 presence checks ran over the full includeGlobal discovery, so this plugin's own examples/optimal-setup (vendored across plugin-cache versions) satisfied every tier-3 check — masking real feature gaps to GAP=0 on ANY target. And the real ~/.claude/settings.json is invisible to the settings-key checks (includeGlobal gotcha + maxFiles cap), which would flip statusLine/autoMode to false positives once the maskers were removed. - isAuthoredConfig: exclude plugin-bundled (~/.claude/plugins/) + nested examples/ and tests/fixtures/ (relPath-relative, so a fixture scanned AS the target keeps its own files) from ctx.files + parsedSettings. - readSettingsCascade: read the user->project->local settings cascade directly and merge into parsedSettings — immune to the discovery cap/gotcha. Empty target: ~0 (masked) -> 18 humanized opportunities; no statusLine/autoMode false positives. Frozen v5.0.0 snapshots + SC-5/6/7 byte-stable (marketplace-medium has no nested demo trees; hermetic-HOME cascade adds nothing). Suite 1350->1355/0. Found by dogfooding feature-gap against the machine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01683eAqVecv9VZfQzL8CQ9h
This commit is contained in:
parent
b58393099a
commit
f4bf3ae2cb
3 changed files with 207 additions and 5 deletions
|
|
@ -254,6 +254,39 @@ model-switch is a *runtime* behaviour, not static config a scanner can reliably
|
|||
automation. "No overstated behavioral finding ships" — so even the permitted opusplan *info*-advisory was
|
||||
left out; the verified @import extension is the whole of B6.
|
||||
|
||||
### GAP scanner — authored-config scoping + direct cascade read (M-BUG-13)
|
||||
|
||||
The 25 presence checks ask "does the user's effective config have feature X?" and GAP **always**
|
||||
runs `includeGlobal: true`. Two failure modes made the answer wrong on a real machine, both surfaced
|
||||
by dogfooding `feature-gap`/`posture --global`:
|
||||
|
||||
1. **Demo/vendored config masks real gaps.** This plugin's own `examples/optimal-setup/` is a complete
|
||||
config (sets `outputStyle`/`statusLine`/`worktree`/`model`/`keybindings.json`/`.lsp.json`), and its
|
||||
copies vendored under `~/.claude/plugins/cache/.../config-audit/<ver>/examples/` are pulled into the
|
||||
includeGlobal discovery. Because `anySettingsHas`/`files.some(...)` accept ANY discovered file, that
|
||||
one demo file drove every tier-3 check to "present" → **GAP=0 on any target** (false negative).
|
||||
Fix: `isAuthoredConfig` filters `ctx.files`/`parsedSettings` to the user's authored cascade —
|
||||
excludes `~/.claude/plugins/` (absPath marker, mirrors CNF's M-BUG-2 exclusion) and any file whose
|
||||
path **relative to the scan target** sits under `examples/` or `tests/fixtures/`. relPath (not
|
||||
absPath) is deliberate: a fixture scanned AS the target keeps its own files, so the frozen v5.0.0
|
||||
snapshots (scanned from `tests/fixtures/marketplace-medium`, which has no such nested trees) are
|
||||
byte-stable.
|
||||
|
||||
2. **The real `~/.claude/settings.json` is invisible to the settings-key checks.** Discovery misses it
|
||||
(its relPath carries no `.claude` segment when the walk root IS `~/.claude` — the gotcha) AND, when
|
||||
vendored plugins flood the walk, the `maxFiles=2000` cap drops it. After (1) removed the demo
|
||||
maskers, `statusLine`/`autoMode`/`permissions` (which the user HAS) would flip to false **positives**.
|
||||
Fix: `readSettingsCascade` reads the four canonical cascade paths (user `settings.json`/`.local`,
|
||||
project `settings.json`/`.local`) directly and merges them INTO `parsedSettings` — immune to the
|
||||
cap and the gotcha. Merge (not replace) keeps non-canonical project settings and leaves the snapshot
|
||||
(hermetic empty HOME → cascade adds nothing new) byte-stable.
|
||||
|
||||
Net: an empty target now surfaces ~18 humanized opportunities (was masked to ~0); config-audit's own
|
||||
repo still shows 0 in output via its intentional `.config-audit-ignore` `CA-GAP-*` self-suppression
|
||||
(a plugin repo legitimately lacks user-project features) — suppression is an envelope-layer concern,
|
||||
orthogonal to this scanner fix. Scoped GAP-local; the includeGlobal discovery gotcha itself is left
|
||||
to other consumers (see auto-memory `discovery-includeglobal-user-settings-gotcha`).
|
||||
|
||||
### CML scanner — context-window-scaled char budget
|
||||
|
||||
Beyond the line-count checks (200/500 lines, both MEDIUM), the CML scanner mirrors
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue