config-audit/docs/cc-2.1.x-fase4-items-2-3-plan.md
Kjell Tore Guttormsen 66433fee48 feat(skill-listing): add CA-SKL-002 aggregate listing-budget check
Syklus 2 of Fase 4 Items 2+3. Flags when the sum of active skill
descriptions exceeds the listing budget (~2% of context, CC 2.1.32).

Design (operator-confirmed "fact-first, 200k anchor"):
- low severity (estimate) vs medium for the verified 1,536-char cap
- each description counted up to the 1,536 cap (what actually loads in
  the listing) — avoids double-counting the tail CA-SKL-001 flags
- fires when sum > 2% x 200k = 4000 tok; evidence leads with the measured
  sum + a calibration note that the budget scales 5x on 1M-context models
- aggregate emitted after the per-skill loop so the common case reads
  001=cap, 002=aggregate (finding IDs are a sequential counter, not stable
  semantic IDs — tests match on title, never NNN)

Also:
- tailored humanizer static entry for the aggregate title
- fix latent HOME leak in posture-grade-stability.test.mjs: it spawned
  posture.mjs without hermeticEnv(), so a real ~/.claude leaked HOME-scoped
  SKL/COL findings into the baseline grade (Token Efficiency A->B). Now
  isolated like the 8 other CLI-spawning tests.
- docs sync: test count 868->875, scanner-internals, gap-matrix, plan status

Suite 875/875, no snapshot drift, self-audit clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ter3E2JSi1Khgmuf2kady8
2026-06-18 18:06:17 +02:00

10 KiB
Raw Blame History

Plan — Fase 4 Items 2 + 3 (skill-listing token-styring)

Skrevet: 2026-06-18 · Scope: kun config-audit/ · Status: LEVERT 2026-06-18 (alle 4 sykluser). Designvalg bekreftet: A=fold inn i SKL, B=Syklus 2 NÅ LEVERTCA-SKL-002 aggregat-budsjett implementert med «faktum-først, 200k-anker» (operatør-bekreftet 2026-06-18): low severity, sum av beskrivelser (hver tellet opp til 1 536-cap) > 2 %×200k = 4000 tok → funn m/ CALIBRATION_NOTE om 5×-skalering på 1M-kontekst. C=skillOverrides i KNOWN_KEYS (IKKE TYPE_CHECKS — verdien er objekt; avvik fra §C-skissen, verify-først). Suite 875/875. Detaljer i STATE.md.

Syklus 2-notat (avvik fra §B-skissen, verify-først): (1) Aggregatet teller hver beskrivelse capped på 1 536 (= det som faktisk lastes i listingen; unngår dobbelttelling av halen CA-SKL-001 allerede flagger). (2) Finding-IDs er sekvensiell teller (output.mjs:33), ikke stabil semantisk ID — tester matcher på tittel, aldri NNN; aggregatet emitteres ETTER cap-loopen så vanlig-tilfellet leser 001=cap, 002=aggregat. (3) Eksponerte en latent HOME-lekkasje i posture-grade-stability.test.mjs (kjørte CLI uten hermetisk HOME → ekte ~/.claude lekket inn → Token Efficiency falt A→B); fikset med hermeticEnv() (samme mønster som 8 andre CLI-tester). (4) Egen tilpasset humanizer-static-entry for aggregat-tittelen (ikke generisk _default). Forrige: Fase 4 Item 1 (4.7→modell-nøytral) levert som 8376dab. Baseline 856/856 grønn.

Mål

Lukke matrise-radene 167 + 169 (skill-listing token-styring): gjøre config-audit i stand til å anbefale/varsle om skill-listing-budsjett før CC selv trunkerer det. Item 2(a) (false-positive) er allerede gjort (Batch 1).


Verifiserte fakta (changelog-cache, CC 2.1.181 — re-verifisert 2026-06-18 FØR skriving)

Fakta Versjon Changelog-linje
disableBundledSkills + CLAUDE_CODE_DISABLE_BUNDLED_SKILLS — skjuler bundled skills/workflows/built-in slash commands fra modellen 2.1.169 L176
Skill-listing-truncation-varsel viser nå antall berørte beskrivelser 2.1.178 L64
Truncation-varsel flyttet fra startup til /doctor 2.1.144 L666
skillOverrides: off / user-invocable-only / name-only (kollapser beskrivelse) 2.1.129 L995
Per-beskrivelse listing-cap hevet 250 → 1 536 tegn + startup-varsel ved truncation 2.1.105 L1502
Skill-tegnbudsjett skalerer med kontekstvindu = 2 % av kontekst 2.1.32 L2860

