config-audit/docs/delete-and-rebuild-brief.md
Kjell Tore Guttormsen e9921d3c9d feat(optimize): add --subtract, the subtraction axis, behind a deterministic floor
Every command so far asked an addition question — what to add, what to move,
what it costs. Nothing asked what is no longer earning its always-loaded rent.
This adds that axis as a fourth lensCheck on the existing hybrid motor rather
than a new scanner or a 22nd command: the measured payoff (~18% of one file)
justifies a mode, not machinery.

It is the only lens that proposes REMOVING config, so it carries a guarantee
the others don't need: a load-bearing block is never a candidate. Precision is
asymmetric — a missed dead line costs a few tokens per turn, a deleted one
costs a wrong remote or a broken script — so the floor is decided in code
(lib/floor-exclusion.mjs) before the opus judge sees anything, never in prose.

Granularity is the leaf block, with two structural exceptions: a paragraph
ending in ':' merges with the list it introduces, and an ordered list is a
contract whose steps inherit floor from any sibling. Unordered lists
deliberately do not inherit — a load-bearing bullet and a disposable one
routinely share a list, and container-reasoning is the error the hand-built
ground truth exists to catch.

Verified against that ground truth (built before any classifier existed), with
the comparison machine-checked rather than read by eye: zero load-bearing
blocks proposed, 11/18 deletable groups surfaced, ~756 tok ~ 18% of a ~4300
token file — inside the pre-registered band. The first run found five floor
violations the synthesized fixture missed; each got a structural rule and a
fixture shape so it cannot regress.

Three real bugs the dogfood run exposed, all now covered:
- JS \b is ASCII-only, so /\bunngå\b/ never matches — every Norwegian keyword
  ending in æ/ø/å was silently dead.
- A bare word/word is not a path; "pros/cons" vetoed the largest deletable
  block until PATH_RE was tightened to rooted paths and globs.
- "Mid-sentence" must key on a preceding lowercase letter; the loose version
  read **bold labels:** and quoted openers as entities, costing 4 of 11 groups.

BP-SUB-001 is grounded entirely in the Anthropic steering blog already cited by
BP-MECH-001..004 and asserts nothing from the talk that motivated the feature —
no "80%", no ablation figure.

Suite 1365 -> 1382/0. Frozen v5.0.0 snapshots untouched; plain optimize output
byte-identical on identical input (--subtract adds keys only when passed).
knowledge-refresh-cli's reference date moved to 2026-08-01: its premise that
every seed entry was verified 2026-06-20 expired when BP-SUB-001 got a genuine
verification date, and backdating the entry to fit the test would have been a
lie about when its source was checked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RW2haJXbxZpKivKHseSXNh
2026-07-31 16:24:51 +02:00

26 KiB
Raw Blame History

Brief — Delete-and-Rebuild (config subtraction)

Status: BRIEF, not a plan. No code, no chunk breakdown, no version number committed. Written 2026-07-29 so a session starting Thursday evening has a durable starting point. STATE.md is gitignored in this repo, so this file — not STATE — is the record.


1. Trigger and its provenance

The operator relayed a third-party YouTube summary (Hyper Automation Labs) of a talk Boris Cherny reportedly gave at Y Combinator Startup School, one day after Opus 5 shipped. Claims attributed to him in that summary:

  • Anthropic deleted ~80 % of Claude Code's own system prompt when Opus 5 landed.
  • Advice to users: every six months, delete your CLAUDE.md, your skills, your hooks — see what the model does.
  • Rebuild method: delete everything, use it, add one line back only when the model stumbles on the same thing repeatedly.
  • The model measured slightly more intelligent with the built-in prompts stripped.

Two levels of confidence here, and they must not be collapsed (updated 2026-07-29 after the operator corrected the first draft):

  • Attribution — confirmed. The operator watched the recording and identifies Boris Cherny on stage. This is not a channel's claim about who spoke; it is direct observation by the operator. The talk happened and it is him.
  • The verbatim figures — still summary-level. "80 % of the system prompt", "the model measured slightly more intelligent without the prompts", the Bun numbers: these reach us through the channel's editing, not through a primary transcript. They are plausible and consistent with §2, and they are not quoted as fact anywhere below.

