# Egnethetsreview → plan — funnene gjort varige, én økt av gangen
> **Hva dette er.** Fable-reviewen (2026-08-09, kjørt fra
> `2026-08-09-fable-egnethetsreview-prompt.md`) leverte funnene sine i et chat-transkript som
> forsvinner. Dette dokumentet er den varige formen: hvert funn i klarspråk, med belegget som
> produserte det, rangert som en plan `STATE.md` peker inn i økt for økt. Chatten kan glemmes —
> alt som trengs står her.
>
> **Slik brukes den:** `STATE.md`s «👉 NESTE»-blokk peker alltid på det ØVERSTE ulukkede
> P-punktet her. En økt lukker et punkt → setter ✔ med commit-hash HER → overskriver STATE.md →
> neste økt leser videre. **Demo-uke-planen (`2026-08-06-demo-uke-plan.md`) og innholdsgate-planen
> (`2026-08-09-innholdsgate-og-aerlighet.md`) BESTÅR uendret** — denne planen føyer review-funnene
> inn i samme løp og flytter ingenting som er besluttet (O1–O4 står).
>
> **Voyage:** småjobber (≤1 økt, kjent sti) kjøres direkte med `/tdd`-disiplin. Full
> Voyage-syklus (`/trekbrief → /trekplan → /trekexecute → /trekreview`) brukes der et punkt er
> merket **[Voyage]** — punktene med reell design-usikkerhet eller ≥2 økters bygging.
>
> **Revidert 2026-08-07 (planrevisjonen — seks innsigelser målt og avgjort, se §6):** ukas største
> måletekniske risiko (S4.0-forankringen) er flyttet fra tirsdag til helgen, stderr-beslutningen tas
> FØR pinningen, `[project.scripts]` er flyttet ut av frysedagen, tirsdag har fått abortsti, og
> demoen har fått en runbook-post (P4.5). **Datonote (I6):** filnavnets `2026-08-09` beholdes
> (omdøping koster lenker), men øktene dokumentet daterer til 08-08/08-09 ble committet
> **2026-08-06** (målt 08-07: `git show -s --format='%h %ad' --date=short c96ef90 0eb0f3d 295e966
> 688ee24 e93e921 d6f3359` → alle `2026-08-06`).
## 0. TO SPOR (operatørbeslutning 2026-08-09 — overordner rekkefølgen under)
Operatøren har delt uka i to spor. P-punktene under består, men hører nå hjemme slik:
### SPOR 1 — KOMPLETT VERSJON 1, klar til torsdag 13. (inkludert andre repo)
v1 = den **målte kjernen** (alle åtte steg wiret, 42 load-bearing-testfiler, 766/770 grønn —
inventaret i `2026-08-06-v1-inventory.local.md`) + to lukkinger + release-kuttet:
| Post | Innhold | Kost | Nedgradering hvis tid/kvote ryker |
|---|---|---|---|
| S1.a = **P1** | Steg 7-innboksen inn i demoløpet | 1 økt | ærlig etikett (0,1 økt) |
| S1.b = **P2** | Innholdsgaten (Spor B) | 1–2 økter | NEI-varianten i ærlighets-teksten (ferdigskrevet) |
| S1.c (ny) | **Release-kuttet:** versjon `1.0.0` synket FIRE steder (`pyproject`/`__init__`/`uv.lock`/`test_smoke`) + CHANGELOG (`[Unreleased]` → 1.0.0; Steg-5-API-endringen står alt der) + tag `v1.0.0` på begge remotes ETTER grønn generalprøve. *(`[project.scripts]` er flyttet videre til P4 pkt. 5 i HELGEN (I3): en ny entry point endrer install-flaten, så den må ligge FØR fresh-clone-målingen — aldri på frysedagen.)* | 0,5–0,75 økt (ons kveld) | tag fredag i stedet — aldri tag før grønn generalprøve |
**Andre repo — hva som faktisk MÅ gjøres der (målt, ikke antatt):**
- **commons:** energieksemplet MED `cost-baseline.json` — ALLEREDE bestilt (frist tir 11.,
coord `20260806T112037Z…`); GO/NO-GO tirsdag står. Reserven (mikro) gjør at v1 ALDRI
blokkeres av commons: **rammeverket er v1, innholdet er data.**
- **llm-ingestion-okf:** ingenting — pinnet `v0.3.2` gjennom v1 (målt at den holder).
- **guard-repoet:** ingenting — `v0.3.4` finnes, stdlib-only; wiringen skjer HER (S1.b).
- **po-claude:** PARKERT (ramme B) — v1 er MAF-siden alene, og det SIES i release-notatet.
→ **Ingen ny coord-melding trengs.** Alt andre-repo-arbeid er enten bestilt eller ikke nødvendig.
**Flagget konflikt (operatøren eier den):** O4 sier README-løftet kommer ETTER demoen (fre–lør).
Anbefaling: tag `v1.0.0` onsdag med nøktern README-status; nivå-2-påstanden inn i README fre/lør
som besluttet. Beviset først, påstanden etterpå — det gjelder også taggen.
**EKSPLISITT UTE av v1 (sies i release-notatet, ikke i en fotnote):** CLI-porteføljetak (P6),
commons-amendmentene (P7), metode-skillen (P8), bestiller-flaten (åpen beslutning i STATE),
bundle-fabrikken (O1), søsken-repoet (parkert), okf `v0.4.0`+.
### SPOR 2 — KOMPLETT OG OVERBEVISENDE DEMO av alle åtte steg
= **P3** (GO-dag + re-måling av kostnads-sjekken) + **P4** (forankret prøvekjøring +
fresh-clone-/stderr-/golden-kriterier + to ærlighets-setninger) + **P4.5** (demo-runbook, VED
frysen — I5) + generalprøven + én **muntlig** mandat-setning (bestillingsflyten er svaret
på «kan vi styre hva som analyseres?» — `docs/bestille-en-kjoring.md`).
**Stderr-dempingen er BESLUTTET (I2, 2026-08-07): JA — utføres i HELGEN som del av
P4-forskuddet, FØR stderr-pinningen** (demping etter pinning ville ugyldiggjort fasiten på
frysedagen). Målt 08-07: stderr er SEKS linjer — de fire støylinjene (to `ExperimentalWarning` +
to «forcing completion») pluss blanklinje + `arbeidskopi:`-linja, som er bevisst
ikke-deterministisk (`simulation.py:531-534`) og IKKE skal dempes. Dempingen rører ikke stdout
(kriterium 6). Faller den: NEI-fallback = pin de fire linjene som fasit, med
`arbeidskopi:`-linja normalisert på prefiks.
**Økt-regnskap for uka i dette repoet (revidert 08-07):** S1.a (1) + S1.b (1–2) +
S1.c (0,5–0,75) + P3 (0,25) + P4/generalprøve — utvidet med forankret prøvekjøring,
10 %-prøven, `[project.scripts]` og dempingen (0,75–1,25) + P4.5 runbook (0,25)
≈ **3,75–5,5 økter** på seks dager (fre 7.–ons 12., ny full ukeskvote). Totalen går opp med
slakk i normal drift (1–2 økter/dag). **Første kutt hvis den ikke gjør det: S1.b →
NEI-varianten i ærlighets-teksten** (nedgraderingskolonnen — ferdigskrevet, frigjør 1–2 økter,
og Spor B er ikke en frys-betingelse). Deretter gjelder nedgraderingskolonnen rad for rad —
v1 forblir ærlig komplett på hvert nivå, den blir aldri stille ufullstendig.
## 1. Funnene i klarspråk
Reviewen fant ingen brann i koden: suiten er grønn (766 passed / 4 skipped), demo-outputen er
byte-identisk over to kjøringer, og alle åtte steg har sin merkede linje. Det den fant, er fire
steder der **demoen lover mer enn den viser**, og noen hull i sikkerhetsnettet rundt torsdag.
**Funn 1 — kostnads-sjekken har aldri kjørt på ekte innhold.**
Validatoren KAN avstemme et forslag mot prosjektets faktiske kostnadstall (S4.0), men sjekken
aktiveres bare når kunnskapsbasen shipper `cost-baseline.json` — og **ingen demo-bundle under
`shared/examples/` har den fila** (målt, §4 rad 3). *(Korrigert 08-07, I1: den opprinnelige
formuleringen «ingen bundle i repoet» var målt for smalt — repoet shipper en fungerende,
format-definerende baseline-bundle i `src/portfolio_optimiser/data/bundles/bygg-energi-baseline-mikro/`,
i bruk av S4.0-testens målte mutasjoner, og kjørestien leser fila: `run.py:516`.)* I dagens demo
regner validatoren derfor kun på tall forslaget selv oppgir. Bestillingen til commons krever fila
(bra) — men slik planen sto, ville sjekken møtt ekte innhold FØRSTE gang på leveransedagen; avviker
manus-tallene mer enn 5 % fra de leverte kostnadstallene, avvises BÅDE det overdrevne og det
korrigerte forslaget på scenen. **Derfor er forankringen flyttet til helgen (P4 pkt. 0):** reserven
kan ikke få fila I `shared/` (pull-only subtree + kriterium 8 krever goldenene byte-uendret), men
det er en *plasserings*-begrensning, ikke en umulighet — demoen kjører uansett på en KOPI av
bundelen (`simulation.py:316`), så en repo-lokal kopier-og-utvid-variant gir en forankret kjøring
uten å røre commons. NO-GO-setningen i P4 pkt. 4 er omskrevet tilsvarende.
**Funn 2 — demoen sier «fil-innboks for ekspertdommer», men bruker den ikke.**
Steg 7-linja i demoen sier «lang fil-løkke». I virkeligheten leveres dommen som et
funksjonsargument — `simulate_learning_loop` kaller `run_project` uten `verdict_dir`
(§4 rad 4). Fil-innboksen finnes og er testet (`test_step7_async_loop_loadbearing.py`), men
demoen kjører den ikke. Dette er samme klasse som Steg 5 var før 7. august: **et steg som
omtales er ikke vist.**
**Funn 3 — «last ned og kjør» er aldri testet fra en fersk nedlasting.**
Ingen av de åtte demo-kriteriene kjører fra en ren klone. `uv.lock` finnes, så beviset er én
kommandosekvens — og den fanger miljøavhengigheter (`PORTFOLIO_SHARED_ROOT` re-peker
kunnskapsbasen!), utrackede filer og lokal `.venv`-drift.
**Funn 4 — små presisjonshull i det som sies og vises.**
Kjøring A kalles «fersk kunnskapsbase, ingen tidligere dommer», men bundelen shipper ett
dom-frø, og Kjøring B viser «2 dommer» der bare én kom fra sløyfa — én muntlig setning retter
det. Stderr-støyen (to warnings + to «forcing completion») er det første publikum ser.
**Etter demoen (feature-settet):**
- **Funn 5:** porteføljekjøring fra kommandolinja har ikke noe samlet token-tak — taket finnes i
biblioteket (`PortfolioMeter`, seks målte mutasjoner), men `main()` kobler det aldri på; koden
sier det selv (§4 rad 6).
- **Funn 6:** spec-gjelden mot commons/søskenet vokser — seks lokale semantikk-beslutninger er
uspeilet (D7-speiling ÅPEN i CLAUDE.md), og «rettferdig sammenligning» (A6) blir mindre sann
for hver av dem.
- **Funn 7:** «metoden som Agent Skill» er en CLAUDE.md-konvensjon uten realisering — kun
ekspert-personaen finnes (§4 rad 5).
- **Funn 8:** `[project.scripts]` mangler (release-hygiene, målbilde §11 pkt. 7).
- **Null-funn:** bytte av orkestrering (Sequential/Handoff/graf-laget/checkpointing) skal IKKE
gjøres — målt: debatten er i praksis en fast sekvens og Group Chat beholdes av byttekost-grunner,
gevinsten er kosmetisk, kostnaden er re-verifisering av hele offline-beviskjeden (§4 rad 7–8).
## 2. Plan FØR demoen (P1–P4, i utførelsesrekkefølge)
### P1 — Steg 7-innboksen kobles på i demoen ✔ (2026-08-09)
**[1 økt · Opus 5/high · TDD direkte · MÅ lande før onsdags-frysen]**
Rute persona-dommen gjennom en faktisk `verdict_dir`-katalog i `simulate_learning_loop` —
sømmene finnes allerede (`run_project(verdict_dir=…)` + `write_verdict` er offentlig primitiv).
Ny load-bearing-test: detach innboks-lesingen → markør-/Steg 7-linja endres → RØD. Kriterium 6
(byte-identisk stdout) måles på nytt etterpå.
**Faller den på tid:** minimumsvarianten = ærlig etikett i `_run_trace_lines` («dom levert
direkte her; fil-innboksen er samme søm, bevist i test») + én muntlig setning. 0,1 økt.
**UTFØRT — men IKKE slik punktet var formulert, og forskjellen er bærende.** Å rute
*persona-dommen* gjennom innboksen ville gitt ÉN markør på to veier: Steg 7 (innboks) og Steg 8
(promotering) ender begge i Run B's hypotese-prompt, så hver av dem kunne båret markøren alene —
og `test_simulation_loadbearing.py`s promoterings-assert ville stått GRØNN med promoteringen
detached. Punktet ville altså gjort en eksisterende load-bearing test vakuøs for å lukke seg selv.
Utført i stedet: en ANDRE dom, med sin egen markør (`realiseringsgrad=0.66`), skrives som fil med
`write_verdict` MELLOM kjøringene, og Run B får `verdict_dir=`. `simulate_learning_loop` raiser
`ValueError` hvis de to markørene er like. 766 → 769 grønne (773 kollektert).
- **Kriterium 6 re-målt:** stdout byte-identisk over to kjøringer (`diff` tomt). Stderr uendret
6 linjer. *(Lærdom: første stderr-måling ga 62 linjer — `2>&1 >/dev/null` under zsh MULTIOS
blander stdout inn. Formen som holder er `>/dev/null 2>fil`. Målefeilen, ikke koden.)*
- **Mutasjoner MÅLT mot hele suiten (~110 s hver), fire røde + grønn kontroll:** detach
`verdict_dir=` (2 røde) · la Run B lese en TOM mappe mens fila fortsatt skrives (2 røde) ·
markør = `realization_rate: 0.82`, målt til stede i dom-frøet (1 rød) · markør =
`energy performance gap`, målt til stede i en navigert konseptfil (1 rød) · godartet omdøping av
innboks-katalogen (grønn kontroll).
- **Ærlighets-grense funnet UNDER målingen:** de to siste mutasjonene felte
kausalitets-asserten (markøren finnes i bundelen), IKKE Run A-kontrollen — fordi
genererings-prompten bærer `Project: {id} - {name}` + debatt-outputen, ikke bundle-konteksten.
Run A-kontrollen kan altså ikke alene fange en bundle-tilstedeværende markør; det er
kausalitets-asserten som lukker det hullet. Paret holder, men det er verdt å vite hvilken av
dem som faktisk bærer hvilken egenskap.
- **Lærdom, samme klasse som 08-06:** første markør-mutasjon satte `realiseringsgrad=0.82` og gikk
GRØNN — bundelen bærer `realization_rate: 0.82`, ikke den strengen. Mutasjonen endret ingen
betingelse og beviste ingenting. En mutasjon må måles mot hva fila FAKTISK inneholder, ikke mot
hva STATE kaller verdien.
### P2 — Spor B: innholdsgaten ☐
**[1–2 økter · Opus 5/high · TDD direkte · følger innholdsgate-planen §3–§4 uendret]**
Reviewens skjerpelse, ellers ingen endring: §4-beslutning 2 (avvisning per dokument eller per
bundle?) tas FØR bygging, og innholdsgate-planens kriterium 5 (byte-uendret demo-stdout) måles
ETTER wiring. Målt frys-sikker: verken `run.py` eller `simulation.py` importerer `ingest`.
### P3 — GO/NO-GO + kostnads-sjekken (nå RE-måling, med abortsti) ✔ (2026-08-09, `02ddc67`) — **GO**
**UTFØRT SØNDAG 09.08, ikke tirsdag 11.** Rekkefølge-avviket er uttalt i STATE: commons leverte to
døgn før fristen, og et golden-transkript (P4 pkt. 3) pinnet mot RESERVEN ville blitt ugyldig i det
øyeblikk `main()` pekte på levert bundle. Å pulle først gjør pkt. 3 én gang i stedet for to.
**Abortstien ble fulgt i rekkefølge.** Pre-pull-hash `7acd331` notert FØR pull (verifisert med
`git rev-parse`, ikke lest fra STATE). Pull av `002f000`+`27cdce9`. **Kriterium 8 grønt, målt to
uavhengige veier:** `git diff --stat` på begge nav-golden-katalogene → tomt, OG `shasum -c` mot et
pre-pull-manifest → 15/15 OK. Full suite etter pull: 785 passed / 4 skipped — identisk med før.
Ingen reset, ingen NO-GO. Pullen var ren tilføyelse pluss ÉN endret fil (`ingest-spec.md`, se
åpent punkt under).
**(b) Retningen er snudd.** `_CANDIDATES` har nå en `VEGLYS-FV-SOER`-oppføring hvis kostlinjer er
skrevet FRA `shared/examples/veglys-fv-soer/cost-baseline.json`; `baseline_from_scripted_candidate`
brukes IKKE på denne stien (`main()` leser levert fil via `okf.load_optional_cost_baseline`). Det
korrigerte svaret ER den leverte IR-projeksjonen ordrett — inkludert `assumptions`-bandet, så
Monte Carlo-en er ekte og ikke degenerert.
**(4) Overdrivelsen: `2 100 000`.** Målt fraværende fra bundelen (også som `2 100 000`/`2.100.000`),
og over BEGGE terskler — målt P90 er **1 769 915** (commons' anslag var ~1 770 000; vår seedede MC er
fasit, og de traff). `600 000`/`900 000` ville klarert gaten.
**(a) Demo-kriterium 1+2 mot NY bundle:** åtte steg-linjer står; hypotese #1 REJECTED
(`2100000 exceeds P90 feasible 1769915`) og den korrigerte VALIDATED (`445500`) — samme kandidat,
og det er P90-stagen som feller, ikke stage 0. Begge læringsveiene lukkes også på levert innhold
(Steg 8-markøren og Steg 7-innboksmarkøren når begge Kjøring B's prompt; Kjøring A har ingen).
**(c) 10 %-prøven mot levert innhold** er `test_a_deviating_delivered_baseline_forkaster_the_run_before_the_solver`:
levert baseline avviket 10 % → FORKASTET i stage 0 med avstemmings-grunnen, ikke P90-grunnen.
**Måling felte en defekt reserven skjulte:** `:g` slår over i eksponentform ved 7. signifikante
siffer, så den leverte baselinen printet `4.38615e+06`. Reservens `300000` har seks siffer og nådde
aldri overgangen — syntetiske tall skjulte den, levert innhold avslørte den på FØRSTE kjøring.
`_num` erstatter `:g` begge steder.
**Load-bearing MÅLT mot hele suiten, fem mutasjoner alle røde + grønn kontroll:** detach
main-wiringen · reverter `_num` til `:g` · drift registeret ETT siffer (`4386151` — innenfor
5 %-toleransen, og fanget av **ingenting i 792 tester** bortsett fra den nye) · sett `flip_key` til
et token som finnes i bundelen · detach forankringen på bundle-stien. 785 → 793.
**Abortstien står fortsatt:** reserven har sin registeroppføring, og `materialize_anchored_bundle`
er urørt — NO-GO er tre linjer i `main()`.
Planteksten slik den sto før utførelse
**[0,25 økt, del av tirsdagsøkta · Opus 5/medium]**
Som demo-uke-planen — men etter planrevisjonen 08-07 (I1) er dette en **re-måling mot nytt
innhold, ikke førstegangskjøring**: S4.0-forankringen og 10 %-avviks-prøven kjøres første gang i
HELGEN mot den lokalt forankrede reserven (P4 pkt. 0). Tirsdag: (a) kjør demo-kriterium 1+2
(åtte steg-linjer; REJECTED- og VALIDATED-linje for samme kandidat) mot den NYE bundelen;
(b) skriv manus-registerets tall FRA den leverte `cost-baseline.json`, aldri ved siden av den;
(c) gjenta 10 %-prøven mot levert innhold (mekanismen er alt bevist — dette måler INNHOLDET):
bevisst avvik → FORKASTET; korrigert → FORESLÅTT.
**Abortsti (I4, ufravikelig rekkefølge):** (1) FØR pull: noter `git rev-parse HEAD` i STATE;
(2) pull → kriterium 8 (`git diff --stat` på goldens → tomt) + full suite; (3) rødt utfall →
`git reset --hard ` (squash-pullen er lokale commits uten push — resetten fjerner
dem helt) og NO-GO er UTLØST — **senest kl. 18:00 tirsdag, uten videre diskusjon**: reserven ER
demoinnholdet (den forankrede varianten fra helgen), ærlighets-setningen per P4 pkt. 4. NO-GO er
et planlagt utfall, ikke en krise — generalprøve nr. 0 mandag har allerede verifisert det.
### P4 — Forankret prøvekjøring + fire kriterier + to setninger (FORSKUTTERES i helgen; onsdag gjenstår kun re-måling mot valgt innhold) ☐
**[0,75–1,25 økt · Opus 5/low–medium · alt under bygges/måles mot mikro-reserven i helgen — se §5]**
0. **Forankret prøvekjøring ✔ (2026-08-09)** — se UTFØRT-blokka under punkt 5.
**(NY 08-07, I1 — ukas største måletekniske risiko, nå TIDLIGST):**
lag en repo-lokal kopier-og-utvid-bundle — mikro-reservens innhold + `cost-baseline.json` i
S4.0-formatet fixturen definerer (`project_id` + `items{code:{quantity,unit_cost}}`), med
baseline-tall avledet FRA manus-registerets tall (samme disiplin som P3 b, speilvendt). Kjør
HELE demoløpet mot den: `simulate_learning_loop` tar `bundle_dir` som argument og kopierer den
(`simulation.py:280/:316`), og `run.py:516` leser fila. Inkluder 10 %-avviks-prøven (flyttet hit
fra P3): bevisst avvik → FORKASTET i stage 0; korrigert → FORESLÅTT. Ligger utenfor `shared/` →
kriterium 8 urørt; kriterium 6 er selv-identitet og påvirkes ikke. Ved NO-GO tirsdag kjører
demoen denne varianten (call-site-valg i `main()` — samme søm GO-utfallet uansett bruker).
**Faller den:** fallback = uforankret reserve + den gamle NO-GO-setningen — ingenting tapt mot
planen slik den sto før revisjonen.
1. **Fresh-clone-kriterium ✔ (2026-08-09, `ab7f45a`)** — se UTFØRT-blokka under punkt 5.
2. **Stderr: FØRST beslutningen, SÅ pinningen (I2) ✔ (2026-08-09, `ab7f45a`)** — beslutningen er
tatt og målt; se UTFØRT-blokka under punkt 5. **Konsekvens for pinningen (pkt. 3):** fasiten kan
IKKE være literal — de to gjenstående `ExperimentalWarning`-linjene bærer en absolutt sti inn i
`.venv/…/site-packages`, som er ulik i fersk klon og arbeidskopi (målt). Normaliser på BEGGE:
site-packages-stien OG `po-sim-`-suffikset. Pinnet stderr er da fire linjer, ikke to.
3. **Golden-transkript:** sjekk inn demo-outputen som fasit-fil og diff mot den — selvidentitet
(kriterium 6) fanger ikke-determinisme, men ikke regresjon mellom onsdag og torsdag.
**Transkriptet er også demoens abortsti** (gjort eksplisitt i P4.5).
4. **To ferdigskrevne setninger** inn i ærlighets-teksten (mønsteret fra innholdsgate-planen §5).
NO-GO-varianten er OMSKREVET etter I1: «kostnads-forankringen er aktiv også i reserve-eksemplet,
men kostnadstallene der er syntetiske — avledet av manuset, ikke levert av et fagmiljø»
(fallback hvis pkt. 0 faller: den gamle setningen «kostnads-forankringen er ikke aktiv i
reserve-eksemplet»). Frø-setningen står: «én av de to tidligere dommene i Kjøring B fulgte med
eksempelet — den andre er den demoen lærte».
5. **`[project.scripts]` (flyttet HIT fra S1.c, I3) ✔ (2026-08-09, `ab7f45a`)** — se UTFØRT-blokka
rett under.
**UTFØRT — punkt 5, 2 og 1 (2026-08-09, `ab7f45a`). 775 → 785 passed / 4 skipped.**
*Punkt 5:* to konsoll-kommandoer — `portfolio-optimiser` (`run:main`) og `portfolio-optimiser-demo`
(`simulation:main`). **Bevisst to av fem `main()`:** `costsim`/`hitl`/`preflight` beholder
`-m`-formen; hvert navn her er et navn frysen må bære. Testen leser den INSTALLERTE distribusjonens
metadata, ikke TOML-en — en `[project.scripts]`-linje som aldri er `uv sync`-et er en påstand, ikke
en kommando. Målt: stdout er byte-identisk mellom `uv run portfolio-optimiser-demo` og
`uv run python -m portfolio_optimiser.simulation`.
*Punkt 2 — den åpne beslutningen, avgjort ved måling:* **rund-taks-linjene dempes, de to
`ExperimentalWarning`-linjene gjør det ikke.** Loggeren er lest ut av MAFs kilde
(`logger.warning` i `_base_group_chat_orchestrator`), ikke gjettet; filteret er nøklet på MELDINGEN
og installeres i `main()`, aldri ved import. **Hvorfor de to andre ikke dempes:** de fyrer mens
`portfolio_optimiser/__init__.py` importerer `run` → `agent_framework` — alltid FØR `simulation` sin
egen importblokk, under BEGGE kjøreformer. Å dempe dem ville krevd et warnings-filter inne i
bibliotekpakken, altså at rammeverket bestemmer hva MAF får si til enhver konsument. En wrapper bak
konsoll-kommandoen ble avvist av en andre grunn: de to kjøreformene ville da skrevet ULIK stderr, og
en byte-fasit ville pinnet kommandoen i stedet for programmet. **stderr 6 → 4 linjer.**
*Første implementasjon ble FJERNET etter måling:* en scoped mute rundt `simulation`s egen
`agent_framework`-import kan aldri fyre (pakken har allerede importert den) — en grønn-men-død søm.
*Punkt 1 — fresh-clone, målt mot `ab7f45a`:* klon fra `origin` → `uv sync` → `uv run
portfolio-optimiser-demo`. **stdout byte-identisk** med arbeidskopien; stderr identisk normalisert
på site-packages-sti + `po-sim-`-suffiks. READMEens egen verifikasjon kjørt i klonen: **785 passed /
4 skipped**. *(Merk: `open/`-speilet står fortsatt på `520e7412` = `v0.1.0` — publisering dit er
S1.c onsdag, ikke en del av denne målingen.)*
**Load-bearing MÅLT mot HELE suiten, fem mutasjoner alle røde + grønn kontroll:** fjern
`[project.scripts]` · typo i target · detach `main()`-kallet · la filteret droppe alt · installer
filteret ved import. **Typo-mutasjonen felte en TEST:** resolve-asserten resolverte det FORVENTEDE
targetet mot seg selv; den leser nå det distribusjonen faktisk installerer. Fjerde gang på fem økter
at mutasjonsmålingen feller testen, ikke koden.
**UTFØRT — punkt 0 (2026-08-09).** `materialize_anchored_bundle` kopierer reserven og legger til
`cost-baseline.json` utenfor `shared/`; `main()` kjører den varianten, og hele demoløpet er kjørt
mot den. **Baselinen avledes i KODE fra manus-registeret** (`baseline_from_scripted_candidate`),
ikke skrevet ved siden av det — på GO-dagen snus retningen (punkt b i P3), og en håndskrevet kopi
ville vært den andre kilden som drifter. Begge skriptede svar må oppgi samme kostlinjer, ellers
`ValueError`: var de ulike, ville hypotese #1 blitt avvist av stage 0 istedenfor av P90, og demoens
REJECTED-linje kommet fra en annen mekanisme enn den den forteller om.
**10 %-prøven, målt:** bevisst avvik (baseline ×1,10) → `FORKASTET — quantity 300000 for cost code
'ENERGI-TOTAL-EL' is outside the 5.0% tolerance around the baseline quantity 330000`, i stage 0,
FØR løseren. Korrigert (manus = baseline) → `FORESLÅTT — LED-retrofit av kontorbelysning: 30000 NOK`.
Kontroll: hypotese #1 avvises fortsatt av P90-stagen, så demo-kriterium 2 viser samme mekanisme som
før. Suite 769 → 775 passed / 4 skipped.
**Kriterium 6 re-målt:** stdout byte-identisk mellom to kjøringer; stderr uendret 6 linjer. Eneste
diff mot uforankret demo er den nye fire-linjers KUNNSKAPSBASE-blokka — **alt annet er
byte-identisk, og det er selve problemet:** forankringen er usynlig, derfor må den printes, og
derfor er `provenance` et påkrevd argument (kallstedet som velger bundelen er det eneste som vet
hvor tallene kom fra). Punkt 4s NO-GO-setning står nå ordrett på skjermen.
**Målingen felte TESTEN først.** Første form av entry-point-testen asserterte
`"kostbaseline erklært" in stdout` — men den uforankrede grenen sa «ingen kostbaseline erklært»,
som INNEHOLDER strengen; og `ENERGI-TOTAL-EL` står allerede i Steg 2-linja. Detach-mutasjonen gikk
GRØNN. De to grenene deler nå ingen ordlyd, og asserten navngir hele linja. Fem mutasjoner røde +
grønn kontroll (`tests/test_anchored_reserve_loadbearing.py`).
**GO-dagens endring er ÉN blokk i `main()`:** `bundle = materialize_anchored_bundle(...)` +
`provenance = _RESERVE_PROVENANCE` byttes mot den leverte bundelens sti og dens egen provenans.
Kjørestien er uendret — `run.py` leser baselinen fra hvilken som helst bundle-katalog.
### P4.5 — Demo-runbook: ÉN side operatøren følger på scenen (NY 08-07, I5) ☐
**[0,25 økt · Opus 5/low · produseres VED frysen onsdag, ETTER generalprøve ×2 — så den matcher frosset output]**
Det som skal SIES torsdag ligger i dag på fire steder: demo-uke-planen §1 (tre ærlighets-punkter),
innholdsgate-planen §5 (opplesnings-avsnittet), P4 pkt. 4 (to setninger) og §0 Spor 2 (muntlig
mandat-setning). Runbooken samler dem på én side: kjøresekvens (kommandoen + forventede
steg-linjer), hva som sies hvor, og **abortstien**: feiler live-kjøringen, vis golden-transkriptet
fra P4 pkt. 3 og si høyt at det er gårsdagens frosne kjøring. Sti:
`docs/plan/2026-08-12-demo-runbook.md` (datert sti — utenfor `_LIVE_DOCS`-gaten). Runbooken er
lesestoff, ikke kjøresti — den kan skrives etter frysen uten å røre den.
## 3. Plan ETTER demoen (P5–P10, i verdirekkefølge)
### P5 — README + nivå-2-påstanden (O4, fre 14.–lør 15.) ☐
**[1 økt · Opus 5/medium]** Allerede besluttet (O4). Reviewens tillegg: G5-forbeholdet skal stå
i teksten som løftes — sammenligningen mot søskenet gjelder den spec-ede kjernen, ikke hele
dette repoet (mandat/hovedbok/portefølje-budsjett m.m. er utenfor spec-ene, målt 0 treff).
### P6 — Globalt token-tak inn i CLI-en ☐
**[1 økt · Opus 5/high · TDD direkte]** `--budget`-dør i `main()`: `PortfolioMeter` +
`read_spend`/`write_spend`-wiring + `BudgetRefused` inn i except-tuplen (TRAP-kommentaren i
`run.py` sier selv at den ikke fanges i dag). Feller: CLI-test med spend-fil nær taket +
`--portfolio` → strukturert refusal; detach flagget → rød.
### P7 — Amendment-pakken til commons — ÉN samlet bestilling ☐
**[1 økt · Fable 5/high (spec-review er formen) · leveres via coord-send, ALDRI arbeid i commons]**
D-A-restene samlet i én tekst: F2/F3-validator-semantikken, S3.2-seedingregelen,
S4.0-baseline-formatet, (p)-kvantiseringen, Steg-5-returtypen. Feller: amendmentet gir
spec-tester/goldens som binder semantikken på tvers av stackene — i dag kan søskenet følge
spec-en korrekt og likevel divergere fra dette repoet.
### P8 — Metoden som Agent Skill (B6) ☐ **[Voyage]**
**[/trekbrief først; bestilling til commons + liten konsum-søm her]** Målt: kun
`shared/skills/expert-reviewer/SKILL.md` finnes. Innholdet eies av commons (bestilling som
tekst); konsum-sømmen her er liten (MAF `SkillsProvider` er experimental — pin versjon).
[Voyage] fordi formen har reell design-usikkerhet — hva av metoden som skal være skript vs.
referanse er ikke avgjort.
### P9 — Småting ☐
**[0,5 økt samlet · Opus 5/low]** Kapabilitetskartets to korreksjoner (topologi-notatet fra
funn «null»: debatten er en fast sekvens, Group Chat beholdes av byttekost; checkpointing-raden
nedgraderes fra «ADOPT (later)» til «NEI med begrunnelse» — pass-nivå-gjenopptakelse er allerede
levert via spend-fila). *(`[project.scripts]` er flyttet inn i v1-release-kuttet, §0 S1.c.)*
### P10 — Eksplisitt NULL (ingen økt) ✔
Ingen Sequential-swap, ingen Handoff, ingen graf-adopsjon, ingen checkpointing. Står her så
ingen senere økt «oppdager» dem på nytt. Falsifisering av selve null-beslutningen: forsvinner
«forcing completion»-linjene en dag uten bytte, var topologi-analysen feil.
## 4. Belegg (kommandoene bak påstandene — RE-MÅLT 2026-08-07 på HEAD `bb3df79`; opprinnelig måling 2026-08-06, se datonoten øverst)
| # | Påstand | Kommando → resultat |
|---|---|---|
| 1 | Suiten grønn | `uv run pytest -q` → 766 passed / 4 skipped (107 s) — re-målt 08-07 |
| 2 | Demo deterministisk + 8 steg | to kjøringer 08-07, stdout adskilt fra stderr: `diff` → tom; `grep -cE "^ *Steg [1-8]"` → 8. Stderr målt: **6 linjer** — 2 `ExperimentalWarning` + 2 «forcing completion» + blanklinje + ikke-deterministisk `arbeidskopi:`-linje (bevisst, `simulation.py:531-534`) |
| 3 | **(KORRIGERT 08-07, I1)** Ingen bundle under `shared/examples/` shipper kostbaseline — men REPOET gjør, og kjørestien leser den | `ls shared/examples/bygg-energi-mikro/` → 8 filer, ingen baseline (re-målt, står — men var målt for SMALT: én katalog). `find . -name 'cost-baseline.json' -not -path './.git/*'` → `src/portfolio_optimiser/data/bundles/bygg-energi-baseline-mikro/cost-baseline.json` (gyldig S4.0-format, merket SYNTHETIC); i bruk: `grep -n BASELINE_BUNDLE tests/test_s40_cost_baseline_loadbearing.py` → `:42/:162/:242`; kjørestien: `run.py:516` `load_optional_cost_baseline`; bundelen er kopiert parameter: `simulation.py:280/:316` |
| 4 | Steg 7 vises uten fil-innboksen | re-målt 08-07: `run_project` kalles uten `verdict_dir` (`simulation.py:328-338/:356-366`); dommen er argumentet `verdict_input` (`:322`); etiketten «lang fil-løkke» står i `:478` |
| 5 | Metode-skill finnes ikke | `find shared -name "SKILL.md"` → kun `expert-reviewer` (re-målt 08-07) |
| 6 | CLI-porteføljen uten pass-tak | `run.py:1679-1686` (re-lest 08-07): budget-stop-armen «currently UNREACHABLE from here»; TRAP-kommentar: `BudgetRefused` (RuntimeError) utenfor except-tuplen |
| 7 | Debatten er en fast sekvens | `workflow.py:99-108` (re-lest 08-07): round-robin-selector, terminerings-nett = `max_rounds*2+1` = 7 > 3 dispatcher → fyrer aldri; «forcing completion» ×2 målt i dagens stderr |
| 8 | MAF-alternativene gir ikke gevinst | re-målt 08-07: installert `_group_chat.py:145-155` har round-robin kun som docstring-eksempel; `inspect.signature(SequentialBuilder.__init__)` → `checkpoint_storage` direkte. *(Handoff = modelldreven ruting: 08-06-introspeksjonen, ikke re-målt)* |
| 9 | `[project.scripts]` mangler — bygges i HELGEN (P4 pkt. 5, I3) | `grep -n scripts pyproject.toml` → 0 treff (re-målt 08-07) |
| 10 | Spor B er frys-sikker | `grep -nE '^(from\|import).*ingest' src/portfolio_optimiser/{run,simulation}.py` → 0 treff (re-målt 08-07, skarpere grep — treffene som finnes er kommentarer/hjelpetekst, ingen import) |
| 11 | (NY 08-07) Begge baseline-loaderne finnes | `grep -n 'def load_optional_cost_baseline\|def load_cost_baseline' src/portfolio_optimiser/okf.py` → `:305` + `:323` |
| 12 | (NY 08-07, I6) Daterings-avvik | `git show -s --format='%h %ad' --date=short c96ef90 0eb0f3d 295e966 688ee24 e93e921 d6f3359` → ALLE `2026-08-06`; `date` → 2026-08-07 (fredag); 13. aug = torsdag |
## 5. Ukens kalender (hvor punktene lander)
**Justert fre 7. aug (operatør): arbeid starter I DAG, helg inkludert, ny full ukeskvote —
full sti er hovedsporet, nedgraderingene i §0 er forsikring.** Prinsippet bak fordelingen:
alt som IKKE krever det nye commons-innholdet gjøres FØR tirsdag, så tirsdag/onsdag er tynne
og risikoen ligger tidlig med slakk bak seg.
| Dag | Innhold |
|---|---|
| fre 7. | **Planrevisjonen (I1–I6)** ✔ + **P1/S1.a**: Steg 7-innboksen inn i demoløpet (økt 1) |
| lør 8.–søn 9. | **P2/S1.b**: innholdsgaten (økt 2, evt. 3) + **P4-forskuddet UTVIDET** (0,75–1,25 økt), i denne rekkefølgen: forankret prøvekjøring + 10 %-prøven (pkt. 0, I1) **✔ 08-09** → `[project.scripts]` (pkt. 5, I3) → stderr-demping FØR pinning (pkt. 2, I2) → fresh-clone (pkt. 1) → golden-transkript-mekanikk (pkt. 3) → de to ærlighets-setningene (pkt. 4) — alt bygges og måles mot den FORANKREDE mikro-reserven NÅ |
| man 10. | **Generalprøve nr. 0 mot forankret reserve**: alle kriterier ende-til-ende → NO-GO-utfallet er ferdig verifisert FØR tirsdag; rest-slakk er buffer |
| tir 11. | **P3**: noter pre-pull-hash → subtree pull → GO/NO-GO (**abortsti I4:** rød suite/goldens → `git reset --hard ` + NO-GO senest **kl. 18:00**) + RE-måling: kriterium 1+2 mot NY bundle; manus-tall skrives FRA levert `cost-baseline.json`; 10 %-prøven gjentatt; goldens byte-uendret |
| ons 12. | **P4** re-målt mot valgt innhold → generalprøve ×2 → **FRYS** → **P4.5: demo-runbook (I5)** → **S1.c: versjonssynk + CHANGELOG + tag `v1.0.0`** (uten `[project.scripts]` — den ligger i helgen, I3) |
| tor 13. | **DEMO = v1 vises** (runbooken i hånda) |
| fre 14.–lør 15. | **P5**: README (O4) |
| deretter | **P6 → P7 → P8 → P9**, ett punkt per økt; STATE.md peker på øverste åpne |
## 6. Planrevisjonen 2026-08-07 — seks innsigelser, avgjørelser med belegg
Kjørt på Fable 5/xhigh uten advisor; hvert premiss fra innsigelses-prompten er derfor re-målt i
økta med egne kommandoer (§4 + kolonnen her) — ingen tall er gjenbrukt.
| # | Innsigelse | Avgjørelse | Nøkkelmåling (kjørt 08-07) |
|---|---|---|---|
| I1 | Funn 1 målt for smalt; «reserven kan aldri få fila» feil som formulert | **TAS INN** — forankret prøvekjøring + 10 %-prøve flyttet til helgen (P4 pkt. 0); §1/§4 korrigert | `find . -name 'cost-baseline.json'` → fixturen finnes (gyldig S4.0-format); `run.py:516` wirer loaderen; `simulation.py:280/:316` — bundelen er kopiert parameter |
| I2 | Demping (ons) etter pinning (helg) ugyldiggjør fasiten | **TAS INN, SKJERPET** — beslutning JA tatt nå; demping i helgen FØR pinning; målt at stderr uansett trenger definert form | to sim-kjøringer: stderr = **6** linjer, ikke 4 — `arbeidskopi:`-linja er ikke-deterministisk (`simulation.py:531-534`) |
| I3 | `[project.scripts]` på frysedagen endrer install-flaten ETTER fresh-clone-målingen | **TAS INN** — flyttet til P4 pkt. 5 (helg), FØR fresh-clone; S1.c = synk + CHANGELOG + tag | `grep -n scripts pyproject.toml` → 0 treff |
| I4 | Tirsdagens pull mangler avbruddssti | **TAS INN** — pre-pull-hash + reset-regel + NO-GO senest kl. 18:00 skrevet inn i P3 og §5 | kriterium 8 finnes (demo-uke-plan §5 pkt. 8, lest 08-07), men ingen revert-regel sto i noe dokument |
| I5 | Ingen demo-runbook allokert | **TAS INN** — ny post P4.5 (0,25 økt, VED frysen); golden-transkriptet gjort eksplisitt til abortsti | de fire spredte kildene bekreftet (demo-uke-plan §1, innholdsgate §5, P4 pkt. 4, §0 Spor 2 — lest 08-07) |
| I6 | Datoene ligger 2–3 dager fram i tid | **TAS INN** — §4 re-datert til faktisk måling; STATE-loggen korrigert; filnavnet står med datonote | `git show -s --format='%h %ad'` → alle refererte commits `2026-08-06`; `date` → 2026-08-07 (fredag) |
**Avvist: ingen.** I1s mot-spørsmål ble målt, ikke antatt: ingen kollisjon med
`_default_bundle_dir()`/`PORTFOLIO_SHARED_ROOT` (bundelen er et funksjonsargument, og demoen
kjører på en kopi — `simulation.py:280/:316/:492`), ingen kollisjon med kriterium 6
(selv-identitet: en forankret kjøring diffes mot seg selv) eller kriterium 8 (den lokale bundelen
ligger utenfor `shared/`), og syntetisk forankring beviser MEKANISMEN live — tall-ærligheten
dekkes allerede av nivå 2-regelen (demo-uke-planen §1 pkt. 3) og fixture-notatet «SYNTHETIC».
Kostnaden (~0,25–0,5 økt ekstra i helgen) er dekket av ny full ukeskvote og kjøpes tilbake ved at
tirsdag/onsdag blir tynnere.