docs(review): full-paritet review + sesjonsplanverk + beslutningsbrief (Fable 5 + 6 Opus-agenter)

Operatør-mandat 2026-07-16: full MAF-paritet (D-G pkt. 2). Review-økt, ingen kildekode.

- review-paritet.md: C-serien re-verifisert (alle åpne), 10 nye R-funn. Kjørt-bevist av
  orkestrator: R-2 (Infinity → validates=True, NaN avvist), R-3 (tom CSV krasjer ingest →
  delvis bundle). R-1 = §11-raden «Closed loop» ubundet. 4/4 detach røde i throwaway-kopi;
  SDK-premisser holder mot 0.2.110→0.2.120; model-id gyldig+billigst; docs §1-ærlige.
- sesjonsplan-paritet.md: ERSTATTER 2026-07-10-planen. 35-raders paritetsmatrise (opphevet
  «Overføres IKKE»-lista, re-klassifisert rad for rad). 16 ugatede sesjoner + gatede med
  eksakte utløsere + avhengighetsgraf + binær leveringsklar-sjekkliste.
- beslutningsbrief.md: operatør-køen i klarspråk (D-A+C-P1, amendment, toolkit-§8, D-B,
  + nytt foreslått delt punkt).
- 2026-07-10-sesjonsplan-d7.md: superseded-merket med peker.

Steg 0 verifisert: commons-amendment IKKE landet, okf-toolkit-repo finnes IKKE.
STATE.md er local-only (gitignored) — ikke committet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-07-16 08:36:07 +02:00
commit d746891f06
4 changed files with 1254 additions and 1 deletions

View file

