feat(ost): v5.6 C — output-style scanner (CA-OST, count 13→14)

New orchestrated scanner output-style-scanner.mjs — first new family since
SKL. Three findings, each pinned to a CONFIRMED V-row of the steering-model
plan + re-verified against code.claude.com/docs/en/output-styles:

- CA-OST-001 (medium, V10): user/project custom style missing
  keep-coding-instructions:true (default false) → silently strips built-in
  software-engineering instructions when active. Scoped to user/project.
- CA-OST-002 (low, V11): plugin style with force-for-plugin:true overrides the
  user's selected outputStyle. Verifiseringsplikt correction — the plan bullet
  said "project/user style," but force-for-plugin is plugin-styles-only per the
  docs, so the check keys on source==='plugin'.
- CA-OST-003 (medium): settings outputStyle matching no built-in
  (Default/Explanatory/Learning/Proactive, case-insensitive) nor discovered
  custom style → dead config.

Byte-stability — a scanner addition, not a field addition. Growing the
scanners array + scanners_ok cannot be hidden by a field strip, but re-seeding
frozen v5.0.0 (the SKL precedent) would now bake in B2's hotspot triple +
claudeMd drift. So, per the B2 lesson, frozen v5.0.0 snapshots are PRESERVED
and the OST entry is stripped at compare time via new
tests/helpers/strip-added-scanner.mjs (wired into json/raw-backcompat + the
Step 5/6 humanizer tests); only SC-5 default-output is regenerated (additive
OST entry, diff reviewed). OST is fixture-gated (no output styles on
marketplace-medium / hermetic HOME → silent).

Wiring: orchestrator; humanizer (OST→Configuration mistake) + humanizer-data
OST family (title-coupled); scoring (OST→Settings, keeps 10 areas). Suite
1012→1023 (+11). Badges: scanners 14, tests 1023, TRANSLATIONS families 15.
Lore swept: README, CLAUDE.md, scanner-internals, humanizer.md. self-audit A/A.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-06-20 21:02:44 +02:00
commit e3b044a476
20 changed files with 557 additions and 47 deletions

View file

