config-audit/tests/snapshots/default-output/scan-orchestrator.json
Kjell Tore Guttormsen 4027cdcf54 fix(scanners): retire the autoMode GAP dimension, a /doctor duplicate (D1)
CC 2.1.226's /doctor Check 8 covers auto mode with usage-weighted judgement.
The binding positioning forbids carrying a feature whose whole value is
duplicating a /doctor check, so the "adopt this feature" nudge goes. The
deterministic side stays: SET still validates autoMode structure and still
flags it as dead config in shared project settings. GAP dimensions 25 -> 24.

The title lived in FOUR tables, not the two the removal was scoped against:
the dimension list, scoring TITLE_TO_ID, the humanizer's static translations,
and the scoring denominators (TIER_COUNTS t3 8->7, TOTAL_DIMENSIONS 25->24,
MAX_WEIGHTED 42->41) -- the one that moves a user-visible number. findGapId
falls back to 'unknown' silently, so a partial removal would have degraded
without failing. A blanket sync invariant now asserts all four against
GAP_CHECKS instead of comparing occurrences pairwise; each arm was verified
red against its own defect (denominator drift, orphaned humanizer entry,
resurrected dimension).

Frozen tests/snapshots/v5.0.0/ stays untouched. strip-retired-gap.mjs is the
removal twin of strip-added-scanner.mjs: it strips the retired dimension from
whichever side still carries it and re-derives GAP IDs, since retiring a
dimension from mid-list shifts every later ID by one. Derived utilization
figures are dropped from comparison rather than recomputed -- recomputing them
in a test helper would assert the new arithmetic against itself, and
scoring.test.mjs already pins them exactly. Re-seeding was rejected: it would
silently bake in any other drift across every scanner those four files cover.

risk_score, risk_band, verdict, overallGrade, maturity and segment are
byte-identical across the change (severity info carries zero risk weight; GAP
is excluded from the overall grade). Utilization shifts 43 -> 44 on the fixture.

D2 (CA-SKL-002) is NOT removed. Verified against the primary source first: the
CC changelog carries exactly one budget-fraction statement (L3786, 2.1.32) and
nothing supersedes it, so our 2% is current and 002 is not a duplicate with a
stale figure. /doctor's ~1% could not be reconciled from the changelog and it
discloses its own numbers as disk estimates, so it is recorded, not adopted.
Left explicitly unverified in a code note: L3786 says "character budget" while
we express tokens -- a 4x difference nobody can settle from the wording.

Suite 1531 -> 1535, all green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RsfPGxgwbR3MY54wDC6hat
2026-08-09 22:43:04 +02:00

616 lines
21 KiB
JSON

