docs(prepass): before/after on K2, the mutation battery and the invariant row

Steg 8. Ingen produksjonskode i denne commiten utover de TRE testarmene tre GROENNE
mutasjoner tvang fram.

MAALING (`docs/2026-09-07-okf-prepass-i-debatten.md`), instrumentet validert mot en
kjent-positiv FOER foerste tall (K2 rotlisting = 3 954 tegn / 1 495 o200k-tokens,
S7a-3s publiserte tall eksakt; skriptet asserterer paa det og nekter aa rapportere
ellers):
- KUTTET paa levert K2: 629 = 621 + 8, tre regler navngitt. Payload paa disk 40 425
  tok; renderingen debatten ser 5 162 tok -- 87 % av kostnaden er withheld-lista, som
  aldri naar prompten.
- FOER/ETTER, tre armer fordi "FOER" ikke er ett tall. Like-for-like (en debatt som
  GAAR stigen mot det deklarerte kuttet): 10 prompter / 7 031 tok -> 3 prompter /
  10 641 tok. **+51 %, og dokumentet paastaar ikke at dette er en besparelse.** Det som
  kjoepes er nevnerne, et re-maalbart `ref`, og at stempelet slutter aa overdrive:
  siteringer 629 -> 8.
- SPOERSMAALET BASEN IKKE SVARER PAA: aatte arkitekttegninger, og **5,5x dyrere** enn
  det gode spoersmaalet (28 312 mot 5 162 tok). En TOM leveranse er bevis for fravaer;
  en FULL er IKKE bevis for tilstedevaerelse -- og med verktoeyene trukket har debatten
  ingen vei til aa oppdage det selv. Uttalt som den reelle handelen, ikke oppdaget i
  drift.

LOAD-BEARING: 32 mutasjoner, ALLE ROEDE mot HELE suiten, maks en per Bash-kall,
restaurert fra `scratchpad/` med `shasum -c` (aldri `git checkout`). Groenn kontroll
**1467 passed / 5 skipped** (fra 1387/5; **+80 node-ider, 0 fjernet**, maalt med `comm`
mot en baseline tatt foer foerste commit). Golden `shasum -a 1` av INNHOLDET =
ea8c534773acdbe41ae68f2c55724d69aaf8be4f, BYTE-UENDRET. `pyproject.toml` uroert.

TRE MUTASJONER VAR GROENNE FOERST, og alle tre var TESTFEIL -- ikke soemfeil. Ingen ble
droppet:
- M9: injeksjonsarmen satte `text_sha256` fra den INJISERTE teksten, saa
  `text_sha256`-grenen fyrte i stedet, og armen matchet paa "text" -- en DELSTRENG av
  `text_sha256`. En angriper kontrollerer begge avledede medlemmer, saa fixturen setter
  naa `text_sha256` til digesten av den EKTE teksten; da er likhetssjekken det eneste
  som staar i veien. Ny parallell arm beviser at de to sjekkene ikke er en sjekk.
- M18: fixturbasen navigerer til fire ikke-verdict-konsepter og payloadet leverer ALLE
  fire, saa "siter de leverte" og "siter alt navigerbart" ga SAMME sett. Armen flytter
  naa ett utdrag til `withheld` og asserterer `delivered < navigable` FOER den maaler.
- M32: uten raden falt kjoeringen gjennom til "--explore requires --explore-config",
  som ogsaa navngir `--explore`. Oekt 57s regel ordrett -- assert aldri paa en
  delstreng to nekter deler. Armen bruker naa en argv `--explore` ellers ville blitt
  AKSEPTERT paa.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-07 14:39:50 +02:00
commit 183191e51c
5 changed files with 385 additions and 15 deletions

View file

