portfolio-optimiser/docs/2026-09-07-okf-prepass-i-debatten.md
Kjell Tore Guttormsen 183191e51c 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>
2026-09-07 14:39:50 +02:00

228 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.