So if this becomes a BP-* entry in the best-practices register, the source field reads "Boris Cherny, YC Startup School talk (attribution confirmed by operator); figures via third-party summary, not primary-verified" — not "unverified", and not a bare citation either. Getting a primary transcript for the figures is a nice-to-have, never a prerequisite: the feature is argued from this repo's own logic (§3), and this repo has one scar from treating a plausible quote as load-bearing fact («Fable low ≈ Opus high», fabricated, rejected 2026-07-14).

What the operator has affirmed as in scope: delete CLAUDE.md, then rebuild by adding back what the model needs help with — starting with what it must have. That last clause is not a detail; it is the design constraint in §6.0.

2. Verified ground truth (checked against the local CLI, 2026-07-29)

These are facts, and they are what make an empirical variant buildable:

Fact How verified
claude --bare exists — "Minimal mode: skip hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. Sets CLAUDE_CODE_SIMPLE=1." claude --help
claude --system-prompt <prompt> — replaces the session system prompt claude --help
--append-system-prompt, --add-dir, --setting-sources <user,project,local>, --plugin-dir, --settings, --agents — all present and all usable to compose an isolated config for a controlled run claude --help

So the CLAUDE_CODE_SIMPLE=1 env var the video calls "undocumented" is, in this CLI version, a documented flag (--bare). That matters: an A/B ablation harness would not need an undocumented hook.

3. Why this fits this repo (the argument that does not depend on §1)

The plugin has three pillars — Health, Opportunities, Action. Every existing command answers a question on the addition axis:

  • feature-gap — what could you add?
  • optimize — what would fit a better mechanism?
  • posture / tokens / manifest — how good/expensive is what you have?
  • fix / implement — apply changes.

Nothing answers the subtraction question: what is no longer earning its rent? feature-gap has no inverse. That is a real hole, independent of who said what on a stage.

Two further reasons this belongs here specifically:

  1. Nothing in the repo measures instruction age. Verified by grep over scanners/: stale appears only for knowledge-register entry age (lib/knowledge-refresh.mjs) and for stale plugin-cache versions (scan-orchestrator.mjs, M-BUG-11). No scanner touches git blame, mtime, or the vintage of a CLAUDE.md block. An instruction written for Sonnet 3.5 and an instruction written last week are indistinguishable to every current scanner.
  2. Deleting bravely is only sane if you can undo it. That is already pillar three: lib/backup.mjs, rollback-engine.mjs, auto-backup-config.mjs (PreToolUse), and drift's saveBaseline / loadBaseline / diffEnvelopes. The safety net exists; the feature that would use it does not. This is arguably the strongest framing: config-audit is already the infrastructure that makes "delete it and see" a measurement rather than a gamble.

4. Reusable machinery (do not rebuild these)

Need Already exists
Snapshot config before deleting scanners/lib/baseline.mjs (saveBaseline), used by drift
Diff before/after diffEnvelopes in the same module
Backup + restore individual files w/ sha256 manifest scanners/lib/backup.mjs, scanners/rollback-engine.mjs
Cost of each source, always-loaded subtotal scanners/manifest.mjs, token-hotspots.mjs
Human-approved-writes command pattern knowledge-refresh, campaign (both non-byte-stable by design)

5. Candidate shapes (sketches — pick on Thursday, do not pre-commit)

All three inherit the floor constraint in §6.0: whatever the shape, load-bearing local facts are never deletion candidates, and a rebuild restores them first. A shape that cannot express that distinction is disqualified regardless of how cheap it is.

A. Deterministic vintage scanner (CA-VIN-*). Per instruction block in CLAUDE.md / rules / skills / hooks: age from git history, plus a compensatory-phrasing signal (blocks that exist to correct model behaviour — "ALWAYS", "never forget", "read the whole file first", "don't guess"). Output: ranked deletion candidates with age + token cost + why it looks compensatory. Cheapest, most testable, fits the existing scanner architecture, and composes with tokens/manifest for the payoff figure.

