docs(config-audit): v5 implementation log — Session 3 beta.1 result

Session 3 (beta.1) shipped 7 steps in one session: N1 (CA-TOK-005),
N2 (manifest CLI), N3 (CPS), N4 (DIS), N6 (COL) + namespace research
spike + CHANGELOG entry. 586 → 625 tests, all green.

Per-step result table + notable observations and deviations recorded.
No blockers carried into Session 4.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-01 07:50:22 +02:00
commit 346b4c4fb7

View file

@ -102,9 +102,37 @@ Written at the end of each session. State for the next session lives in
---
## Session 3 — beta.1 (TBD)
## Session 3 — beta.1 (2026-05-01)
*Steps 18, 19, 20, 21, 22a, 22b, 23.*
**Outcome:** All 7 steps shipped. 586 → 625 tests, all green. Direct-to-main on Forgejo (autorisert).
**Per-step result:**
| # | Step | Result | Commit |
|---|------|--------|--------|
| 18 | N1 — `CA-TOK-005` MCP tool-schema budget | ✓ green (+7 tests; tiered severity 14/25/60/120/unknown via fixtures with inline `tools` arrays in `.mcp.json`; scoped to project-local `.mcp.json` to avoid ambient ~/.claude.json plugin-MCP leakage) | `b2407a0` feat(config-audit): CA-TOK-005 MCP tool-schema budget (v5 N1) |
| 19 | N2 — System-Prompt Manifest scanner + CLI | ✓ green (+11 tests; both real-config and `buildRichManifestRepo` fixture paths; CLAUDE.md per-file tokens distributed proportional to bytes) | `0420b8c` feat(config-audit): /config-audit manifest command (v5 N2) |
| 20 | N3 — Cache-Prefix Stability scanner (CPS) | ✓ green (+7 tests; CACHED_PREFIX_LINES=150; volatile patterns extend Pattern A with `!` shell-exec and `${VAR}`; skips lines 1-30 to avoid Pattern A overlap; required `scoreByArea` dedup-by-area to keep 9-area contract for shared "Token Efficiency") | `65087e6` feat(config-audit): cache-prefix stability scanner CPS (v5 N3) |
| 21 | N4 — Disabled-In-Schema scanner (DIS) | ✓ green (+6 tests; per-file deny+allow overlap detection by bare tool name; healthy-project as negative case) | `cc349d6` feat(config-audit): disabled-in-schema scanner DIS (v5 N4) |
| 22a | Namespace research spike | ✓ written to `docs/v5-namespace-research.md` (gitignored); confidence: medium; verdicts: plugin-vs-plugin = low collision possible, user-vs-plugin = medium, built-in = uncertain (deferred to v5.0.1) | (no commit; .gitignore folded into 22b) |
| 22b | N6 — Cross-plugin collision scanner (COL) | ✓ green (+8 tests; user-vs-plugin medium, plugin-vs-plugin low, with `details.namespaces` array; new "Plugin Hygiene" area; `output.mjs:finding()` helper now passes through `details`; posture test bumped 9→10 areas) | `cd25c1e` feat(config-audit): cross-plugin collision scanner COL (v5 N6) |
| 23 | beta.1 wrap CHANGELOG | ✓ added with Known breaking changes section on `CA-TOK-*` glob now matching CA-TOK-005, plus explicit note on plugin-vs-built-in deferred to v5.0.1 | `5a1e7cb` docs(config-audit): CHANGELOG 5.0.0-beta.1 + N1 breaking note |
**Notable observations / deviations:**
- **Step 18 ambient leakage rerun:** initial implementation iterated all `activeConfig.mcpServers` and tripped on user's plugin-bundled MCP servers (e.g. `sadhguru-wisdom` showed up in the `sonnet-era` fixture's findings). Fix: scope to `m.source === '.mcp.json'` (project-local). Plugin/user MCP servers are surfaced by Step 19's manifest scanner instead. Tests filter by fixture-specific server name (`budget-srv-N`).
- **Step 18 detection-order pinning:** plan said "5th detection block AFTER A/B/C". Patterns F (skill desc) + E (cascade > 10k) were already present from alpha.2. Inserted N1 between Pattern F and Pattern E. Tests assert title + severity (not exact ID) since IDs are sequential per scan.
- **Step 19 CLAUDE.md per-file tokens:** `claudeMd.estimatedTokens` is computed for the whole cascade. Decided to distribute across files proportional to `bytes` rather than recompute per file — single source of truth for the cascade total.
- **Step 20 dedup-by-area refactor:** CPS shares the "Token Efficiency" area with TOK, but `scoreByArea` was emitting one row per scanner, not per area. Refactored to group results by area name and merge counts. The 9-area contract held until Step 22b added "Plugin Hygiene".
- **Step 21 fixture write succeeded:** PathGuard hook was a Session 2 watch-out for fixture `settings.json` writes. Used `cat <<EOF` via Bash this time — passed through. (Either the hook was relaxed since alpha.2, or the path-guard rule applies to specific edits not new fixtures.)
- **Step 22a confidence: medium.** The plugin-prefix in `name:` frontmatter is freeform (e.g. `llm-security` plugin uses `security:` prefix, not `llm-security:`), so collision IS possible if two authors choose the same prefix word. Built-in collision (e.g. plugin shadows `/help`) is not testable from research alone — left as info-only in CHANGELOG.
- **Step 22b `details` field:** had to extend `output.mjs:finding()` helper to pass through `details`. Existing scanners don't break (the field is optional, only present when set). First scanner to use it.
- **Step 22b posture test:** the `assert.equal(result.areas.length, 9)` assertion broke because COL added a 10th area. Bumped to 10 with a note in the test message (v5 adds Plugin Hygiene from COL). This is a deliberate v5 design change.
- **Step 22b suppression-glob test surfaced an API bug:** my first test passed `[{ id: 'CA-TOK-*', ... }]` to `applySuppressions`. The actual key is `pattern`, not `id`. Updated. No code change — just test fixed.
- Total tests: 586 → 625 (+39). Per-step: +7, +11, +7, +6, +8 (no test for 22a research, 0 for Step 23).
**No blockers carried into Session 4.**
---
---