portfolio-optimiser/docs/plan/2026-07-25-amendment-underlag.md
Kjell Tore Guttormsen e0fa223591 Squashed 'shared/' changes from a2b57d2..ddaae5d
ddaae5d chore(release): publiseringsklar for open/ — README for standalone rot + MIT + policy-filer
f98b287 docs(plan): V1 RATIFISERT — og :275 er en andre tabellrad, ikke prosa
d6bced7 docs(plan): SS11 ankrer ikke SS8 — funnet var reelt, men ikke raden som ble bestilt
3174475 docs(plan): §7.2 — feilanker-failuremoden var ikke hypotetisk, den inntraff

git-subtree-dir: shared
git-subtree-split: ddaae5d637ba4ee8425291d99cfe5c8f7b632001
2026-08-05 08:24:14 +02:00

547 lines
34 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Amendment-underlag — hva frossen tekst sier i dag, per køpunkt
**Status:** underlag. Spec-en er IKKE endret, og dette dokumentet foreslår INGEN ny tekst.
Ny tekst er pakken operatøren ratifiserer, og den eies oppstrøms (`portfolio-optimiser`,
sammen med `portfolio-optimiser-claude`s tekstforslag). Dette dokumentet svarer bare på
spørsmålet commons kan svare på uten å foregripe ratifiseringen: **hvilke seksjoner røres,
hva står der i dag (fil + linje), og hva koster endringen mot fasit-bundelen.**
**Foranledning:** `portfolio-optimiser` klarerte 2026-07-25 (05:09Z, punkt 3) generelt
underlag som trygt arbeid som ikke invalideres av at pakken deres holdes: *«preparing GENERAL
underlag (which spec sections those five stories touch, what the frozen text says today) is
safe work that will not be invalidated»*. Dette er det arbeidet.
**Grunnlag:** commons HEAD `a67a243`. Normativ spec-tekst er uendret siden `bfa5a9b`
(ingest-spec, D1-stempelmodellen) / `9801d35` (method-spec §3 Steg 1, Q3-navigasjonen) /
`b641741` (nav-golden-fixtures) — alle 2026-07-21. Hver sitat-blokk under er hentet fra HEAD
og linjeankeret verifisert, ikke gjengitt fra hukommelse.
> **Leseanvisning for konsumenter (tilføyd 2026-07-26).** Alle linjeankere i dette dokumentet
> gjelder **commons HEAD**. Konsumentene er pinnet på eldre `shared/`-subtrær, og et
> linjenummer overlever ikke en pull-grense: `portfolio-optimiser-claude` står på `7aa53fc`,
> der `method-spec.md` er 441 linjer og §12 begynner på `:413` — mot 464 linjer og `:436` her.
> **Sitér seksjon + ordrett tekst; linjenummeret er en bekvemmelighet, aldri ankeret.** Et
> linjenummer sitert over en pull-grense er et *premiss*, ikke et faktum (metodenote fra
> `portfolio-optimiser-claude`, 2026-07-26 — de fant den på dette dokumentets egne sitater).
---
## 0. Køen, avstemt
To korreksjoner fra `portfolio-optimiser` (16:11Z) er **godtatt**, begge verifisert:
1. **Tittel-whitespace er ikke et eget punkt** — det ER amendment-innholdet i S3.5. Vår
telling dobbeltførte det. (Deres kø-linje `(a) commons-amendment tittel-whitespace → S3.5`
ble lest som «punkt ved siden av», ikke «innholdet i».)
2. **B1 er ute av pakken** — commons-eid, ingen adferds-interesse oppstrøms. Bæres separat
(§8 her).
Én korreksjon går **tilbake** oppstrøms, og den er grunnen til at underlaget er verdt å
skrive før pakken lukkes:
3. **De to oppstrøms-enumerasjonene er ikke den samme mengden.** `portfolio-optimiser`
teller fem *stories* (S2.7 / S2.22.4 / S3.2 / S3.5 / S4.0); `portfolio-optimiser-claude`
teller fem *D-A-punkter*. Bare tre par binder (S2.7 = D-A#1, S3.2 = D-A#4, S4.0 = D-A#2).
De to gjenstående D-A-punktene har **ingen story-etikett** oppstrøms:
- **D-A#3 (ledende `/`)** — trenger ingen amendment i det hele tatt. Frossen tekst i
commons HEAD sier allerede det punktet ber om (§3 under). **Årsaken er repo-avhengig**
(begge konsumenter svarte, med hver sin — begge er sanne): drift over pull-grensen hos
`portfolio-optimiser-claude`, målt konformitetsgap i `okf.py` hos `portfolio-optimiser`.
Anbefalingen er den samme uansett hvilken som gjelder hvor.
- **D-A#5 (hovedbok-projeksjoner)** — er reell og har ingen tekst å endre (§6 under), men
mangler story-etikett. Ratifiserer operatøren «pakken» slik `portfolio-optimiser`
beskriver den, faller D-A#5 utenfor.
Netto, fra commons' side: pakken er deres seks **pluss** hovedbok-kontrakten = **sju
ratifiserbare punkter**, med D-A#3 strøket som amendment. B1 utenfor, som avtalt.
Tallet er ikke poenget — membership er.
**S2.22.4 (D-B)** var det ene punktet commons ikke kunne ankre. **Substansen kom 2026-07-26**
og er ført i §7.17.2: D-B er en *scope*-beslutning, ikke spec-tekst. **To av de tre gatede
storiene viste seg UGATED** — S2.2 fordi §4s `http`-punkt normativt plasserer MCP-konnektorer i
`http`-familien (MUST på samme kontrakter), S2.4 fordi berikelsen holder seg innenfor §8s tre
felt. **Kun S2.3 (`doc`) krever amendment.** Begge frigjøringene kom av ankring i frossen tekst,
ingen av dem av en endring.
---
## 1. S2.7 / D-A#1 — nominal feasibility skal GATE, + IR-invariant `low ≤ unit_cost ≤ high`
**Seksjoner:** `method-spec.md` §3 Steg 4 (`:150-166`), §7.1 (`:335-346`), §7.2 (`:348-365`),
§12 (`:458`).
**Hva frossen tekst sier i dag.** Den nominale grensen *beregnes*, og bare `p90` *blokkerer*:
> **`method-spec.md:157-160`** (§3 Steg 4, punkt 2)
> 2. **Feasibility bound:** the maximum feasible saving is capped at a policy fraction
> (0.30) of the affected items' total cost. *(reference: computed with an LP solve whose
> closed form here is `0.30 × Σ quantity·unit_cost`; a missing solver MUST escalate, never
> silently fall back.)*
> **`method-spec.md:163-166`** (§3 Steg 4, punkt 4)
> 4. **Structural block:** a claim above the optimistic feasible bound (`p90`) yields a
> **rejection that is a distinct type from a validated proposal** …
Punkt 2 sier `capped at`, men gir ingen avvisningsregel; punkt 4 er den ENESTE blokkeringen
og bruker `p90`. Påstanden «beregnes, men bare p90 blokkerer» holder altså mot teksten.
§7.2 sier det samme eksplisitt om hva assertionen betyr:
> **`method-spec.md:356-358`** (§7.2)
> … The meaningful assertion is `validates` = true (claimed ≤ `p90`); the frozen numbers are
> the regression net.
`nominal_feasible` er et frosset felt (`:352-356`, kryssjekk `:458`) — det er allerede
normativt *rapportert*, bare ikke *gatende*.
**IR-invarianten finnes ikke.** §7.1 har én construction-time-invariant, og den handler om
noe annet:
> **`method-spec.md:343-344`** (§7.1)
> - Construction-time invariant: the claimed saving MUST NOT exceed the affected items' own
> total (`Σ quantity·unit_cost`); violation is a schema error, not a validator rejection.
`assumptions` er definert som band per kostkode (`:341-342`), men ingenting binder
`unit_cost` til å ligge INNI sitt eget band. Hullet er reelt.
**Målt mot fasit-bundelen (`examples/bygg-energi-mikro/`) — begge endringene er byte-nøytrale:**
| Sjekk | Verdi i fasit | Konsekvens |
|---|---|---|
| `claimed_saving_nok` vs. `nominal_feasible` | `30000` vs. `90000.0` | claimed ≤ nominal → en nominal gate endrer ikke `validates` (fortsatt `true`) |
| `unit_cost` vs. eget band | `1.0` i `[0.70, 1.40]` | invarianten er allerede oppfylt → fixture trenger ingen endring |
Kilder: `examples/bygg-energi-mikro/golden.json` (validator-blokken),
`examples/bygg-energi-mikro/validator-input.json` (`affected_items[0]`, `assumptions`).
**Klassifisering:** ekte hull i frossen tekst (begge deler). Gratis mot goldenbytene.
**Operatør-spørsmålet:** skal nominal-grensen gi samme *type* avvisning som p90-blokket
(`:163-166` sier «distinct type … carrying the claimed and feasible figures … and no
percentiles») eller en egen? Teksten har i dag én avvisningsform, og den er definert av p90.
---
## 2. S3.2 / D-A#4 — seedet dom skal nøkles på SINE EGNE features
**Seksjoner:** `method-spec.md` §3 Steg 1, experience fold (`:105-123`).
> **`method-spec.md:108-114`**
> - The retrieval query key is the bundle's candidate features, read from the IR projection
> (§7.1) — available *before* any proposal exists.
> - Seeding: every `type: verdict` file in the bundle becomes a store entry keyed on those
> candidate features, with `decision` from frontmatter (default `approved`) …
`those candidate features` refererer tilbake til forrige kulepunkt — bundelens ENE
IR-projeksjon. Frossen tekst sier altså eksplisitt det punktet vil bort fra: hver seedet dom
arver bundelens projeksjonsnøkkel, ikke sin egen. Hullet er reelt og teksten er entydig.
**Berøringsflate videre:** nøkkelen er det rangeringen (`:115-120`) og id-mintingen
(§4.2 `:254-260`) hviler på. `affected_codes` / `measure_type` / `claimed_saving_nok` er
feltene en «egen-features»-nøkling må komme fra, og §4.2 `:250-252` sier at `description`
bevisst er utenfor både likhet og minting. En amendment her må si hvor en seed-fils egne
features LESES fra (frontmatter? egen projeksjon?) — det er den åpne enden, ikke prinsippet.
**Målt:** fasit-bundelen har én seed (`verdict-led-fro.md`) og én projeksjon, så
`golden.json` kan ikke skille gammel og ny nøkling. Endringen er byte-nøytral her, og
fasiten er derfor ikke et vern mot regresjon på dette punktet.
**Klassifisering:** ekte hull. **Operatør-spørsmålet:** kilden for en seeds egne features.
---
## 3. D-A#3 — ledende `/` : INGEN amendment nødvendig
**Dette punktet er allerede normativt i commons HEAD** (landet `9801d35`, 2026-07-21):
> **`method-spec.md:67-71`** (§3 Steg 1)
> - Navigation starts at `index.md` and follows its intra-bundle markdown cross-links
> (`](target.md)`). A target is resolved **relative to the bundle** and boundary-checked
> fail-closed (below): a leading `/` denotes the **bundle root** (NEVER a filesystem-absolute
> path), any other form is relative to the linking file's own directory — so a target MAY
> address a nested directory (`sub/index.md`, `/a/b.md`).
Og §11 har allerede rød-betingelsen som feiler hvis en implementasjon hopper over den:
> **`method-spec.md:425`** (§11, «Navigation boundary»)
> … an escaping cross-link (`..`, a filesystem-absolute path, or a bundle-root `/` read as
> filesystem-absolute) is followed, a malformed target … is raised instead of skipped, or a
> legitimate nested in-bundle link is skipped
Teksten sier også selv at den ERSTATTET den gamle skip-heuristikken (`:73-74`).
**Klassifisering:** **drift over pull-grensen** — verken spec-hull eller konformitetsavvik.
Ligger et forslag om å «endre» §3 Steg 1 her, endrer det tekst som allerede sier det forslaget
vil oppnå — og risikoen er at ratifiseringen omformulerer en fungerende regel. **Meldt
oppstrøms.**
> **Årsaks-korreksjon (2026-07-26).** Første utgave av dette avsnittet klassifiserte D-A#3 som
> «konformitetsgap i implementasjonen» og skrev at forslaget beskrev implementasjonens
> oppførsel framfor specens. **Det var feil årsak.** `portfolio-optimiser-claude` målte det mot
> eget tre og svarte at deres `shared/method-spec.md` greper 0 for «bundle root» og
> «filesystem-absolute» — fordi teksten landet i `9801d35`, og:
>
> ```
> git merge-base --is-ancestor 9801d35 7aa53fc -> false (reprodusert her)
> ```
>
> Deres split er `7aa53fc`; driften er 15 commits per 2026-07-26. De står i «ikke pullet»
> **bevisst** — avtalen er samme commons-commit i begge repo før noen bygger. D-A#3 var altså
> korrekt formulert mot den frosne teksten de har lov til å se; regelen landet oppstrøms
> etterpå. **Anbefalingen er uendret** (punktet ut av pakken, siden regelen er normativ når
> pakken lander), men den følger av drift, ikke av et avvik hos dem.
>
> Lærdommen generaliserer og er derfor løftet til leseanvisningen øverst: **samme felle venter
> på ethvert punkt målt mot en bevegelig frossen tekst mens konsumentene er pinnet.**
> **Andre korreksjon, samme dag — årsaken er REPO-AVHENGIG, og begge svar er sanne.**
> `portfolio-optimiser` svarte kort etter og klassifiserte D-A#3 som **«et KONFORMITETSGAP i
> implementasjonen vår — ikke et spec-hull»**, med en konkret årsak: *«okf.py hopper over enhver
> lenke med `/`»*. Det er den motsatte klassifiseringen av den `portfolio-optimiser-claude` ga.
>
> **Ingen av dem tar feil.** De beskriver to forskjellige repo:
>
> | Repo | Har `9801d35`? | Årsak der |
> |---|---|---|
> | `portfolio-optimiser-claude` | nei (pinnet `7aa53fc`) | **drift** — regelen finnes ikke i teksten de har |
> | `portfolio-optimiser` | nei (pinnet `7aa53fc`) | **konformitetsgap** — de har målt eget avvik i `okf.py` og har det på operatørkøen som implementasjonssak |
>
> Begge konsumenter står på samme commons-commit (`7aa53fc`, bekreftet av begge uavhengig), så
> pullen er én koordinert handling, ikke en opprydding etter usynk.
>
> **Dette avsnittets egen historie er poenget:** første utgave ga én universell årsak, korreksjonen
> ga en annen universell årsak, og begge var for brede. «Årsaken til D-A#3» er ikke én ting når
> konsumentene er pinnet og har ulik implementasjonstilstand. Anbefalingen har vært uendret hele
> veien — punktet ut av pakken — og den avhenger ikke av hvilken årsak som gjelder hvor.
---
## 4. S4.0 / D-A#2 — kostbaseline-forankring (`cost-baseline.json`)
**Seksjoner:** `method-spec.md` §7 (`:330-333`), §7.1 (`:335-346`), §12 (`:441-464`).
**Frossen tekst har ingen baseline-forankring**`grep -c 'cost-baseline'` over begge
spec-er: **0 treff**. Det som finnes, og som en ubetinget baseline kolliderer med:
> **`method-spec.md:332-333`** (§7)
> The shared example bundle ships two JSON files that are **the only ground truth** ("fasit")
> for cross-implementation equivalence. Implementations MUST consume them unchanged.
**Målt:** `examples/bygg-energi-mikro/` inneholder nøyaktig to JSON-filer
(`validator-input.json`, `golden.json`) og seks markdown-filer. Ingen baseline. Et ubetinget
krav gjør en tredje fil til ground truth og gjør setningen over usann samtidig — pluss at
fasit-bundelen må utvides, hvilket er en fixture-endring, ikke bare en tekstendring.
`portfolio-optimiser-claude`s egen formulering («åpent om den skal være obligatorisk … et
ubetinget krav endrer golden-bytene») treffer riktig, og §7:332-333 er ankeret som gjør det
konkret.
**Presedens for hvordan en required input formuleres**, hvis den blir obligatorisk:
> **`method-spec.md:345-346`** (§7.1)
> - Loading the IR projection from a bundle is FAIL-FAST: a missing file raises (required
> input — contrast the tolerant inbox, §5).
**Klassifisering:** ekte hull, men det eneste punktet i køen som (hvis ubetinget) **endrer
fasit-bundelen** og ikke bare prosa. **Operatør-spørsmålet:** obligatorisk for alle kjøringer
(→ fixture-endring + §7-setningen må omskrives), eller opsjonell med fail-fast-semantikk kun
når den finnes (→ ren prosa-utvidelse, fasiten uendret)?
---
## 5. S3.5 / D-F — tittel-whitespace
**Seksjoner:** `ingest-spec.md` §4 (`:125`), §5 (`:149-161`), §6 (`:194-197`), §11 (`:278`),
§12 (`:301`).
> **`ingest-spec.md:125`** (§4, extraction-tabellen)
> | `title` | Human-readable title; … Single-line, and MUST NOT contain `[` or `]` … Validated
> fail-fast at manifest load — rendered verbatim thereafter (§5, §6). |
> **`ingest-spec.md:158-161`** (§5, frontmatter-kulepunktet)
> … All values MUST be single-line; `title` is emitted **verbatim** (it is `[`/`]`-free by §4,
> so verbatim rendering is safe — the invariant is met by validation, not repair); the
> materializer MUST collapse whitespace runs (including newlines) in `source_query` to single
> spaces.
Formen på hullet, presist: **collapse er scoped til `source_query` alene**, og `title` er
uttrykkelig `verbatim` med invarianten «met by validation, not repair». En tittel med interne
whitespace-runs er derfor ikke normalisert noe sted — den er bare «single-line», og hva
`single-line`-valideringen dekker (bare `\n`? `\r`? ledende/etterfølgende blanke?) står ikke.
Amendment-punktet ligger i den sømmen, og valget er **validere hardere** vs. **reparere**
teksten har i dag valgt validering for `title` og reparasjon for `source_query`.
**⚠ Anker-avvik oppstrøms (viktig for denne teksten spesielt).** `portfolio-optimiser` ankret
sitatet til `shared/ingest-spec.md:140`. Det linjenummeret er commons ved **`7aa53fc`**, ikke
HEAD:
- ved `7aa53fc`, linje 140: `` `generated`. All values MUST be single-line; the materializer MUST collapse whitespace runs ``
- ved HEAD (`bfa5a9b`): samme setning er splittet over `:158` og `:160-161`, og `title is
emitted verbatim` + «validation, not repair» er **ny tekst** fra `bfa5a9b`.
`bfa5a9b` (+39/9) skrev om nettopp dette kulepunktet OG `title`-raden i §4 (som gikk fra
bare «Single-line.» til dagens `[`/`]`-forbud + fail-fast + verbatim). Deres `shared/`-kopi
ser altså ut til å ligge ett commons-commit bak, fra FØR D1-stempelmodellen landet. Det
betyr at S3.5 kan være formulert mot tekst som ikke lenger finnes i den formen — og det er
samme risiko de selv navnga («pullen må være koordinert, samme commons-commit»). **Meldt
oppstrøms.**
**Klassifisering:** ekte, men smal søm. Ingen fasit-effekt her (våre fixtures har ingen
ingest-manifester; goldenbundlene for ingest bor i implementasjonene, jf. §11 `:259-261`).
---
## 6. D-A#5 — projeksjoner over besparelses-hovedboken (INGEN eksisterende tekst)
**Målt:** `grep -ci 'ledger'` og `grep -ci 'hovedbok'` over `method-spec.md` +
`ingest-spec.md` → **0 og 0**. Ingen monetær avrundingsregel finnes heller: alle 13
forekomster av `round` (12 linjer: 9 i method-spec, 3 i ingest-spec) er andre ting
(`round-capped` debatt `:141`/`:386`, `max_rounds` `:378`/`:385`, `shortest round-trip
decimal` `ingest-spec.md:165`, `round-trip` `ingest-spec.md:85`, `around` `:323`).
Nærmeste eksisterende flater, som en ny kontrakt må forholde seg til uten å kollidere:
- **`method-spec.md:367-372`** (§7.2 `learning_surface`) — de monetære feltene som ER frosset
(`modelled_saving_nok`, `expected_actual_saving_nok`, intern konsistens påkrevd).
- **`method-spec.md:199-202`** (§3 Steg 6) — råresultater er output-laget, «plain JSON», og
bruker bevisst IKKE wiki-formatet.
- **`method-spec.md:250-252`** (§4.2) — `claimed_saving_nok` som tall i verdict-kontrakten,
og `description` bevisst utenfor likhet/minting.
- **`method-spec.md:436-464`** (§12) — kryssjekk-tabellen er *fullstendighets-håndhevet* av
spec-integritetstesten (§11 `:434`), så en ny kontrakt med nye felter MÅ inn her, ellers
feiler den testen. Dette er den mekaniske konsekvensen ingen av oppstrøms-meldingene nevner.
**Klassifisering:** ny seksjon, ikke en amendment. Dette er køens største punkt (den eneste
som utvider spec-ens virkeområde) og samtidig den uten story-etikett oppstrøms — mest utsatt
for å falle mellom de to enumerasjonene. **Meldt oppstrøms.**
**Note, videreformidlet ikke verifisert her:** `portfolio-optimiser` melder (16:11Z, pkt. 4)
at forslagets A5-regel 1 («Monetary figures MUST NOT be rounded in the projection») treffer
en persisterings-kant hos dem (NOK→øre-kvantisering) og bør skille projeksjons-aritmetikk fra
enhets-kvantisering. Commons har ikke lest deres kode og fører det som deres måling, ikke som
vårt faktum.
---
## 7. S2.22.4 / D-B — substansen er ikke ankret hos commons
Punktet er kjent bare som etikett. Vi leste det ut av `portfolio-optimiser`s STATE
(GATES-blokk) 2026-07-25 04:05Z og har aldri fått innholdet. `grep -rn 'D-B'` over dette
repoet gir **0 treff** — heller ikke i vår egen STATE, som bare bærer story-etiketten
`S2.2-2.4`. Koblingen `S2.22.4 (D-B)` finnes utelukkende i coord-arkivet
(`20260725T040535Z`, vår egen melding), ikke i noen commons-tekst.
Commons kan derfor ikke si hvilken seksjon det rører. **Ingen antakelse føres.** Dette er den
ene raden i underlaget som er blank av en grunn — og den blir stående blank til substansen
kommer. **Etterspurt oppstrøms.**
### 7.1 Substansen ER LEVERT (2026-07-26) — raden er ikke lenger blank
`portfolio-optimiser` leverte D-B-substansen på direkte forespørsel. Kilde:
`docs/plan/2026-07-10-sesjonsplan-fase2-6.md` **i deres repo, ikke commons** — gjengitt her som
mottatt, ikke verifisert av oss (vi har ikke lesetilgang til premisset, og fører det som
*rapportert*, ikke *målt*).
**D-B er en SCOPE-beslutning, ikke en spec-tekst.** Det er den avklaringen som gjør raden
meningsfull: vi lette etter hvilken seksjon den rører, og svaret er at *den selv* ikke rører
noen — den avgjør om tre andre stories gjør det. Fire delbeslutninger (`:56-62`): (1) amender
ingest-målbildet bevisst vs. nedskopér roadmap-B til mock-herding *(deres anbefaling: nedskopér
nå)*; (2) første live-kilde *(anbefaling: SQL — `read_sql` er mest herdet, read-only by
construction)*; (3) dokument-konnektor-avgrensning *(PDF via `pypdf` nå, DOCX utsatt)*;
(4) MCP-kildefamiliens nettverks-/subprosess-grant-form.
**Konsekvensen for commons — hvilke av de tre gatede storiene som faktisk krever amendment:**
| Story | Krever ingest-spec-amendment? | Hva |
|---|---|---|
| **S2.2** MCP-konnektor | **NEI — UGATED** (se §7.2) | §4s `http`-punkt (HEAD `:113-114` = pin `:101-102`) sier normativt at en MCP-konnektor **er en utvidelse av `http`-familien** med MUST på samme kontrakter. Ingen ny familie, ingen amendment. Bygges mot `http` + §8-grant |
| **S2.3** Dokument-konnektor | **JA** — ny kildefamilie | `{type: "doc"}`. PDF→OKF-konseptfil med provenance, deterministisk mot committede fixtures |
| **S2.4** Konnektor-herding | **NEI — UGATED** (bekreftet av po) | Timeout-parameter, feilkategorisering, beriket §8-logg (kilde/tidspunkt/radantall — aldri innhold). Retry KUN hvis D-B sier ja (default nei, av hensyn til determinisme). Inkrementell re-ingest: **ikke**, med mindre D-B amender §8 |
**Commons' observasjon, ikke et forslag:** §4 har i dag tre kildetyper (`file`, `sql`, `http`),
og §1 (`:27-31`) binder konformans til `file` + `sql` som påkrevde med `http` som eksplisitt
OPTIONAL utvidelsespunkt. To nye familier reiser derfor et spørsmål ingen av meldingene har
stilt: **blir `mcp` og `doc` påkrevde for konformans, eller valgfrie som `http`?** Svaret
avgjør om `:27-31` må skrives om i samme amendment. Vi fører ingen antakelse om hvilket.
**⚠️ Og frossen tekst sier allerede noe om MCP som ingen av meldingene har nevnt.** Ordrett,
`ingest-spec.md:29-31`:
> The `http` source type is an OPTIONAL extension point: implementing it (e.g. against a local
> mock, **or via an MCP-based connector**) does not require any change to this spec, and NOT
> implementing it does not break conformance.
Specen forutser altså eksplisitt at MCP kan være **transporten under `http`**, og sier at den
veien **ikke krever noen spec-endring**. Det gjør S2.2s premiss — «krever ingest-spec-amendment
i commons FØRST» — til noe som må avgjøres, ikke antas:
- Er `mcp` en **fjerde kildefamilie** (nytt `{type: "mcp"}`-skjema, amendment nødvendig), eller
en **transport for den eksisterende `http`-familien** (allerede dekket, ingen amendment)?
- Distinksjonen er ikke akademisk: den avgjør om S2.2 er blokkert på commons i det hele tatt.
Under den andre lesningen er S2.2 **ugated** og kan bygges nå, mot `http` + opt-in-flagget (§8).
### 7.2 Spørsmålet er AVGJORT av frossen tekst — det er ikke to forsvarlige svar (korr. 2026-07-26)
Avsnittet over stilte (a)/(b) som et åpent valg. **Det var feil, og `portfolio-optimiser` fant
hvorfor: det finnes et ANDRE anker vi ikke siterte, og det er normativt.**
> **`ingest-spec.md` §4, kildetypelisten, `type: "http"`-punktet** — sitert ORDRETT fordi
> linjenumrene ikke overlever pull-grensen (se rammen under):
> `type: "http"` — a remote endpoint (OPTIONAL extension point, §1). Field `base_url`: the
> endpoint base; it MUST NOT embed credentials. Optional field `credential_ref`: the NAME of
> a runtime-resolved secret reference. **An MCP-based connector is an extension of this family
> and MUST honour the same extraction, materialization, and gate contracts.**
> **⚠️ Ref-binding for sitatet over (korr. 2026-07-27, meldt av `repos`).** Avsnittet siterte
> tidligere «`:112-114`» uten ref. To feil i én: (1) numrene er HEAD-relative, og konsumentene
> står på `7aa53fc`; (2) selv mot HEAD var de av med én linje. Målt:
>
> | Ref | MCP-setningen | Hele `http`-punktet |
> |---|---|---|
> | commons HEAD | `:113-114` | `:111-114` |
> | `7aa53fc` (konsumentenes pin, verifisert identisk i BEGGE arbeidstrær) | `:101-102` | `:99-102` |
>
> **Failure-moden er grunnen til at dette er verdt en korreksjon:** en konsument som slår opp
> `:112-114` i SIN fil finner ikke ingenting — den finner felt-tabellen for `extractions`
> (`id`/`title`/`query`), troverdig og relatert spec-tekst uten et ord om MCP. Den mest
> sannsynlige konklusjonen er da at ankeret ikke finnes og at kjennelsen hviler på løs grunn.
> Et åpenbart tomt treff hadde vært tryggere. **Regel, samme klasse som `git log -S`-regelen
> under: sitér SEKSJON + ORDRETT TEKST når mottakeren står på en annen ref — eller skriv
> hvilken ref numrene gjelder.**
>
> **⚠️ Failure-moden er ikke lenger hypotetisk — den INNTRAFF (målt 2026-08-01).**
> `portfolio-optimiser` stilte MCP-spørsmålet **på nytt** fem dager etter at det var avgjort
> (`20260731T193214Z`), med S2.2 ført som blokkert på oss — nøyaktig utfallet avsnittet over
> beskrev som «den mest sannsynlige konklusjonen». Kjennelsen var korrekt, allerede levert
> (`20260726T190922Z`) og allerede ført her i §7.2; **det som ikke overlevde pull-grensen var
> ankeret.** Svar sendt `20260801T175201Z` med begge refs oppgitt eksplisitt.
>
> To ting generaliserer, og de er verdt mer enn korreksjonen:
>
> 1. **Et feil linjeanker svikter STILLE.** Kostnaden er ikke at mottakeren blir forvirret —
> den er at mottakeren *rimelig* konkluderer at kjennelsen din hviler på løs grunn, og
> behandler et avgjort spørsmål som åpent igjen. Ingen av partene ser feilen; begge ser en
> uenighet som ikke finnes.
> 2. **Et spørsmål som kommer TILBAKE er et signal om VÅR formidling, ikke om deres hukommelse.**
> Riktig første grep er ikke «det sa vi allerede», men å lese hva den forrige meldingen
> faktisk bar (`~/.claude/coord/<dem>/archive/`). Feilen lå der.
`:29-31` sier at MCP-veien ikke krever spec-endring. `http`-punktet sier **normativt hvor den
hører hjemme** — som en utvidelse av `http`-familien, med **MUST** på de samme kontraktene.
Frossen tekst har altså allerede valgt (b). En fjerde `{type: "mcp"}`-familie ville **motsagt**
MCP-setningen, ikke utfylt den.
**Konsekvens: S2.2 er UGATED.** Premisset «krever ingest-spec-amendment i commons FØRST» er
avkreftet av vår egen frosne tekst. S2.2 kan bygges mot `http`-familien + §8s opt-in-grant uten
å vente på noe herfra.
**Og §1-spørsmålet i 7.1 faller bort for MCP:** MCP arver `http`s status, og `http` er eksplisitt
OPTIONAL (`:27-31`). `:27-31` trenger derfor **ingen** omskriving for MCP. Spørsmålet gjenstår
kun for **S2.3 (`doc`)**, som fortsatt er en genuint ny familie. `portfolio-optimiser`s
anbefaling der: valgfri som `http` — en konform implementasjon bør ikke tvinges til en
PDF-parser. Det er deres anbefaling til ratifisering, ikke en beslutning.
**(a)-argumentet lever videre, men som implementasjonssak, ikke spec-tekst.** At
`base_url`/`credential_ref` passer dårlig på en kommando, og at env-var-med-kommando er en
subprosess-grant, er ekte friksjon — men MCP-setningen sier MUST på *kontraktene*, ikke på
*feltnavnene*, og §8 dekker «any other non-local transport». Friksjonen lever i hvordan en
kommando uttrykkes innenfor `http`-familien. Støter implementasjonen faktisk på noe MCP-setningen
forbyr, er det et målt funn og kommer tilbake hit.
**Vår egen feil, ført åpent fordi den er tredje instans samme dag:** vi skrev at `:29-31` var
«frossen siden `bfa5a9b`». Målt med `git log -S`: **begge** MCP-ankrene landet i **`7aa53fc`** —
nøyaktig commit-en konsumentene står på. `bfa5a9b` rørte bare D1-stempelmodellen. Vi tok repoets
*siste* ingest-spec-commit og antok at filen daterte derfra. Og vi fant ikke `:113` fordi vårt
`grep -n 'connection_ref' | head -3` stoppet på `:109` uten å lese omgivelsene — setningen i §1
er dessuten linjebrutt (`:30-31`), så et grep på hele frasen ville også bommet.
**Sikt grepet mot seksjonen, ikke mot ett token — og bekreft opphav med `git log -S`, aldri med
«siste commit som rørte filen».**
Merk også at S2.4s «beriket ingest-logg» ligger mot §8, som allerede sier *«Source calls are
logged (which source, when, row count)»* — en berikelse innenfor de tre feltene er neppe en
tekstendring; en berikelse *utover* dem er det. Grensen går ved «aldri innhold», som deres egen
formulering allerede respekterer.
---
## 8. B1 — nav-golden-klassen (utenfor pakken, commons-eid)
Ankret, etter å ha vært et etikett-punkt i tre uker. `llm-ingestion-okf` svarte
`portfolio-optimiser` 2026-07-25 04:19Z at «B1 bundle class» ikke finnes hos dem, og at
beskrivelsen matcher **D4 fra OKF-runden, ratifisert i trinn F 2026-07-21**: commons eier
nav-golden-bundleklassen + forventet utfall og leverer den inn; catalog eier
korpus-containeren, de adversarielle aksene og runner/gate.
**Commons-halvdelen er levert** (`b641741`, 2026-07-21):
| Case | Innhold |
|---|---|
| `examples/nav-golden-escape/` | `bundle/`, `expected-read-context.md`, `README.md`, `SHOULD-NOT-BE-READ.md` |
| `examples/nav-golden-hierarchy/` | `bundle/` (nestet `a/b/`, `c/orphan.md`), `expected-read-context.md`, `README.md` |
**Det åpne spørsmålet er ett, og det er vårt:** `grep -c 'nav-golden'` i `method-spec.md`,
`ingest-spec.md`, `CONCEPT.md`, `README.md` og `skills/expert-reviewer/SKILL.md` → **0 i alle
fem**. Klassen er levert som fixture, men ingen normativ seksjon peker på den — i motsetning til
`validator-input.json` / `golden.json` (navngitt i §7 `:330-346`) og
`examples/ingest-golden-{source type}/` (navngitt som konvensjon i `ingest-spec.md:259-261`).
§11-raden «Navigation boundary» (`:425`) beskriver rød-betingelsen, men nevner ikke fixturene
som beviser den.
**Operatør-spørsmålet:** skal nav-golden-klassen få en normativ referanse (§7 ground truth
og/eller §11-raden), eller forbli en informativ fixture? Dette er commons' eget punkt, ingen
venter på oss, og det hører IKKE inn i oppstrøms-pakken.
**Utskrevet i sin helhet:** `docs/plan/2026-07-25-b1-nav-golden-normative-status.md` — fire
opsjoner med målt kostnad. Spørsmålet viste seg ikke å være binært: specen har **tre**
referanseformer i bruk (artefaktnavn som fasit, katalogkonvensjon, informativ lenke), og
method-spec navngir aldri en repo-sti (`grep -c 'examples/' method-spec.md` → 0).
---
## 9. Sammendrag
| # | Punkt | Fil + seksjoner | Klassifisering | Fasit-effekt |
|---|---|---|---|---|
| 1 | S2.7 / D-A#1 nominal gate + IR-band | method §3.4 `:157-166`, §7.1 `:339-346`, §7.2 `:352-358` | ekte hull | ingen (målt) |
| 2 | S3.2 / D-A#4 seed-nøkkel | method §3.1 `:108-114` | ekte hull | ingen (fasiten skiller ikke) |
| 3 | D-A#3 ledende `/` | method §3.1 `:67-71`, §11 `:425` | **allerede normativt i HEAD — drift, ikke avvik** | — |
| 4 | S4.0 / D-A#2 kostbaseline | method §7 `:332-333`, §7.1 `:345-346` | ekte hull | **endrer fasit hvis ubetinget** |
| 5 | S3.5 / D-F tittel-whitespace | ingest §4 `:125`, §5 `:158-161`, §6 `:194-197`, §11 `:278` | ekte, smal søm | ingen |
| 6 | D-A#5 hovedbok-projeksjoner | ingen tekst; naboer method §7.2 `:367-372`, §12 `:436-464` | **ny seksjon** | ingen direkte; §12 må utvides |
| 7 | S2.22.4 / D-B | **ANKRET** (§7.17.2): kun **S2.3** (`doc`) krever amendment. **S2.2 + S2.4 er UGATED** — S2.2 av §4s `http`-punkt, S2.4 innenfor §8s tre felt | **scope-beslutning, ikke spec-tekst** | ingen |
| 8 | B1 / D4 nav-golden | levert `b641741`; 0 spec-referanser | commons-eget, utenfor pakken | — |
Commons' rolle er uendret: vi forbereder underlaget, operatøren ratifiserer, og frossen tekst
endres ikke uten den ratifiseringen.
---
## Verifiseringslogg
| Påstand | Sjekk | Resultat |
|---|---|---|
| Spec-tekst uendret siden 2026-07-21 | `git log -- method-spec.md ingest-spec.md` | `9801d35` / `bfa5a9b`, begge 07-21 |
| Bare p90 blokkerer i dag | lest `method-spec.md:150-166` i sin helhet | punkt 2 «capped», punkt 4 eneste blokk |
| Ingen `low ≤ unit_cost ≤ high`-invariant | lest §7.1 `:339-346` | én invariant, om claimed vs. total |
| Nominal gate er byte-nøytral | `golden.json`: claimed `30000` ≤ nominal `90000.0` | `validates` uendret `true` |
| IR-band-invarianten er alt oppfylt i fasit | `validator-input.json`: `1.0` ∈ `[0.70, 1.40]` | ingen fixture-endring |
| Seeding nøkles på bundelens projeksjon | lest `:108-114` | «keyed on those candidate features» |
| Ledende `/` alt normativt | `git log -S'denotes the **bundle root**'` | `9801d35`, 2026-07-21 |
| §11 har alt rød-betingelsen | `method-spec.md:425` | «bundle-root `/` read as filesystem-absolute» |
| Ingen hovedbok-/baseline-tekst | `grep -ci ledger\|hovedbok\|cost-baseline` | 0 / 0 / 0 |
| Ingen monetær avrundingsregel | `grep -n round` begge spec-er, alle 18 treff lest | alle urelaterte |
| Fasit-bundelen har to JSON-filer | `ls examples/bygg-energi-mikro/` | `validator-input.json`, `golden.json` |
| Oppstrøms-anker `:140` er stale | `git show 7aa53fc:ingest-spec.md \| grep -n` | treff på `:140` ved `7aa53fc`, `:158/:160` ved HEAD |
| `bfa5a9b` rørte nettopp den teksten | `git show bfa5a9b -- ingest-spec.md` | +39/9; §5-kulepunkt + §4 `title`-rad omskrevet |
| Multi-manifest er extension point | `ingest-spec.md:173-174` | «Version 1 assumes ONE manifest per bundle» |
| B1 = D4, ikke okf-eid | `~/.claude/coord/portfolio-optimiser/archive/20260725T041948Z-*` | okf: «never owned here; it is D4» |
| nav-golden levert | `git log -- examples/nav-golden-*` | `b641741`, 2026-07-21 |
| nav-golden ikke normativt referert | `grep -c 'nav-golden'` i de fem normative filene | 0 i alle fem |
| D-B ikke ankret hos commons (per 07-25) | `grep -rn 'D-B'` | 0 treff utenfor STATE |
| D-B-substansen levert 07-26 | coord fra `portfolio-optimiser` | rapportert fra deres `sesjonsplan-fase2-6.md:56-62`, ikke målt av oss |
| §1 gjør `http` OPTIONAL, `file`+`sql` påkrevd | `ingest-spec.md:27-31` | ordrett sitert i §7.1 |
| …og nevner MCP som `http`-transport | `ingest-spec.md:29-31` | «or via an MCP-based connector … does not require any change to this spec» |
| **ANDRE anker: MCP hører NORMATIVT til `http`** | `ingest-spec.md` §4, `http`-punktet (HEAD `:113-114` = pin `:101-102`) | «An MCP-based connector **is an extension of this family** and **MUST** honour the same … contracts» |
| Begge MCP-ankere landet i `7aa53fc`, ikke `bfa5a9b` | `git log -S` på hver frase | `7aa53fc` for begge — altså i konsumentenes egen kopi |
| `bfa5a9b` rørte kun stempelmodellen | `git show --stat bfa5a9b` | 39 innsettinger, D1-stempel |
| §8 logger tre felter | `ingest-spec.md:230` | «which source, when, row count» |
| `connection_ref` er env-var-NAVN | `ingest-spec.md:109`, `:117` | «the NAME of a runtime-resolved …», secret resolved at run time |
| Begge konsumenter står på `7aa53fc` | coord fra begge, uavhengig | po: `git log --grep=git-subtree-split` → `ef1a2c5`; po-claude: egen måling |