MAALING, ingen produksjonskode. Instrumentet validert mot publisert fasit FOER bruk (tunnel read_bundle 259 tok, bundle_context 12 595 tok - begge eksakt). Tre premisser felt av maalingen i stedet for omgaatt: - ordrens "ny profil med adjudication": 0 av 39 konsepter baerer noekkelen (kjent-positiv kontroll: 39 av 39 baerer ^type). Ingen verified/sources heller. - ordrens punkt 4 ber om et konsept med adjudication: proposed - det finnes ikke. K5-terskelen er derfor kjoert paa det korpuset faktisk baerer, mot en patchet kopi som kontroll: admits_falsification flipper False -> True, saa "alle 39 diskontert" er en maaling av korpuset og ikke av en doed funksjon. - mandat-diffen foer/etter revise er TOM ved konstruksjon (hypotesiseren er et konstant manus). Maalt i stedet: kjeden i tre ledd. Operatoerens tekst naar manageren (6 av 8 kall), aldri deltakerne direkte (0 av 4 / 0 av 1); den naar hypotesiseren KUN via managerens egen instruction_or_question (1 av 1, diskriminerende sentinel), aldri via plan-teksten. Ledd 3 er ikke maalbar offline og er rapportert som det. Maalt ellers: 39 konsepter, 0 ufulgte lenker, bundle_id mount-derived (foerste i naturen). list_bundles 127 tok, read_bundle 2 312 tok, bundle_context 682 303 - MAJOR-3 er det som gjoer K2 navigerbar i det hele tatt, ikke bare billigere. tool_calls: list_bundles -> read_bundle -> read_file, i rekkefoelge (plan SS 5s dialog-rad oppfylt). Ingen "object at" noe sted (BLOCKER-1 lukket paa begge doerene); current_progress sier "(no progress ledger yet)" (PM-tillegg 4 lukket). Tokenprofil 45 643 o200k over 13 prompter; de tre stoerste postene er 54 % og deler aarsak: navigatoerens read_file rir med i hver senere prompt. Tre krav for S7b, i den rekkefoelgen de blokkerer: 1. bundelen mangler validator-input.json - kjoeringen nekter etter utforskningen uansett priser. Kryss-repo mot llm-ingestion-okf. 2. MAJOR-4 nekter mot det ekte prisskjemaet (ingen tabell med alle tre roller; "Enhetspris" forekommer 0 ganger; eneste prisede rad er post 82 = 5 647 500). Kontroll: syntetisk fixture gir 3 kostlinjer, saa nekten er K2s egenskap. 3. adjudication mangler i hele korpuset. Kryss-repo, samme klasse som 1. Levende kjoering IKKE gjort - alle fem env-variabler tomme, ingen model_map. Kontroll: 1230 passed / 5 skipped uendret, golden ea8c534 byte-uendret, ruff ren. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
18 KiB
Syretest S7a — K2 → kunnskapsbase → utforskning → revise
Dato: 2026-09-03 · Ordre: 20260902T233842Z-2955810469-from-.claude ·
Grunnlag: ~/.claude/docs/helhetlig-plan-okf-og-portfolio-optimiser.md § 0, § 5, § 9.1
Dette er en måling. Ingen produksjonskode er endret; hele måleoppsettet ligger utenfor treet
(scratchpad/s7a/, utracket) og hver tabell under er produsert av en kommando som står i teksten.
Ingen validert besparelse er forventet eller funnet — K2 er pre-award og prisskjemaet er
uutfylt (plan § 9.1). Det som måles er navigasjonen, dialogen, revise-sløyfa, falsifiseringen mot
proveniens og tokenprofilen.
0. Instrumentet, validert mot en kjent positiv FØR bruk
Alle tokentall er tiktoken o200k_base over den fulle prompt-blobben (tekst + function_call +
function_result), kjørt med uv run --with tiktoken — tiktoken er fortsatt ikke en
prosjektavhengighet.
| Kjent-positiv sjekk | Publisert fasit | Målt nå |
|---|---|---|
read_bundle over tunnel-hauglia |
259 tok (docs/2026-09-02-read-bundle-kontekstkostnad.md) |
259 tok |
bundle_context over tunnel-hauglia |
12 595 tok (samme) | 12 595 tok |
Instrumentet reproduserer begge eksakt. Først etter det er K2-tallene under lest som tall.
En andre instrumentfeil ble fanget underveis og er verdt å skrive ned, fordi den er samme klasse
som misjonsreview v2 rapporterte: første versjon av prompt-sonden leste repr(Content) og fikk
<agent_framework._types.Content object at 0x…> for hver melding, altså en prompt som så tom ut
mens den bar 108 000 tegn. Sonden henter nå text/result/arguments ut av hvert Content.
1. Kunnskapsbasen slik den faktisk er levert
Bygget av llm-ingestion-okf 02.09 (tools/okf_corpus_run.py, steg 17) til /tmp/k2-trinn1-bundle;
kopiert til scratchpad/s7a/k2-bundle og målt der (/tmp er flyktig).
| Egenskap | Målt |
|---|---|
Konseptfiler (context_files) |
39 |
Filer totalt (files) |
40 (39 + index.md) |
type: verdict-lag |
0 |
Ufulgte kryss-lenker (skipped) |
0 |
bundle_id / opphav |
k2-bundle / mount-derived |
index.md-body |
6 044 tegn, ingen frontmatter, ren lenkeliste |
log.md (OKF § 7) |
finnes ikke |
Ordrens N=43, merged 39 er delvis verifiserbart. merged = 39 er målt direkte (39
konseptfiler). N = 43 er produsentens tall og kan ikke verifiseres fra bundelen: den bærer
ingen log.md og ingen manifest-oppføring som teller inn-dokumentene. Det står som produsentens
påstand, ikke som en måling gjort her.
adjudication-nøkkelen: fraværende, med nevner
cd scratchpad/s7a/k2-bundle && grep -l '^adjudication:' *.md | wc -l # 0
grep -l '^type:' *.md | wc -l # 39 (kjent-positiv kontroll)
Frontmatter-folketellingen over alle 39, med sifre i nøkkelnavnet tatt med:
| Nøkkel | Antall (av 39) |
|---|---|
type, title, source_file, source_sha256, ingested_at, generated, derived |
39 |
references |
20 |
adjudication |
0 |
verified |
0 |
sources |
0 |
Ordrens premiss om «den nye profilen (adjudication)» holder ikke mot det som ble levert.
Bundelen bærer ingen adjudication-nøkkel og ingen provenienss-nøkkel i det hele tatt. Det er et
faktum om bundelen, ikke om leseren — se § 4, der gaten bevises å kunne si ja.
Navigasjonskostnad, per kall
| Kall | Tegn | o200k-tokens |
|---|---|---|
list_bundles (1 base) |
352 | 127 |
read_bundle("k2-bundle") |
6 244 | 2 312 (39 oppføringer) |
read_file × 39, sum |
— | 684 236 |
read_file, median / min / maks |
— | 6 709 / 541 / 121 462 |
bundle_context (formen før MAJOR-3) |
— | 682 303 |
Tre ting følger av tabellen.
(a) MAJOR-3 er det som gjør K2 navigerbar i det hele tatt. Den gamle read_bundle-kroppen
returnerte bundle_context — 682 303 tokens for denne basen, altså mer enn noe kontekstvindu
tar, og den ville ridd med i hver senere prompt. Den nye formen koster 2 312. Reduksjonen er
99,7 %, og forskjellen her er ikke «billigere», den er «mulig mot umulig».
(b) Katalogtaket holder på et 39-dokuments korpus. list_bundles koster 127 tokens, og
index_truncated kommer tilbake true — de 6 044 tegnene i indeksen blir til et 200-tegns
utdrag. Det bekrefter det docs/2026-08-26-katalogkostnaden.md forutså for maskin-importerte
baser: utdraget er nesten innholdsløst (første lenkelinje), men det er bundet, og hele indeksen
er ett read_file(id, "index.md") unna.
(c) read_bundle er O(dokumenter), og på 39 dokumenter er det 2 312 tokens.
tests/test_read_bundle_cost_loadbearing.py setter taket til 1 500 tegn mot 3-dokuments
baser. K2 ligger på 6 244 tegn. Det er ikke et brudd på gaten — gaten måler sine egne baser — men
det er den ærlige lesningen av hva taket er: en per-base-grense som skalerer med dokumentantallet,
ikke en absolutt grense.
(d) To dokumenter sprenger § 5s tokenkriterium hvis de leses hele. Kriteriet er «ingen
enkeltpost > 100 000 tok uten en navngitt grunn». To av 39 passerer det som read_file:
| Dokument | Tokens |
|---|---|
inbox-del-ii-bilag-3-1-milj-teknisk-rapport-med-tiltaksplan.md |
121 462 |
inbox-del-ii-bilag-9-1-avtale-som-tiltransporteres-norconsult-as.md |
119 909 |
Grunnen er navngitt her: begge er enkeltdokumenter fra korpuset som ikke er delt opp i konsepter. De ble ikke lest i kjøringene under — men en navigatør som velger dem, betaler det.
2. Dialogen: én offline utforskning med verktøyspor
PYTHONIOENCODING=utf-8 uv run python -m portfolio_optimiser.run K2-STANGE \
--docs-dir scratchpad/s7a/k2-bundle --bundle-dir scratchpad/s7a/k2-bundle \
--explore "Finn kostnadsbesparelser i Stange skole-anbudet" \
--explore-config scratchpad/s7a/explore-config.json \
--scripted-replies scratchpad/s7a/scripted-replies.json \
--outbox-dir scratchpad/s7a/outbox --run-id s7a-offline
MAJOR-1s trinn-manus er brukt: navigatøren får {"call": …}-steg, manageren én tekst per stadium
(fakta, plan, tre ledgere, sluttsvar). Uten manager-manuset avslutter kjøringen etter én runde uten
å gi noen deltaker en tur — det er MAJOR-1s egen måling, og den er grunnen til at manageren er
skriptet i stadier.
{run_id}-exploration.json:
| Felt | Målt |
|---|---|
completed |
true |
stop |
null |
tool_calls |
list_bundles → read_bundle(k2-bundle) → read_file(k2-bundle), i kallrekkefølge |
rounds |
3, alle med speaker_known: true og en ekte deltaker som next_speaker |
approaches (i mandatet) |
1 — hypothesis-1 — SENTINEL-ALFA prisskjema-post 82 |
Plan § 5s dialog-rad er oppfylt og målt: ≥ 1 read_bundle/read_file-kall er logget i
artefaktet. Kjøringen er ikke-vakuøs i den forstand MAJOR-1 definerte: tre runder, kjent taler
hver gang, tre verktøykall, ett mandat.
Kjøringen ender likevel rc = 1, og det er S7bs skarpeste funn
run refused: IR projection not found in bundle: 'validator-input.json'
Utforskningen fullførte, mandatet ble kunngjort — og så nektet pipelinen. Bundelen bærer ingen
validator-input.json, så run_projects bundle-arm kan ikke slå opp prosjektet. Artefaktet
overlevde fordi det skrives fra en finally, som er nøyaktig hva den konstruksjonen finnes for.
Dette er et mer spesifikt S7b-gap enn «K2 har ingen priser»: selv med priser ville kjøringen
stoppet her. Ingesterings-profilen emitterer ingen IR-projeksjon. Kryss-repo-funn for
llm-ingestion-okf.
Levende kjøring: ikke kjørt
Ordrens escape-klausul fyrer. Målt, ikke antatt:
| Variabel / fil | Tilstand |
|---|---|
PORTFOLIO_FOUNDRY_PROJECT_ENDPOINT |
tom/usatt |
FOUNDRY_PROJECT_ENDPOINT |
tom/usatt |
PORTFOLIO_MODEL_MAP |
tom/usatt |
OPENAI_API_KEY / AZURE_OPENAI_API_KEY |
tom/usatt |
data/model_map.json |
finnes ikke |
az account show svarer riktignok med en konto, men Fase 4e målte at AZURE-armen slår opp et
deployment-navn i modell-mappet før noen klient bygges — uten mappet er en innlogget CLI
ikke nok. Levende kjøring ikke gjort, mangler nøkkel og modell-map. Ingen konflikt med
STATE-ens IKKE RØR AZURE oppsto.
3. Revise-sløyfa
printf 'revise SENTINEL-BRAVO: …\napprove\n' | uv run python -m portfolio_optimiser.run K2-STANGE \
… --explore-config scratchpad/s7a/explore-config-review.json --plan-review \
--outbox-dir scratchpad/s7a/outbox-review --run-id s7a-review
| Egenskap | Målt |
|---|---|
| Plan-reviewer stilt | 2 (#1 besvart revise, #2 besvart approve) |
| Manageren replanla mellom dem | ja — plan #1 1 115 tegn, plan #2 1 132 tegn, ulik tekst |
| Tilbakemelding i artefaktet | ordrett, SENTINEL-BRAVO: … |
"object at" i artefakt eller stdout |
0 forekomster (BLOCKER-1 bekreftet lukket på begge dørene) |
current_progress |
"(no progress ledger yet)" — ikke ordet None (PM-tillegg 4 bekreftet lukket) |
Mandat-diffen er TOM, og grunnen er instrumentet — ikke systemet
Mandatet bygges av hypotesiserens HYPOTHESIS:-merkede turer. Under et konstant manus sier
hypotesiseren det samme uansett hva revisjonen sa, så før/etter er identiske ved konstruksjon. Å
rapportere den tomme diffen som et funn ville vært å lese et instrumentresultat som et faktum om
verden. Det som kan måles offline er kjeden: hvilke prompter bærer operatørens
tilbakemelding? Med to ASCII-sentineler (norske tegn serialiseres escaped i prompten og ville gitt
falske nuller — samme felle misjonsreview v2 rapporterte):
| Ledd | Bærer | Målt |
|---|---|---|
| 1. Operatørens revise-tekst → managerens prompt | SENTINEL-BRAVO |
6 av 8 manager-kall |
| 1b. Samme tekst → deltakernes prompt | SENTINEL-BRAVO |
0 av 4 navigatør, 0 av 1 hypotesiser |
| 2. Managerens post-revise-output → hypotesiserens prompt | SENTINEL-CHARLIE i instruction_or_question |
1 av 1 |
| 2b. Samme, via plan-TEKSTEN | revidert plan-streng | 0 av 1 hypotesiser, 0 av 4 navigatør |
| 3. Endret hypotese ut av deltakeren | — | ikke målbar offline |
Mekanismen, uttalt: operatørens tilbakemelding når manageren, aldri deltakerne direkte.
Den når deltakerne bare gjennom det manageren selv skriver i neste rundes
instruction_or_question — og det er bevist diskriminerende: sentinelen manageren skrev etter
revisjonen står i hypotesiserens prompt, mens plan-teksten (verken den opprinnelige eller den
reviderte) gjør det ikke.
Sløyfa er altså hel, men leddet som faktisk former hypotesen er managerens omskriving av tilbakemeldingen. Under et skriptet manus er den omskrivingen min, ikke en modells. At en revise endrer hva hypotesiseren foreslår er derfor ikke bevist her, og kan ikke bevises offline — det krever en levende manager. Det er S7bs andre åpne krav.
4. Falsifisering mot proveniens (K5-terskelen)
Ordren ber om et K2-konsept med adjudication: proposed. Det finnes ikke: 0 av 39. Terskelen
er derfor kjørt på det korpuset faktisk bærer, mot en påstand om den ene prisede posten:
«Post 82 Prosjektering (tiltransport av prosjekterende) i Bilag 7 Prisskjema er priset til 5 647 500 NOK og er derfor en kandidat for kostnadskutt.»
| K2 slik den er levert | Kjent-positiv kontroll (patchet kopi) | |
|---|---|---|
adjudication_for |
unknown |
adjudicated |
(state, reason, items_seen) |
(absent, None, 0) |
(present, None, 1) |
trust_tier |
None |
human-reviewed |
admits_falsification |
False |
True |
Over alle 39, med nevner: adjudication unknown 39/39 · evidence.state absent 39/39 ·
tier None 39/39 · admits_falsification False 39/39.
Kontrollen er bærende. Uten den er «alle 39 diskontert» ikke til å skille fra «funksjonen
diskonterer alltid» — repoets vakuøs-gate-klasse. Kontrollen er en kopi under
scratchpad/s7a/k2-control/ der ett konsept har fått
verified: { by: human:…, at: … } + adjudication: adjudicated; gaten flipper False → True.
Den leverte bundelen er aldri skrevet til.
Dommen, slik skillen krever den: undecided, aldri survived. Diskonteringen sies eksplisitt
med trippelen, ordrett fra evidence_notice:
provenance absent in …/inbox-del-ii-bilag-7-prisskjema.md; items_seen=0
Og med skillens egen regel: en gjendrivelse som ikke navngir en gjendriver er ingen gjendrivelse — her finnes ingen kilde som klarerer terskelen, så «vi kan ikke bekrefte» må aldri skrives om til «påstanden er gal».
5. Tokenprofil
Ekte usage finnes ikke: ScriptedChatClient rapporterer 8 tokens per svar, så artefaktets
tokens_spent (88 offline, 104 med review) er syntetisk og sier ingenting om kostnad. Profilen
under er derfor instrument-målt over de faktiske prompt-blobbene i revise-kjøringen.
13 prompter, 45 643 o200k-tokens.
| Rolle | Prompter | Tokens | Andel |
|---|---|---|---|
| manager | 8 | 29 568 | 65 % |
| navigator | 4 | 9 392 | 21 % |
| hypothesiser | 1 | 6 683 | 15 % |
De tre største postene — til sammen 24 598 tokens, 54 % av hele kjøringen:
| # | Post | Tokens |
|---|---|---|
| 1 | manager-kall 6 (ledger etter at navigatøren hadde lest prisskjemaet) | 8 572 |
| 2 | manager-kall 5 (samme, runden før) | 8 444 |
| 3 | manager-kall 7 (sluttsvar) | 7 582 |
Det de tre har til felles er årsaken. Alle tre bærer navigatørens read_file-resultat —
Bilag 7 Prisskjema, 100 695 tegn / 4 043 tokens — fordi utforskningens deltakere deler én
samtalehistorikk. Ett read_file betales altså av hver senere prompt i kjøringen, som er nøyaktig
mekanismen docs/2026-09-02-read-bundle-kontekstkostnad.md beskrev for bundle_context, ett trinn
ned på stigen. Ingen enkeltpost passerer § 5s 100 000-tak i denne kjøringen; de to dokumentene som
ville gjort det (§ 1d) ble ikke åpnet.
6. Hva som mangler for S7b (validert besparelse)
Tre krav, alle målt her, i den rekkefølgen de blokkerer:
1. Kunnskapsbasen mangler en IR-projeksjon. run_projects bundle-arm nekter med
IR projection not found in bundle: 'validator-input.json' (§ 2). Uten den stopper kjøringen etter
utforskningen uansett hva prisskjemaet inneholder. Ingesterings-profilen emitterer den ikke.
Kryss-repo-krav mot llm-ingestion-okf — ingen brief i dette repoet kan lukke det.
2. Prisskjemaet er uutfylt, og MAJOR-4 nekter — korrekt. Kjørt mot det ekte K2-prisskjemaet:
CostBaselineDerivationError: no cost table found in bundle 'scratchpad/s7a/k2-bundle':
no concept file carries a markdown table whose header names all three of
['code', 'quantity', 'unit_cost']
Kontroll: samme funksjon mot tests/fixtures/k2-prisskjema-SYNTETISK gir 3 kostlinjer, så
avlederen virker — nekten er en egenskap ved K2, ikke ved koden.
Formen er målt presist: K2s Bilag 7 er ett ark (## Prissammenstilling), en pandoc SIMPLE table
med kolonneparet Post … SUM. Ordet Enhetspris forekommer 0 ganger i hele filen, og
Mengde/Timepris står bare i prosa — de tilhørende cellene er tomme, fordi totalentreprenøren
skal fylle dem. Den eneste prisede raden i hele skjemaet er
82 Prosjektering (tiltransport av prosjekterende) = 5 647 500.
S7b trenger altså den syntetisk utfylte kopien plan § 9.1 anbefaler. MAJOR-4 har allerede formen:
okf.derive_cost_baseline (eier B) og fixturparet
tests/fixtures/k2-prisskjema-SYNTETISK / …-uprisert-SYNTETISK, med
--derive-cost-baseline som CLI-døra.
3. adjudication mangler i hele korpuset (0/39). K5-terskelen diskonterer derfor hvert konsept
(§ 4). En validert besparelse kan formelt sett fortsatt produseres — terskelen gjelder
falsifiseringsdommen, ikke validatoren — men den kan ikke hvile på noe i basen. Kryss-repo-krav
mot llm-ingestion-okf, samme klasse som punkt 1.
Ett krav er ikke blokkerende og bør ikke telles med: at en revise endrer hypotesen (§ 3). Det krever en levende manager, ikke en endring i noe av dette.
7. Verifiseringslogg
| # | Påstand | Kommando → resultat |
|---|---|---|
| 1 | Instrumentet reproduserer publisert fasit | uv run --with tiktoken python scratchpad/s7a/m1_navigation.py → tunnel read_bundle 259, bundle_context 12 595 |
| 2 | 39 konsepter, 0 adjudication, kjent-positiv 39 type |
grep -l '^adjudication:' *.md | wc -l → 0; grep -l '^type:' → 39 |
| 3 | N=43 ikke verifiserbart |
ingen log.md i bundelen (Path(base)/'log.md').exists() → False) |
| 4 | Navigasjonstall | samme skript → § 1-tabellen |
| 5 | Verktøysporet | outbox/s7a-offline-exploration.json → tool_calls = 3, i rekkefølge |
| 6 | Pipelinen nekter på manglende IR | stderr → IR projection not found in bundle |
| 7 | Levende ikke kjørbar | alle fem env-variabler tomme; data/model_map.json finnes ikke |
| 8 | Revise → replan → nytt spørsmål | outbox-review/s7a-review-exploration.json → 2 plan_reviews, ulik plan |
| 9 | Ingen object at |
grep -c 'object at' over artefakter + stdout → 0 |
| 10 | Kjeden, tre ledd | uv run --with tiktoken python scratchpad/s7a/m3_revise_chain.py → § 3-tabellen |
| 11 | K5 diskriminerer | uv run python scratchpad/s7a/m4b_falsification.py → False vs True |
| 12 | MAJOR-4 nekter mot ekte K2, godtar syntetisk | uv run python scratchpad/s7a/m6_derive.py → feilmelding vs 3 kostlinjer |
| 13 | Tokenprofil | samme skript som 10 → § 5-tabellene |
Ikke verifisert her: at en levende modell kaller verktøyene eller velger godt (samme grense som
structured-output-raden); at N=43 stemmer; at leverandørens caching treffer prefiksene; K2s
Prisskjema slik en utfylt versjon faktisk ville sett ut (fixturen er syntetisk).
Premisser som ble felt av målingen, og som er rapportert i stedet for omgått: ordrens
«ny profil med adjudication» (0/39), ordrens punkt 4 (ingen proposed-konsept finnes), og
antakelsen om at mandat-diffen ville vise revisjonens virkning (tom ved konstruksjon).