@ -0,0 +1,751 @@
# Sesjonsplan — full MAF-paritet (K-serien + videreførte C-sesjoner · delt kø D-AD-E)
> **Status:** GJELDENDE sesjonsplan for dette repoet. ERSTATTER
> [`2026-07-10-sesjonsplan-d7.md`](2026-07-10-sesjonsplan-d7.md) (markert superseded med peker
> hit). Forfattet 2026-07-16 (Fable 5, review-/plan-økt) på operatør-mandatet **FULL
> MAF-PARITET** (D-G pkt. 2: «Claude-repoet skal være minst like godt som MAF-repoet»,
> operatør-besluttet 2026-07-16). Den gamle planens §4-liste «Overføres IKKE hit
> (MAF-spesifikt)» er **OPPHEVET som blanko-unntak** — hvert punkt er re-klassifisert i
> paritetsmatrisen (§1). Ingen stille kutt.
>
> Funn-referanser: C-serien peker til [review 2026-07-10](review-2026-07.md); R-serien til
> [review-paritet 2026-07-16](2026-07-16-review-paritet.md); MAF-referansene (S2.0S5.4,
> D-AD-I, M1M3, T0) til hovedrepoets `docs/plan/2026-07-10-sesjonsplan-fase2-6.md`,
> `2026-07-14-revisjonspakke-DF-DI.md`, `2026-07-14-commons-amendment-utkast.md` og
> `2026-07-14-toolkit-repo-brief.md` — lest på KAPABILITETS-/PLAN-nivå; MAF-kildekode leses
> aldri (D7-regelen står for metode-laget; D-G endrer den bevisst KUN for OKF-formatlaget,
> og kun via okf-toolkit når det finnes).
>
> Prinsipp (uendret): hver bygg-sesjon er én-sesjons-stor, offline, gratis (ScriptedClient),
> TDD (Iron Law: failing test først), load-bearing (§11: detach-punkt per søm), og
> **Opus 4.8 xhigh-eksekverbar** med «Les STATE.md og følg instruksjonene». Ingen
> live-kjøringer: D6 står — S10 var programmets ene; ny spend krever eksplisitt
> operatør-godkjenning (M2-analogen §6 er operatør-milepæl, aldri autonom sesjon).
> «Suiten kjører uten nøkkel/nett» er invariant i ALLE sesjoner under.
---
## 0. Faktisk gate-status ved planleggingstidspunktet (verifisert 2026-07-16)
| Gate | Status | Belegg |
|---|---|---|
| D-AD-E (delt kø) | ÅPNE | MAF-plan §2 + MAF-STATE 2026-07-16 («Operatør-kø uendret») |
| D-FD-I | BESLUTTET 2026-07-14 | revisjonspakka (fasit) |
| Commons-amendment (D-F/D-G-utkastet) | **IKKE landet** — utkast venter operatør | subtree-diff `HEAD:shared``commons/main`: kun `.gitignore` + guard-adopsjonsdoc, ingen spec-endring |
| okf-toolkit-repo (T0) | **Finnes IKKE** | `ls ~/repos/okf-toolkit` + `git ls-remote` mot Forgejo → not found |
| MAF-fremdrift | Fase 1 + Fase 2-bolk A (S2.0/S2.1/S2.5) + S3.6 + S4.1 + S4.2 + S5.1 komplett; S5.2 EXECUTE neste; suite 389 | MAF `STATE.md` 2026-07-16 07:40 |
| Dette repoet | 265 passed offline · ruff/mypy rene · HEAD `b46f32c` == origin/main; open @ `42f320b` | kjørt i Steg 0 (review-paritet §0) |
| `shared/`-subtree | 2 commons-commits bak (docs-only) | samme diff; hentes ved neste koordinerte pull — ingen spec-endring, ufarlig |
Planen bygger på DENNE statusen. Endres gate-status (amendment lander, toolkit-repo opprettes),
gjelder §4-sesjonenes utløser-tekst, ikke antakelsene her.
## 1. Paritetsmatrise MAF ↔ D7 (kapabilitetsnivå)
Kilde: MAF-planene/STATE (aldri MAF-src). Klassifisering: **FINNES HER** (kapabiliteten er
bygget og testet i dette repoet) / **BYGGBAR NÅ** (ingen beslutnings-gate) / **GATED**
(navngitt gate) / **SPEILES IKKE** (etterprøvbar begrunnelse). Alle den gamle planens
«Overføres IKKE»-punkter er re-klassifisert her; ingen rad er stille droppet.
| # | Kapabilitet (MAF-referanse) | MAF-status | D7-status i dag (belegg) | Klassifisering | D7-sesjon |
|---|---|---|---|---|---|
| 1 | Dimensjons-begrep + katalog (Fase 1 / D-F pkt. 5 / amendment §13.3) | Bygget (Fase 1); katalog spec-es av amendmenten | MANGLER — ingen dimensjons-modell i src (filkatalog) | **GATED: commons-amendment (D-F)** — katalog-kontrakten blir spec (§13.3); bygges fra spec-en når den lander, ikke fra utkast | K13 |
| 2 | Mål-kontrakt (absolutt/prosent, hard/soft, stopp ved mål) (Fase 1) | Bygget; prosent-baseline åpen (D-E) | MANGLER | **BYGGBAR NÅ** (absolutt + hard/soft); prosent-baseline-semantikken alene er **GATED: D-E** | K1 |
| 3 | Besparelses-hovedbok (typet ledger, fail-closed `realize`-ekspertgate, provenance) (Fase 1) | Bygget | MANGLER | **BYGGBAR NÅ** (stack-lokal — MAF bygde den også uten delt spec) | K1 |
| 4 | Portefølje-kjøring (flere prosjekter, referanse-konfig, sekvensiell) (Fase 1) | Bygget | MANGLER — eneste kjøresti er `run_s10.py` (én bundle, fasit-frossen) | **BYGGBAR NÅ** | K2 |
| 5 | Portefølje-læringssløyfe — dom på prosjekt k når k+1s prompt (S2.0) | **FERDIG** (bolk A) | MANGLER (ingen portefølje-sti; primitivene finnes: store/fold/inbox) | **BYGGBAR NÅ** (etter K2) | K3 |
| 6 | Offline closed-loop-bevis — to-kjørings-simulering m/ markør (method-spec §11-raden «Closed loop»; MAF-original) | Bygget (originalbygget, `test_simulation_loadbearing`-raden) | **MANGLER** — step7/step8-testene beviser hver sin halvdel; ingen test kjører markøren gjennom to komponerte kjøringer (funn **R1**) | **BYGGBAR NÅ** — også et konformitetsgap, ikke bare paritet | K4 |
| 7 | Outbox-persistens (S2.1) | **FERDIG** | DELVIS — `artifacts.py` persisterer proposal/result/provenance/usage deterministisk (også stop-artefakter), men uten run_id-navngitt forslag/utfall-par → ingen pending-sporing mulig | **BYGGBAR NÅ** (utvidelse av artifacts-laget) | K5 |
| 8 | MCP-ingest-konnektor (S2.2, D-B-gated) | GATED D-B | MANGLER; `extending.md` ærlig «ubygd» | **GATED: D-B + commons-ingest-amendment** — SDK-nativ analog: in-process MCP-fixture via `create_sdk_mcp_server` (SDK-primitiv, verifisert i CLAUDE.md) i stedet for MAFs `mcp`-pakke-klient | K14 |
| 9 | Dokument-konnektor PDF (S2.3, D-B-gated) | GATED D-B | MANGLER | **GATED: D-B + commons-ingest-amendment** | K15 |
| 10 | Konnektor-herding http (S2.4, D-B-gated) | GATED D-B (MAF HAR http-demo å herde) | MANGLER MER — D7 har ingen http-kilde i det hele tatt (avvist fail-fast, `ingest.py:129`; valgfri per ingest-spec §1) | **GATED: D-B** — sesjonen bygger http-familien + herding + guard-G1-wiring i ett | K16 |
| 11 | Inbox-/robusthetsherding (S2.5 ↔ C2.5) | **FERDIG** (bolk A) | MANGLER — vokabular-sjekk/tak finnes ikke (C-F7 kjørt-bevist); SDK-pin løs uten versjonsvakt (C-N3) | **BYGGBAR NÅ** | C2.5 |
| 12 | Validator-stramming nominal-gate + band-invariant (S2.7 ↔ C2.7) | GATED D-A | Samme spec-defekt bekreftet her (C-F2, kjørt bevis) | **GATED: D-A pkt. 1 + commons-pull** | C2.7 |
| 13 | Semantisk henting (S3.1, D-C) | GATED D-C | MANGLER; OBS delt kollisjon C-P1: D-C som planlagt (cosine over tekst) bryter frossen §3 Steg 1 «structural, never textual» | **GATED: D-C OG C-P1-avklaring i D-A-bolken** (begge må lande) | K17 |
| 14 | Multi-kandidat ExpeL-seeding (S3.2 ↔ C3.2) | GATED D-A | Feature-halvdelen bekreftet defekt her (C-F5); id-halvdelen alt løst (verbatim) | **GATED: D-A pkt. 4 + commons-pull** | C3.2 |
| 15 | Concurrency/feilmodell (S3.3, D-D) | GATED D-D | Ikke anvendbar i dag (ingen portefølje-sti) — blir reell når K2 lander | **GATED: D-D** (+ K2 som forutsetning) | K18 |
| 16 | Kostnadsstyring på tvers av kjøringer (S3.4) | GATED D-D | MANGLER; pre-call-guard-delen er ugatet (C-N4) | **GATED: D-D** for portefølje-delen; pre-call-guard + run-total USD-tak er **BYGGBAR NÅ** | K19 (gated) + C3.5 (nå) |
| 17 | Innholdsmodell/bibliotek-materialisering + summary-tier-render (S3.5, D-F) | GATED amendment | MANGLER | **GATED: commons-amendment (D-F/D-G-utkastet)** — inkluderer §13-typene, `library`-ingest-familien (4a/5a), summary-tier (§3 Steg 1-endringen) og dimensjonskatalogen (rad 1) | K13 |
| 18 | Kostnadssimulering FØR kjøring (S3.6, D-I pkt. 3 — MÅ-krav) | **FERDIG** | MANGLER | **BYGGBAR NÅ** — D7-analog: what-if over `model_map.json` (Claude-modeller × effort), prisdata som skjema-validert konfig m/ kilde+dato | K6 |
| 19 | Kostbaseline-forankring (S4.0 ↔ C4.0) | GATED D-A | Samme spec-defekt bekreftet her (C-F3, 2.9 MNOK-beviset) | **GATED: D-A pkt. 2 + commons-pull** | C4.0 |
| 20 | Preflight (S4.1 — Foundry-spesifikk i MAF) | **FERDIG** | MANGLER | **BYGGBAR NÅ** — SDK-nativ analog: Anthropic-API/SDK-preflight, offline (env-kontrakt, model-map-konsistens, placeholder-nekt) — Foundry-auth-delen SPEILES IKKE (sant MAF-spesifikk på kapabilitetsnivå: D7s backend er Anthropic-API) | K7 |
| 21 | Live-kjørings-drill + artefakt-fangst (S4.2) | **FERDIG** | MANGLER | **BYGGBAR NÅ** (etter K5+K7) — `--live-dry-run`: bygg alt, STOPP før første modellkall (kall-tellende mock beviser 0 kall) | K8 |
| 22 | HITL-verdict-ruting + pending-sporing (S5.1) | **FERDIG** | MANGLER | **BYGGBAR NÅ** (etter K5 — id-join outbox↔inbox) | K9 |
| 23 | Varsling/Notifier (S5.2) | Plan klar, EXECUTE neste | MANGLER (D7 har ingen notify-stub engang — bygges rent) | **BYGGBAR NÅ** — kapabilitets-koordinering med MAF S5.2 (protokoll-form, webhook-opt-in, socket-fri suite), aldri kode-titting | K10 |
| 24 | CLI-paritet + dokumentsync + D-H-oppskrift (S5.3) | Gjenstår i MAF | MANGLER — ingen leverbar CLI utover fasit-stien | **BYGGBAR NÅ** (sist i ugatet rekke; C2.0 er første skritt) | C2.0 (inngang) + K12 (full paritet) |
| 25 | Verdirapport per kjøring (S5.4, D-I pkt. 2) | Gjenstår i MAF | MANGLER | **BYGGBAR NÅ** (etter K5 + K1 + K6) | K11 |
| 26 | okf-toolkit-adopsjon inkl. skrive-halvdelen A2 (D-G/T0) | T0 blokkerer også MAF | MANGLER — `okf.py` er kun-les (134 l); skrive-primitivene (promotion har egne) deles ikke | **GATED: T0** (repoet finnes ikke, verifisert 2026-07-16) + operatør (§8-spørsmålene i toolkit-briefen) | K20 |
| 27 | llm-ingestion-guard-wiring | MAF: planned (S2.4/S2.5-utvidelse) | Planned her (guard-plan 2026-07-16): G1 http-persist-gate / G2 inbox-depth / G3 import_bundle | G1 **GATED: D-B** (inn i K16) · G2 valgfri depth **vurderes i C2.5** · G3 **GATED: D-E**-retning | K16 / C2.5 / (D-E) |
| 28 | Steg-7 kjøresti-inngang (C2.0 — D7-egen) | (MAF har den via run-laget) | MANGLER (C-N2) | **BYGGBAR NÅ** | C2.0 |
| 29 | Method-spec-integritetsvakt (C1.1 — §11-raden «Spec integrity») | MAF HAR (`test_method_spec_loadbearing.py`, referert i amendment-utkastet §5.1) | MANGLER (C-N1) | **BYGGBAR NÅ** | C1.1 |
| 30 | OKF `/`-lenke-mapping (C2.8 / D-A pkt. 3 / D-G pkt. 1) | GATED D-A (MAF mangler også bygg-sesjon — flagget) | Spec-tro skip i dag (`okf.py:112`) | **GATED: D-A pkt. 3 + commons-pull** | C2.8 |
| 31 | Budsjett-guard pre-call + run-total USD (C3.5) | Del av S3.4 i MAF | MANGLER (C-N4; per-kall-USD-tak finnes alt — bedre enn MAF) | **BYGGBAR NÅ** | C3.5 |
| 32 | Operatør-milepæler M1M3 | Definert i MAF-planen | Ingen definert her | **SPEILES som milepæl-definisjoner** (§6) — aldri autonome sesjoner. M1-analogen (tenant+smoke) er Foundry-spesifikk; D7-ekvivalenten (nøkkel + preflight grønn) foldes inn i M2-analogens forutsetninger | §6 |
| 33 | Validator robust mot ikke-finite tall (review-paritet R-2 — D7-EGEN korrekthet) | (egen implementasjons-defekt) | **DEFEKT**`Infinity` gir `validates=True` (kjørt-bevist) | **BYGGBAR NÅ** | C2.6 |
| 34 | Ingest robust mot tom/BOM/malformert kilde (R-3/R-4/R-5/R-7 — D7-EGEN) | (egen implementasjons-defekt) | **DEFEKT** — tom CSV krasjer midt i materialisering → delvis bundle (kjørt-bevist) | **BYGGBAR NÅ** | K2.9 |
| 35 | Closed-loop to-kjørings-vakt (R-1 — §11-raden «Closed loop») | MAF HAR (`test_simulation_loadbearing`) | MANGLER — §11 rad 8 ubundet | **BYGGBAR NÅ** | K4 |
**Re-klassifisering av den opphevede «Overføres IKKE»-listen** (gammel plan §4): S2.0-portefølje
→ rad 45 (BYGGBAR NÅ); S2.1-outbox → rad 7 (BYGGBAR NÅ — «output-laget finnes her» var bare
delvis sant); S2.2 MCP → rad 8 (GATED D-B, SDK-nativ analog); S2.3 doc → rad 9 (GATED D-B);
S2.4 http-herding → rad 10 (GATED D-B); S3.1 → rad 13 (GATED D-C+C-P1); S3.3 → rad 15 (GATED
D-D); S3.4 → rad 16 (delt: C3.5 nå, K19 gated); S4.1/S4.2-Foundry → rad 2021 (SDK-nativ
analog, BYGGBAR NÅ; kun Foundry-*auth* speiles ikke); S5.x → rad 2225 (BYGGBAR NÅ-kjede);
M1M3 → rad 32. Setningen «`extending.md` står: ingen D7-HTTP/MCP-økt planlagt» er ikke
lenger dekkende — K14K16 planlegges nå, gated D-B; `extending.md` oppdateres i K16
(docs-ærlighet, §1).
## 2. Den delte beslutnings-køen (uendret — bor i HOVEDREPOET)
D-AD-E ligger i MAF-planens §2 og besluttes der; dette repoet planlegger ingen egen variant —
kun sesjoner gated på den. Det som gater arbeid HER, med anbefaling i klarspråk, står i
[beslutningsbriefen](2026-07-16-beslutningsbrief.md). Koblings-flagget **C-P1** (D-C ↔ frossen
§3 Steg 1) står uendret og MÅ inn i D-A-bolken. Ett NYTT beslutnings-kandidat-punkt foreslås
inn i den delte køen via briefen (delbarhet av ledger-/outbox-format) — det besluttes ALDRI
ensidig her.
**Commons-regel (uendret):** amendments skrives i commons, pulles med
`git subtree pull --prefix=shared commons main --squash`. ALDRI subtree push. Etter hver
amendment-bølge re-pinner/puller BEGGE repo og BEGGE suiter kjøres (sammenligningsprotokollen);
golden re-fryses kun koordinert i commons.
## 3. Byggbare NÅ (ingen beslutnings-gate) — anbefalt rekkefølge
> Felles verifisering for ALLE sesjoner (gjentas ikke per sesjon): full gate
> (`uv run pytest` + `uv run ruff check .` + `uv run ruff format --check .` +
> `uv run mypy src`) grønn; golden-regresjonen (`test_bygg_energi_mikro.py` +
> ingest-goldens) uendret grønn; suiten kjører uten nøkkel/nett; `runs/s10/` urørt;
> `run_s10.py` byte-urørt (fasit-sti). Nye moduler holdes SDK-frie (ren stdlib+pydantic)
> med mindre sesjonen eksplisitt sier noe annet, og SDK-frihet bindes med import-vakt etter
> `test_okf`-purity-mønsteret.
### C1.1 Method-spec-integritetsvakt (C-N1) — UENDRET fra gammel plan, ÅPNING
- **Mål:** §11-raden «Spec integrity» håndheves lokalt — spec-drift i subtree-synken fanges her.
- **Scope (filliste):** ny `tests/test_method_spec_loadbearing.py` (KUN testkode).
- **IKKE-scope:** ingen src-endring, ingen spec-endring, ingen endring i ingest-spec-vakten.
- **Gate:** ingen.
- **TDD-plan:** testen er selv vakten; RØD-bevis via mutert spec-KOPI i `tmp_path`
(parametrisert mot kopien, aldri mot `shared/`): (a) slett fila → rød; (b) injiser
rammeverksnavn (MAF/Claude/Anthropic/Azure/…, samme navneliste som ingest-vakten) → rød;
(c) fjern et konsumert §12-felt → rød. Innhold: (1) fil-eksistens + struktur-markører
(`## 1.``## 12.`, `### Step 1``### Step 8`, «MUST»); (2) framework-nøytralitet;
(3) §12-dekning for feltene DENNE koden konsumerer (`decision`, `rationale`, `id`,
`proposal_features`, `affected_codes`, `measure_type`, `claimed_saving_nok`, `description`,
IR-feltene `project_id`/`measure`/`affected_items`/`code`/`quantity`/`unit_cost`/`assumptions`,
golden-feltene `outcome`/`validates`/`nominal_feasible`/`p10`/`p50`/`p90`,
learning-surface-feltene, `type`, vokabular-verdiene `approved`/`rejected`/
`approved_with_adjustment`). Feltlisten valideres mot review-paritet §-vedlegget
(spec-konformitetsagentens konsumliste) i sesjonen. Presisjons-lærdom fra
detach-stikkprøven av ingest-vakten (review-paritet §3): substring-hvor-som-helst-assertion
gjør at et felt som også nevnes i løpeteksten ikke detacher ved ren tabell-fjerning —
dokumentér samme begrensning i method-spec-vakten, eller scope assertion til
§12-tabellblokken der det er praktisk.
- **Nøkkelantakelse (+test):** markørene i dagens method-spec matcher listen — testes FØRST
ved å kjøre vakten grønn mot uendret `shared/method-spec.md` før mutasjons-parametrene.
- **Verifisering:** `uv run pytest tests/test_method_spec_loadbearing.py` grønn; mutasjons-
parametrene røde mot kopi; full gate. **VIKTIG koordinering:** amendment-utkastet (§5.1) er
konstruert mot MAFs vakt-design (presence-asserts, ikke forbud mot nye seksjoner) — bygg
vakten HER med samme presence-semantikk, så en senere amendment-pull ikke gjør den rød.
### C2.5 Inbox-herding + SDK-versjonsvakt (C-F7, C-N3) — UENDRET + guard-G2-vurdering
- **Mål:** inboxen slutter å være en uvalidert injeksjonsflate; SDK-attributt-premissene får
en vakt som tvinger bevisst re-verifisering ved oppgradering.
- **Scope (filliste):** `src/portfolio_optimiser_claude/inbox.py`, `pyproject.toml`,
`tests/test_step7_async_loop_loadbearing.py` (utvidelse), ny `tests/test_sdk_version_guard.py`.
- **IKKE-scope:** guard-*wiring* (kun vurderingsnotat, se under); endring i tolerant-lasting-
semantikken for øvrige felter; `experience.py`.
- **Gate:** ingen.
- **TDD-plan:** RØD: inbox-fil med `decision: "hva-som-helst"` når ALDRI storen — reviewens
kjørte C-F7-bevis blir fixturen (detach-punkt: fjern vokabular-sjekken → den entrer → rød).
Vokabular på fil-laget = §4.2-settet {approved, rejected, approved_with_adjustment}; ukjent
→ SKIP, aldri raise (tolerant-regelen består). RØD: rationale > konfigurerbart tak →
fail-fast med presis feil (aldri stille kutt); RØD: antall filer > tak → fail-fast. RØD
(R-6): `VerdictDocument.id` med path-traversal (`../../escaped`) → avvist/sanert FØR
`write_verdict` skriver (detach id-grammatikken → fil skrives utenfor inbox → rød;
sikkerhetsagentens kjørte bevis blir fixturen; speil `_ID_RE` fra `ingest.py` eller
`promotion._filename_token`-saneringen). RØD:
versjonsvakt mot fake-versjon (monkeypatch `importlib.metadata.version`) — melding skal
navngi `sdk_client.py`-premissene som må re-verifiseres. Pin: **`claude-agent-sdk>=0.2.111,<0.3`**
(sdk-review 2026-07-16: alle attributt-premisser verifisert mot installert 0.2.110 OG mot
releases t.o.m. nyeste 0.2.120 — ingen brudd; 0.2.111 bærer NDJSON-/content-parsing-fikser
som treffer nettopp denne klientens leseløkke, se review-paritet §2). Sesjonen re-kjører
attributt-verifiseringen mot versjonen `uv sync` faktisk resolver.
I tillegg (fra R4/R5, test-detach + sdk-review): (5) bind `sdk_client._complete_async`-
meldingshåndteringen offline med en syntetisk strøm (fake_query som yield-er
AssistantMessage/ResultMessage-verdier: tekst-aggregering, error-fail-paths,
usage/kost-ekstraksjon, `_total_tokens`-fail-closed, `max_budget_usd_per_call<=0`-guarden
— i dag kjøres ingenting av dette i suiten); (6) rett `test_sdk_isolation`-docstringen som
hevder `--system-prompt ""`-serialisering testkroppen ikke beviser (grønn-men-død for
akkurat den claimen — ærligst å omformulere docstringen; å binde transport-serialisering
ville lese SDK-privat API og gjeninnføre F11-skjørhet).
- **Guard-G2-vurdering (leveranse i sesjonen, ikke wiring):** kort avsnitt i commit-meldingen/
STATE om `scan_output`-depth over `rationale` er verdt en senere additiv økt —
C2.5-allowlisten er den nødvendige delen (guard-planen §4 G2). Markørlinjen i STATE
oppdateres hvis vurderingen endrer trigger-bildet.
- **Nøkkelantakelse (+test):** step7-suitens tolerant-lasting består uendret — kontrolltest:
eksisterende `test_non_json_broken_and_incomplete_files_are_skipped` forblir grønn.
- **Verifisering:** nye tester grønne + detach → rød; step7-suiten uendret grønn; full gate.
### C2.0 Steg-7 kjøresti-inngang (C-N2) — UENDRET
- **Mål:** en skipbar inngang komponerer §5-sekvensen (merge inbox → seed → fold → run), så
README-ens inbox-avsnitt er sant om en leverbar sti.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/run.py` (offline-testbar
komposisjonsfunksjon `compose_run_context(bundle_dir, inbox_dir=None, k=...)` + tynn CLI
`python -m portfolio_optimiser_claude.run --bundle/--inbox/--out` som gjenbruker
contracts/meter/artifacts), ny `tests/test_run_entrance_loadbearing.py`, README-avsnittet
om inboxen (peker på ny inngang).
- **IKKE-scope:** `run_s10.py` (byte-urørt fasit); ny live-kjøring (CLI testes kun med
ScriptedClient; SDK-klienten wires men eksekveres ikke i suiten); portefølje (K2).
- **Gate:** ingen.
- **TDD-plan:** RØD: dom droppet i inbox-mappe → inngangens komponerte kontekst bærer dommens
markør (detach-punkt: fjern merge-kallet i komposisjonen → rød); kontroll: tom/manglende
inbox → base-kontekst uendret; RØD: inngangen skriver ALDRI til inboxen (byte-sammenligning
før/etter, §5-rolledelingen); RØD (fra R3, test-detach-coverage): budsjett-stopp under
kjøring via den NYE inngangen → stopp-artefaktene persisteres + strukturert exit
(ScriptedClient + lavt tak — binder orkestrerings-grenen `run_s10.py:99-114` aldri fikk
bundet; fasit-stien forblir byte-urørt, bindingen skjer på den nye stien).
- **Nøkkelantakelse (+test):** komposisjonen gjenbruker `fold_experience`/
`merge_inbox_into_store`/`seed_store_from_bundle` uendret — ingen ny søm, kun wiring;
testes ved at ingen eksisterende testfil endres.
- **Verifisering:** ny testfil grønn + detach → rød; `grep -n "inbox" README.md` viser claim
som matcher en skipbar sti; full gate.
### C2.6 Validator/IR finitthets- og gyldighets-hardening (R-2 primær) — NY, BYGGBAR NÅ, HØY VERDI
- **Mål:** den obligatoriske validatoren kan ikke lenger settes ut av spill av ikke-finite
eller ugyldige tall — `Infinity` klarerer ikke porten vakuøst lenger.
- **Scope (filliste):** `ir.py` (`allow_inf_nan=False` på de numeriske feltene, eller eksplisitt
finitthetssjekk av `quantity`/`unit_cost`/`claimed_saving_nok` + bånd-endepunkter; forby
negative bånd-verdier), `contracts.py` (`min_length` på modell-id-verdier — tom-streng-
bug), `loop.py` (fjern/dokumentér den døde `check_turn_safety_net`-vokteren `:111` — eller
gjør §8s turn-safety-net faktisk nåbar), `tests/test_ir.py`, `tests/test_validator.py`,
`tests/test_contracts.py`.
- **IKKE-scope:** kostbaseline (C4.0); nominal-gate (C2.7, D-A-gated) — dette er ren
finitthets-/gyldighets-hardening, ikke spec-strammingen.
- **Gate:** ingen. **Golden uendret** (golden-tallene er finite).
- **TDD-plan:** RØD: `unit_cost: Infinity` → IR-konstruksjon eller validering avvises (i dag
`ValidatedProposal(validates=True, p90=inf)` — reviewens kjørte R-2-bevis blir fixturen;
detach-punkt: gjeninnfør `allow_inf_nan=True` → inf validerer → rød); RØD: `assumptions`-bånd
med `Infinity`/negativ endepunkt → avvist; kontroll: NaN avvises fortsatt (regresjon);
kontroll: golden-bundelens finite tall validerer uendret; RØD: tom-streng modell-id →
ModelMapContract avviser.
- **Nøkkelantakelse (+test):** ingen golden-/fixture-tall er ikke-finite — VERIFISERT
(golden.json + alle fixtures er finite); bindes ved at `test_bygg_energi_mikro` forblir grønn.
- **Verifisering:** nye tester grønne + detach → rød; golden uendret; full gate.
### K2.9 Ingest-robusthet (R-3/R-4/R-5/R-7) — NY, BYGGBAR NÅ
- **Mål:** ingest krasjer ikke midt i materialisering på tomme/BOM-/malformerte kilder, og
etterlater aldri en delvis bundle.
- **Scope (filliste):** `ingest.py` (R-3: vokt tom `rows` med fail-fast FØR disk-mutasjon —
aldri delvis bundle; R-4: les CSV med `utf-8-sig`; R-7 valgfritt: `LIMIT max_rows+1`/
`fetchmany` for SQL + streaming-tell for CSV), `okf.py` (R-5: eksplisitt beslutning for
malformert-men-eksisterende lenket concept-fil — tolerér-og-hopp ELLER dokumentert fail-fast,
ikke stille asymmetri), nye tester + evt. golden-fixture-tillegg (repo-lokalt, ikke `shared/`).
- **IKKE-scope:** ny kildefamilie (K14K16, D-B-gated); endring i eksisterende ingest-goldens
(byte-fasit).
- **Gate:** ingen.
- **TDD-plan:** RØD: tom CSV-ekstraksjon → fail-fast MED bundle uendret (detach fail-fast-
vakten → delvis bundle + krasj → rød; kontroll: byte-sjekk at ingen fil ble skrevet ved feil);
RØD: BOM-CSV → header `code` ikke `code` (detach `utf-8-sig` → korrupt header → rød); RØD:
malformert lenket fil → valgt semantikk bevist (hopp-og-fortsett: resten av bundelen
navigeres; ELLER fail-fast: presis feil) — detach → motsatt oppførsel → rød.
- **Nøkkelantakelse (+test):** eksisterende ingest-goldens er upåvirket (ingen tom/BOM/
malformert fixture i dem) — bindes ved at begge ingest-golden-suiter forblir grønne.
- **Verifisering:** nye tester grønne + detach → rød; ingest-goldens uendret; full gate.
### K4 Closed-loop to-kjørings-simulering (R-1 — §11-raden «Closed loop»; MAF-paritet rad 6)
- **Mål:** §11s siste udekkede rad (utover C1.1) lukkes: en skriptet to-kjørings-simulering
beviser at persona-markøren krysser kjøringer VIA promotering — og IKKE krysser uten.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/simulation.py` (deterministisk
to-run-driver over `run.py`-komposisjonen + persona-artefakten + promotion; ScriptedClient;
null modellkall), ny `tests/test_simulation_loadbearing.py`.
- **IKKE-scope:** endring i loop/promotion/persona-primitivene; live-kjøring; portefølje.
- **Gate:** ingen (forutsetter C2.0 — komposisjonsinngangen er kjøretøyet).
- **TDD-plan:** RØD: kjøring A → persona-dom (markør fra `shared/skills/expert-reviewer/`-
artefakten) → promotering → kjøring B med FERSK store: markøren MÅ nå Bs hypotese-prompt
(detach-punkt 1: fjern promoterings-steget → markøren uteblir → rød). RØD (symmetrisk
kontroll): UTEN promotering krysser markøren ALDRI (detach-punkt 2: la konteksten rendre
verdict-laget → markøren lekker → rød — gjenbruker verdict-eksklusjonens invariant på
simulerings-nivå). Honesty-krav: modulen docstring-merkes som skriptet stand-in (§1).
- **Nøkkelantakelse (+test):** persona-artefaktens `marker` er substring av `rationale`
(spec §4.3) — allerede bundet av `test_persona_skill_loadbearing.py`; simuleringen
gjenbruker den, ingen ny persona-kilde.
- **Verifisering:** ny testfil grønn + begge detach-punkter røde; full gate.
### K1 Besparelses-hovedbok + mål-kontrakt (paritetsrad 23; Fase-1-analog)
- **Mål:** D7 får en typet hovedbok over realiserte besparelser (fail-closed ekspert-gate,
provenance-stemplet) og en mål-kontrakt (absolutt beløp, hard/soft) med «stopp når mål
nådd»-logikk — distinkt fra token-budsjettet.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/ledger.py` (typet `SavingsLedger`;
`realize` KUN med eksplisitt ekspert-argument + eksplisitt timestamp — samme
determinisme-regel som promotion §6; deterministisk JSON-persistens sort_keys/indent 2/LF),
ny `goals.py` (`GoalContract`: absolutt mål, hard/soft; fail-fast konstruksjon §10-stil),
nye `tests/test_ledger_loadbearing.py` + `tests/test_goals.py`.
- **IKKE-scope:** prosent-mål-baseline (D-E-gated — kontrakten reserverer feltet med
eksplisitt `NotImplementedError`-nekt + TODO-peker til D-E, aldri stille semantikk);
portefølje-wiring (K2); verdirapport (K11).
- **Gate:** ingen for absolutt-delen. **Prosent-delen: D-E.**
- **TDD-plan:** RØD: `realize` uten ekspert-stempel → nekt (detach-punkt: fjern gate-sjekken
→ uekspederte «realiserte» tall entrer boken → rød); RØD: hovedboken akkumulerer og
persisterer deterministisk (to identiske sekvenser → byte-identisk fil); RØD: hardt mål
nådd → strukturert stopp-signal (typet event, aldri stille); soft mål → flagg uten stopp;
RØD: prosent-mål forsøkt konstruert → eksplisitt nekt med D-E-melding.
- **Nøkkelantakelse (+test):** ledger-semantikk kan speiles på kapabilitetsnivå fra
MAF-planens beskrivelse (typet store, fail-closed realize, dimensjonsfri sum-nøkkel mot
dobbelttelling) uten MAF-kode — RISIKO: detaljsemantikk kan divergere fra MAF; markeres i
docstring som stack-lokal kontrakt (delbarhet er foreslått beslutningspunkt i briefen).
Test på antakelsen: dimensjonsfri sum-nøkkel bindes med en to-dimensjoner-samme-prosjekt-
fixture der summen IKKE dobbelttelles.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K2 Portefølje-kjøring (paritetsrad 4; Fase-1-analog)
- **Mål:** `run_portfolio` kjører N prosjekter sekvensielt fra en skjema-validert
referanse-konfig (per-prosjekt bundle-sti), med collect-per-prosjekt-resultater — den
kjørestien MAF fikk i Fase 1 og D7 aldri har hatt.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/portfolio.py`
(`run_portfolio(projects, client, meter, ...)` + `PortfolioResult`), ny
`data/reference_projects.json` (eksempel-konfig; skjema-validert fail-fast i
`contracts.py`-stil), `contracts.py` (konfig-modell), mini-bundle-fixture repo-lokalt under
`tests/data/` (ALDRI i `shared/`), ny `tests/test_portfolio.py`.
- **IKKE-scope:** læringstreing på tvers (K3); concurrency (K18/D-D); goals/ledger-wiring
utover å ta imot dem som valgfrie argumenter; endring i `loop.py`-kjernen.
- **Gate:** ingen.
- **TDD-plan:** RØD: to-prosjekt-konfig → begge kjøres, resultatliste i konfig-rekkefølge
(deterministisk); RØD: malformet konfig (manglende bundle-sti) → fail-fast FØR første
kjøring (§10-disiplin; detach-punkt: fjern skjema-valideringen → kjøring starter på
ugyldig konfig → rød); RØD: feil i prosjekt 1 propagerer som typet feil — feilpolicyen
(collect-and-continue vs raise) dokumenteres eksplisitt som stack-lokalt valg inntil D-D
(default: raise, som «i dag kastes alt» — endres bevisst av K18 når D-D lander).
- **Nøkkelantakelse (+test):** loop-kjernen er re-entrant per prosjekt (fresh debate-state
per run — spec §3 Steg 3) — bindes med test: to sekvensielle kjøringer deler ingen
muterbar tilstand utover eksplisitt delt store.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K3 Portefølje-læringssløyfe (S2.0-analog; paritetsrad 5)
- **Mål:** en dom på prosjekt k når prosjekt k+1s hypotese-prompt i samme porteføljepass —
delt store + verdict_dir tres gjennom `run_portfolio`.
- **Scope (filliste):** `portfolio.py` (delt store + `verdict_dir`-parameter tres gjennom;
inbox-merge FØR hver kjørings fold — gjenbruker C2.0-komposisjonen),
`tests/test_portfolio_learning_loadbearing.py`.
- **IKKE-scope:** semantisk henting (K17); multi-kandidat-nøkling (C3.2 — dagens
feature-nøkling brukes som den er, med kjent C-F5-begrensning notert).
- **Gate:** ingen (forutsetter K2 + C2.0).
- **TDD-plan:** RØD: dom om prosjekt k (droppet i verdict_dir mellom kjøringene / promotert
i ks bundle) → k+1s genererings-prompt bærer dommens id+markør (detach-punkt: fjern
store-/verdict_dir-trådingen gjennom porteføljen → rød); kontroll: tom store/inbox → k+1
uendret base-prompt.
- **Nøkkelantakelse (+test):** first-write-wins-merge (§4.2) gjør gjentatte merges over
porteføljepasset idempotente — bindes med dobbel-merge-test på porteføljenivå.
- **Verifisering:** ny testfil grønn + detach → rød; full gate.
### K5 Outbox-persistens (S2.1-analog; paritetsrad 7)
- **Mål:** hver kjørings forslag/utfall persisteres run_id-navngitt i en outbox-mappe, så
utestående dommer kan spores (K9) og live-artefakter fanges (K8) — sammenligningsprotokoll
§4.2-formen.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/outbox.py` (gjenbruker
`artifacts.py`-serialisering; skriver `{run_id}-proposal.json` + `{run_id}-outcome.json`
med outcome-type, reason/percentiler, checker_verdict, provenance-referanse, verdict-id;
`run_id` PÅKREVD når outbox er satt — ingen wall-clock-default), `run.py` (valgfritt
`outbox_dir`/`run_id`), ny `tests/test_outbox_loadbearing.py`.
- **IKKE-scope:** ruting/pending (K9); varsling (K10); endring i `artifacts.py`-formatene
(S10-fasiten leses av dem).
- **Gate:** ingen.
- **TDD-plan:** RØD: kjøring med outbox_dir → filparet finnes, byte-deterministisk
(sort_keys/indent 2/LF; to kjøringer samme input+run_id → `diff` tom) (detach-punkt: fjern
outbox-skrivingen → rød); kontroll: uten outbox_dir skrives ingenting; RØD: outbox satt
uten run_id → fail-fast. Docstring siterer method-spec §2: systemet EIER output-laget
(rolledelingen §5 gjelder inbox/wiki, ikke systemets eget output-lag).
- **Nøkkelantakelse (+test):** `ValidatedProposal`/`Rejection` er JSON-serialiserbare via
eksplisitt mapping — testes FØRST med begge utfallstyper (artifacts.py gjør alt dette i
dag for run-artefaktene; antakelsen er at samme mapping bærer outcome-formen).
- **Verifisering:** ny testfil grønn + detach → rød; full gate.
### C3.5 Budsjett-guard (C-N4) — VIDEREFØRT, løftet fra «valgfri» til paritetskrav (rad 16/31)
- **Mål:** pre-call-guard (nekt kall når rest-tak < 0) + eksplisitt run-total USD-grense over
SDK-klientens akkumulerte kost — på plass FØR enhver fremtidig live-kjøring.
- **Scope (filliste):** `budget.py` (pre-call-sjekk-primitiv + run-total USD-tak i meteren),
`loop.py` (guard-kall FØR `client.complete`), `sdk_client.py` (eksponer akkumulert
`total_cost_usd` — leses allerede fra ResultMessage), `tests/test_budget.py` (+utvidelse).
- **IKKE-scope:** portefølje-nivå-tak (K19, D-D-gated); endring i post-charge-semantikken
(består som belte-og-seler).
- **Gate:** ingen.
- **TDD-plan:** RØD: mock-klient som teller kall — når rest < neste kall er kallet ALDRI
gjort (detach-punkt: fjern pre-call-guarden → kallet skjer → rød); RØD: run-total USD-tak
krysset → strukturert stopp (samme event-form som token-stoppen, §8); kontroll:
usage-fail-closed-testen (`test_budget`) uendret grønn.
- **Nøkkelantakelse (+test):** `ResultMessage.total_cost_usd` akkumuleres pålitelig per kall
på 0.2.110 (verifisert i sdk-review 2026-07-16, review-paritet §2) — versjonsvakten fra
C2.5 dekker drift.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K6 Kostnadssimulering før kjøring (S3.6-analog; D-I pkt. 3 MÅ-krav; paritetsrad 18)
- **Mål:** operatøren ser estimert kost for en (portefølje-)kjøring FØR start — what-if over
model_map (Claude-modeller × effortnivåer), prisdata som skjema-validert konfig.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/costsim.py` (funksjons-API +
`python -m portfolio_optimiser_claude.costsim`; deterministisk øvre-grense-estimat fra
portefølje-form × tak — merket ESTIMAT i output), ny `data/pricing.example.json` (skjema:
kr-eller-USD/Mtok per modell-id, PÅKREVD kilde+dato-felt; fail-fast ved manglende/ugyldig
pris — aldri hardkodet), `contracts.py` (pris-skjema), nye tester.
- **IKKE-scope:** live prisoppslag (nett); faktisk modellkall; kvalitets-benchmarking
(kvalitetsutsagn kun som veiledning-med-kilde, D-I-regelen).
- **Gate:** ingen.
- **TDD-plan:** RØD: konfig uten pris for en modell i model_map → fail-fast «missing price
for <modell-id>» (detach-punkt: fjern pris-valideringen → estimat gjettes → rød); RØD:
deterministisk og skalerer med modell × effort (to modeller, samme portefølje →
forskjellig, reproduserbart estimat; detach effort-faktoren → identisk → rød); RØD:
grep-guard: ingen pris-literal i `costsim.py`-kildekode (pris MÅ komme fra konfig).
- **Nøkkelantakelse (+test):** eksempel-prisene kan kildeføres mot offisiell Anthropic-
prisside med dato (sdk-modelmap-reviewens kilder gjenbrukes); IKKE VERIFISERT utover
review-datoen — derfor kilde+dato-felt i skjemaet, så stale priser er synlige, aldri stille.
- **Verifisering:** nye tester grønne + detach → rød; `uv run python -m
portfolio_optimiser_claude.costsim` gir estimat-tabell uten nettverk; full gate.
### K7 SDK-/API-preflight (S4.1-analog, SDK-nativ; paritetsrad 20)
- **Mål:** alt som KAN valideres uten et modellkall valideres før operatøren betaler for ett.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/preflight.py`
(`python -m portfolio_optimiser_claude.preflight --profile anthropic`): env-kontrakt
(`ANTHROPIC_API_KEY` satt + ikke-placeholder-form — nøkkelVERDIEN valideres aldri online),
model_map-konsistens (profil finnes, `default` finnes, modell-id-form), placeholder-nekt
også i `resolve_model`-stien, SDK-importerbarhet + bundlet CLI til stede
(claude-agent-sdk-premisset), budsjett-/stoppkontrakt satt. Nekt-liste med aksjonérbar
melding per mangel. Tester.
- **IKKE-scope:** faktisk API-kall (aldri — preflighten er selve grensen); Foundry/Azure
(SPEILES IKKE, rad 20-begrunnelsen).
- **Gate:** ingen.
- **TDD-plan:** RØD: manglende env-nøkkel → strukturert nekt med aksjonérbar melding
(detach-punkt: fjern env-sjekken → preflight «grønn» uten nøkkel → rød); RØD:
placeholder-modell-id i map → nekt; RØD: grep-guard ingen socket-/httpx-sti i modulen.
- **Nøkkelantakelse (+test):** «bundlet CLI til stede» kan sjekkes offline via SDK-pakkens
egne filer (verifiseres i sesjonen mot installert 0.2.110; hvis ikke mulig offline —
droppes sjekken eksplisitt med begrunnelse i docstring, aldri en nett-sjekk).
- **Verifisering:** nye tester grønne + detach → rød; `uv run python -m
portfolio_optimiser_claude.preflight` korrekt nekt/OK uten nettverk; full gate.
### K8 Live-kjørings-drill + artefakt-fangst (S4.2-analog; paritetsrad 21)
- **Mål:** en eventuell fremtidig live-kjøring (M2-analogen, operatør-gated) er ferdig-rigget:
alt bygges, artefakter fanges, drillen er øvd offline — uten ett modellkall.
- **Scope (filliste):** `run.py` (`--live-dry-run`: last kontrakter, kjør preflight, bygg
klient-konfig, valider budsjett, skriv kjøringskonfig-logg (modell-id, parametre, tak —
sammenligningsprotokoll §4.3-form) til outbox, STOPP før første modellkall), tester med
kall-tellende mock.
- **IKKE-scope:** selve live-kjøringen (M2-analog, operatør); endring i preflight/outbox.
- **Gate:** ingen (forutsetter K5 + K7).
- **TDD-plan:** RØD: dry-run mot kall-tellende mock-klient → NULL kall skjedde (detach-punkt:
fjern stopp-punktet → kall telles → rød); RØD: artefakt-settet (konfig-logg + preflight-
resultat) komplett og deterministisk i outbox.
- **Nøkkelantakelse (+test):** klient-konstruksjon uten kall er gratis og nøkkel-fri
(CLAUDE.md-verifisert SDK-premiss: import og konstruksjon fungerer uten API-nøkkel) —
bindes med test som konstruerer klienten i suiten (uten nøkkel).
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K9 HITL verdict-ruting + pending-sporing (S5.1-analog; paritetsrad 22)
- **Mål:** operatøren ser hvilke forslag som venter på dom og hvem som skal dømme — ren
fil-basert id-join outbox↔inbox.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/hitl.py` (pending-registry =
outbox-forslag uten matchende inbox-/promotert dom, id-join på verdict-id; ruting-konfig
`nøkkel → ekspert` skjema-validert fail-fast — nøkkelen er en konfig-streng nå,
dimensjonskatalog-integrasjon kommer med K13), CLI `python -m portfolio_optimiser_claude.hitl
pending|route`, tester.
- **IKKE-scope:** varsling (K10); web-UI; skriving til inbox (rolledelingen §5 — hitl LESER
begge lag).
- **Gate:** ingen (forutsetter K5).
- **TDD-plan:** RØD: forslag i outbox uten dom → listes utestående; dom lander i inbox →
forsvinner fra pending (detach-punkt: fjern id-joinen → dømt forslag listes fortsatt →
rød); RØD: malformet ruting-konfig → fail-fast; RØD: hitl skriver aldri (byte-sammenligning
av outbox+inbox før/etter).
- **Nøkkelantakelse (+test):** outbox-outcome bærer verdict-id-en å joine på (K5-formen) —
bindes i K5s testfil og gjenbrukes her.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K10 Varsling/Notifier (S5.2-analog; paritetsrad 23)
- **Mål:** leverbare varslings-implementasjoner uten å bryte ingen-stille-egress.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/notify.py` (`Notifier`-protokoll +
`console`/`file`/`webhook`; webhook krever eksplisitt per-kjøring opt-in-flagg — mirror av
ingest-spec §8-mønsteret («flagget er et run-argument, aldri konfig-felt») — + injiserbar
transport, canned i tester, null socket i suiten), `run.py`/`hitl.py` (opt-in seam), tester.
- **IKKE-scope:** e-post/Teams-adaptere; retry-politikk; kø.
- **Gate:** ingen. **Koordineringspunkt (kapabilitetsnivå):** MAF S5.2 eksekveres nå — les
MAF-STATE/plan-oppsummeringen (aldri koden) før sesjonen og speil kapabilitetsvalgene
(protokoll-form, webhook-opt-in, socket-fri suite) der de er beskrevet på plan-nivå.
- **TDD-plan:** RØD: webhook uten opt-in → nekt fail-fast (detach-punkt: fjern opt-in-sjekken
→ transporten kalles → rød); RØD: canned transport mottar korrekt payload (struktur, ikke
prosa); RØD: grep-guard ingen socket-sti utenfor den injiserbare seamen.
- **Nøkkelantakelse (+test):** payload-formen kan holdes stack-lokal (ingen delt spec for
varsling) — divergens mot MAF er akseptert og dokumentert i docstring.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K11 Verdirapport per kjøring (S5.4-analog; D-I pkt. 2; paritetsrad 25)
- **Mål:** hver kjøring/porteføljepass produserer en deterministisk verdirapport — modellert →
ekspert-korrigert → realisert, målprogresjon, tallfestet læringseffekt, kost-mot-verdi —
uten ett modellkall.
- **Scope (filliste):** ny `src/portfolio_optimiser_claude/valuereport.py` (ren projeksjon
over ledger (K1) + outbox (K5) + costsim-estimat (K6); JSON + markdown-render, byte-stabil
sort_keys/indent/LF), `run.py`/`portfolio.py` (opt-in `--value-report`), tester + committede
fixtures.
- **IKKE-scope:** dashboard; live-oppdatering; modellkall; nivå-2-README-påstander (kommer
FØRST når beviset finnes — D-I pkt. 1).
- **Gate:** ingen (forutsetter K1 + K5 + K6).
- **TDD-plan:** RØD: to kjøringer med økende godkjenningsandel → læringseffekt-metrikk stiger
og gap-krymping rapporteres (detach-punkt: fjern gap-beregningen → flat/feil → rød); RØD:
prosjekt uten dom → «realisert» tomt/umerket, ALDRI lik modellert (detach ærlighets-grensen
→ realisert=modellert → rød); RØD: byte-determinisme (samme ledger+outbox → identisk
rapport, `diff`).
- **Nøkkelantakelse (+test):** ledger+outbox bærer alt rapporten trenger — rapporten er ren
projeksjon, ingen ny tilstand; testes ved å bygge rapport fra committede fixtures uten
kjøring.
- **Verifisering:** nye tester grønne + detach → rød; full gate.
### K12 CLI-paritet + dokumentsync + D-H-oppskrift (S5.3-analog; paritetsrad 24) — SISTE ugatede
- **Mål:** operatøren driver ALT bygget (kjøring, portefølje, inbox, outbox, ledger, goals,
pending, costsim, preflight, verdirapport) fra kommandolinja; README/extending.md/CHANGELOG
påstår nøyaktig det koden gjør (§1); D-H-oppskriften leveres som dokument.
- **Scope (filliste):** `run.py` (samlende CLI-flater: `--bundle/--inbox/--outbox/--verdict-dir/
--goals/--ledger/--portfolio/--value-report`), `README.md`, `docs/extending.md`,
`CHANGELOG.md`, nytt `docs/oppskrift-kunnskapsbase.md` (D-H pkt. 1: dokumentert team-prosess,
ærlig 12-ukers-forventning; IKKE veiviser — B9 er FORKASTET i D-H), CLI-tester.
- **IKKE-scope:** nye kapabiliteter; fabrikk-/demo-sti (T0-gated — oppskriften peker på den
som fremtidig, merket ubygd).
- **Gate:** ingen (forutsetter at K1K11-kjeden er landet — ellers krymper scope ærlig).
- **TDD-plan:** RØD: CLI-kjøring med goals+ledger på fixtures → mål-stopp observerbar i
output (detach-punkt: koble goals fra CLI-stien → stopp uteblir → rød); RØD:
ærlighets-grep i testform: README-claims-listen (inbox, portefølje, CLI) matcher skipbare
stier (testen leser README og asserter at hver dokumentert kommando finnes i CLI-hjelpen).
- **Nøkkelantakelse (+test):** ingen — ren wiring + docs.
- **Verifisering:** CLI-tester grønne; manuell `uv run python -m portfolio_optimiser_claude.run
--help`-røyk dokumentert i STATE; full gate.
## 4. Gatede sesjoner (startes IKKE før gaten er utløst — eksakt utløser per sesjon)
> Felles mal for D-A-bølgen (uendret fra gammel plan): amendment lander i commons →
> koordinert subtree-pull i BEGGE repo → BEGGE suiter kjøres → failing test først
> (review-moteksemplene ER fixturene) → impl → detach-bevis → full gate → golden uendret
> (eller koordinert re-frosset i commons FØRST).
### C2.7 Validator-stramming (C-F2) — **Gate: D-A pkt. 1 godkjent + commons-pull utført**
Uendret fra gammel plan §3: (a) strukturell blokk `claimed > nominal_feasible``Rejection`;
(b) IR-invariant `low ≤ unit_cost ≤ high` (Pydantic `model_validator`). Premiss VERIFISERT
2026-07-10 (golden- og fixture-kompatibel: alle ikke-tomme bands omslutter unit_cost;
golden-claim 30 000 ≤ 90 000). TDD: moteksempel #1 (claim 100k/nominal 90k/band [0.70,1.40])
→ MÅ bli Rejection; band [1.8,2.2] om unit_cost 1.0 → ValidationError; detach nominal-blokken
→ rød. Filer: `validator.py`, `ir.py`, `tests/test_validator.py`, `tests/test_ir.py`;
`test_bygg_energi_mikro.py` uendret grønn.
### C2.8 OKF `/`-lenke-mapping (C-F4) — **Gate: D-A pkt. 3 godkjent + commons-pull utført**
Uendret fra gammel plan §3: ledende `/` mappes til bundle-rot i `navigate_bundle`;
boundary-sjekken består fail-closed. TDD: `](/tiltak.md)` → navigeres (detach → rød);
`](/../escape.md)` → fortsatt skippet. Filer: `okf.py`, `tests/test_okf.py`. Merk: MAF-siden
mangler fortsatt egen F4-byggsesjon — flagget står (operatøren legger den til der).
**Toolkit-kobling:** lander T0/K20 FØR D-A pkt. 3, flyttes `/`-mappingen inn i okf-core og
C2.8 blir en konsum-oppgradering — sesjonene merges da eksplisitt.
### C3.2 Per-verdict seeding (C-F5) — **Gate: D-A pkt. 4 godkjent + commons-pull utført**
Uendret fra gammel plan §3: seed leser features fra verdict-filas egen frontmatter (nye
valgfrie felt `affected_codes`/`measure_type`/`claimed_saving_nok`; fallback = dagens
nøkling); `promote` skriver feltene; multi-kandidat-fixture repo-lokal. TDD: to kandidater i
én bundle → dom om B når ALDRI As prompt via retrieval på As features (detach → rød);
eksisterende step1/step7/step8 uendret grønne (fallback). **R-8 (count-ærlighet, foldet inn):**
`seed_store_from_bundle` skal returnere FAKTISK lagret antall (eller logge drops), ikke
fil-antallet — RØD: to seed-filer uten `verdict_id`, ulik decision → i dag `seeded=2` men
`len(store)==1`; med per-verdict-nøkling blir de distinkte, og count matcher (detach nøklingen
→ count/antall divergerer igjen → rød). Filer: `experience.py`, `promotion.py`,
loadbearing-testene, ny fixture.
### C4.0 Kostbaseline-forankring (C-F3) — **Gate: D-A pkt. 2 godkjent + commons-pull utført**
Uendret fra gammel plan §3: baseline-projeksjon i bundle (`cost-baseline.json`,
commons-format) + fail-closed avstemmings-stage i `validate_proposal` (ukjent kode →
Rejection; utenfor toleranse → Rejection; toleranse konfig; baseline-argument VALGFRITT =
dagens oppførsel, men kjøresti-inngangen (C2.0/`run.py`) SETTER den når fila finnes). TDD:
F3-moteksemplet (diktet kode, 10 MNOK) → Rejection «unknown cost code» (detach → validated →
rød); golden-bundelen (uten baseline-fil) validerer uendret. Filer: `validator.py`,
`okf.py`/`ir.py` (loader), commons-fixture, nye tester. **MÅ være grønn før M2-analogen.**
### K13 Innholdsmodell + bibliotek + dimensjonskatalog + summary-tier (S3.5-analog) —
**Gate: commons-amendmenten (D-F/D-G-utkastet 2026-07-14) operatør-godkjent, committet i
commons OG pullet hit (koordinert med MAF; begge suiter grønne etter pull)**
- **Scope:** bygg fra den nye spec-teksten (aldri fra utkastet før det er landet):
(1) `dimension_catalog.py` — §13.3-katalogen, skjema-validert fail-fast (id, label,
allowed_measure_types, allowed_code_prefixes) + scoping-gate; eksempel-katalog under
`data/`; (2) `ingest.py``library`-kildefamilien (4a/5a: `library-{id}.md`, kuratert
frontmatter + additivt provenance-lag, kildebelegg-håndheving fail-fast ved tom/manglende
`sources`); (3) `okf.py` — summary-tier-render for bibliotek-typene (description-linje
default; full body kun for deterministisk pre-run-utvalg — kandidatens dimensjon); (4) ny
golden-case `examples/ingest-golden-library/` KUN hvis commons shipper den (fasit eies der).
- **TDD:** RØD per amendmentens fire detach-punkter (S3.5-malen): ugyldig katalog → fail-fast;
materialisert bibliotek-fil når prompten via `bundle_context` (detach → markør borte → rød);
summary-tier gir én linje, ikke fulltekst (detach → fulltekst-stuffing → rød);
separasjons-kontroll: bibliotek-fil når ALDRI prompten via dom-kanalen (folden).
- **Nøkkelantakelse (+test):** default uten bibliotek-filer er byte-identisk med dagens
render (amendment §3.2s garanti) — bindes med regresjonstest på eksisterende bundle FØR ny
funksjonalitet skrives. C1.1-vakten skal forbli GRØNN gjennom pullen (amendment §5.1 er
konstruert for det — verifiseres som pull-ens første sjekk).
- **Verifisering:** nye tester grønne + detach → rød; `test_bygg_energi_mikro` + begge
ingest-goldens uendret; full gate; sammenligningsprotokoll-kjøring i BEGGE repo.
### K14 MCP-ingest-konnektor (S2.2-analog) — **Gate: D-B besluttet + ingest-spec-amendment
(mcp-familien) landet i commons + pullet hit**
SDK-nativ analog: kildefamilie `mcp` i manifestet; test-fixture = in-process MCP-server via
SDK-primitivet `create_sdk_mcp_server`/`@tool` (av-demoer extension-pointet uten socket).
Per-run-grant: eksplisitt flagg (ingest-spec §8-mønsteret — run-argument, aldri manifest-felt).
TDD: manifest med `type: mcp` uten grant → `IngestError` (detach → rød); golden-materialisering
mot fixture-server byte-deterministisk; verdict-reservasjonen gjelder også mcp-familien.
Nøkkelantakelse (testes FØRST i sesjonen): SDK-MCP-serveren kan drives i-prosess uten socket —
hvis ikke, subprosess-fixture med eksplisitt merking. OBS: `ingest.py` er i dag SDK-fri —
mcp-konnektoren legges i EGEN modul (f.eks. `ingest_mcp.py`) så ingest-kjernens renhet består
(detach-vaktene i `test_ingest_loadbearing` urørte).
### K15 Dokument-konnektor PDF (S2.3-analog) — **Gate: D-B besluttet (inkl. pypdf-dep-valget)
+ ingest-spec-amendment (doc-familien) landet + pullet**
Tekst-ekstraksjon per side, fenced-verbatim-render (gjenbruk http-regelen fra spec §5),
`max_rows`-cap, fail-fast på ikke-tekst-PDF; DOCX utsatt (D-B). TDD: golden byte-determinisme;
cap-overskridelse → feil, aldri trunkering; pin pypdf-versjon (golden fanger drift).
### K16 http-kilde + konnektor-herding + guard-G1 (S2.4-analog) — **Gate: D-B besluttet MED
http/live-kilde i scope (i dag eksplisitt utenfor D7-roadmap)**
Bygger http-familien (i dag avvist fail-fast — det er selve utløseren som endrer det):
`base_url`/`credential_ref` per ingest-spec §4, nettverks-opt-in per §8 (fail-fast uten flagg
— load-bearing §11-raden «Network gate»), timeout + feilkategorisering mot injisert transport
(aldri live), OG guard-planens G1-wiring i samme økt: `prepare_input` → deterministisk render
`screen_output` FØR skriving av konseptfila; FAIL_SECURE → ikke skriv, alert med gate-kode
uten innhold. Guard-dep pinnes + versjonsvakt (samme disiplin som C2.5). TDD: per feilmodus
canned transport → presis IngestError; uten opt-in → nekt (detach → rød); injeksjons-fixture →
fila skrives ALDRI (detach guard-gaten → payload lander i bundelen → rød — guard-planens §7).
STATE-markørlinjen oppdateres `planned``integrated` med detach-bevis.
### K17 Semantisk henting (S3.1-analog) — **Gate: D-C besluttet OG C-P1 avklart i D-A-bolken
(amendment av ranking-regelen ELLER re-scoping til strukturelle features) + evt. commons-pull**
Scope avhenger av C-P1-utfallet: (a) amendment-varianten: `Retriever`-seam +
`HybridRanker` (strukturell + cosine over lagrede vektorer, delt format .npy+jsonl per D-C),
deterministisk fake-embedder i tester; (b) re-scoping-varianten: embeddings over strukturelle
features alene. Uansett: ny `semretrieval.py` SDK-fri, opt-in seam i `experience.py`, ingen
endring i `shared/`. TDD: syntetisk base der KUN den nye komponenten kan rangere riktig dom
øverst (detach → rød); determinisme ×2 kjøringer; fake-embedder bit-stabil.
`test_surface_text_never_contributes` består i variant (b); i variant (a) endres den KUN slik
amendmenten krever.
### K18 Concurrency/feilmodell (S3.3-analog) — **Gate: D-D besluttet (+ K2 landet)**
Bølge-modellen fra D-D-fasiten når den kommer: `run_portfolio(concurrency=k)`, snapshot per
bølge, deterministisk merge-barriere, collect-and-continue-feilpolicy (erstatter K2s
raise-default bevisst). TDD: concurrency=3 byte-identisk med concurrency=1 på 3-prosjekt-
fixturen (detach barrieren → rød over repetisjoner); injisert feil i prosjekt 2 → 1+3 bevart.
Nøkkelantakelse å teste FØRST: asyncio-samtidighet i én event-loop med ScriptedClient
(SDK-klienten er async — anyio-premisset verifiseres i sesjonen).
### K19 Kostnadsstyring på tvers (S3.4-analog) — **Gate: D-D besluttet (deler feilpolicy)**
`PortfolioBudget` (globalt tak + per-run-tak) over C3.5-primitivene; spend-persistens
(deterministisk JSON, eksplisitt stamp); oppstartsnekt når rest < minimum per kjøring. TDD:
globalt tak krysses midt i passet → strukturert stopp med fullførte runs bevart (detach → rød);
pre-call-guard nekter kallet (kall-tellende mock).
### K20 okf-toolkit-adopsjon inkl. skrive-halvdelen (D-G/T0) — **Gate: okf-toolkit-repoet
finnes, T1 (okf-core + formatprøve) er publisert/installerbar, OG operatøren har godkjent
koordinert A1+A2-migrering (toolkit-briefens §7: migreringene er koblet, ikke uavhengige)**
- **Scope:** importér `okf-core`; `okf.py`-lesekjernen delegerer/erstattes; skrive-halvdelen
(render_frontmatter/write_concept_file/link_in_index-ekvivalentene) blir tilgjengelig her —
D-Gs «minst like godt»-hovedgevinst; kjør formatprøven (conformance-testsettet) mot egne
bundler i suiten; `pyproject.toml` (+dep, pin + versjonsvakt samme disiplin som C2.5).
- **TDD:** RØD: formatprøven kjører i suiten og en bevisst malformert fixture-bundle feiler
minst én conformance-test; RØD: skrive-primitivene importérbare og brukt av promotion-stien
(detach → promotion faller tilbake/feiler → rød); eksisterende okf-purity-vakt beholdes
(okf-core er stdlib-only per toolkit-briefen §2 — verifiseres, ikke antas).
- **Bevisst avvik:** dette endrer «from spec alone» for formatlaget — operatør-besluttet
(D-G pkt. 2, revisjonspakke §0.2); dokumenteres i README/CLAUDE.md i samme sesjon.
- **Verifisering:** full gate; golden uendret; sammenligningsprotokoll-kjøring i BEGGE repo
(A1-migreringen skjer koordinert på MAF-siden).
### Guard G3 (`okf.import_bundle`) — **Gate: delt D-E-retning åpner bundle-utveksling**
Ingen egen sesjon planlegges før gaten: wiring-formen står i guard-planen §4 G3.
## 5. Avhengighetsgraf + anbefalt sekvens
```mermaid
flowchart TB
subgraph OPER["Operatør-gater (delt kø i HOVEDREPOET + amendment/toolkit)"]
DA["D-A (+C-P1)"]; DB["D-B"]; DC["D-C"]; DD["D-D"]; DE["D-E"]
AMD["commons-amendment D-F/D-G"]; T0[["T0 okf-toolkit (finnes ikke)"]]
end
C11["C1.1 spec-vakt"] --> C25["C2.5 inbox+SDK-vakt+R6"] --> C20["C2.0 kjøresti-inngang"]
C26["C2.6 validator-finitthet (R2)"]; K29["K2.9 ingest-robusthet (R3-R7)"]
C20 --> K4["K4 closed-loop-sim (R1)"]
C20 --> K2["K2 portefølje-kjøring"]
K1["K1 ledger+goals"] --> K2 --> K3["K3 portefølje-læring"]
K5["K5 outbox"] --> K8["K8 live-drill"]; K7["K7 preflight"] --> K8
K5 --> K9["K9 HITL-ruting"] --> K10["K10 notifier"]
K1 --> K11["K11 verdirapport"]; K5 --> K11; K6["K6 costsim"] --> K11
C35["C3.5 budsjett-guard"] --> K8
K3 --> K12["K12 CLI-paritet+oppskrift"]; K9 --> K12; K11 --> K12
DA --> C27["C2.7 validator"]; DA --> C28["C2.8 /-lenker"]; DA --> C32["C3.2 seeding"]; DA --> C40["C4.0 kostbaseline"]
AMD --> K13["K13 bibliotek+katalog+summary-tier"]
DB --> K14["K14 MCP-ingest"]; DB --> K15["K15 doc-PDF"]; DB --> K16["K16 http+guard-G1"]
DC --> K17["K17 semantisk henting"]; DA -. C-P1-avklaring .-> K17
DD --> K18["K18 concurrency"]; DD --> K19["K19 kost på tvers"]; K2 --> K18; C35 --> K19
T0 --> K20["K20 okf-core-adopsjon"]
C40 --> M2A{{"M2-analog: evt. ny live-kjøring (operatør + D-E + D6-ny-godkjenning)"}}
K8 --> M2A; DE --> M2A
```
**Anbefalt sekvens (ugatet først — åpningen C1.1 → C2.5 → C2.0 står, med review-begrunnelse
uendret):**
1. **C1.1 → C2.5 → C2.0** (vakt → herding → inngang)
2. **C2.6 → K2.9** (korrekthets-hardening — R-2 validator-omgåelsen har høyest verdi av alt
ugatet; kan tas rett etter C1.1 hvis ønskelig, uavhengig av C2.5/C2.0)
3. **K4** (closed-loop-sim — lukker §11-gapet R-1 tidlig)
4. **K1 → K2 → K3** (portefølje-fundamentet)
4. **K5 → C3.5 → K6 → K7 → K8** (outbox/kost/preflight/drill)
5. **K9 → K10 → K11 → K12** (HITL/varsling/verdirapport/CLI-sluttsync)
6. Ved D-A (når som helst, uavhengig av 15): **C2.7 → C2.8 → C3.2 → C4.0** etter koordinert
pull; ved amendment: **K13**; ved D-B: **K14 → K15 → K16**; ved D-C+C-P1: **K17**; ved
D-D: **K18 → K19**; ved T0: **K20**.
7. Vedlikehold når som helst: koordinert subtree-pull av de to docs-only commons-commitene
(ingen spec-endring — men kjør begge suiter etter pull likevel, protokoll-regelen).
**Koordineringspunkter med MAF (absolutte):** (a) etter HVER amendment-bølge: begge repo
puller subtree og BEGGE suiter kjøres — aldri én side alene; (b) golden re-fryses kun
koordinert i commons; (c) K10 speiler MAF S5.2 på kapabilitetsnivå (plan-lesing, aldri kode);
(d) K20/A1-migreringen er koblet på tvers av repoene (toolkit-brief §7); (e) C2.8-flagget om
manglende MAF-F4-byggsesjon står til operatøren har lagt den til der.
## 6. Operatør-milepæler (aldri autonome sesjoner)
- **M2-analog — eventuell ny live-kjøring:** krever ALT av: eksplisitt operatør-godkjenning
(D6: ny spend), D-E (stack-paritet for ekte kjøring — avgjør om D7 i det hele tatt skal
kjøre live igjen), C4.0 grønn (kostbaseline FØR ekte modell), C3.5 + K6 + K7 + K8 grønne
(guard, estimat, preflight, drill), harde tak satt. Forutsetningen «nøkkel satt + preflight
grønn» er D7-ekvivalenten av MAFs M1. Utfall re-rulles ikke (protokoll §4.5).
- **M3-analog (pilot):** følger MAF-planens M3 — ikke planlagt her før D-B/D-E/toolkit-
fabrikken foreligger; D7-deltakelse avgjøres av D-E.
## 7. Leveringsklar-definisjon (binær sjekkliste)
«Leveringsklart» er nådd når ALLE punkter under er sanne (hver enkelt er kommando-verifiserbar):
- [ ] Alle paritetsmatrise-rader (§1) er enten **FINNES HER** (bygget + load-bearing-testet)
eller **SPEILES IKKE** med begrunnelse operatøren har sett — ingen rad står i BYGGBAR
NÅ; GATED-rader er enten utløst+bygget eller eksplisitt operatør-akseptert som
utestående (beslutnings-køens ansvar, dokumentert i STATE).
- [ ] Full gate grønn: `uv run pytest` (alle tester, offline uten nøkkel/nett) +
`uv run ruff check .` + `uv run ruff format --check .` + `uv run mypy src`.
- [ ] §11-tabellen komplett: hver rad (inkl. «Spec integrity» C1.1 og «Closed loop» K4) har
en navngitt test som er detach-bevist rød (bevis i testfil eller sesjonslogg).
- [ ] README/docs ærlige (§1): hver kapabilitets-påstand matcher en skipbar sti (K12s
ærlighets-test grønn); skriptede stand-ins merket; ingen nivå-2-verdipåstand uten
D-I-belegget.
- [ ] Guard-markørlinjen i STATE.md er korrekt (planned/integrated per faktisk wiring-status,
med detach-bevis hvis integrated).
- [ ] Golden-bytene uendret mot commons (eller re-frosset KOORDINERT i commons med begge
suiter grønne).
- [ ] `runs/s10/` byte-urørt; `run_s10.py` byte-urørt.
- [ ] Subtree i synk med commons (ingen utestående spec-commits; verifisert med subtree-diff).
- [ ] STATE.md oppdatert etter konvensjonen; CHANGELOG dekker alle landede sesjoner.
- [ ] **`open`-speiling som EGEN operatør-gated sluttpost:** push til `open` skjer ALDRI
automatisk — operatøren godkjenner eksplisitt hvilke commits som speiles, som siste
handling etter alt over.
## 8. Endringer mot 2026-07-10-planen
| Gammel plan | Endring |
|---|---|
| §4 «Overføres IKKE hit (MAF-spesifikt)» | **OPPHEVET** — re-klassifisert rad for rad i §1 (operatør-mandat 2026-07-16) |
| C1.1/C2.0/C2.5/C2.7/C2.8/C3.2/C3.5/C4.0 | Videreført uendret i substans (C3.5 løftet fra «valgfri» til paritetskrav; C2.5 utvidet med guard-G2-vurdering) |
| «ingen D7-HTTP/MCP-økt planlagt» | Erstattet av K14K16, gated D-B |
| (fantes ikke) | K-serien: K1K20 (paritetssesjoner) + M2-/M3-analoger + leveringsklar-definisjon (§7) |
| (fantes ikke) | Review-paritet R-serien (2026-07-16): C2.6 (R-2 validator-finitthet), K2.9 (R-3/R-4/R-5/R-7 ingest-robusthet), K4 (R-1 closed-loop); R-6→C2.5, R-8→C3.2, R-10→C2.0/C2.5 |