portfolio-optimiser/docs/2026-09-06-major2-levende-k2.md
Kjell Tore Guttormsen 446150eecc docs(major2): SC1/SC4/SC8/SC13 maalt live - modellen etterkom ikke
Ordre 20260906T050506Z, gjenopptatt etter at operatoeren satte deployment-
capacity 10 -> 100. Veggen fra returen er MAALT borte foer noen arm ble
startet (3 742 og 5 475 tokens passerer isolert der 3 000 foer ble avvist);
0 stk. 429 i ni betalte kjoeringer.

Hovedfunn: MAJOR-2-doera virker mekanisk i hvert ledd - ekspertens ord naar
prompten ordrett (2 av 6 genererings-prompter, samme nevner som skriptet),
forsoeket kjoepes og hentes (honoured: true, attempts remaining 2 -> 0),
forslaget endrer seg og artefaktet baerer alt - men modellen gjorde det
MOTSATTE av instruksjonen: bedt om aa halvere, oekte den 25 % (212 500 ->
265 625 NOK). Forsoek 2 ba om 531 250 (= 50 % av kostlinja); det var
VALIDATOREN som stoppet det, og Steg 5 matet avvisningen tilbake. D6 er
dermed maalt i praksis: validatorens siste dom vinner, aldri revieweren sin.

Tre funn i src/ RAPPORTERT, IKKE RETTET (ordrens gjerde): genererings-
prompten sier ikke at affected_items skal baere BASELINE-linja; stage 0
navngir kun foerste overtredelse, saa Steg-5-loekka oscillerer innenfor
max_attempts=3; modellen leser katalog-oppfoeringer som filnavn.

Retter ogsaa dokumentets az-kommando: `deployment update` finnes ikke i
CLI-en (kun create|delete|list|show, maalt mot --help) - riktig verb er
`create` med samme modell/versjon/sku, siden ARM-PUT oppdaterer.

Kostnadsgaten: estimat NOK 2,01, brukt NOK 2,15, tak 50. Overskridelsen er
navngitt (ordren forutsatte to armer; seks kjoeringer naadde ikke doera).
Takene max_rounds/max_tokens/max_attempts UROERT. src/ og tests/ UROERT.
1368 passed / 5 skipped, golden shasum -a 1 (INNHOLD) ea8c534..., ruff+mypy
rene. Ingen ekte Azure-vert i sporet innhold - verifisert ETTER git add.

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

329 lines
19 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.

