portfolio-optimiser/docs/2026-09-03-syretest-s7a2-k2.md
Kjell Tore Guttormsen 5adb1cca62 fix(docs): rediger vekk absolutt hjemmesti i S7a-2-rapporten - handover-gaten var roed paa HEAD
Ikke en del av S7a-3s fire punkter, men funnet mens kontrollen ble kjoert:
test_package_leaks_no_secret_content leser `git archive HEAD`, saa den ble roed
foerst etter at 1c540e6 var committet (funn 35: gaten er ekte, men forsinket med
en commit). Rapportens ene `/Users/ktg/corpora/...` er erstattet med `~/corpora/...`
- samme kommando, ingen hjemmesti i en pakke en ekstern organisasjon faar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 06:02:17 +02:00

23 KiB
Raw Blame History

Syretest S7a-2 — re-måling mot den EKTE K2-bundelen (629 konsepter)

Dato: 2026-09-03 · Ordre: 20260903T031843Z-5600416337-from-.claude · Baseline: docs/2026-09-03-syretest-s7a-k2.md (S7a, 39 konsepter) · Kunnskapsbase: ~/corpora/okf-telling-20260829/K2-bundle-20260903/, bygd av llm-ingestion-okf 03.09 (ordre …72037075)

Dette er en måling. Ingen produksjonskode er endret — git statussrc/, tests/, shared/ og pyproject.toml er tom, hele måleoppsettet ligger i scratchpad/s7a2/ (utracket), og hvert tall under er produsert av en kommando som står i teksten. Kontroll: 1230 passed / 5 skipped, ruff check src tests ren.

Ingen validert besparelse er funnet, og ingen var mulig. To av S7as tre S7b-krav står uendret; det tredje er innfridd. Se § 7.


0. Instrumentet, validert mot en kjent positiv FØR bruk

Samme protokoll som S7a: tiktoken o200k_base over den fulle prompt-blobben (tekst + function_call + function_result), kjørt med uv run --with tiktoken.

Kjent-positiv sjekk Publisert fasit Målt nå
read_bundle over tunnel-hauglia 259 tok 259 tok
bundle_context over tunnel-hauglia 12 595 tok 12 595 tok

Begge reproduseres eksakt. Først etter det er K2-tallene lest som tall.

S7as to instrumentfeller er arvet som rettelser, ikke gjenoppdaget: sonden henter text/result/arguments ut av hvert Content (aldri repr), og Message.text telles ikke i tillegg til Content.text. Multiplikator-sonden (§ 5) bruker en ASCII-sentinel (inbox-del-ii-bilag-6-teknisk-oppsett.md), fordi S7a målte 0 kopier med en sentinel som inneholdt norske tegn prompten serialiserer escaped.

Én kontroll er ny, og den er advisor-foranlediget: hvert verktøyresultat asserteres ikke-tomt. Et manus som åpner en sti som ikke finnes gir like mange kall i samme rekkefølge, og dialogen ser identisk ut med en som virket. Alle fire resultater i § 3 er ikke-tomme (§ 5).


1. BLOKKERENDE FUNN: basen kan ikke åpnes slik den er levert

$ uv run python -c "from portfolio_optimiser import okf; \
    okf.reconcile_bundle_id('~/corpora/okf-telling-20260829/K2-bundle-20260903')"
BundleIdMismatch: knowledge base '…/K2-bundle-20260903' declares bundle_id
'k2-trinn1-20260903' but is mounted as 'K2-bundle-20260903'; an approach names a base by
that id, so a run would evaluate against one and report the other (source: declared-index)

Rot-index.md erklærer bundle_id: k2-trinn1-20260903; katalogen heter K2-bundle-20260903. D6/B1-gaten fyrer og nekter. Det rammer hvert kallsted som avstemmer: explore.read_bundle, run_projects bundle-arm og dispatcheren.

Dette er første gang en declared-gren fyrer i naturen. CLAUDE.md fører begge som DEFENSIVE («null ^bundle_id-treff noe sted under shared/, src/, tests/»). Målt nå: 619 filer erklærer nøkkelen (rot-index.md + 618 konsepter, alle samme verdi), så også declared-concept ville fyrt, med samme mismatch.