@ -101,7 +101,7 @@ Default: auto-detects scope from git context. Override with `/config-audit full|
```
### Finding ID Format
`CA-{SCANNER}-{NNN}` — e.g. `CA-CML-001`, `CA-SET-003`, `CA-HKV-002`, `CA-RUL-005`, `CA-TOK-005`, `CA-CPS-001`, `CA-DIS-001`, `CA-COL-001`, `CA-SKL-001`
`CA-{SCANNER}-{NNN}` — e.g. `CA-CML-001`, `CA-SET-003`, `CA-HKV-002`, `CA-RUL-005`, `CA-TOK-005`, `CA-CPS-001`, `CA-DIS-001`, `CA-COL-001`, `CA-SKL-001`, `CA-OST-001`
## Testing
@ -109,7 +109,7 @@ Default: auto-detects scope from git context. Override with `/config-audit full|
node --test 'tests/**/*.test.mjs'
```
1012 tests across 56 test files (17 lib + 29 scanner + 1 hook + 1 agent + 3 commands + 1 knowledge + 4 top-level). Test fixtures in `tests/fixtures/`. Top-level humanizer tests: `json-backcompat.test.mjs`, `raw-backcompat.test.mjs`, `scenario-read-test.test.mjs`, `snapshot-default-output.test.mjs`.
1023 tests across 57 test files (17 lib + 30 scanner + 1 hook + 1 agent + 3 commands + 1 knowledge + 4 top-level). Test fixtures in `tests/fixtures/`. Top-level humanizer tests: `json-backcompat.test.mjs`, `raw-backcompat.test.mjs`, `scenario-read-test.test.mjs`, `snapshot-default-output.test.mjs`.
### active-config-reader — load-pattern model + rule/agent/output-style enumeration (v5.6 Foundation)
@ -307,6 +307,48 @@ The two sub-checks are independent (a malformed autoMode in shared scope yields
orchestrator, so SC-5 was re-checked after this change — byte-equal (the snapshot fixture has no
`autoMode`, so the block never fires there).
### OST scanner — output-style validation (`CA-OST`, v5.6 C, count 13→14)
New orchestrated scanner `output-style-scanner.mjs` — the first new scanner family since SKL
(v5.2.0). It reads the active config (`readActiveConfig`) and each output-style file's frontmatter
(via `parseFrontmatter`, keys hyphen→underscore-normalized, so it reads `keep_coding_instructions` /
`force_for_plugin`). Three findings, every claim pinned to a CONFIRMED row of
`docs/v5.5-steering-model-plan.md` (V9/V10/V11/V12), re-verified against
`code.claude.com/docs/en/output-styles` + `.../plugins-reference`:
- **`CA-OST-001`** (medium) — a **user/project** custom style not setting `keep-coding-instructions:
true`. The flag defaults to **false**, so the style silently **removes** Claude Code's built-in
software-engineering instructions when active (V10). Scoped to user/project (the styles the user
authors); a plugin author's choice is out of scope.
- **`CA-OST-002`** (low) — a **plugin** style with `force-for-plugin: true`, which auto-applies and
**overrides** the user's selected `outputStyle` (V11). **Verifiseringsplikt correction:** the v5.5+
plan's CA-OST-002 bullet said "in a project/user style," but `force-for-plugin` is
**plugin-styles-only** per the docs (its own cited V11 + `output-styles.md`), so the check keys on
`source === 'plugin'` — a user/project style with the flag is simply ignored, not an override.
- **`CA-OST-003`** (medium) — a settings `outputStyle` value resolving to **no** built-in
(`Default`/`Explanatory`/`Learning`/`Proactive`, matched case-insensitively) and **no** discovered
custom style → dead config (CC falls back to default; the configured behavior never applies).
**Byte-stability — a scanner addition, NOT a field addition.** Adding the 14th scanner grows
`envelope.scanners` by one entry and bumps `aggregate.scanners_ok` 12→13 on the deterministic
fixture **regardless of findings** — a field-strip helper cannot paper this over. The SKL precedent
(`7bb2547`) re-seeded the frozen v5.0.0 snapshots, but that predates B2's strip-preservation regime;
re-seeding now would **bake in** B2's hotspot triple + `claudeMdEstimatedTokens` drift (verified by
inspecting the seed diff). So, consistent with the B2 lesson ("preserve frozen via strip-helper;
regen ONLY SC-5"), C **preserves** the frozen v5.0.0 snapshots and **strips the OST entry at compare
time**: shared `tests/helpers/strip-added-scanner.mjs` (`stripAddedScanners` removes OST entries +
decrements `scanners_ok`; `stripAddedScannerStderr` drops the `[OST]` progress line) is wired into
json/raw-backcompat + the Step 5/6 humanizer wiring tests (cli-humanizer did **not** break — its
v5.0.0 compares don't grow a scanners array). Only **SC-5 default-output** (scan-orchestrator +
posture) is regenerated (additive OST entry only — diff reviewed). OST is fixture-gated: the
`marketplace-medium` fixture and the hermetic HOME have no output styles, so it emits nothing there.
Wiring: orchestrator import + `SCANNERS` entry; `humanizer.mjs` `SCANNER_TO_CATEGORY`
(`OST: 'Configuration mistake'`); `humanizer-data.mjs` OST family (title-coupled to the three exact
finding titles); `scoring.mjs` `SCANNER_AREA_MAP` (`OST: 'Settings'` — keeps the 10 quality areas,
byte-stable on zero-finding projects). Count badges: self-audit scanner count 13→14; humanizer-data
TRANSLATIONS families 14→15 (PLH is a translation family but not orchestrated).
## Gotchas
- Session directories accumulate — use `/config-audit cleanup` to manage