# S7b — søm 1 og syretesten på K2 **Dato:** 2026-09-04 · **Ordre:** `20260903T204605Z-215167684-from-.claude` (DEL A, B, C) **Base:** `~/corpora/okf-telling-20260829/K2-bundle-20260903/` (erklært id `k2-trinn1-20260903`) > **⚠️ PRISENE ER SYNTETISKE.** K2s eget prisskjema er upriset — dette er et anbud FØR tildeling. > Hver kroneverdi i dette dokumentet stammer fra MAJOR-4s syntetiske prisskjema-fikstur > (`tests/fixtures/k2-prisskjema-SYNTETISK/`), montert inn i en arbeidskopi av basen. Ingen av > tallene er priser noen har tilbudt for Stange skole. Det som måles her er at **maskineriet** > kommer helt fram — fra et ingestert korpus til en dom med et beløp — ikke hva beløpet er. --- ## 0. Sammendrag | spørsmål ordren stiller | svar | |---|---| | Validert besparelse per kandidat | § 3.2 | | Hvor mange kandidater validatoren feller, og på hvilket stage | § 3.3 | | Tokenbruk per fase | § 3.4 | | Hvilke konsepter navigatøren åpnet | § 3.5 | Ingen terskel settes her — det er operatørens. --- ## 1. DEL A — søm 1, og de to premissene som ble felt ### 1.1 Formen `okf.load_optional_ir_projection` ved siden av den fail-faste `load_ir_projection`, nøyaktig `load_cost_baseline`/`load_optional_cost_baseline`-paret. Et **par**, ikke et `required=`-flagg: PM-tillegg 5 målte hva en uøvet parameter koster (alle elleve `evidence_for`-kallsteder brukte defaulten, så den andre grenen råtnet til den reiste), og et flagg ville dessuten gjort usanne de docstringene på tvers av `hitl`/`ledger`/`verdicts`/`contracts` som siterer `load_ir_projection` som **den** fail-faste presedensen. **Toleransen stopper ved fravær.** En projeksjon som FINNES men er malformed reiser fortsatt, og en `name` som rømmer basen reiser fortsatt. Å lese en korrupt projeksjon som «ingen projeksjon» ville gitt en unøklet kjøring i forkledning — S4.0-radens egen regel. ### 1.2 Tre kallsteder, tre ULIKE stillinger Nevneren er skrevet ned i `docs/2026-09-03-forslag-fra-mandat.md § 1.1`, og linjenumrene der er premisser som ble verifisert mot kilden før de ble handlet på. | kallsted | stilling ved fravær | hva som fortsatt nekter | |---|---|---| | `run._project_from_bundle` | hopper over en fail-fast som ikke har noe å sjekke mot | en projeksjon som FINNES og navngir et ANNET prosjekt | | `run.run_mandate_across_bundles` | ruter på basens ERKLÆRTE `bundle_id` (S7a-3) | — (fila vinner når den finnes) | | `verdicts.bundle_candidate_features` | Steg-1-folden hopper over, og SIER hvor mange dommer som falt ut | `seed_store_from_bundle`: en dom uten egen strukturell nøkkel NEKTES ved navn | **Presedensen i dispatcheren bærer i BEGGE retninger.** Erklæring-først ville re-adressert hver eksisterende base der `project_id` ≠ `bundle_id` — fila er dét de basene alltid har vært rutet etter. Fil-bare var nekten sømmen fjerner: et ingestert korpus bærer ingen projeksjon, så det kunne ikke rutes i det hele tatt. **De to konsumentene av den tredje sømmen svarer ULIKT, og det er designet.** Folden hopper over fordi fraværet av en kandidat er et faktum om basen; `seed_store_from_bundle` nekter fordi å mynte en nøkkel for en dom som erklærer ingen er nøyaktig defekten S3.2 lukker (dommen ville blitt festet til en kandidat den ikke handler om). Validering, ALDRI reparasjon. ### 1.3 Synligheten: et ANTALL, og bæreren er målt `RunResult.unkeyed_verdicts` teller de tidligere ekspertdommene som lå i storen men IKKE kunne foldes inn i hypotese-prompten. `run.unkeyed_verdicts_notice` er ENESTE renderer og returnerer `None` ved null — omisjon, aldri tom rad. * **Et ANTALL, ikke et flagg.** «Folden skjedde ikke» og «to dommer nådde aldri modellen» er ulike operative fakta — `BudgetExceeded`-kø-(y)-regelen ett nivå ned. * **Null er et ærlig POSITIVT utsagn** («hver dom storen holdt var nøklbar»), så feltet defaulter, som `skipped_links`' tomme tuppel — motsatt av `cost_baseline_anchored`, der begge defaults ville løyet. * **Bæreren er MÅLT, ikke valgt.** `DryRunReport` kan ikke bære den: dry-run-kuttet returnerer OVER folden, så et felt der kunne bare rapportert null — ulikt `cost_baseline_anchored` og `skipped_links`, som begge oppløses over kuttet. `ProvenanceStamp` heller ikke: stempelet beskriver gaten som dømte ÉN kandidat, mens dette avgjøres én gang per kjøring før noen kandidat finnes (`skipped_links`' egen begrunnelse). **Ærlighets-grenser, uttalt.** (1) Feltet når ikke utboksen — `write_proposal` dumper stempelet, og dette er ikke på stempelet; det er samme grense `skipped_links` alt har. (2) Portefølje-armen er BEVISST ikke wiret: folden er gatet på `bundle_dir`, som intet referanse-prosjekt setter, så en utskrift der ville vært død kode. Det er `bundle_id_notice`s avgjørelse, ikke `cost_baseline_notice`s (som ble wiret defensivt og drevet fra en crafted `PortfolioResult`) — asymmetrien står her fordi stillhet om den er det eneste gale svaret. ### 1.4 To premisser felt før noe ble bygget på dem **(a) Prosjektnavnet var et ikke-spørsmål.** Den arkiverte selv-ordren flagget fallbacken for `Project.name` som «en REELL beslutning». MÅLT: `SavingsProposal` har fem felt — `project_id`, `measure`, `affected_items`, `claimed_saving_nok`, `assumptions` — og ingen av dem er et navn. Projeksjonen har **aldri** vært en navnekilde. `Project.name` kommer fra `type: project`-konseptets `title` med den forespurte id-en som siste utvei, uendret før og etter. **(b) DEL B kan ikke være ÉN kommando.** Ordren skriver kjeden `--explore → --mandate → --proposals-from-mandate → validator → --revise`. Målt i kilden: `--explore` NEKTES sammen med `--mandate` (to kilder til ett mandat), `--proposals-from-mandate` er en TERMINAL modus som settler og returnerer før enhver kjøre-dispatch, og det finnes **ingen `--revise`-flagg** i det hele tatt. Kjeden er derfor tre faser (§ 3), og `--revise` leses som plan-review-døra `--plan-review` åpner (`approve` / `revise `) — sagt her som en tolkning, ikke som en oppdagelse. --- ## 2. DEL C — sidefunnet `--mandate` sto IKKE i `report_forbidden`-partisjonen, så `--report --ledger X --mandate Y` droppet kommisjonen i **stillhet**: rapporten ble skrevet, kommisjonen hverken annonsert eller settlet, exit 0. Report-modus returnerer over hver dispatch, så en utelatelse der er et stille DROPP og ikke en nekt — F4-klassen. Flagget er nå en rad, og testarmen kjører mot en argv report-modus ellers ville AKSEPTERT (gyldig `--ledger`, pluss en kontroll som beviser rc 0 uten flagget), så rc 1 er mutantens motsatte utfall. --- ## 3. DEL B — syretesten på K2 ### 3.1 Oppsettet, og hva som er syntetisk Basen er KOPIERT ut av `~/corpora` (aldri mutert der), og MAJOR-4s syntetisk prisede prisskjema er montert inn i K2s egen `del-ii-bilag-7-prisskjema/`-katalog, kryss-lenket fra den katalogens `index.md` — `navigate_bundle` følger lenker, aldri katalog-enumerering, så en umontert fil ville vært usynlig. **Et premiss ble målt før noe ble bygget på det.** Ordren sier K2s prisskjema er upriset (0/28). Målt er det verre enn som så: K2 som levert har **null** kandidat-tabeller — `prissammenstilling-sheet-1.md` renderes som en pandoc SIMPLE table med ÉN kolonne-overskrift (`Prisskjema`), så den navngir ikke rollene `Postnr`/`Mengde`/`Enhetspris` i det hele tatt. Det betyr at monteringen legger til nøyaktig én kandidat-tabell, og at `derive_cost_baseline`s «mer enn én tabell»-nekt ikke er i veien. Basen etter montering: **630 konseptfiler, 0 ufulgte lenker**, erklært id `k2-trinn1-20260903` mot monteringsnavnet `K2-priset-SYNTETISK` — så S7a-3-slakken øves samtidig, og kjøringen sier det (`bundle_id_notice` fyrer). Det avledede prisskjemaet (SYNTETISKE priser): | kode | mengde | enhetspris | sum | |---|---|---|---| | 21.1 Grunnarbeider | 1 250 | 850 | 1 062 500 | | 24.2 Bærekonstruksjon stål | 48 000 | 42,5 | 2 040 000 | | 36.1 Ventilasjonsaggregat | 4 | 187 500 | 750 000 | | **sum** | | | **3 852 500** | ### 3.2 At løkka kommer HELT fram — hovedresultatet Hele åtte-stegs-løkka kjørte på et ingestert korpus UTEN `validator-input.json`: utforskning → mandat → generering → deterministisk validator → dom. Det er nøyaktig nekten søm 1 fjerner; før i dag stoppet den samme kommandoen på `FileNotFoundError` før første modellkall. ``` uv run portfolio-optimiser K2 \ --docs-dir scratchpad/s7b-syretest/K2-priset-SYNTETISK \ --bundle-dir scratchpad/s7b-syretest/K2-priset-SYNTETISK \ --derive-cost-baseline \ --explore "Finn kostnadsbesparelser i Stange skole-anbudet" \ --explore-config scratchpad/s7b-syretest/explore-config.json \ --scripted-replies scratchpad/s7b-syretest/scripted-replies.json \ --outbox-dir scratchpad/s7b-syretest/outbox --run-id syretest-s7b ``` → `K2: ValidatedProposal (no expert verdict given; verdict key=be8535e204cdc4c6)`, mandatet settlet 2 av 2 tilnærminger validert, beste 200 000 NOK. ### 3.3 Validert besparelse per kandidat, og hvem validatoren feller Den deterministiske døra, med en kommisjon på fem tilnærminger — **null modellkall** (`evaluate_mandate_candidates` er SYNC, så det er en egenskap ved typen, ikke et løfte kroppen må holde): ``` uv run portfolio-optimiser K2 \ --docs-dir scratchpad/s7b-syretest/K2-priset-SYNTETISK \ --bundle-dir scratchpad/s7b-syretest/K2-priset-SYNTETISK \ --derive-cost-baseline --proposals-from-mandate \ --mandate scratchpad/s7b-syretest/kommisjon.json ``` | id | tiltak | kostlinjer | krav | utfall | stage | |---|---|---|---|---|---| | a1 | Redusert sprengningsvolum i sone A | 21.1 | 200 000 | **VALIDERT** | — | | a2 | Slankere stålprofiler | 24.2 | 900 000 | FELT | **stage 4** — P90 feasible 612 000 | | a3 | Færre ventilasjonsaggregater | 36.1 | 150 000 | **VALIDERT** | — | | a4 | Samordnet rigg | 21.1 + 24.2 | 500 000 | **VALIDERT** | — | | a5 | `energy_efficiency` (samme linje som a3) | 36.1 | 150 000 | FELT | **stage 5** — metode-cap 112 500 | **Validert i alt: 850 000 NOK** av et prisskjema på 3 852 500 NOK (22,1 %). **2 av 5 felt, på TO ULIKE stages.** a5 er ikke pynt: den bærer SAMME kostlinje og SAMME krav som a3, og skiller seg bare ved at `label` ordrett er et REGISTRERT metodenavn. Da slår `METHOD_CAPS` inn med 15 % i stedet for den generiske 30 %-en, og samme tall felles. Det er § 2.1s grense i `docs/2026-09-03-forslag-fra-mandat.md` gjort konkret: en ekspert-label treffer metode-cap-en KUN når den ER et registrert metodenavn. **Ærlighets-grense, uttalt (og den er strukturell):** stage 0 — avstemmingen mot baselinen — kan **ikke** felle noe på denne veien, fordi kandidaten er BYGGET fra baselinen og derfor avstemmer med 0 % avvik ved konstruksjon. Det er samme faktum som M7 i økt 82, som forble grønn av samme grunn. Og `assumptions` er tom (et bånd kan ikke avledes fra én pris), så Monte Carlo er degenerert: P10 == P50 == P90. Det som faktisk binder er stage 4/4b og stage 5. ### 3.4 Tokenbruk per fase — og det dominerende funnet Instrumentet (`o200k_base`, prompt lest som tekst + `function_call` + `function_result`) er validert mot en KJENT POSITIV før bruk: rotnivå-listingen på levert K2 måles til **3 954 tegn / 1 495 o200k-tokens over 629 konsepter**, som reproduserer S7a-3s publiserte tall eksakt. | fase | prompter | o200k-tokens | andel | |---|---|---|---| | 1 — utforskning (navigatør 5, manager 6, hypotesiser 1) | 12 | **18 355** | 0,9 % | | 2 — debatt + generering (proposer 3, checker 1) | 4 | **1 947 342** | 99,1 % | | 3 — deterministisk dom | 0 | **0** | 0 % | | **sum** | **16** | **1 965 697** | | **Funnet:** MAJOR-3 og S7a-3 gjorde UTFORSKNINGEN billig — den koster nå 18 355 tokens over hele K2 — men **debatten stapper fortsatt hele basen inn i hver prompt**. `okf.bundle_context` på denne basen er **648 962 o200k-tokens**, og den rir i **3 kopier** (2 debatt-turer + genererings-prompten): 3 × 648 962 = 1 946 886, altså praktisk talt hele fase 2. Nitti-ni prosent av en K2-kjørings tokenkostnad er kontekst ingen ba om på nytt. Dette er IKKE en ny oppdagelse i sin form — CLAUDE.mds MAJOR-3-rad sier allerede at «debattens 3× er PM-ens egen beslutning og er urørt», og at prefiks-caching er NOTERT, ikke bygget. Det nye er **nevneren på et ekte korpus**: på de tre eksempelbasene var den samme kopien 12 047–39 104 tokens, her er den 648 962. Ingen terskel settes her; det er operatørens. ### 3.5 Hvilke konsepter navigatøren åpnet Fra `{run_id}-exploration.json`s `tool_calls`, i KALL-REKKEFØLGE (S7a-3 pkt. 3s `path`-felt er dét som gjør dette lesbart i det hele tatt — uten det leser sporet `read_file, k2` og hvilken av 630 det var kan ikke leses ut av leveransen): | # | verktøy | bundle_id | path | |---|---|---|---| | 1 | `list_bundles` | — | — | | 2 | `read_bundle` | `k2-trinn1-20260903` | — | | 3 | `read_dir` | `k2-trinn1-20260903` | `del-ii-bilag-7-prisskjema` | | 4 | `read_file` | `k2-trinn1-20260903` | `del-ii-bilag-7-prisskjema/prisskjema-SYNTETISK.md` | Stigen brukes som den er ment: katalog → basens rotnivå → én underkatalog → ETT dokument. `tokens_spent` i artefaktet er 96 (ledger-regnskapet, ikke prompt-tokens — de to måler ulike ting). ### 3.6 Ærlighets-grenser for hele DEL B * **Prisene er syntetiske.** Ingen levende K2-pris er lest. Det som er vist er at maskineriet kommer fram, ikke hva et tilbud koster. * **Ingen levende modell er kalt.** Hver agent-replikk kommer fra `--scripted-replies`; banneret sier det på hver kjøring. Dette er den GRATIS halvdelen av måleprotokollens stige. Multiplikatoren 3 gjelder dette manuset. * **Kjeden er tre faser, ikke én kommando** (§ 1.4 b), og `--revise` er lest som plan-review-døra. * **Artefaktet bærer ikke de formede tilnærmingene.** `{run_id}-exploration.json` har `rounds`/`tool_calls`/`plan_reviews`/`quick_validations`, mens hvilke approaches løkka formet står i mandat-annonseringen på stdout. Uttalt, ikke endret. * **`BudgetExceeded` ut av `--explore` tracebacker fortsatt** — målt her ved et uhell, da et uparsebart proposer-svar brant rundetaket. Det er CLAUDE.mds egen uttalte grense fra økt 57, nå observert på et ekte korpus. --- ## 4. Mutasjonsmålingen (DEL A + DEL C) Grønn kontroll **1290 passed / 5 skipped** (fra 1275/5 — supersett, 0 fjernet), golden `demo-transcript.stdout` BYTE-UENDRET, `shasum -a 1` av **INNHOLDET** = `ea8c534773acdbe41ae68f2c55724d69aaf8be4f` (ikke git-blob-id-en). Hver mutasjon kjørt mot HELE suiten, én om gangen, alltid restaurert. | id | mutasjon | røde | |---|---|---| | M1 | `_project_from_bundle` tilbake til den fail-faste loaderen | 4 | | M2 | toleransen utvidet fra FRAVÆR til UENIGHET | 3 | | M3 | den valgfrie loaderen svelger en MALFORMED projeksjon også | 1 | | M4 | presedensen INVERTERT: erklært id slår den håndskrevne projeksjonen | 7 | | M5 | dispatcheren tilbake til den fail-faste loaderen | 1 | | M6 | folden hoppes over i STILLHET (ingenting telles) | 2 | | M7 | over-rapportering: hver kjøring med en store påstår at dommene var unøklbare | 1 | | M8 | antallet forlater aldri `run_project` (konstant 0 på resultatet) | 2 | | M9 | rendereren skriver ALLTID linja — omisjonen er selv gatet | 1 | | M10 | rendereren kalles aldri fra CLI-en | 1 | | M11 | en unøklbar dom hoppes STILLE over i stedet for å nektes | 1 | | M12 | seedens fallback beholder den fail-faste loaderen | 3 | | M13 | `--mandate` faller ut av report-partisjonen igjen (DEL C) | 1 | **To mutasjoner har vitner UTENFOR den nye fila, og det er dét som gjør dem sterke.** M2 (toleranse utvidet til uenighet) rødner `test_content_keyed_script_loadbearing::test_the_project_id_is_data_too` og `test_live_dry_run::test_cli_live_dry_run_local_unknown_project_no_azure_hint` — begge eldre enn dette arbeidet. M4 (invertert presedens) rødner fire eksisterende armer i `test_multibase_loadbearing` og `test_bundle_id_reconciliation_loadbearing`, altså nøyaktig den retningen hovedarmen strukturelt ikke kan se. **Ingen mutasjon forble grønn.** Alle tretten rødnet en NAVNGITT test.