Matrise-korreksjon (verify-først): rad 170s hypotetiske settings-nøkler skillListingBudgetFraction / maxSkillDescriptionChars finnes ikke som nøkler. Budsjettet (2 % kontekst) og cap-en (1 536 tegn) er interne CC-mekanismer. Ekte config-levere er skillOverrides (2.1.129) + disableBundledSkills (2.1.169).


Item 2 — disableBundledSkills som token-lever (matrise-rad 166 + 167)

2(a) — false-positive-fiks → ALLEREDE GJORT (Batch 1)

disableBundledSkills ligger allerede i KNOWN_KEYS (scanners/settings-validator.mjs:25) + TYPE_CHECKS boolean (:53), og dekkes av testen NEW_KEYS (tests/scanners/settings-validator.test.mjs:133,176-180). Ingen kode. Matrise-rad 166 markert DONE.

2(b) — anbefaling (matrise-rad 167)

Designfunn: GAP-checks (scanners/feature-gap-scanner.mjs:91 GAP_CHECKS) er binære {id,tier,title,recommendation,check} der finding fyres når check() = false. En ren binær «disableBundledSkills ikke satt»-check ville fyre for nær alle brukere → støy + dårlig råd (lever-en fjerner ALLE bundled skills; bare verdt det ved faktisk listing-press).

Anbefalt (DESIGNVALG A — confirm): IKKE en frittstående GAP-check. Folde disableBundledSkills-anbefalingen inn som en remediation-lever i Item 3s SKL-scanner (fyres bare ved kvantitativt budsjett-press). Substansen i Item 2(b) leveres dermed via Item 3. Matrise-rad 167 omklassifiseres «folded into SKL (Item 3)». Alternativ: frittstående tier-4 GAP-check gated på antall aktive skills (krever skill-enumerering → samme kobling som Item 3; mer kode, mer støyrisiko).


Item 3 — SKL-scanner: skill-listing-budsjett (matrise-rad 169)

Ny scanner scanners/skill-listing-scanner.mjs, prefiks SKL (ledig; bekreftet mot alle eksisterende prefikser). Finding-IDs CA-SKL-NNN.

Hva den gjør

  1. Primær (høy konfidens): flagg hver aktiv skill-beskrivelse > 1 536 tegn — verifisert hard cap → CC trunkerer den. Severity medium. Dette er rock-solid (ikke estimat).
  2. Aggregat (estimat, lavere konfidens): sum av skill-beskrivelse-tegn på tvers av ALLE aktive skills (user + plugin + bundled). Varsle når summen nærmer seg/overskrider budsjett. Budsjett = 2 % av kontekst → krever kontekstvindu-antakelse (se DESIGNVALG B). Merk med CALIBRATION_NOTE-mønster (jf. TOK) og ±-usikkerhet — IKKE lat som vi vet brukerens kontekstvindu.
  3. Remediation (alle funn): trim beskrivelse < 1 536; skillOverrides: name-only (kollaps); disableBundledSkills: true (fjern bundled). ← her bor Item 2(b).

Gjenbruk (ikke gjenoppfinn)

  • Aktiv-skill-enumerering: enumerateSkills(pluginList) i scanners/lib/active-config-reader.mjs:465{name, source:'user'|'plugin', pluginName, path, bytes, estimatedTokens}. Dekker user + plugin skills (bredere enn project-local).
  • Beskrivelse-uttrekk: parseFrontmatter(content)?.frontmatter?.description (scanners/lib/yaml-parser.mjs), nøyaktig som TOK pattern F (token-hotspots.mjs:381-411). Les fil via readTextFile (lib/file-discovery.mjs).
  • estimateTokens() (active-config-reader.mjs:35) — markdown = bytes/4. Brukes hvis budsjett uttrykkes i tokens.

Avgrensning mot eksisterende TOK pattern F

TOK pattern F flagger project-local skill-md med beskrivelse > 500 tegn (strukturell «bloat»-heuristikk, SKILL_DESCRIPTION_THRESHOLD, token-hotspots.mjs:53). SKL er en annen linse: ALLE aktive skills (ikke bare project-local) + den verifiserte 1 536-cap-en (hard truncation) + aggregat-budsjett. Dokumentér de to linsene eksplisitt i begge scanner-headere så det ikke leses som duplikat.