# MAJOR-2 — den levende K2-målingen
> **Måledato:** 2026-09-06
> **Ordre:** `20260906T050506Z-8827117206-from-.claude` (operatørvalg 06.09: alternativ (b), alle
> fire kriterier; returnert 06:19Z på en kvoteverdi, gjenåpnet etter at operatøren sa ja til
> veivalg 1)
> **Kode målt ved:** `1f2a045` — ingen fil under `src/` eller `tests/` er rørt; hele målingen skjer
> i `scratchpad/major2-live/` gjennom `run._default_factory`, repoets egen dokumenterte
> injeksjonssøm (Fase 4e)
> **Utfall:** SC1, SC4, SC8 og SC13 er **MÅLT** mot en levende modell. Svaret på hovedspørsmålet er
> ikke det man ville antatt: døra virker mekanisk i hvert ledd, og modellen gjorde det **motsatte**
> av det eksperten ba om.
---
## 0. Hva som ER målt, og hva som IKKE er det
| Spørsmål | Status |
|---|---|
| Er auth/RBAC/endepunkt/deployment i orden? | **JA, målt** — ett-ords-proben grønn |
| Koster målingen mindre enn taket? | **JA, målt** — estimat NOK 2,01, faktisk brukt **NOK 2,15**, tak 50 |
| Er kvoteveggen fra 06:19Z borte? | **JA, målt** — § 2. 0 stk. 429 i ni kjøringer |
| Navigerer en LEVENDE modell kunnskapsbasen (S2c)? | **JA** — § 3, målt både 06:19Z og nå |
| **Når ekspertens ord proposer-prompten (SC4)?** | **JA, MÅLT** på det deklarerte oppsettet (§ 4 rad 6) — 2 av 6 genererings-prompter, ordrett. § 6 |
| **Kjøpes forsøket, og hentes det (SC13)?** | **JA, MÅLT** på samme oppsett — `honoured: true`, `attempts remaining` 2 → 0. § 6 |
| **Er forslag 2 forskjellig fra forslag 1 (SC1)?** | **JA, MÅLT** på samme oppsett — tre felt endret. § 5 |
| **Flytter utfallet seg (SC8)?** | **JA, MÅLT** på samme oppsett — 212 500 → 265 625 NOK. **Feil vei.** § 5 |
| Følger modellen instruksjonen? | **NEI, målt.** Den ble bedt om å halvere og økte med 25 %. § 5 |
| Ledger per fase mot 19 prompter / 19 776 tokens | **MÅLT** — § 7 |
**Les de fire MÅLT-radene sammen med § 4.** På 09-04-oppsettet URØRT nås review-døra ikke i det
hele tatt (seks kjøringer, tre distinkte årsaker); de fire kriteriene er målt på et oppsett der to
fikstur-detaljer er endret og deklarert. Begge halvdeler er funn, og den første er ikke den svake.
Ingenting under er utledet. Der noe ikke er målt, står det.
---
## 1. Kostnadsgaten
**Deployment** (målt med `az cognitiveservices account deployment show`, ikke hentet fra minnet):
`gpt-4-1-mini` → modell `gpt-4.1-mini`, versjon `2025-04-14`, **GlobalStandard**, på
`<resource>` / `<resource-group>` / eastus. **`capacity` er 100** etter operatørens trekk (var 10 da
ordren ble returnert), og deploymentets egne `rateLimits` leser nå **100 forespørsler / 60 s** og
**100 000 tokens / 60 s**.
**Det finnes ingen operatør-fil for `PORTFOLIO_MODEL_MAP`** — variabelen er usatt i skallet, og
`~/.zshenv`/`~/.zshrc` nevner den ikke (målt). Det pakkede `data/model_map.json` bærer fortsatt
`REPLACE-WITH-FOUNDRY-DEPLOYMENT`. Kartet for denne målingen er derfor
`scratchpad/major2-live/model_map.json` (utracket) — en måleartefakt, ikke en kodeendring.
**Listepris, Azure Retail Prices API** (`https://prices.azure.com/api/retail/prices`,
`api-version=2023-01-01-preview`, hentet **2026-09-06**), metere `gpt 4.1 mini Inp glbl Tokens` /
`gpt 4.1 mini Outp glbl Tokens`, `armRegionName=eastus`:
| | NOK / 1K tokens | USD / 1K tokens |
|---|---|---|
| input | **0,003734** | 0,0004 |
| output | **0,014936** | 0,0016 |
NOK-tallene er Microsofts **egne** NOK-listepriser fra samme API (`currencyCode='NOK'`), ikke en
valutakonvertering.
**Estimat FØR første betalte kall**, etter ordrens formel:
`(19 776 inn + 40 000 ut) × pris × 2 armer × 1,5 margin` = **NOK 2,01**.
**Faktisk forbruk, alle ni betalte kjøringer summert: 522 052 input + 13 137 output = NOK 2,15.**
Det er **7 % over estimatet og 4,3 % av taket på 50**. Overskridelsen har en navngitt grunn: ordren
forutsatte to armer, og målingen krevde ni kjøringer fordi de første seks ikke nådde review-døra
(§ 4). Ordrens punkt 4 («overstiger noe enkeltpost 100 000 tokens uten navngitt grunn, stopp og
rapporter») er ikke utløst: største enkeltkall er **5 798 tokens**. Én kjøring traff run-takets
100 000 tokens (§ 4, variant D på den udekkede basen) — det er takets egen mekanisme som fyrer, ikke
en enkeltpost. **Takene (`max_rounds` / `max_tokens` / `max_attempts`) er URØRT.**
---
## 2. Veggen fra 06:19Z — borte, og det er målt før noe annet ble startet
Ved returen var `capacity: 10`, og en isolert forespørsel på 3 000 tokens ble avvist med 429 etter
**150 s helt stille** — et tak per forespørsel som ingen backoff kan vente seg forbi. Operatøren
satte `capacity: 100`.
**En 60-sekunders bøtte kan ikke forklare det som ble målt ved returen**, så at kapasitetstrekket
løser det var en hypotese, ikke et faktum. Den avgjørende prøven ble derfor gjentatt ordrett **før
første arm ble startet**, som et nytt trinn på 14.08-stigen:
| Prøve | Ved `capacity: 10` (06:19Z) | Ved `capacity: 100` (nå) |
|---|---|---|
| 2 342 tokens | OK | — |
| 3 000 tokens | **429** | — |
| 3 742 tokens | — | **OK** (5,30 s, fakturert 3 755 inn) |
| 5 475 tokens | — | **OK** (2,99 s, fakturert 5 475 inn) |
| 4 000 tokens | **429** | — |
Veggen var altså gjennomstrømning. **0 stk. 429 i alle ni kjøringene under**, med
`PACE_SECONDS=2` (var 12, dimensjonert for capacity 10).
**Rettelse til dokumentet slik det sto ved returen:** kommandoen ble skrevet som
`az cognitiveservices account deployment update`. **Det verbet finnes ikke**`az cognitiveservices
account deployment` har kun `create | delete | list | show` (målt mot `--help`). Riktig form er
`create` med samme modell, versjon og sku, siden ARM-PUT oppdaterer den eksisterende deploymenten:
```bash
az cognitiveservices account deployment create \
-n <resource> -g <resource-group> \
--deployment-name gpt-4-1-mini \
--model-name gpt-4.1-mini --model-version 2025-04-14 --model-format OpenAI \
--sku-name GlobalStandard --sku-capacity 100
```
På GlobalStandard er `capacity` en gjennomstrømnings-kvote, ikke en pris — faktureringen er per
token uansett, så kostnadsgaten er uendret av trekket.
---
## 3. S2c-navigasjonen, live (uendret funn fra 06:19Z, reprodusert)
`docs/2026-09-04-s2c-debatt-k2.md` lukket med ærlighets-grensen *«ingen levende modell har
navigert»*. Den var lukket allerede ved returen, og er reprodusert i hver kjøring siden. Debattens
proposer får kun PEKEREN (fast tekst + erklært `bundle_id` + antall konseptdokumenter + stigen) og
de fire navigatør-verktøyene, og går stigen uoppfordret:
```
list_bundles → read_bundle("k2-trinn1-20260903") → read_dir("del-ii-bilag-7-prisskjema")
→ read_file("del-ii-bilag-7-prisskjema/prisskjema-SYNTETISK.md")
```
Fra 630 konseptdokumenter finner modellen prisskjemaet i **tre** navigasjonssteg.
**To nye navigasjons-funn, målt her:**
1. **Modellen forveksler katalog med fil.** `read_dir` på et nivå med underkataloger (`30-1`,
`30-7`, `521-001` …) ble fulgt av `read_file(".../30-7.md")` — modellen la på `.md`. Tre slike
på rad, og MAF stopper da videre verktøykall for den forespørselen («Maximum consecutive
function call errors reached»). Katalog-oppføringene i `directory_listing` bærer `documents`, men
modellen leste dem som filnavn.
2. **Én stor fil kan spise hele run-taket.** Prisskjema-katalogen i syretest-fiksturen bærer både
K2s ekte, *uprisede* sammenstillingsark (101 188 tegn ≈ 25 000 tokens) og den syntetiske,
*prisede* linja (637 tegn). I én kjøring åpnet debatten den store og traff run-takets 100 000
tokens før den var ferdig (`run refused: budget exceeded: tokens limit=100000 observed=100664`).
---
## 4. Hvorfor det tok seks kjøringer å komme fram til døra — hvert steg er en måling
Review-døra (`--proposal-review`) stiller sitt spørsmål **kun når validatoren har akseptert en
kandidat**. Seks kjøringer nådde den ikke, og hver ga et distinkt, reproduserbart funn. Alle seks
kjørte den samme argv-en og det samme skriptede utforsknings-manuset som `docs/2026-09-04-…`; det
som varierer er navngitt i hver rad.
| # | Variant | Utfall — stage 0 | Funn |
|---|---|---|---|
| 1 | 09-04-manuset ordrett, syretest-basen (approve) | `unknown cost code '21.1 grunnarbeider'` | Modellen kopierte mandatets **prosa** inn i kodefeltet |
| 2 | samme (revise) | **identisk** | Reprodusert i uavhengig kjøring |
| 3 | begrunnelsen sier «Kostkode 21.1» i stedet for «Post 21.1 grunnarbeider» | `quantity 1000 … utenfor 5 % rundt baseline 1250` | Koden nå riktig; mengden gjettet |
| 4 | som 3, uten det upriste 101K-arket | **identisk** | Proposeren **leste** det prisede skjemaet to ganger og gjettet likevel |
| 5 | begrunnelsen oppgir kostlinja (1250 m3 à 850) , syretest-basen | run-taket 100 000 tokens | Det upriste arket spiser budsjettet (§ 3, funn 2) |
| 6 | som 5, uten det upriste arket | **VALIDERT — døra åpner** | § 5 |
**Rotårsaken er semantisk, ikke en modellsvakhet.** `affected_items` skal bære **baseline**-linja
slik den står i prisskjemaet — det er dét stage 0 (S4.0) avstemmer mot. Genererings-prompten sier
kun `affected_items (list of {code, quantity, unit_cost})` og forklarer ikke hvilken av de to
mengdene den vil ha. En levende modell som blir bedt om å *redusere* utgravingsvolumet fyller
naturlig inn sin **foreslåtte reduserte** mengde (1000), og blir avvist. Det skriptede 09-04-manuset
skrev 1250/850 fordi et menneske skrev manuset og kjente regelen.
**Steg 5-løkka virker, men den oscillerer.** Stage 0 rapporterer **én** overtredelse om gangen, og
avvisningen mates tilbake i neste forsøks prompt. Målt sekvens i kjøring 3:
```
1000/500 → «quantity 1000 … baseline 1250» → 1188/350 → «unit_cost 350 … baseline 850»
→ 1000/850 → forsøkene brukt opp (max_attempts=3)
```
Modellen fant hver av de to riktige verdiene, men aldri samtidig: den retter feltet avvisningen
navngir og brekker det andre. Med `max_attempts = 3` per tilnærming rekker den ikke å konvergere på
to felt.
**Dette er funn, ikke fiks.** Alle tre — prompt-teksten for `affected_items`, at stage 0 kun navngir
første overtredelse, og at katalog-oppføringer leses som filnavn — bor i `src/`, som ordrens gjerde
holder utenfor. De er rapportert, ikke rettet.
**De to fikstur-endringene er deklarert, og de forteller ikke modellen hva den skal foreslå.**
(a) Mandatets begrunnelse oppgir kostlinja slik dokumentet har den — det er hva en fagperson ville
skrevet. (b) Det upriste 101K-arket er fjernet fra en KOPI av basen; en ekte priset leveranse ville
båret prisene i selve skjemaet. Ingen av dem rører tilbakemeldingen, som er det som er under test,
og modellen ser den først ved review-døra.
---
## 5. SC1 og SC8 — forslaget FØR og ETTER ekspertens ord
Begge armer kjørte identisk konfigurasjon; **det eneste som skiller dem er svaret på stdin.**
Kontrollarmen svarer `approve`, revise-armen svarer:
> `revise Anslaget er for hoeyt. Bare halvparten av mengden i denne kostlinjen er styrbar - halver
> claimed_saving_nok og behold de samme kostlinjene og forutsetningene.`
At kontrollen er en kontroll er **målt, ikke påstått**: begge armer produserte det **samme første
forslaget** — 212 500 NOK, dom-nøkkel `ee11886ddce76568`.
| Felt | Forslag 1 (begge armer) | Forslag 2 (etter `revise`) | Ba eksperten om det? |
|---|---|---|---|
| `claimed_saving_nok` | **212 500** | **265 625** | Ja — men om å **halvere**. Modellen økte **25 %** |
| `affected_items` | `21.1 · 1250 · 850` | `21.1 · 1250 · 850`**uendret** | Ja: «behold de samme kostlinjene» ✅ |
| `assumptions["21.1"]` | `[750, 950]` | `[800, 900]`**innsnevret** | Nei: «behold … forutsetningene» ❌ |
| `measure` | «Redusert utgravingsvolum i grunnarbeider» | «… **ved å halvere mengden styrbar volum i kostkode 21.1**» | Ikke bedt om, men den **siterer** tilbakemeldingen |
| dom-nøkkel | `ee11886ddce76568` | `4bf297e2e2ce4bc8` | — |
| `validator_decision` | `validated` | `validated` | — |
| `cost_baseline_anchored` | `true` | `true` | — |
**Utfallet (SC8): 212 500 → 265 625 NOK. Feil vei, og med et tall som passerte hele gaten.**
**Mekanismen bak feilretningen er målt, ikke gjettet.** Modellen leste «bare halvparten av mengden
er styrbar» som *«spar halve kostlinja»*:
```
forsoek 1 (uten feedback): 212 500 = 20,0 % av 1 062 500
forsoek 2 (MED feedback): 531 250 = 50,0 % av linja -> AVVIST av validatoren
forsoek 3 (avvisningen matet tilbake): 265 625 = 25,0 % -> VALIDERT
```
Den mente altså «halver mengden» der eksperten skrev «halver `claimed_saving_nok`» — og det tallet
eksperten faktisk ba om var 106 250. **Det som stoppet 531 250 var validatoren, ikke modellen.**
Dette er nøyaktig hvorfor D6 er som den er: **validatorens siste dom vinner, aldri revieweren sin.**
Hadde revieweren fått bestemme, ville et menneskes ønske om ett forsøk til ha forbedret utfallet
uten at noen falsifiserer sa ja.
**Ærlig lesning:** døra virker i hvert mekanisk ledd — ordene når prompten, forsøket kjøpes og
hentes, forslaget endrer seg, utfallet flytter seg og artefaktet bærer alt. **Det den ikke gir, er
at modellen etterkommer.** Ingenting i MAJOR-2 lovet det, og ingen test påsto det; men før denne
kjøringen var det ikke målt at den lar være.
---
## 6. SC4 og SC13 — når ordene fram, og ble forsøket kjøpt?
**SC4 — ordrett i prompten:** ekspertens setning står **ordrett i 2 av 6 genererings-prompter** i
revise-armen (og i 2 av 23 levende proposer-prompter totalt — de 17 andre er debatt-turer, som
aldri ser tilbakemeldingen). Nevneren er den samme som den skriptede målingen 09-04 fant: **2 av 6.**
De to er nøyaktig forsøk 2 og 3 for `hypothesis-1`; `own-proposal`s tre forsøk har den ikke, som
seg hør og bør — tilbakemeldingen tilhører den tilnærmingen den ble gitt om.
**SC13 — forsøket ble kjøpt, og det ble hentet.** `{run_id}-proposal-reviews.json`:
```json
{"approach_id": "hypothesis-1", "attempt": 0, "decision": "revise",
"feedback": "Anslaget er for hoeyt. ... halver claimed_saving_nok og behold de samme kostlinjene og forutsetningene.",
"honoured": true, "p50": 291467.85, "verdict_key": "ee11886ddce76568"}
{"approach_id": "hypothesis-1", "attempt": 2, "decision": "approve",
"feedback": "", "honoured": true, "p50": 319311.90, "verdict_key": "4bf297e2e2ce4bc8"}
```
Feedbacken står **ordrett** i artefaktet, `honoured: true` på begge, og terminalen viste
`attempts remaining: 2` ved review #1 og `0` ved review #3 — den ledger-bevisste nedtellingen
(M38) med ekte tall. Kontrollarmen skrev det samme artefaktet med **én** rad
(`1 approve, 0 revise`), og linja «proposal review: 2 answer(s) across 1 candidate(s) — 1 approve,
1 revise» er rendereren som rapporterer det.
**Ville en levende oppfølging blitt avvist?** Ja, én av dem ble det: forsøk 2 (531 250 NOK) falt hos
validatoren, og Steg 5 matet avvisningen tilbake. Den reviderte kandidaten som til slutt nådde
review #3 var altså **selv et produkt av to falsifiserere i serie** — mennesket og validatoren.
---
## 7. Ledger per fase, mot den skriptede profilen
**Ordren ber om at «§ 5-tabellens rader Feedback → forbedret og Token fylles med levende
tall». Ingen slik tabell finnes i dette repoet** — målt over 31 markdown-filer (`docs/*.md` +
README): 0 treff på en tabellrad som begynner med «Feedback», mens kjent-positiv-kontrollen viser
at samme regex finner eksisterende `| Token…`-rader i to andre dokumenter. Tabellen tilhører
ordre-avsenderens eget dokument. Radene er derfor besvart her: «Feedback → forbedret» i § 5 og
§ 6, «Token» i tabellen under.
Ordren ber om sammenligning mot `docs/2026-09-04-major2-proposal-review-k2.md:207` (19 prompter /
19 776 tokens). Sammenligningen er **like-for-like på utforskningen ved konstruksjon** — manuset er
det samme, så de 12 utforsknings-promptene er skriptede og ubetalte i begge — og **ikke**
like-for-like på debatt og generering, som her er levende og derfor navigerer og resonnerer fritt.
| | Skriptet (09-04) | LEVENDE kontroll (approve) | LEVENDE revise |
|---|---|---|---|
| utforskning | 12 prompter / 18 355 tok | 12, skriptet (ubetalt) | 12, skriptet (ubetalt) |
| debatt: proposer | 2 / 314 tok | **15 / 29 030 inn / 1 026 ut** | **23 / 62 654 inn / 1 572 ut** |
| debatt: checker | 1 / 199 tok | inkl. over: **5 prompter / 9 547 / 326** | **8 / 18 881 / 441** |
| generering | 4 / 908 tok | 3 forsøk (i proposer-tallet) | 6 forsøk (i proposer-tallet) |
| **prompter totalt** | **19** | **32** (20 levende + 12 skriptede) | **43** (31 + 12) |
| **betalte tokens** | — (ingen) | **38 577 inn / 1 352 ut** | **81 535 inn / 2 013 ut** |
| **kostnad** | — | **NOK 0,164** | **NOK 0,335** |
**Forskjellen er navigasjonen, ikke døra.** Den skriptede debatten svarte med ett fast utsagn per
tur; den levende går stigen, leser dokumenter og bærer resultatene videre i én delt samtale — det er
`docs/2026-09-04-s2c-debatt-k2.md` sin egen handel, målt live for første gang. **Døras egen kostnad
er den ene ekstra genererings-runden per revise**, og den er liten: revise-armen har 3 flere
genererings-forsøk enn kontrollen.
---
## 8. Ærlighets-grenser
* **Ett kall er én kjøring.** Alt i § 5 og § 6 er én modell, én gang, på ett korpus. At
`gpt-4.1-mini` gjør det motsatte av en tilbakemelding er målt her, ikke et utsagn om modeller
generelt eller om samme modell i snitt.
* **Fiksturen er endret to ganger for å nå døra, og begge er deklarert i § 4.** Målingen i § 57 er
derfor ikke «09-04-oppsettet med levende modell», men «09-04-oppsettet med en begrunnelse som
oppgir kostlinja og uten det upriste arket». Radene 16 i § 4 er hva det uendrede oppsettet gjør.
* **Prisene i basen er SYNTETISKE** (`K2-priset-SYNTETISK`) — K2 som levert har ingen priser
(målt, S7b). Tallene 212 500 og 265 625 er derfor ikke besparelser i Stange skole-anbudet; de er
besparelser i en syntetisk prising av det. Det gjelder SC8 uansett hvilken modell som kjører.
* **`own-proposal` validerte aldri i noen kjøring.** Den fant ingen ekte kostkode i en eneste av de
ni kjøringene (`RIG01`, `Prosjektering`, `VENT-01`, `Steel`, `Architectural_Design` …). Systemets
eget forslag er dermed **umålt** mot review-døra; alt i § 56 gjelder `hypothesis-1`.
* **429-forespørsler er antatt ikke fakturert.** Det er Azures dokumenterte oppførsel, men det er
ikke verifisert mot en faktura her. Her er det uansett uten betydning: 0 stk. 429.
* **Prisene er LISTEPRIS**, hentet 06.09.2026. Rabatter og avtaler er ikke reflektert.
* **Måleharnesset er ikke gatet av suiten.** `scratchpad/major2-live/live_major2.py` er en
måleartefakt som enhver annen `scratchpad/`-profiler; den asserteres ingen steder. Det som ER
gatet er `src/`, som er urørt, og suiten som er kjørt etter (§ 9).
* **`max_attempts` er ikke eksponert på CLI-en**, så § 4s oscillasjons-funn er målt ved defaulten 3.
Om en høyere verdi ville latt modellen konvergere er **ikke** målt — å heve den ville krevd en
endring i `src/`.
---
## 9. Etterkontroll
Ingen fil under `src/` eller `tests/` er rørt (`git diff --stat -- src/ tests/` tom). Suiten og
golden-fasiten er kjørt etter dokumentendringen; tallene står i commit-meldingen og i `STATE.md`.
Alle måleartefakter — de ni kjøringenes `*-records.json`, utboksene og de to fikstur-variantene —
ligger utracket i `scratchpad/major2-live/`.