Nekten er riktig, og den er ikke en defekt i noen av repoene — den er en ekte grensesnittfriksjon: produsenten navngir bundle_id etter kjøringen, operatøren navngir katalogen etter korpuset. Måling fortsetter mot en kopi montert under det erklærte navnet (scratchpad/s7a2/k2-trinn1-20260903), som er nøyaktig det botemiddelet en operatør har. Etter monteringen: origin = declared-index — første naturlige forekomst.


2. Navigasjon: tre tall, og stigen eksponerer bare det siste

Ordren spør hva «dokument» betyr når indeksene er hierarkiske. Det finnes tre tall, og de er ulike:

Telling Antall
.md på disk totalt 1 108
— herav index.md (navigasjon) 478
— herav ikke-index 630
Nådd av navigasjonen (bundle.files) 1 107
Konseptfiler (context_files) 629
Foreldreløse (på disk, aldri lenket) 1 (log.md)
Ufulgte kryss-lenker (skipped) 0

log.md (OKF § 7) finnes nå — S7a målte at den manglet — men ingen index lenker den (grep -rl 'log\.md' --include='index.md' → 0), så navigasjonen når den aldri. Den blir derfor verken konsept eller ufulgt lenke: den er usynlig. Det er grunnen til at skipped = 0 ikke kan leses som «alt ble nådd»; nevneren mot disk er det eneste som avslører den.

Konsekvens for adjudication-nevneren (§ 4): produsentens 629 og leserens context_files = 629 er samme tall — nettopp fordi log.md er foreldreløs. Hadde den vært lenket, ville leseren talt 630 og de to nevnerne divergert.

Dybde og synlighet fra rot:

Antall
Lenker i rot-index.md 39 (11 konsepter + 28 underindekser)
Konsepter på dybde 0 / 1 / 2 11 / 54 / 564

Stigen har ingen trinn for hierarkiet. list_bundles sier hvilke baser som finnes, read_bundle gir alle 629 konseptene flatt, read_file gir ett dokument. De 478 indeksene er konsumert av navigasjonen og forkastet av context_files (basenavn-regelen). En agent kan lese en nestet index.md med read_file (målt: del-ii-bilag-7-prisskjema/index.md = 41 tok), men ingenting i read_bundles svar forteller den at de 478 finnes. Hierarkiet er lesbart, ikke oppdagbart.

Kostnad per kall

Kall S7a (39) S7a-2 (629)
list_bundles (1 base) 127 112
read_bundle 2 312 42 761
read_file, sum over alle konsepter 684 236 726 848
read_file, median 6 709 290
read_file, maks 121 462 119 909
bundle_context (formen før MAJOR-3) 682 303 648 787

Katalogtaket holder. 112 tokens for én base, uendret i form, og index_excerpt er avkortet. S2c/katalog-invariantens O(BASER) står.

read_bundle er O(dokumenter), og det er nå hele kostnaden. 2 312 → 42 761 tokens er 18,5× for 16× flere dokumenter — asymptotisk nøyaktig som MAJOR-3 lovet. Men konstanten er ikke lenger neglisjerbar: se § 5, der dette ene resultatet er 90 % av kjøringen.

MAJOR-3 gjør K2 navigerbar. bundle_context ville vært 648 787 tokens — mer enn noe kontekstvindu — og ville ridd med i hver senere prompt.

Største konsept, MÅLT (produsenten ba om re-måling)

Tegn o200k-tokens
Produsentens tall (body) 217 472 ~98 700 (derivert)
Målt (body) 217 471 119 763
Målt (read_file-output, m/frontmatter) 217 850 119 909

Produsentens tegn-tellinger reproduseres til ±1 (median: oppgitt 441, målt 440 — differansen er avsluttende linjeskift). Token-derivasjonen var 18 % for lav: den hviler på ~2,2 tegn/token, mens norsk juridisk-teknisk tekst her måler 1,82 tegn/token.

Konsepter over § 5s 100k-tak: 1 av 629 (inbox-del-ii-bilag-9-1-avtale-som-tiltransporteres-norconsult-as.md, 119 909 tok). S7a hadde 2 av 39. Segmenteringen har flyttet massen: median falt fra 6 709 til 290 tokens.


3. Dialog: fire verktøykall, tre runder, speaker_known gjennomgående

