feat(prepass): payload model, loader, shape gate and the binding to the mounted base [skip-docs]

[skip-docs]: ingen brukervendt flate ennaa -- CLI-flagget kommer i steg 6/7 med
README-blokka, og CLAUDE.md-raden i steg 8. Modulen er ikke naabar utenfra i denne
commiten.

Steg 1 og 2 av planen, committet sammen fordi begge armene bor i samme testfil og
ble skrevet mot samme ekte produsent-payload.

`prepass.py` konsumerer et OKF-konsumkontrakt-SS-8-payload som INPUT-fil (SS 2.4:
transporten er ikke del av kontrakten). po produserer ingen payload og vendrer ingen
produsent -- en subprosess mot produsentens checkout ville bundet pakka til en sti paa
en maskin og doedd i `git archive HEAD`, og en kopi ville vaert kø-(p)-driften.

`check_payload_shape` -- seks nekter, hver ved navn: ukjent revisjon (`==`, aldri
prefiks), nevnere som ikke lukker (SS 5.2, med DEKLARERT og OBSERVERT som to tall),
`len(excerpts)` og `len(withheld)` mot sine tellere (SS 8.1s to halvdeler), `spent >
limit` (SS 7.3) og en kjent-positiv som ikke ble reprodusert (SS 7.4). De to siste er
DEFENSIVE og uvitnet: produsenten nekter dem selv foer den emitterer.

`verify_against_bundle` -- fem sjekker mot den MONTERTE basen: erklaert id (aldri
mountet, S7a-3), joinen gjennom `safe_resolve` med `PathSecurityError` re-reist som
nekt, filas `sha256`, og -- baerende -- at `text` er RE-UTLEDBAR fra det monterte
dokumentet. Den siste lukker injeksjonsflaten: et payload kan ikke levere bytes basen
ikke holder. De to gatene som bodde i det tilbaketrukne `read_file` er reist paa nytt
her paa DOKUMENTET (verdict-laget og SS 4.1a), aldri delegert til produsentens egne
regler.

MAALT foer bygging, ikke antatt:
- Pre-passet nekter ALLE tre av repoets leverte baser ("declares no bundle_id") --
  S7a-3s egen maaling sett fra produsentsiden. `shared/` er pull-only, saa fixturen er
  bygget paa en KOPI med erklaert id, som ogsaa gir S7a-3s slakk-tilfelle gratis.
- `concept_id + ".md"`, `sha256` = HELE fila, og tekst-utledningen (frontmatter delt
  paa `splitlines()`, NFC, per-linje rstrip) holder for alle fire utdrag i et EKTE
  produsent-payload. En naiv `split("\n")` er UENIG med produsenten -- derfor er
  regelen transkribert fra kilden og gatet av fixturen, aldri gjettet.

Fixturen `tests/fixtures/prepass/` er produsentens output ORDRETT (okf `54a0bc2`), saa
ingen arm er groenn mot en form ingen pre-pass emitterer.

TO TEST-FIXTURER VAR FEIL, funnet ved aa kjoere roedt: excerpt/withheld-armene brakk
ogsaa nevnerne, saa lukke-sjekken fyrte foerst; og dimensjons-armen kjoerte mot et
umerket dokument, der `in_dimension` aldri dropper uskopet kunnskap. Begge armene ville
staatt groenne mot en implementasjon uten sjekken de er skrevet for.

1413 passed / 5 skipped (fra 1387/5, +26, 0 fjernet). ruff + mypy rene.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-07 10:52:20 +02:00
commit ad9686517a
4 changed files with 860 additions and 0 deletions

26
tests/fixtures/prepass/README.md vendored Normal file
View file