@ -0,0 +1,228 @@
# Pre-passet foran debatten — hva et DEKLARERT kutt koster, og hva det kjøper
**Måledato:** 2026-09-07. **Ordre:** `20260907T080223Z-62649864-from-.claude`.
**Premiss:** coord-melding `20260907T073755Z-900124162` fra `llm-ingestion-okf` (Amendment,
07:37Z). **Produsent:** `llm-ingestion-okf` revisjon `54a0bc2`, `tools/okf_consume.py`.
**Kontrakt:** `llm-ingestion-okf/docs/consumption-contract.md` (normativ) — `okf-consumption/1`.
---
## 0. Hva som ER målt, og hva som IKKE er det
**Målt her, med et instrument validert mot en kjent-positiv FØR første tall ble rapportert:**
kuttets nevnere på levert K2, payloadets og renderingens kostnad i o200k-tokens, en FØR-arm der
debatten faktisk går stigen, en ETTER-arm med kuttet, siteringstallet i stempelet, og hva et
spørsmål bundelen ikke svarer på produserer.
**IKKE målt:** ingen LEVENDE modell har lest et rendret kutt. At en modell resonnerer BEDRE (eller
verre) med et deklarert kutt enn med fri navigasjon er ikke vist — samme klasse som
structured-output-grensen. Alt under er plumbing, kostnad og nevnere.
**Kjent-positiv, kjørt først:** rotnivå-listingen på levert K2 måler **3 954 tegn / 1 495
o200k-tokens** over 629 konseptfiler — S7a-3s publiserte tall, eksakt. Måleskriptet *asserterer*
på dette og nekter å rapportere et eneste tall hvis det ikke reproduseres.
---
## 1. Kuttet, på levert K2
Spørsmål: **«Hva er enhetsprisen for kostkode 21.1 i prisskjemaet?»**
Base: `k2-trinn1-20260903`, ref `sha256-tree:9a4e5561…a968b5`. Veggklokke: ~1,0 s.
| | |
|---|---|
| considered | **629** |
| withheld | **621**`no_lexical_match` 582, `below_k` 37, `over_budget_alone` 2 |
| delivered | **8** |
| identiteten lukker | 629 = 621 + 8 ✔ |
| payload på disk | 164 987 B / **40 425 tok** |
| renderingen debatten ser | 72 287 tegn / **5 162 tok** |
**Renderingen fjerner 87 % av payloadets token-kostnad**, og det er `withheld`-lista: 621
konsept-ider som en leser ikke kan åpne. Regelen med ANTALL er faktumet; ide-lista er kostnad uten
informasjon. Full liste ligger i payloadet operatøren allerede holder.
---
## 2. FØR og ETTER, samme base, samme spørsmål, samme økt
Tre armer, fordi «FØR» ikke er ett tall: en debatt som *kan* navigere og en som *gjør det* koster
ulikt, og bare den andre er en ærlig sammenligning.
| | FØR, konstant manus (navigerer ikke) | FØR, går stigen | **ETTER, deklarert kutt** |
|---|---|---|---|
| prompter | 3 | **10** | 3 |
| prompt-tokens | 515 | **7 031** | **10 641** |
| største prompt | 210 | 2 013 | 5 251 |
| debatt-verktøy | 4 | 4 | **0** |
| verktøykall | 0 | 3 (`list_bundles``read_bundle``read_dir`) | 0 |
| **siteringer i stempelet** | **629** | **629** | **8** |
| nevnere rapportert | ingen | ingen | **629 = 621 + 8, tre regler** |
| validator-dom | validated | validated | validated |
**Like-for-like er kolonne 2 mot kolonne 3: +3 610 tokens (+51 %) og syv prompter færre.**
Mot den konstante armen er det +1 966 %, men den armen navigerer ikke og er ikke sammenlignbar —
den står her fordi den er den eneste som isolerer *pekerens* egen kostnad (99 tokens).
**Dette er ikke en besparelse, og dokumentet påstår ikke at det er det.** Det som kjøpes er:
1. **Nevnerne finnes.** Før kunne ingen lese ut av en kjøring hvor mye av basen som ikke ble lest.
2. **Stempelet slutter å overdrive.** 629 → 8 siteringer. Et stempel som siterte hele korpuset for
et forslag som så åtte dokumenter var en uerklært påstand inne i selve etterprøvbarhets-
artefaktet.
3. **`ref` gjør kjøringen re-målbar.** Et tall forankret i en versjon kan ikke re-måles etter at
basen har flyttet seg; `sha256-tree` er et faktum om bytes.
---
## 3. Spørsmålet bundelen ikke svarer på
Produsenten sa det i meldingen, og det er reprodusert her: **«Hvilken farge har fyrtårnet i
Alexandria?»** på K2.
| | |
|---|---|
| considered / withheld / delivered | 629 / 621 / **8** |
| regler | `no_lexical_match` 590, `below_k` 30, `over_budget_alone` 1 |
| leverte dokumenter | arkitekttegninger (romskjemaer, gulvbelegg), utvelgelse av leverandører |
| rendering | 72 808 tegn / **28 312 tok** |
To ting følger, og begge er ubehagelige:
- **En tom leveranse er bevis for fravær; en full er IKKE bevis for tilstedeværelse.** Kuttet
leverer sine nærmeste leksikalske treff uansett. Renderingen sier dette til agentene ordrett og
navngir `[sourced-not-sufficient]` fra kontraktens § 4.
- **Det ubesvarlige spørsmålet er 5,5× DYRERE enn det gode** (28 312 mot 5 162 tokens), fordi de
nærmeste treffene tilfeldigvis er lange tegnings-skjemaer. Kostnaden følger altså ikke hvor godt
spørsmålet passer basen. Notert, ikke løst.
Og med verktøyene trukket har debatten **ingen vei til å oppdage det selv**. Det er den reelle
handelen dette kutt-regimet gjør, og den står her fordi den ellers ville blitt oppdaget i drift.
---
## 4. Gatene som bodde i verktøyet som ble trukket
`explore.read_file` holdt to invarianter som forsvinner med det: verdict-lagets nekt (04.09) og
§ 4.1a-dimensjonsskopet. Begge er reist på nytt i `prepass.verify_against_bundle`, på det
**MONTERTE dokumentet** — aldri på payloadets egen påstand om det. Produsenten ekskluderer
verdict-laget selv (`verdict_layer_excluded` var den ENE tilbakeholdte i fixtur-basen), og det er
nøyaktig derfor det ikke kan delegeres dit: en av repoets nyest gatede invarianter ville da hvilt
på en fil en ekstern kaller leverte.
**Injeksjonsflaten er lukket ved konstruksjon, ikke ved prosa.** `sha256` digester HELE den
monterte fila mens `text` er et AVLEDET medlem, så et payload kan bære korrekt digest ved siden av
vilkårlig tekst — og `text` er det som lander i task-meldingen. `verify_against_bundle` re-utleder
teksten lokalt (frontmatter delt på `splitlines()`, NFC, per-linje `rstrip` — transkribert fra
produsentens kilde og MÅLT mot et ekte payload; en naiv `split("\n")` er uenig) og krever likhet.
Et payload kan dermed **ikke levere bytes basen ikke holder**. Eksponeringen er redusert fra
«eksternt innhold i prompten» til «basens eget innhold i prompten», som er dét `read_file` alt
gjør — det som gjenstår er POSISJONEN (task-melding mot `function_result`), og renderingen legger
teksten i en avgrenset DATA-blokk under instruksjonen (§ 9.3). Det er lindring, uttalt som det;
gaten er re-utledningen.
---
## 5. Load-bearing: 32 mutasjoner, alle røde, tre funn underveis
Grønn kontroll **1467 passed / 5 skipped** (fra 1387/5 ved øktstart; **+80 node-ider, 0 fjernet** —
strengt supersett, målt med `comm` mot en baseline tatt før første commit). Golden
`demo-transcript.stdout` **BYTE-UENDRET**, `shasum -a 1` av INNHOLDET =
`ea8c534773acdbe41ae68f2c55724d69aaf8be4f` (aldri git-blob-id-en). `pyproject.toml` urørt — ingen
ny kjøretidsavhengighet.
Hver mutasjon kjørt mot HELE suiten, maks én per Bash-kall, restaurert fra `scratchpad/` og
verifisert med `shasum -c` (aldri `git checkout`).
| # | Sømmen som ble detachet | Røde |
|---|---|---|
| M1 | nevnere som ikke lukker aksepteres | 2 |
| M2 | `len(excerpts)` mot telleren | 1 |
| M3 | `len(withheld)` mot telleren | 1 |
| M4 | kontrakt-revisjon som prefiks i stedet for `==` | 1 |
| M5 | `text` gjøres valgfri | 1 |
| M6 | `question` gjøres valgfri | 1 |
| M7 | `bundle_id` mot MOUNTET i stedet for erklæringen | 22 |
| M8 | fil-digesten droppes | 1 |
| M9 | **tekst-re-utledningen droppes (injeksjonsarmen)** | 1 |
| M10 | tekst utledet med `split("\n")` | 20 |
| M11 | verdict-gaten droppes | 1 |
| M12 | dimensjonsgaten droppes | 1 |
| M13 | `PathSecurityError` slipper ut | 1 |
| M14 | withheld-IDER rendres i stedet for regel-antall | 2 |
| M15 | pekeren beholdes ved siden av renderingen | 1 |
| M16 | de fire navigatørverktøyene beholdes | 2 |
| M17 | `debate_tools = []` uten MCP | 4 |
| M18 | **`bundle_citations`' 629 beholdes** | 1 |
| M19 | verifiseringen detaches | 3 |
| M20 | kjør videre på `delivered == 0` | 1 |
| M21 | artefaktet skrives aldri | 2 |
| M22 | artefaktet skrives også uten payload | 48 |
| M23 | rendereren skriver alltid linja | 2 |
| M24 | CLI-printen detaches | 1 |
| M25 | dry-run-dispatchen mister flagget | 1 |
| M26 | full-run-dispatchen mister flagget | 3 |
| M27 | `report_forbidden`-raden droppes | 1 |
| M28 | `single_only`-raden droppes | 1 |
| M29 | `--bundle-dir`-kravet droppes | 1 |
| M30 | `--proposals-from-mandate`-nekten droppes | 1 |
| M31 | `--dimension-config`-nekten droppes | 1 |
| M32 | **`--explore`-nekten droppes** | 1 |
### Tre mutasjoner var GRØNNE først, og alle tre var testfeil — ikke sømfeil
Repoets vakuøs-gate-klasse, nittende til tjueførste gang.
1. **M9 (injeksjonsarmen).** Fixturen satte `text_sha256` fra den INJISERTE teksten, så
`text_sha256`-sjekken fyrte i stedet — og armen matchet på `"text"`, som er en **delstreng av
`text_sha256`**. En angriper kontrollerer begge avledede medlemmer, så fixturen setter nå
`text_sha256` til digesten av den EKTE teksten: da er likhetssjekken det eneste som står i
veien. Armen asserterer på ordlyd bare den grenen produserer, og en parallell arm beviser at de
to sjekkene ikke er én sjekk.
2. **M18 (siteringene).** Fixturbasen navigerer til fire ikke-verdict-konsepter og payloadet
leverer **alle fire** — så «siter de leverte» og «siter alt navigerbart» ga SAMME sett. Armen
flytter nå ett utdrag til `withheld` først og asserterer `delivered < navigable` FØR den måler
noe som helst.
3. **M32 (`--explore`-nekten).** Uten raden falt kjøringen gjennom til «`--explore` requires
`--explore-config`», som også navngir `--explore`. Økt 57s egen lærdom ordrett: *assert aldri
på en delstreng to nekter deler.* Armen bruker nå en argv `--explore` ellers ville blitt
AKSEPTERT på, og asserterer på ordlyd bare denne nekten har.
---
## 6. Ærlighets-grenser, uttalt
- **Ingen LEVENDE modell har lest et rendret kutt.** At en modell dømmer bedre eller verre med et
deklarert kutt enn med fri navigasjon er ikke bevist.
- **`sha256-tree` re-beregnes IKKE.** Det er produsentens algoritme, og å re-utlede den her ville
vært den vendrede kopien modulen finnes uten. Vi verifiserer de LEVERTE dokumentene mot de
monterte bytene; hele treet er ikke verifisert. En base som endret seg i et dokument payloadet
ikke leverte, fanges ikke.
- **`budget.limit` er produsentens valg.** Vi nekter `spent > limit`, men vi setter ikke taket.
Renderingens OVERHEAD er bundet i testen (O(levert tekst) + O(1)); den leverte teksten selv er
bundet av produsenten.
- **`--explore` er nektet, ikke løst.** Utforskningens eget kutt er fortsatt uerklært, og
Amendmentets motiv er derfor bare halvt innfridd. En egen beslutning.
- **Den hostede flaten er BEVISST urørt** (MAJOR-4/S7b-presedensen): feltet kommer inn i ingen av
de tre settene, så den generiske `unknown field(s)`-400-en svarer, og Fase 4es to halvdeler står.
Gatet av en testarm, ikke av en redigering.
- **`ProvenanceStamp` bærer IKKE deklarasjonen.** Stempelet beskriver gaten som dømte ÉN kandidat;
kuttet er et RUN-nivå-faktum. Det når utboksen via `{run_id}-prepass.json`, ikke via stempelet.
- **`run_mandate_across_bundles` tar intet payload.** ETT payload er bundet til ÉN `ref`; N baser
ville trengt N. Ikke bygget.
- **Pre-passet kan ikke lese en eneste av repoets egne baser** — ingen av dem erklærer `bundle_id`
på rot-indeksen (S7a-3s måling sett fra produsentsiden), og `shared/` er pull-only. Fixturen er
derfor bygget på en KOPI med erklært id, som samtidig gir S7a-3s slakk-tilfelle gratis.
- **`concept_id`-joinen forutsetter at ideen er den bundle-relative stien minus `.md`.** Målt mot
ekte produsent-output, ikke antatt — men det er produsentens konvensjon, ikke kontraktens, og en
annen produsent kan velge en annen.
---
## 7. Instrumentet
`scratchpad/prepass-k2/measure.py` og `measure2.py` (utracket), `tiktoken==0.8.0` i en pinnet
scratch-venv, encoding `o200k_base`. Begge skriptene kjører kjent-positiv-sjekken først og
`assert`-er på den. Payloadene er produsert med kommandoen i
`tests/fixtures/prepass/README.md`, mot en kopi av levert K2 med `bundle_id` erklært på
rot-indeksen.