uv run python -m portfolio_optimiser.run K2-STANGE \
  --docs-dir scratchpad/s7a2/k2-trinn1-20260903 \
  --bundle-dir scratchpad/s7a2/k2-trinn1-20260903 \
  --explore "Finn kostnadsbesparelser i Stange skole-anbudet" \
  --explore-config scratchpad/s7a2/explore-config.json \
  --scripted-replies scratchpad/s7a2/scripted-replies.json \
  --outbox-dir scratchpad/s7a2/outbox --run-id s7a2

--docs-dir peker på bundelen, og det er inert. Flagget finnes kun for å tilfredsstille enkeltprosjekt-modusens argument-sjekk (run refused: single-project mode requires PROJECT_ID and --docs-dir); på bundle-stien setter run.py selv docs_dir=bundle_dir (run.py:463) og avleder prosjektet fra validator-input.json. Katalogen bidrar altså ingen kontekst — og det er nettopp derfor kjøringen likevel nekter.

Exploration: concluded after 3 round(s); 1 approach(es) to evaluate, deretter rc=1 run refused: IR projection not found in bundle: 'validator-input.json' — samme utfall som S7a, og artefaktet skrives fra finally.

Fra s7a2-exploration.json:

Felt Målt
completed true
tool_calls list_bundlesread_bundleread_fileread_file
runder 3, alle speaker_known: true, siste is_request_satisfied: true
tokens_spent 96
stop null

§ 5s dialog-rad er oppfylt, som i S7a.

De to read_file-målene er valgt, og valget står her fordi det bestemmer § 5:

  1. del-ii-bilag-7-prisskjema/prissammenstilling-sheet-1.md — direkte analog til S7as ene read_file (prisskjemaet), og nestet, så hierarkisk sti-oppløsning blir øvet.
  2. inbox-del-ii-bilag-2-3-riggplan.md — flatt rot-konsept uten adjudication, så sporet dekker begge proveniens-tilstandene. Beskjedent (1 180 tok), så det ikke dominerer profilen.

Funn: artefaktet sier IKKE hvilke konsepter navigatøren åpnet

tool_calls registrerer navn + bundle_id, aldri path:

{"bundle_id": "k2-trinn1-20260903", "name": "read_file"}
{"bundle_id": "k2-trinn1-20260903", "name": "read_file"}

På 39 konsepter var det knapt et tap. På 629 er «basen ble lest» og «hvilke to av 629 ble lest» to helt ulike opplysninger, og bare den første overlever til artefaktet. Ordrens punkt 3 ber om «hvilke konsepter navigatøren faktisk åpnet» — det kan ikke leses ut av leveransen; det er målt her via prompt-sonden (§ 5), altså med et instrument, ikke med produktet.


4. Adjudication slik konsumenten leser den

uv run --with tiktoken python scratchpad/s7a2/m1_navigation.py
Målt over context_files
Nevner 629
proposed 618
adjudicated 0
unknown (nøkkelen fraværende) 11

Produsentens tall er bekreftet, eksakt. Rå kontroll: grep -rl '^adjudication:' → 618, alle proposed; kjent-positiv grep -rl '^type:' → 630/630. De 11 uten nøkkel er de flate inbox-*.md-dokumentene som foreslo null segmenter — fravær som ærlig tredje tilstand, akkurat som produsenten skriver.

Ingen uenighet mellom produsent og leser. Nevnerne sammenfaller fordi log.md er foreldreløs (§ 2) og fordi den uansett ville vært type: Log, ikke et konsept.

Dette er S7as største endring. S7a målte adjudication i 0 av 39 og konkluderte at ordrens «ny profil med adjudication» ikke holdt. Den holder nå.

Uendret: verified og sources finnes ingen steder (0 forekomster), så evidence_state = absent for alle 629 og trust_tier = None for alle 629.


5. Falsifisering mot proveniens

uv run python scratchpad/s7a2/m4_provenance_control.py
uv run python scratchpad/s7a2/m4b_falsification.py
Levert base Kjent-positiv kontroll (patchet kopi)
adjudication_for proposed adjudicated
evidence.state absent present
evidence.tier None human-reviewed
evidence.items_seen 0 1
admits_falsification False True