@ -0,0 +1,26 @@
# A real pre-pass payload, checked in verbatim
`bygg-energi-mikro-fixture.payload.json` is the **unedited output** of the OKF consumption
pre-pass. It is here so that every arm in `tests/test_prepass_payload_loadbearing.py` is gated
against a shape a producer actually emits, rather than against one the test built for itself.
Produced 2026-09-07 with:
python3 ~/repos/llm-ingestion-okf/tools/okf_consume.py <base> \
--question "Hva koster energitiltaket i bygget?" --out <this file>
- Producer: `llm-ingestion-okf`, revision `54a0bc2`, `tools/okf_consume.py`
- Contract: `okf-consumption/1` (`llm-ingestion-okf/docs/consumption-contract.md`, normative)
- `<base>`: a COPY of `shared/examples/bygg-energi-mikro` with `bundle_id:
bygg-energi-mikro-fixture` inserted as the first frontmatter line of `index.md`.
**Why a copy and not the base itself.** Measured 2026-09-07: the pre-pass refuses all three of
this repository's shipped bases with `index.md declares no bundle_id` — which is S7a-3's own
measurement (zero `^bundle_id` anywhere under `shared/`) seen from the producer's side. `shared/`
is a pull-only subtree, so the declaration cannot be added there. The test rebuilds the copy the
same way, which also makes this the S7a-3 slack case: a base whose DECLARED id differs from its
mount.
**Do not regenerate casually.** The digests in this file pin the mounted bytes of four concept
files; regenerating after a `git subtree pull` is a deliberate act, and the arms that verify
`sha256` / `text` / `text_sha256` are what would go red first.

View file