⚠️ Åpne designvalg — BEKREFT med operatør FØR kode (per syklus)

  • A — Item 2(b)-plassering: anbefalt = folde inn i SKL-remediation (ikke frittstående GAP-check). [Alternativ: tier-4 GAP-check.]
  • B — kontekstvindu-antakelse for aggregat-budsjettet: anbefalt = konservativ default 200k tokens (2 % ⇒ budsjett), eksplisitt merket estimat m/ CALIBRATION_NOTE. Eventuelt: dropp aggregat-sjekken i v1 og lever KUN den verifiserte 1 536-cap-en (høyest konfidens, null gjetting) — minst risiko. [Anbefaler å starte med per-beskrivelse-cap; aggregat som stretch.]
  • C (valgfri relatert quick-win): skillOverrides mangler i KNOWN_KEYS → egen unknown-key false-positive (matrise-rad 170, L/S). Hvis SKL anbefaler skillOverrides, bør nøkkelen samtidig legges i KNOWN_KEYS + TYPE_CHECKS ('string') for konsistens. Egen mini-syklus.

Utførelsesrekkefølge (hver = ratifisert failing-test-først, Iron Law)

Syklus 1 — Item 3 SKL-scanner (per-beskrivelse 1 536-cap):

  1. Failing test: tests/scanners/skill-listing-scanner.test.mjs + fixture med en skill-beskrivelse > 1 536 tegn → forvent CA-SKL-001. (RED: scanner finnes ikke.)
  2. Skriv scanners/skill-listing-scanner.mjs (gjenbruk enumerateSkills + parseFrontmatter).
  3. Registrer: import + SCANNERS-entry i scanners/scan-orchestrator.mjs:19-65; humanizer-entry i lib/humanizer-data.mjs (SKL.static + _default) + SCANNER_TO_CATEGORY i lib/humanizer.mjs:30-43 (kategori 'Wasted tokens').
  4. README-badge scanners-1213 (validert av self-audit.mjs countScannerShape()); CLAUDE.md scanner-tabell + docs/scanner-internals.md.
  5. Snapshot-reseed (HERMETISK): SEED_SNAPSHOT=1 (v5.0.0/) + UPDATE_SNAPSHOT=1 (default-output/) — scan-orchestrator + posture endres hvis fixturen marketplace-medium trigges. Verifiser git diff tests/snapshots/ + kontaminerings-grep.

Syklus 2 — Item 3 aggregat-budsjett (HVIS designvalg B = inkluder): failing test for sum-over-budsjett → CA-SKL-002; CALIBRATION_NOTE; kontekstvindu-konstant.

Syklus 3 — Item 2(b) remediation: verifiser at SKL-funn lister disableBundledSkills + skillOverrides + trim som levere (test på recommendation-tekst).

(Valgfri) Syklus 4 — designvalg C: skillOverrides i KNOWN_KEYS+TYPE_CHECKS + utvid NEW_KEYS-testen.


Verifisering (testbare kriterier)

  • node --test 'tests/**/*.test.mjs' grønn (baseline 856 + nye SKL-tester).
  • Failing-test-først bevist per syklus (RED → GREEN logget).
  • Fixture med beskrivelse > 1 536 tegn → nøyaktig CA-SKL-funn; fixture med korte beskrivelser → 0 SKL-funn.
  • node scanners/self-audit.mjs --check-readme ren (badge 13 matcher).
  • git diff tests/snapshots/ reseedet bevisst, kontaminerings-grep ren (sadhguru/vegnorm/pluginCount).
  • Ingen ny Opus 4.x-æra-stempling i ny scanner (gjenbruk modell-nøytral framing fra Item 1).

Scope-gjerde

Kun config-audit/. Item 2(a) ferdig. Items 2(b)/3 = ny kode → ratifisert design (A+B) + failing-test-først per syklus. IKKE auto-eskalér; bekreft A/B FØR første scanner-linje.

Risiko

  • Aggregat-budsjett er et estimat (ukjent kontekstvindu) — håndteres med CALIBRATION_NOTE + å lede med den verifiserte 1 536-cap-en. Ved tvil: lever KUN per-beskrivelse-cap i v1.
  • Snapshot-drift: ny orkestrert scanner endrer scan-orchestrator/posture-snapshots → MÅ reseedes hermetisk (hermeticEnv()), ALDRI rå node scanners/....
  • Matrise er agent-generert (2 kjente versjonsfeil) — fakta over er re-verifisert mot changelog; re-verifiser nye påstander før skriving.

Pekere

  • Kartlegging (denne sesjonen): scanner-registrering, GAP-mekanisme, enumerateSkills, snapshot-mønster — alt ankret i koden over.
  • Gap-matrise: docs/cc-2.1.x-gap-matrix.md rad 166 ( DONE), 167 (Item 2b), 169 (Item 3), 170 (skillOverrides quick-win).
  • Mønster-katalog: knowledge/prompt-cache-patterns.md (rad 167/169 retargetet hit).