admits_falsification = False for 629 av 629. Alt er proposed eller unknown, og ingenting bærer verified. Forventningen i ordren er bekreftet.

Kontrollen kjøres på en patchet kopi (scratchpad/s7a2/k2-control), aldri på korpuset, og flipper til True — altså diskriminerer gaten, og «629 diskontert» kan skilles fra «funksjonen diskonterer alltid».

Persona-dom på et proposed-konsept: påstanden «kontraktssummen eksk. mva i Prissammenstilling sheet-1 er 6 647 500 NOK og er derfor en kandidat for kostnadskutt» ender undecided, aldri survived, med den påkrevde diskonterings-linja:

provenance absent in …/del-ii-bilag-7-prisskjema/prissammenstilling-sheet-1.md; items_seen=0

adjudication: proposed alene flytter ikke terskelen — K5 krever present og en tier over unverified, og begge konjunktene faller på fraværende verified. At 618 dokumenter nå erklærer seg som foreslått endrer hva systemet kan si om dem, ikke hva en dom kan hvile på.


6. Tokenprofil for kjøringen i § 3

uv run --with tiktoken python scratchpad/s7a2/m5_prompt_composition.py
uv run --with tiktoken python scratchpad/s7a2/m5b_multiplier.py

12 prompter, 343 437 o200k-tokens.

Rolle Prompter Tokens Andel
manager 6 152 170 44 %
navigator 5 141 842 41 %
hypothesiser 1 49 425 14 %

De tre største postene — 150 445 tokens, 44 % — er hver 9899 % verktøyRESULTATER:

Post Tokens Herav result
manager #4 50 331 49 306 (98 %)
manager #3 50 278 49 306 (98 %)
manager #5 49 836 49 306 (99 %)

De fire verktøyresultatene, enkeltvis (ikke-tom-kontrollen)

Kall Tokens Ikke-tomt
list_bundles 123
read_bundle 43 928
read_file (prissammenstilling, nestet) 4 075
read_file (riggplan, flat) 1 180

Multiplikatoren — hovedfunnet

read_bundle-resultatet rir i 7 av 12 prompter (navigatør 3, manager 3, hypotesiser 1):

43 928 × 7 = 307 496 tokens = 90 % av alle prompt-tokens i kjøringen.

Til sammenligning rir prisskjemaet — det navigatøren faktisk valgte å åpne — 7 ganger for 28 525 tokens, altså 8 %.

MAJOR-3s asymptotiske påstand holder; konstanten er nå hele kostnaden. Sømmen flyttet kostnaden fra bundle_context (O(bytes)) til read_bundle (O(dokumenter)). På 39 dokumenter var det 2 312 tokens og usynlig. På 629 er det ett ubestilt katalogsvar som utgjør ni tideler av alt en utforskning betaler for.

Like-for-like mot S7a

S7a-rapportens profil (40 320 tok / 13 prompter) ble målt på revise-kjeden, ikke på det enkle manuset — den er derfor ikke sammenlignbar. Baselinen er målt på nytt her, med S7as egen base og S7as eget enkle manus:

S7a-base, enkelt manus S7a-2-base, enkelt manus
Prompter 11 12
Tokens 39 500 343 437
read_bundle-resultat 2 354 43 928
Sum verktøyresultater 6 527 49 306
Tre største 21 934 (56 %) 150 445 (44 %)

8,7× flere tokens for 16× flere dokumenter. Ærlighets-grense: manusene er ikke identiske — S7a-2 gjør ett read_file mer (4 kall mot 3), verdt 1 180 tokens × 7 ≈ 8 260. Trekkes det fra, er forholdet 8,5×.

Manus-forskjellen er ikke det som driver tallet, og det er verdt å si presist. Veksten er read_bundle alene: resultatet vokste 2 354 → 43 928 tokens mens multiplikatoren sto stille på 7, altså +291 018 tokens96 % av differansen på 303 937. Det ekstra read_file-kallet er 2,7 %. Innvendingen «manusene er ulike» kan derfor ikke forklare bort forholdet.


7. De tre S7b-kravene, alle tre uttalt