🔴 The age half of this shape is DEAD — measured 2026-07-31 (økt #40), see §8's updated checklist. Per-line git blame over four real instruction files gives single-date shares of 88 % / 55 % / 100 % / 58 %: instruction blocks trace back to bulk commits, so per-block age carries almost no information. Worse, blame reports last touch, not vintage — a reformatting commit (e.g. this repo's own 96e32df, "trim project CLAUDE.md to invariants") makes old instructions look young, which biases the signal rather than merely thinning it. That also kills the mtime fallback. §8 pre-registered this exact outcome and its consequence: shape A's primary signal collapses to the compensatory-phrasing heuristic alone, and §7.2 is answered — the classification needs the agent layer. Do not resurrect age as a "weak secondary signal"; that is the drift the pre-registration existed to prevent. What survives of shape A is the deterministic phrasing + token-cost pre-filter, feeding a precision-gated judge (the optimize architecture).

B. Protocol command (/config-audit rebuild). The delete → live with it → earned re-add ledger loop, spanning sessions: archive current config, record what was archived, and maintain a ledger where a line only returns when the operator records that the model actually stumbled on it. Highest fidelity to the source idea; needs cross-session state (the sessions/ machinery already exists) and is inherently not byte-stable.

C. Measured ablation harness. Use --bare + --system-prompt/--add-dir to run the same prompt with and without a block and compare. Closest to a real verifier, most expensive in tokens, weakest determinism. Probably a later --experimental sub-mode of A or B rather than its own command.

Likely landing: A first (deterministic, testable, immediately useful), with B as the workflow that consumes A's output. C stays a documented idea until A+B exist.

DECIDED 2026-07-31 (#40), superseding the sketch above — see §7 q2/q3. Shape A does not ship as a standalone CA-VIN-* scanner: its age signal is dead, and what remains of it (a phrasing + token-cost pre-filter) is precisely the front half of optimize's existing hybrid motor. The landing is /config-audit optimize --subtract — a fourth lensCheck class emitting CA-OPT-* findings, with a deterministic floor-exclusion step ahead of the judge so a load-bearing block is never a candidate. Shape B (the earned-re-add ledger) stays out of v1 precisely because it is what would demand cross-session state and therefore a command of its own. Shape C unchanged: documented, not built.

6. Hard constraints (carry these into any implementation)

6.0 The floor: compensatory vs load-bearing instructions

This is the invariant all three shapes in §5 must respect, and it is what makes the feature safe to ship at all. Not every line in a CLAUDE.md is the same kind of thing:

Class What it is Test Disposition
Compensatory An instruction correcting model behaviour — "read the whole file first", "don't guess", "ALWAYS verify", "think before you code" A smarter model would do this unprompted Deletion candidate. Returns only when earned.
Load-bearing A local fact the model cannot derive at any capability level — "never GitHub, only Forgejo at git.fromaitochitta.com", "system bash is 3.2, no declare -A", "test with node --test 'tests/**/*.test.mjs'", "~/.claude is not git-tracked" No amount of intelligence produces this from the codebase alone Floor. Never a deletion candidate.

Model capability erodes the first class and does nothing to the second. That is the whole mechanism behind the source idea — and it means "delete your CLAUDE.md" is only correct for one of the two classes. A tool that treats them alike would delete the operator's Forgejo constraint because Opus 5 "is smart enough now", which is a category error: the model isn't failing at intelligence there, it simply cannot know.

Consequence for the rebuild ordering. A rebuild is not one undifferentiated add-back-on-stumble loop. It is three tiers:

  1. Floor — goes back immediately, no trial period. Load-bearing facts. The config is never in a state where these are absent; a "delete everything" that drops them is a broken experiment, not a brave one.
  2. Earned — out, returns only on repeated observed stumbling. Compensatory instructions that turn out to still be needed by this model.
  3. Dead — out and never missed. The payoff, measurable in tokens via manifest.

A third class sits deliberately outside the axis: policy prohibitions ("never commit secrets"). These may well be things the model would honour unprompted, but their cost of being wrong is asymmetric and they are cheap. They stay in the floor by decision, not by classification. Do not let a "the model knows this now" argument reach them.

The hard part is tier 1 vs tier 2, and that classification — not the deletion mechanics — is the real engineering problem in this brief. Precision is asymmetric: a missed dead line costs a few tokens per turn; a deleted load-bearing line costs a wrong remote, a broken bash script, or a lost afternoon.

6.1 Existing repo constraints

  • ~/.claude IS git-tracked as of 2026-07-26 — but archive by mv into _archive/ anyway, never rm. Premise corrected 2026-07-31 (økt #40); the rule it was used to justify is unchanged. Ground truth: /Users/ktg/.claude is a git repo, 7 commits, initial commit 13cd708 2026-07-26, remote backup /Volumes/DharmaBackup/claude-config.git (external volume — not Forgejo, not GitHub), 47 files tracked (hooks/ 19, commands/ 14, scripts/ 9, CLAUDE.md, settings.json, learnings/, docs/). The rule survives on different grounds: only those 47 files are recoverable, the history is days old, and the remote lives on a volume that may not be mounted. Two consequences for this feature — (a) ~/.claude age evidence is bounded by the repo's own birth date and is therefore worthless, and (b) any untracked file there (memory/, coord/, session state) is still unrecoverable after rm.
  • settings.json is pathguard-protected — no Edit/Write. Use jq + temp file + atomic mv, with operator OK (settings-json-pathguard-write).
  • New scanner ⇒ the 7-step byte-stability checklist (adding-scanner-byte-stability): scanner + orchestrator + scoring area-map + strip-added-scanner + humanizer count + SC-5 + humanizer wiring (SCANNER_TO_CATEGORY entry and TRANSLATIONS.static per RAW title — M-16/M-17). Frozen tests/snapshots/v5.0.0/ must stay untouched.
  • TDD is inviolable — red tests before implementation, including for .md contracts.
  • feat: commits require non-trivial diffs in both README.md and CLAUDE.md (docs-gate-feat-requires-readme-claudemd).

7. Open questions for Thursday

STATUS 2026-07-31 (#40): q1, q2, q3 are CLOSED below — decided on measured evidence (dead age signal) plus the hand-built fasit (docs/subtraction-fasit.local.md), under the operator's standing delegation of technical/design calls. q4 was already closed 2026-07-29. Do not re-litigate without new evidence.

The landing: /config-audit optimize --subtract — a fourth lens class in the existing hybrid motor, not a new command and not a new scanner. Full rationale in q3.

  1. Scope of the deletion candidate set: user-level ~/.claude only, project only, or both? (Age evidence is much stronger for project-level, per §5A.)

    CLOSED — both, and user-level is mandatory in v1. The argument that pointed at project-level was git-age evidence, and that evidence no longer exists (§5A box), so scope now follows payoff and testability instead. Two things force user-level in: §8's blocking floor test is defined over the operator's global CLAUDE.md, and that file is where the always-loaded cost actually sits (~4 300 tok every turn, every repo, every session — vs a project CLAUDE.md that loads only in its own repo). Project-level comes along because the same motor reads it and because two of §8's four floor anchors turned out to live there. Implementation note, not a reopening: optimize today takes a repo target. Reading ~/.claude/CLAUDE.md is a target-resolution change, and per §6.1 the ~/.claude write rules apply — but this mode proposes, it never writes.

  2. The core question, given §6.0: can compensatory-vs-load-bearing be classified deterministically with acceptable precision, or does it need the agent layer (like optimize's precision-gated optimization-lens-agent, which stays silent when unsure)? Note the two signals are independent — a load-bearing fact can be old, and a compensatory instruction can be new — so age alone can never carry this call. Prior: a deterministic pre-filter feeding a precision-gated judge, which is exactly the optimize architecture already in the repo. Design the §8 fasit around the ambiguous middle, not the poles. The four named must-survive items are clear-cut and any mechanism will get them right; the gate is really decided by blocks like "Conventional Commits: type(scope): beskrivelse" (local convention, or a nag the model would follow anyway?), "commit ofte med beskrivende meldinger" (pure behaviour correction?), or the model-routing rubric (a table of local policy that reads like advice). Include 35 such blocks deliberately. A fasit built only from obvious cases will pass a tool that fails on real config.

    CLOSED — it cannot be done deterministically. Deterministic pre-filter → precision- gated judge, which is the optimize architecture verbatim. Two independent lines of evidence, both gathered before any code:

    • The age signal is gone (§5A box). It was the only deterministic input that was going to do real discriminating work; phrasing heuristics alone are what remain.

    • The fasit shows phrasing alone is not enough. The blocks that decide the gate all require reading content against container — a load-bearing fact wearing generic phrasing, or vice versa:

      Fasit block The trap
      B-27 (defensive shell-scripting) Reads as universal advice ("quote your variables"), but each line records a specific local incident, and "keep test code ASCII-clean" is inseparable from bash 3.2 (B-26, a §8 floor anchor). A phrasing regex deletes this and fails the gate.
      B-32b ("never work in another repo") Sits inside a bullet list of compensatory anti-patterns, formatted identically to its neighbours, but encodes the polyrepo structure and names coord-send. Container says delete, content says floor.
      B-05 vs B-06 Adjacent preference bullets, near-identical form, opposite calls.
      B-30a / B-30b / B-30c Three consecutive bullets under one heading, three different calls (Conventional Commits is floor, "lesbarhet > cleverness" is not).

      No regex separates these; a judge reading them in context can.

    • Two failure modes the judge must be prompted against, both found in the fasit: staleness is not a deletion signal (B-29 pins Opus 4.8 while the session runs Opus 5 — that is a drift/dead-reference finding about a floor block), and tier-2 is not tier-3 (B-22, premiss-verifisering, is compensatory by class yet earned itself again during this very session).

    Design consequence — the floor is NOT the judge's call. Load-bearing exclusion runs as a deterministic pre-filter step before the judge sees anything, so a floor block is never a candidate at all. §8's gate is blocking and precision is asymmetric; making it depend on a probabilistic judge would be the wrong guarantee. The judge then decides only compensatory-tier questions on the remainder, and stays silent when unsure exactly as optimization-lens-agent already does.

  3. Does this ship as its own command, or as a --subtract mode of optimize? Both are defensible; command count is already 21.

    CLOSED — a --subtract mode of optimize. The discriminator is whether v1 needs cross-session state: it does not. v1 ranks deletion candidates and reports the payoff; the earned-re-add ledger (shape B) is what would require sessions/ state, and it is deliberately not in v1. Without the ledger there is nothing a separate command buys.

    What the mode inherits by not being new (verified against the code, 2026-07-31):

    Requirement optimize already has it
    Deterministic pre-filter → opus judge optimization-lens-scanner.mjs (lens-prefilter) → optimization-lens-agent
    Precision gate, silent when unsure Stated in the agent's own prompt
    "Not a mistake" framing Every optimize finding is a Missed opportunity — exactly right for a line that works but no longer earns its rent
    Register-backed provenance knowledge/best-practices.json, CONFIRMED-only
    Non-byte-stable by design Already documented as such in CLAUDE.md
    Finding IDs CA-OPT-*no new CA-VIN-* scanner

    And what it avoids: the 7-step byte-stability checklist (§6.1), a scanners badge bump 16 → 17, snapshot risk against frozen tests/snapshots/v5.0.0/, and a 22nd command. Proportionality is the clinching argument. The fasit puts the honest ceiling at ~8501 400 always-loaded tokens on a ~4 300-token file — real (~20 %), but nowhere near the source anecdote's 80 %, and 26 of 34 blocks are floor. On a well-maintained config the subtraction axis is mostly a no-op. That payoff justifies a mode on an existing motor; it does not justify a new scanner plus a new command. ("Starte ambisiøse tiltak når en konfig-justering holder" is a named anti-pattern.)

    Registry shape: a 4th lensCheck class alongside the three in the agent's table, with its own BP-SUB-001 register rule. --subtract is the flag because the subtraction axis should not fire on a plain /config-audit optimize run — it asks a different question and needs the operator to have opted into it.

  4. Ordering against the existing queue. Decided 2026-07-29: the operator prioritized this work ahead of pipeline step 4 (rollback), to start Thursday 2026-07-30. Do not re-litigate. The open part is only what follows it — the prior order stands underneath: step 4 rollback, then the M-11→M-20 batch release, then the v5.13 plan.

8. Verifisering (testable criteria)

Before building anything:

  • DONE 2026-07-31 (#40). grep -rniE 'blame|mtime|birthtime' scanners/ returns zero hits → §3.1 confirmed still true at build time.

  • DONE 2026-07-31 (#41). node scanners/drift-cli.mjs . --save --name pre-subtraction succeeds and lib/baseline.mjs round-trips → §4 reuse is real, not assumed. Written envelope is {meta, scanners[16], aggregate, _baseline} with _baseline.target_path = the repo (15 findings, score 55). Run with no flags beyond --save --name, since M-BUG-21 makes an unknown flag's value silently become the scan target.

  • RESOLVED 2026-07-31 (#41) by not needing it. BP-SUB-001 was written confirmed, and asserts nothing from §1 — no "80 %", no ablation figure, no Cherny attribution. Its claim is grounded entirely in the Anthropic steering blog already cited by BP-MECH-001004, re-verified the same day: "Every line loads into every session for every engineer working in the repo, whether it's relevant to their task or not. This consumes tokens and dilutes adherence", "Build commands, directory layout, monorepo structure, coding conventions, and team norms all fit naturally here", and "Keep CLAUDE.md under 200 lines". The anecdote motivated the feature; it is not a premise of the shipped rule.

  • DONE 2026-07-31 (#40) — THE AGE SIGNAL DOES NOT EXIST. Collapse condition met. Per-line git blame (not git log; per-line is the question) over four real instruction files:

    | File | Lines | Largest single-date share |
    |---|---|---|
    | `~/.claude/CLAUDE.md` | 250 | **88 %** (2026-07-26 = repo init; max age 5 days) |
    | `config-audit/CLAUDE.md` | 102 | **55 %** (2026-04-08) |
    | `config-audit/.claude/rules/ux-rules.md` | 32 | **100 %** (one commit) |
    | `llm-security/CLAUDE.md` | 110 | **58 %** (2026-04-08) |
    
    Blocks trace back to bulk commits exactly as the pre-registration feared, and
    `blame` measures last-touch rather than vintage (a reformat resets it), so the
    signal is *biased*, not merely sparse. **Consequence, as pre-registered: shape A's
    primary signal is gone and §7.2 is answered — deterministic phrasing/cost
    pre-filter → precision-gated judge.** See the boxed note in §5A.
    
  • DONE 2026-07-31 (#40): the §8 floor-test fasit is built, before any classifier exists. docs/subtraction-fasit.local.md (LOCAL-ONLY — it quotes the operator's global CLAUDE.md verbatim and this repo's only remote is the public open/ mirror). 34 blocks over ~/.claude/CLAUDE.md, each labelled FLOOR / POLICY-FLOOR / DELETABLE, with 13 marked ⚠ AMBIGUOUS per §7.2. Headline numbers: 26 of 34 blocks are floor; the deletable set is ~1 400 always-loaded tokens, realistically ~850 after tier-2 earn-backs, against a ~4 300-token file (~20 %, not 80 %). Correction it forces: two of §8's four named floor anchors are not in that file at all — the test command is project-scope (config-audit/CLAUDE.md), and "~/.claude is not git-tracked" is now false (§6.1). The floor gate must run over a set of files, not one.

When optimize --subtract is built (was: "if shape A is built" — retitled 2026-07-31 per §7 q3; the two struck items below were premised on a new standalone scanner, which is no longer the shape):

  • DONE (#41). Red tests written first against a synthesized fixture and confirmed failing (module not found) before either module existed.
  • DONE (#41). Suite green at 1382/0 (was 1365).
  • DONE (#41). git diff --stat tests/snapshots/v5.0.0/ empty, and a plain optimize-lens-cli.mjs run diffed byte-identical against its pre-change output (--subtract adds keys only when the flag is present; LENS_DETECTORS still exposes exactly 3 detectors, asserted in the suite).
  • node scanners/self-audit.mjs --check-readme passes (badge counts updated: scanners 16 → 17). No badge bump — no new scanner. --check-readme must still pass, and README/CLAUDE.md still need the docs-gate diffs for a feat: commit (docs-gate-feat-requires-readme-claudemd).
  • Every new finding renders with a non-Other userImpactCategory and a non-_default action language → humanizer wiring correct (M-16/M-17).
  • PASSED 2026-07-31 (#41) — the blocking floor test. Fasit built first (#40), tool run after, and the comparison machine-checked: a script asserts the intersection of the candidate list with every FLOOR / POLICY-FLOOR line range in the fasit is empty. Result: zero load-bearing blocks proposed for deletion. Both §8 anchors present in the subject file (B-25 "Aldri GitHub. Kun Forgejo", B-26 "System bash er 3.2") are excluded, as are B-09, B-13, B-17, B-23, B-27, B-29, B-32b and B-38b. The first run found five violations the synthesized fixture missed; each was fixed with a structural rule (list-stem merge, ordered-list-as-contract, security terms, unresolved-entity, declarative guard) and a fixture shape added so it cannot regress.
  • MET (#41), with the number stated honestly. 11 of 18 deletable groups surfaced, ≈756 always-loaded tokens ≈ 18 % of the ~4 300-token file — inside the pre-registered ~850 / ~20 % band. The 7 misses are the conservative default working as intended (unresolvable entity names, code spans, and declarative/infinitive phrasing carrying no imperative). Precision over recall held throughout: every fix in this session traded recall away, never the gate.