{
"kind": "json",
"payload": {
"meta": {
"target": "<TARGET>",
"timestamp": "<TIMESTAMP>",
"version": "2.2.0",
"tool": "config-audit"
},
"scanners": [
{
"scanner": "CML",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [
{
"id": "CA-CML-001",
"scanner": "CML",
"severity": "low",
"title": "Your instructions file is missing common sections",
"description": "Sections like Project Overview, Commands, and Conventions help Claude apply your guidance consistently across tasks.",
"file": "/Users/ktg/repos/ktg-plugin-marketplace/config-audit/tests/fixtures/marketplace-medium/CLAUDE.md",
"line": null,
"evidence": "Present sections: Marketplace Medium, Plugins, Commands, Conventions",
"category": null,
"recommendation": "Add the missing sections noted in the details.",
"autoFixable": false,
"userImpactCategory": "Configuration mistake",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "test-fixture-no-impact"
}
],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 1,
"info": 0
}
},
{
"scanner": "SET",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "HKV",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "RUL",
"status": "skipped",
"files_scanned": 0,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "MCP",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "IMP",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "CNF",
"status": "ok",
"files_scanned": 2,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "GAP",
"status": "ok",
"files_scanned": 4,
"duration_ms": 0,
"findings": [
{
"id": "CA-GAP-001",
"scanner": "GAP",
"severity": "medium",
"title": "You haven't added any custom shortcuts yet",
"description": "Custom skills give you `/your-shortcut` invocations for tasks you do often.",
"file": null,
"line": null,
"evidence": null,
"category": "t1",
"recommendation": "Create a skill in `.claude/skills/` for a workflow you find yourself repeating.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Fix when convenient",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-002",
"scanner": "GAP",
"severity": "low",
"title": "You only have settings at one level",
"description": "Settings can live at user, project, or local-only scope. Using more than one lets you keep personal preferences separate from team-shared ones.",
"file": null,
"line": null,
"evidence": null,
"category": "t2",
"recommendation": "Consider moving team-wide settings to project scope and keeping personal ones at user or local scope.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-003",
"scanner": "GAP",
"severity": "low",
"title": "You haven't set up path-scoped rules yet",
"description": "Path-scoped rules only load when you're working with files that match — keeps each conversation focused.",
"file": null,
"line": null,
"evidence": null,
"category": "t2",
"recommendation": "Add scoping to your rules so they only load for the files they apply to.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-004",
"scanner": "GAP",
"severity": "low",
"title": "Your automations all listen to similar events",
"description": "Listening to a wider range of events (before-tool, after-tool, session-start, etc.) lets you catch more workflow opportunities.",
"file": null,
"line": null,
"evidence": null,
"category": "t2",
"recommendation": "Look at the events your current automations skip and consider adding one or two.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-005",
"scanner": "GAP",
"severity": "low",
"title": "You haven't set up any specialized helper agents yet",
"description": "Subagents handle parallel work in separate contexts (research, code review, testing) without crowding your main conversation.",
"file": null,
"line": null,
"evidence": null,
"category": "t2",
"recommendation": "Create a subagent in `.claude/agents/` for a task you delegate often.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-006",
"scanner": "GAP",
"severity": "low",
"title": "You haven't pinned a model preference",
"description": "Setting a default model lets you choose between speed and depth of reasoning for your work.",
"file": null,
"line": null,
"evidence": null,
"category": "t2",
"recommendation": "Add a `model` setting in your settings file.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-007",
"scanner": "GAP",
"severity": "info",
"title": "You haven't set up a status line yet",
"description": "A status line shows live context (token usage, current branch, time) at the bottom of your terminal.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Add a `statusLine` setting if you want this information at a glance.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-008",
"scanner": "GAP",
"severity": "info",
"title": "You haven't set up any custom keybindings",
"description": "Custom keybindings let you trigger your most-used skills with a keystroke.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Add bindings in your settings for skills you run often.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-009",
"scanner": "GAP",
"severity": "info",
"title": "You're using the default output style",
"description": "Output styles let you change how Claude formats responses (concise, verbose, bullet-heavy, etc.).",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Try a different `outputStyle` setting if you have a strong preference.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-010",
"scanner": "GAP",
"severity": "info",
"title": "You haven't set up parallel worktree support",
"description": "Worktrees let Claude work on a branch in an isolated copy of the repo without disturbing your main checkout.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Enable worktrees if you regularly work on multiple branches at once.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-011",
"scanner": "GAP",
"severity": "info",
"title": "Your skills don't use the richer settings block",
"description": "Adding richer settings at the top of a skill lets you control when it loads, what tools it uses, and more.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Add fields like `model`, `tools`, or `description` to your skill files where useful.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-012",
"scanner": "GAP",
"severity": "info",
"title": "You haven't set up subagent isolation yet",
"description": "Isolated subagents run in their own copy of the repo so they can't accidentally disturb your main work.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Add `isolation: worktree` to subagents that do destructive or experimental work.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-013",
"scanner": "GAP",
"severity": "info",
"title": "Your skills don't include live context",
"description": "Dynamic context lets a skill see fresh information (file contents, command output) at the moment it runs, not at the time it was written.",
"file": null,
"line": null,
"evidence": null,
"category": "t3",
"recommendation": "Use the dynamic-context block in skills that need up-to-date information.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-014",
"scanner": "GAP",
"severity": "info",
"title": "You haven't built a custom plugin yet",
"description": "Plugins let you bundle skills, automations, and connected services that you want available across many projects.",
"file": null,
"line": null,
"evidence": null,
"category": "t4",
"recommendation": "If you have workflows you repeat across projects, consider packaging them as a plugin.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-015",
"scanner": "GAP",
"severity": "info",
"title": "Your project has no settings managed by your organization",
"description": "Managed settings let your organization apply rules everyone has to follow.",
"file": null,
"line": null,
"evidence": null,
"category": "t4",
"recommendation": "If you work in a team setting, consider whether managed settings would help.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
},
{
"id": "CA-GAP-016",
"scanner": "GAP",
"severity": "info",
"title": "You haven't connected Claude to your editor's language servers",
"description": "Language-server connections let Claude see types, error messages, and definitions the same way your editor does.",
"file": null,
"line": null,
"evidence": null,
"category": "t4",
"recommendation": "Set up LSP integration if you work in a typed language.",
"autoFixable": false,
"userImpactCategory": "Missed opportunity",
"userActionLanguage": "FYI",
"relevanceContext": "affects-everyone"
}
],
"counts": {
"critical": 0,
"high": 0,
"medium": 1,
"low": 5,
"info": 10
}
},
{
"scanner": "TOK",
"status": "ok",
"files_scanned": 2,
"duration_ms": 0,
"findings": [
{
"id": "CA-TOK-001",
"scanner": "TOK",
"severity": "low",
"title": "A connected service exposes many tools, all loading on every turn",
"description": "Each tool a connected service exposes adds its description to every turn. Services with many tools eat space fast.",
"file": ".mcp.json",
"line": null,
"evidence": "tool_count=unknown; server=\"memory\"; source=\".mcp.json\" — severity reflects estimated tokens/turn based on structural heuristic; not measured against runtime telemetry",
"category": "token-efficiency",
"recommendation": "Limit which tools the service exposes (often via a `tools` allow-list), or disconnect services you rarely use.",
"autoFixable": false,
"userImpactCategory": "Wasted tokens",
"userActionLanguage": "Optional cleanup",
"relevanceContext": "affects-everyone"
}
],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 1,
"info": 0
},
"hotspots": [
{
"source": "mcp:memory (.mcp.json)",
"estimated_tokens": 500,
"rank": 1,
"loadPattern": "always",
"survivesCompaction": "yes",
"derivationConfidence": "inferred",
"recommendations": [
"Review whether this source needs to load on every turn."
]
},
{
"source": "CLAUDE.md",
"estimated_tokens": 116,
"rank": 2,
"loadPattern": "always",
"survivesCompaction": "yes",
"derivationConfidence": "confirmed",
"recommendations": [
"Move volatile top-of-file content to the bottom or extract to an @import-ed file.",
"Split overlong CLAUDE.md into focused @imports (≤200 lines each)."
],
"path": "/Users/ktg/repos/ktg-plugin-marketplace/config-audit/tests/fixtures/marketplace-medium/CLAUDE.md"
},
{
"source": "hooks/hooks.json",
"estimated_tokens": 81,
"rank": 3,
"loadPattern": "external",
"survivesCompaction": "n/a",
"derivationConfidence": "inferred",
"recommendations": [
"Deduplicate overlapping entries — each duplicate inflates the per-turn schema payload.",
"Move rarely-used permissions to a project-local override."
],
"path": "/Users/ktg/repos/ktg-plugin-marketplace/config-audit/tests/fixtures/marketplace-medium/hooks/hooks.json"
},
{
"source": ".claude/settings.json",
"estimated_tokens": 59,
"rank": 4,
"loadPattern": "external",
"survivesCompaction": "n/a",
"derivationConfidence": "inferred",
"recommendations": [
"Deduplicate overlapping entries — each duplicate inflates the per-turn schema payload.",
"Move rarely-used permissions to a project-local override."
],
"path": "/Users/ktg/repos/ktg-plugin-marketplace/config-audit/tests/fixtures/marketplace-medium/.claude/settings.json"
},
{
"source": ".mcp.json",
"estimated_tokens": 45,
"rank": 5,
"loadPattern": "external",
"survivesCompaction": "n/a",
"derivationConfidence": "inferred",
"recommendations": [
"Deduplicate overlapping entries — each duplicate inflates the per-turn schema payload.",
"Move rarely-used permissions to a project-local override."
],
"path": "/Users/ktg/repos/ktg-plugin-marketplace/config-audit/tests/fixtures/marketplace-medium/.mcp.json"
}
],
"total_estimated_tokens": 801,
"activeConfig": {
"claudeMdEstimatedTokens": "<ANCESTOR_DERIVED>",
"mcpServerCount": 1,
"pluginCount": 0,
"skillCount": 0
}
},
{
"scanner": "CPS",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "DIS",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "COL",
"status": "ok",
"files_scanned": 0,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "SKL",
"status": "ok",
"files_scanned": 0,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "AGT",
"status": "ok",
"files_scanned": 0,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "OST",
"status": "ok",
"files_scanned": 0,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
},
{
"scanner": "OPT",
"status": "ok",
"files_scanned": 1,
"duration_ms": 0,
"findings": [],
"counts": {
"critical": 0,
"high": 0,
"medium": 0,
"low": 0,
"info": 0
}
}
],
"aggregate": {
"total_findings": 18,
"counts": {
"critical": 0,
"high": 0,
"medium": 1,
"low": 7,
"info": 10
},
"risk_score": 11,
"risk_band": "Medium",
"verdict": "PASS",
"scanners_ok": 15,
"scanners_error": 0,
"scanners_skipped": 1
}
}
}