# Krav S7a S7a-2 Kommando
1 validator-input.json (IR-projeksjon) mangler mangler find … -name 'validator-input.json' → tom
2 Utfylt prisskjema uutfylt uutfylt grep -c 'Enhetspris'0
3 adjudication 0 av 39 618 av 629 § 4
4 Basen kan åpnes slik den er levert ja NEI — BundleIdMismatch § 1

Krav 3 er innfridd. Krav 1 og 2 står uendret, og begge er kryss-repo. Krav 4 er NYTT.

Krav 4 er kryss-repo, ikke en lokal ulempe. Botemiddelet — montér katalogen under det erklærte bundle_id — er et stående manuelt steg i leveransestien, som må utføres på nytt for hver leverte bundle, av en operatør som må vite at det finnes. To utfall kan lukke det, og ingen av dem kan besluttes inne i ett repo: produsenten navngir bundle_id etter monteringspunktet, eller konsumenten slakker avstemmingen. Dette er en PM-beslutning, og den er derfor med i rapporten til .claude.

MAJOR-4s deriver, kjørt mot den nye basen:

CostBaselineDerivationError: no cost table found in bundle
  'scratchpad/s7a2/k2-trinn1-20260903': no concept file carries a markdown table whose
  header names all three of ['code', 'quantity', 'unit_cost']

Kjent-positiv kontroll på tests/fixtures/k2-prisskjema-SYNTETISK: 3 kostlinjer. Gaten diskriminerer; basen mangler tallene.

Prissammenstillingen er fortsatt pre-award: de gule cellene totalentreprenøren fyller står 0.0, og de eneste tallene er beregningsgrunnlaget (5647500, 6647500, 8309375) — samme bilde som S7a fant. Ingen validert besparelse er mulig fra denne basen, uavhengig av adjudication.


8. Sidefunn — RETTET: golden-fasiten er en sha1 av INNHOLDET, ikke en git-blob

Denne seksjonen sto først med motsatt konklusjon, og den var feil. Feilen er min, og den er verdt mer enn funnet den erstatter.

Ved kontrollkjøringen sammenlignet jeg golden-hashen i CLAUDE.md med git hash-object:

$ git hash-object tests/golden/demo-transcript.stdout
55bdea3ad20616480d81b9e7544604b248a541c9        # != ea8c534…
$ git cat-file -t ea8c534773acdbe41ae68f2c55724d69aaf8be4f
fatal: git cat-file: could not get object info
$ git log --all --format=%H | while read c; do \
    git ls-tree -r "$c" | grep -q ea8c534773acdbe41ae68f2c55724d69aaf8be4f && echo "$c"; done
                                                # ingen treff i noe tre i noen commit

Alt dette er korrekt målt, og jeg konkluderte at ni invariant-rader siterte en verdi som aldri hadde eksistert. Konklusjonen var usann. PM stilte den ene sjekken jeg ikke hadde gjort:

$ shasum -a 1 tests/golden/demo-transcript.stdout
ea8c534773acdbe41ae68f2c55724d69aaf8be4f

ea8c534… ER sha1 av fila sitt innhold. Git-blober hashes over blob <len>\0 + innhold, så de to verdiene er ulike av konstruksjon for én og samme fil. De ni radene er RIKTIGE: de førte sha1 av innhold, jeg leste dem som git-blober, og et negativt resultat fra feil spørring ble konsumert som et positivt faktum om verden.

Verdi
shasum -a 1 (det radene fører) ea8c534773acdbe41ae68f2c55724d69aaf8be4f
git hash-object (det jeg målte) 55bdea3ad20616480d81b9e7544604b248a541c9
git rev-parse HEAD:<fila> 55bdea3… (arbeidsfil = HEAD)

Golden er byte-uendret av denne økten, og radene sa det korrekt hele veien.

Dette er Verifiseringsloven ansikt 4 mot mitt eget instrument. Regelen krever at en spørring valideres mot et kjent-positivt tilfelle før et negativt resultat leses som et faktum — nøyaktig disiplinen § 0 anvender på tokenmåleren, og som jeg så hoppet over her. En git hash-object som ikke finner en sha1 beviser at verdien ikke er en git-blob; den beviser ingenting om hvorvidt verdien er riktig. Det eneste som gjenstår som forbedring er ordlyd: radene bør si «sha1 av innhold», ikke bare «hash», så neste leser ikke gjentar feilen. Det er en operatørbeslutning og gjøres ikke her.