@ -0,0 +1,78 @@
{
"contract": "okf-consumption/1",
"bundle": {
"bundle_id": "bygg-energi-mikro-fixture",
"ref": "sha256-tree:5e3f61f6ec4a24b921d0f3f4f9a90ff648d54f57b70998e9a77fbabd5e73218d"
},
"budget": {
"unit": "utf-8 bytes of emitted JSON",
"instrument": "okf_consume.measure (len of the ensure_ascii=False JSON encoding, utf-8)",
"limit": 120000,
"spent": 11644,
"known_positive": {
"case": "docs/consumption-contract.md, encoded as a JSON string",
"expected": 10349,
"measured": 10349,
"raw_bytes": 10060,
"encoding_delta": 289
}
},
"denominators": {
"considered": 5,
"withheld": 1,
"delivered": 4
},
"question": "Hva koster energitiltaket i bygget?",
"excerpts": [
{
"bundle_id": "bygg-energi-mikro-fixture",
"concept_id": "bygg-kontor-nord",
"sha256": "956f4a971d61bbc0093e8ca5e537d2dda75ba9283e6240d6529fbfa61842cbc3",
"adjudication": "unknown",
"trust_tier": "unverified",
"bundle_id_inherited": true,
"text_sha256": "f126aaf1f035dd8426e5650d825b496445c930a41977f736dcc55d6d30264431",
"text": "\n# Kontorbygg Nord (BYGG-KONTOR-NORD)\n\nFiktivt kontorbygg. Tallene er **illustrative men forankret i typiske norske verdier** —\nikke et ekte bygg. En produksjons-deployer erstatter denne med en ekte kunnskapsbase.\n\n## Energibaseline\n\n| Størrelse | Verdi | Merknad |\n|---|---|---|\n| Oppvarmet bruksareal (BRA) | ~2 500 m² | [I] illustrativt |\n| Totalt elforbruk | **300 000 kWh/år** | [I]; ~120 kWh/m²/år — typisk norsk kontor |\n| Herav belysning | ~54 000 kWh/år (~18 %) | 200 armaturer × 90 W × 3 000 t/år |\n| Variabel energikostnad | **1,00 NOK/kWh** ekskl. mva | [V-forankret] kraftpris + nettleie-energiledd + elavgift |\n\n**Energiprisen** (1,00 NOK/kWh) er den marginale variable kostnaden et spart kWh faktisk\nunngår, ekskl. mva (næring trekker fra mva). Sammensetning, forankret i SSB Q1 2026:\nkraftpris tjenesteytende næringer ~0,801,12 NOK/kWh + nettleie energiledd ~0,100,13 +\nelavgift 0,0713. Den varierer kraftig med prisområde (NO4 ~0,13 vs NO2 ~0,96 i kraftpris\nalene) og sesong — derfor er den **konfigurerbar**, og usikkerheten håndteres i Monte\nCarlo-steget (band 0,701,40 NOK/kWh). Se [kilder-realiseringsgap.md](kilder-realiseringsgap.md).\n\n## Rammer (constraints)\n\n- Tiltak vurderes **inne i** dette prosjektet (ikke på tvers av en portefølje).\n- Budsjett og tekniske rammer eies av deployer; her holdes de minimale.\n- Bygget driftes i normal kontortid; belysning styres delvis på timeplan (relevant for\n realiseringsgapet — se [verdict-led-fro.md](verdict-led-fro.md)).\n\n## Kandidat-tiltak\n\n- [tiltak-led-retrofit.md](tiltak-led-retrofit.md) — LED-retrofit av belysning.",
"rank": 1
},
{
"bundle_id": "bygg-energi-mikro-fixture",
"concept_id": "kilder-realiseringsgap",
"sha256": "2828a8a535762af0fe9e48aae95d7220eb3e678dbfdffa5d3ca8eb293fdb063d",
"adjudication": "unknown",
"trust_tier": "unverified",
"bundle_id_inherited": true,
"text_sha256": "1bdb2877f4015e7848134a19dc76dd4d4493238507fa2903a1d92b78761bbdf3",
"text": "\n# Realiseringsgrad (realization rate) — verifisert litteratur\n\n**Realiseringsgrad (RR)** = faktisk evaluert besparelse (ex-post) ÷ modellert/påstått\nbesparelse (ex-ante). RR < 1 betyr at drift leverte mindre enn modellen lovte. Avviket\nkalles *energy performance gap*. Alle tall under er verifisert mot primærkilde [V].\n\n| Nivå | Funn | Kilde |\n|---|---|---|\n| Program (regulatorisk default) | Default gross RR **0,90** for kWh/kW/therm; ex-ante «generally over-estimated» | CPUC Resolution E-4952 |\n| Program (lys, drift lavere) | Operational adjustment ned til **81,1 %** (metrede driftstimer 15 % lavere); coincidence factor **0,566** vs antatt 1,0 | National Grid SBS 2010 (DNV KEMA) |\n| Program (lys, drift høyere) | Hours-of-Use RR **106,5 %**; coincidence 72,2 % — gapet går **begge veier** | Massachusetts Impact Evaluation 2010 |\n| Parameter (driftstimer) | Metret **3 053 t/år** vs antatt **3 772 t/år** (≈19 % lavere); CV ≈ 0,5 | Efficiency Maine 2021 |\n| Portefølje | Commercial lighting **98 %** vs residential **61 %** vs total **93 %** | LADWP Retrospective FY15/1619/20 |\n| Bygg (grønne næringsbygg) | Predikert besparelse **1,53×** realisert; ~⅓ av LEED-bygg bruker mer energi | \"Mind the energy performance gap\", ScienceDirect |\n| Måleterskel | Besparelse bør overstige **~10 % av baseline** for å skilles pålitelig fra støy | FEMP/RDH M&V-veiledning |\n\n## Systematiske årsaker (hvorfor faktisk < modellert) [V]\n\n1. **Driftstimer / Hours-of-Use** — dominerende. Timeplan-baserte estimat (det Option A\n stipulerer) treffer sjelden metret brenntid (3 053 vs 3 772).\n2. **Baseline- og værjustering** — over-predikert baseline blåser opp absolutt besparelse.\n3. **Coincidence / diversity factor** — for effekt(kW): andel last under nett-topp ~0,570,72, ikke 1,0.\n4. **HVAC interactive effects** — mindre spillvarme → endret kjøle-/varmebehov; «too small to measure», stipuleres.\n5. **In-service rate, drift & persistens** — ikke alt installeres/forblir; styringer overstyres; degradering.\n6. **Måleusikkerhet** — under ~10 %-terskelen drukner signalet i støy.\n7. **Rebound / atferd** — mer lys på, lengre, fordi det «koster mindre».\n\n## Kilder (URL)\n\n- EVO IPMVP Generally Accepted M&V Principles (okt. 2018): https://evo-world.org/images/corporate_documents/IPMVP-Generally-Accepted-Principles_Final_26OCT2018.pdf\n- DOE/NREL Uniform Methods Project, Ch. 2 Commercial & Industrial Lighting (NREL 68558): https://docs.nrel.gov/docs/fy17osti/68558.pdf\n- Massachusetts Impact Evaluation of 2010 Prescriptive Lighting: https://ma-eeac.org/wp-content/uploads/Impact-Evaluation-of-2010-Prescriptive-Lighting-Installations-Final-Report-6-21-13.pdf\n- National Grid SBS 2010 Prescriptive Lighting (DNV KEMA): https://www.nationalgridus.com/media/pdfs/our-company/eereports/2014-ngrid-sbs-impact-eval-final-prot.pdf\n- Efficiency Maine Retail & Distributor Lighting 2021: https://www.efficiencymaine.com/docs/Retail-and-Distributor-Lighting-Final-Impact-Evaluation-Report-2021.pdf\n- LADWP Retrospective Impact Evaluation FY15/1619/20: https://www.ladwp.com/sites/default/files/2024-01/LADWP%20Retrospective%20Report%20FINAL%20V4.pdf\n- CPUC Resolution E-4952: https://docs.cpuc.ca.gov/publisheddocs/published/g000/m232/k459/232459122.pdf\n- \"Mind the energy performance gap\" (ScienceDirect): https://www.sciencedirect.com/science/article/abs/pii/S0921344918303860\n- SSB Elektrisitetspriser (kraftpris tjenesteytende næringer, Q1 2026): https://www.ssb.no/energi-og-industri/energi/statistikk/elektrisitetspriser",
"rank": 2
},
{
"bundle_id": "bygg-energi-mikro-fixture",
"concept_id": "metode-ipmvp-a",
"sha256": "28d00e8a4529df56af49c79fc798e4167c88bdbb0a050062565940ae82a57187",
"adjudication": "unknown",
"trust_tier": "unverified",
"bundle_id_inherited": true,
"text_sha256": "4543fb67997767ac2d503999ecb4c1eef4ce1efeeb7d0a3af69d51d15026b379",
"text": "\n# M&V-metode: IPMVP Option A\n\n**IPMVP** (International Performance Measurement and Verification Protocol) er\nkonsensus-rammeverket for å måle og verifisere energibesparelser, eid og vedlikeholdt av\n**EVO** (Efficiency Valuation Organization). Kjerneinnsikten som begrunner hele\nlærings-sløyfa står eksplisitt i protokollen [V]:\n\n> *\"Savings cannot be directly measured, because savings represent the absence of energy use.\"*\n\nBesparelse er en **kontrafaktisk** størrelse — det finnes ingen måler for «det som ikke ble\nbrukt». Den *beregnes*: `Baseline-energi Rapporterings-energi ± justeringer` (IPMVP Eq. 1).\n\n## De fire opsjonene (EVO, offisielle navn) [V]\n\n- **Option A — Retrofit Isolation: Key Parameter Measurement.** Måler nøkkelparameteren\n (typisk effekt) på det berørte utstyret; øvrige parametere (typisk driftstimer) *estimeres*.\n- **Option B — Retrofit Isolation: All Parameter Measurement.** Måler alle relevante parametere.\n- **Option C — Whole Facility.** Besparelse fra byggets hovedmåler, med rutinejustering (vær/produksjon).\n- **Option D — Calibrated Simulation.** Besparelse via simuleringsmodell kalibrert mot måledata.\n\n## Hvorfor Option A for dette tiltaket [V]\n\nEVOs egen tabell bruker nettopp et **lysarmatur-retrofit** som den kanoniske Option A-saken:\neffekt før/etter måles (billig, presist), mens **driftstimer stipuleres** fra byggets\ntimeplan. Det gjør Option A enklest og billigst for ett isolert tiltak.\n\n**Kritisk for lærings-overflaten:** parameteren Option A tillater å *estimere* — driftstimer\n— er nøyaktig der realiseringsgapet oppstår. Den stipulerte timeplanen treffer sjelden den\nfaktiske, metrede brenntiden. Se [verdict-led-fro.md](verdict-led-fro.md) og\n[kilder-realiseringsgap.md](kilder-realiseringsgap.md).",
"rank": 3
},
{
"bundle_id": "bygg-energi-mikro-fixture",
"concept_id": "tiltak-led-retrofit",
"sha256": "314f91204b28d15902cc7f98d55e794a5b544ee0de0089cec5f8f3cf5a8fafd0",
"adjudication": "unknown",
"trust_tier": "unverified",
"bundle_id_inherited": true,
"text_sha256": "a7d653ac276430b8268f20a162ba3d848faa0ec89106e72b53f355ab41280f6e",
"text": "\n# Tiltak: LED-retrofit av kontorbelysning\n\nBytte av 200 lysrørarmaturer (2×4 fluorescerende troffer) til LED-paneler. Dette er det\nvanligste enkelt-ECM-et (Energy Conservation Measure) og IPMVPs egen kanoniske\nOption A-illustrasjon — se [metode-ipmvp-a.md](metode-ipmvp-a.md).\n\n## Parametere\n\n| Parameter | Verdi | Status | Kilde/forankring |\n|---|---|---|---|\n| Antall armaturer | 200 | [I] | mikro-skala valgt |\n| Effekt før (T8 troffer m/ ballast) | 90 W | [V] | 3×32 W ≈ 9096 W m/ ballastfaktor |\n| Effekt etter (LED-panel) | 40 W | [V] | kommersielt 2×4 LED-panel ~40 W |\n| Reduksjon per armatur (ΔW) | 50 W | beregnet | 90 40 |\n| Driftstimer (HOU) | 3 000 t/år | [I] | forankret i metret 3 053 t (Efficiency Maine) |\n| Variabel energipris | 1,00 NOK/kWh | [V-forankret] | se [bygg-kontor-nord.md](bygg-kontor-nord.md) |\n\n## Modellert besparelse (ex-ante)\n\nLysligning (DOE/NREL Uniform Methods Project, Eq. 3):\n`kWh = Σ (W_før W_etter) × antall × HOU / 1000`\n\n> ΔW = 90 40 = **50 W/armatur**\n> kWh/år = 50 × 200 × 3 000 / 1 000 = **30 000 kWh/år**\n> kr/år = 30 000 × 1,00 = **30 000 NOK/år**\n\nHVAC-interaktiv effekt (effektivt lys → mindre spillvarme → endret kjøle-/varmebehov,\nUMP Eq. 6) er ~+5 % i elektrisk kjølte bygg, men **utelatt fra kjernetallet** her\n(konservativt; den lille interaktive justeringen er en ex-post-vurdering eksperten kan\nlegge til). Modellert kjernebesparelse: **30 000 kWh/år ≈ 30 000 NOK/år**.\n\n## Usikkerhet (for Monte Carlo P10/P50/P90)\n\nDen dominerende usikkerheten i en *energibesparelse* ligger i driftstimer (HOU), ikke\nprisen — men den eksisterende validatorens Monte Carlo varierer enhetspris. I denne\nmikro-mappingen brukes derfor **prisbandet 0,701,40 NOK/kWh** som usikkerhetsakse\n(region/sesong, jf. [bygg-kontor-nord.md](bygg-kontor-nord.md)). Den fysiske HOU-usikkerheten\nog — viktigere — den *systematiske* HOU-skjevheten håndteres i verdict-laget, ikke her.\n\n## Mapping til validatoren (hvorfor `validator-input.json` ser ut som den gjør)\n\nDen eksisterende deterministiske validatoren er en *feasibility-gate* (`claimed ≤ 30 % av\naffected total`, Monte Carlo over enhetspris) bygd for kostnadskutt. Energitiltaket mappes\ninn **uendret**:\n\n- `affected_items = [{code: \"ENERGI-TOTAL-EL\", quantity: 300000 kWh/år, unit_cost: 1.00 NOK/kWh}]`\n → byggets **totale** årlige energikostnad (300 000 NOK). LED-besparelsen er ~10 % av den,\n godt innenfor 30 %-cap-en.\n- `claimed_saving_nok = 30000` → den modellerte LED-besparelsen.\n- `assumptions = {\"ENERGI-TOTAL-EL\": [0.70, 1.40]}` → prisbandet for Monte Carlo.\n\n**Ærlig begrensning:** validatorens P10/P50/P90 betyr her «øvre feasible grense» (30 % av\nsamplet energikostnad), *ikke* «LED-besparelsens fysiske band». Det er bevisst — den\ndomenetro besparelses-modelleringen og realiseringsgapet hører hjemme i verdict-laget\n([verdict-led-fro.md](verdict-led-fro.md)), som er nettopp det lærings-sløyfa skal lære.\nEn energi-bevisst validator (ΔW × antall × HOU) er senere fase-arbeid, ikke dette fixturet.",
"rank": 4
}
],
"withheld": [
{
"concept_id": "verdict-led-fro",
"rule": "verdict_layer_excluded"
}
]
}