9. Delta mot S7a i én tabell

Egenskap S7a (02.09-bundelen) S7a-2 (03.09-bundelen) Endring
Konseptfiler 39 629 16×
.md på disk / index.md 40 / 1 1 108 / 478 hierarkisk
Nådd (bundle.files) 40 1 107
Foreldreløse 0 1 (log.md) nytt
Ufulgte lenker 0 0 uendret
bundle_id / opphav k2-bundle / mount-derived k2-trinn1-20260903 / declared-index første i naturen
Åpnes slik den er levert ja NEI — BundleIdMismatch ny blokker
log.md (OKF § 7) mangler finnes (men foreldreløs) delvis
list_bundles 127 tok 112 tok 12 %
read_bundle 2 312 tok 42 761 tok 18,5×
read_file median / maks 6 709 / 121 462 290 / 119 909 segmentert
Konsepter > 100k tok 2 av 39 1 av 629
bundle_context (før MAJOR-3) 682 303 648 787
adjudication 0 av 39 618 proposed / 0 adjudicated / 11 unknown av 629 innfridd
verified / sources 0 0 uendret
evidence_state absent 39/39 absent 629/629 uendret
admits_falsification False 39/39 False 629/629 uendret
Persona-dom undecided undecided uendret
Kjent-positiv kontroll flipper ja ja uendret
Dialog: runder / speaker_known 3 / true 3 / true uendret
tool_calls 3 4 manus
path i artefaktet nei nei uendret (nå merkbart)
Tokenprofil (enkelt manus) 39 500 / 11 prompter 343 437 / 12 prompter 8,7×
read_bundle-multiplikator 7 av 12 = 90 % hovedfunn
validator-input.json mangler mangler uendret
Utfylt prisskjema nei nei uendret
derive_cost_baseline nekter nekter uendret

10. Hva målingen sier

  1. Bundelen kan ikke åpnes slik den er levert. BundleIdMismatch er en ekte, ny blokker (krav 4, § 7). Botemiddelet er enkelt — monter under det erklærte navnet — men det er et stående manuelt steg per leveranse, ikke en engangsopprydding, og hvilket repo som skal endre seg er en kryss-repo-beslutning. Den fyrer i hvert kallsted som avstemmer, og det er første gang en declared-gren fyrer utenfor en crafted base.
  2. adjudication er innfridd, og det flytter ikke falsifiseringen. 618 av 629 er proposed, nøyaktig som produsenten sier — men K5 krever verified, og den finnes ingen steder. Alle 629 er fortsatt diskontert, og dommen er fortsatt undecided.
  3. read_bundle er blitt kostnaden. 90 % av en utforsknings prompt-tokens er ett ubestilt katalogsvar. MAJOR-3 holder asymptotisk og gjør K2 navigerbar i det hele tatt, men på 629 dokumenter er konstanten ikke lenger liten. Dette er et funn, ikke en fiks — ingen produksjonskode er rørt.
  4. Stigen mangler et trinn. 478 nestede indekser bygges av produsenten, konsumeres av navigasjonen og forkastes av context_files. En agent ser 629 flate dokumenter og får aldri vite at hierarkiet finnes.
  5. S7b er fortsatt blokkert på to kryss-repo-krav. Ingen bundle-egenskap kan lukke dem: uten IR-projeksjon stopper kjøringen før validatoren, og uten priser har validatoren ingenting å forankre seg i.

Rettelse ført i teksten, ikke skjult. § 8 sto først med motsatt konklusjon («fantomhash», ni feilaktige rader). Den var min feil, og den er beholdt synlig fordi feilmekanismen — et negativt resultat fra en uvalidert spørring lest som et faktum — er den samme klassen § 0 og § 2 finnes for.

Ærlighets-grenser, uttalt. Ingen levende modell er kjørt — alle agentsvar er skriptet, så at en modell ville valgt riktig konsept fra en 629-lang liste er ikke bevist (samme klasse som structured-output-grensen). Multiplikatoren 7 gjelder dette manuset. Prefiks-caching er ikke målt. Tokenprofilens 8,7× hviler på to manus som skiller seg med ett read_file; differansen er tallfestet i § 6.