The operator is not a domain expert, so the domain content is mine to own --
and the one thing the loop asks a human for is exactly the thing no example
existed for. docs/ekspert-svar.md is written for whoever has to deliver the
verdict: the two forms a judgement can take (a --rationale string during the
run, a JSON file in the inbox for later runs), where each field comes from, and
four complete paste-ready answers.
Every command and every verdict in it was RUN from a fresh clone before it was
written. The `hitl pending` line quoted is verbatim output. The rejection
answers close the gap STATE has carried since the demo shipped: the README
shows the VALIDATOR refusing a number, but nothing showed an EXPERT refusing a
proposal whose numbers are fine -- the only judgement in the whole loop that a
machine cannot make. Two rejection shapes are given, because "not feasible
here" and "right measure, wrong cost base" teach the system different things.
Everything is marked AI-authored and not verified professional judgement.
Also corrects the --outbox-dir help text, which claimed sharing a folder with
--verdict-dir "re-ingests raw agent output past the Step-8 promotion gate".
Measured, by pointing both at one folder and running twice: it does not. The
outbox artefacts are named {run_id}-*.json and carry none of the verdict keys,
so the tolerant inbox loader skips them and the run is unaffected. The hazard is
real but latent -- a future verdict-shaped artefact in the outbox -- so the
warning stays and says what is actually true. This also answers STATE's open
question about enforcing the distinction in the CLI: no. There is no reachable
contamination to refuse, and a guard for an unreachable case is the kind of
error handling this repo declines to write.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118noV9rCfrdREH26XqZB5z
8.9 KiB
Limbare ekspert-svar
Dette dokumentet er for deg som skal avgi dommen i loopen — fageksperten som får et validert forslag i fanget og skal si ja, ja-med-forbehold eller nei. Det gir deg ferdige svar du kan lime rett inn, og forklarer hvor de skal limes.
Ærlighetsmerking. Svarteksten under er AI-forfattet og er ikke verifisert fagdom. Den er laget for å vise formen et ekspertsvar har og for å gjøre gjennomkjøringen mulig uten en levende ekspert. Tallene og resonnementene er forankret i kildene som ligger i kunnskapsbasen (
shared/examples/bygg-energi-mikro/kilder-realiseringsgap.md), men ingen fagperson har godkjent dem. Skal en dom telle som fagdom, må en fagperson skrive den selv.
De to formene, og når du bruker hvilken
Systemet tar imot en ekspertdom på to steder, og de gjør forskjellige ting:
| Form A — begrunnelses-streng | Form B — dom-fil i innboksen | |
|---|---|---|
| Hvor | --decision / --rationale på kommandolinjen |
en JSON-fil i mappa --verdict-dir peker på |
| Når | du er til stede mens kjøringen skjer | du dømmer etterpå, kanskje dager senere |
| Rekkevidde | denne ene kjøringen | alle senere kjøringer som leser innboksen |
| Hva du skriver | bare begrunnelsen (én streng) | hele dommen som JSON-dokument |
Form B er den som lærer systemet noe. Form A er en synkron snarvei.
decision er binær på kjørestien: approved eller rejected. Det finnes ikke et tredje
«godkjent med justering» her — en realiseringskorreksjon er en godkjenning der forbeholdet står
i begrunnelsen. Det er med vilje: forbeholdet er fagkunnskap som skal leses, ikke en enum-verdi som
kan telles.
Form A — begrunnelses-streng på kommandolinjen
uv run python -m portfolio_optimiser.run BYGG-KONTOR-NORD \
--docs-dir shared/examples/bygg-energi-mikro \
--bundle-dir shared/examples/bygg-energi-mikro \
--scripted-replies replies.json \
--decision approved \
--rationale "Godkjent med realiseringskorreksjon. Besparelsen er teknisk korrekt utledet, men i drift realiseres erfaringsvis ~79 % av en timeplan-stipulert LED-besparelse i kontorbygg; forventet faktisk besparelse ca 23 700 NOK/aar."
Form B — dom-fil i innboksen
Slik finner du feltene du må fylle ut
Kjør med --outbox-dir (som krever --run-id), så legger kjøringen igjen artefaktene sine:
uv run python -m portfolio_optimiser.run BYGG-KONTOR-NORD \
--docs-dir shared/examples/bygg-energi-mikro \
--bundle-dir shared/examples/bygg-energi-mikro \
--scripted-replies replies.json \
--outbox-dir utboks --run-id run-001
uv run python -m portfolio_optimiser.hitl pending --outbox-dir utboks --verdict-dir innboks
pending skriver én linje per forslag som fortsatt venter på en dom:
run-001 c91cb2fe1aa139a9 validated
Midterste kolonne er id-en dommen din må bære. Den er en innholds-hash av forslagets
egenskaper, ikke et løpenummer — den er nøkkelen en senere kjøring bruker for å finne igjen dommen
din, så den må gjengis ordrett. Resten av feltene ligger i utboks/run-001-proposal.json:
measure → measure_type, hver affected_items[].code → affected_codes, og
claimed_saving_nok uendret.
Utboks og innboks skal være to forskjellige mapper. De har motsatt eierskap: systemet skriver
utboksen, du skriver innboksen. (Målt: å peke dem på samme mappe ødelegger ingenting i dag —
utboksens filer heter run-001-*.json og mangler dom-feltene, så innboks-lasteren hopper over dem.
Men den dagen noe skriver en dom-formet fil i utboksen, blir rå agent-output lest inn som om en
ekspert hadde godkjent den. Hold dem adskilt.)
Fila legges i innboksen som <id>.json, altså innboks/c91cb2fe1aa139a9.json.
Svar 1 — godkjent med realiseringskorreksjon
Det vanligste ekte svaret på et energitiltak: regnestykket stemmer, men drift leverer mindre enn modellen lovte. Dette er dommen som bærer mest læring, fordi den forteller systemet noe det ikke kunne lest ut av tallene selv.
{
"id": "c91cb2fe1aa139a9",
"decision": "approved",
"rationale": "Godkjent med realiseringskorreksjon. Den modellerte besparelsen er teknisk korrekt utledet fra parameterne, og validatoren bekrefter at den ligger innenfor feasibelt omraade. Men i drift realiseres erfaringsvis ~79 % av en timeplan-stipulert LED-besparelse i kontorbygg (realiseringsgrad=0.79), fordi driftstimene er overestimerte og in-service rate er under 1. Forventet faktisk besparelse er ca 23 700 NOK/aar. Tiltaket gjennomfoeres, men gevinsten foeres opp med det korrigerte tallet.",
"proposal_features": {
"affected_codes": ["ENERGI-TOTAL-EL"],
"measure_type": "LED-retrofit av kontorbelysning",
"claimed_saving_nok": 30000.0,
"description": ""
}
}
Svar 2 — godkjent uten forbehold
Når du faktisk mener tallet står seg som det er. Kort er riktig her; en lang begrunnelse for et enkelt ja gir systemet støy å lære av.
{
"id": "c91cb2fe1aa139a9",
"decision": "approved",
"rationale": "Godkjent. Effekt foer/etter og antall armaturer er verifisert mot anleggets egen dokumentasjon, og driftstimene er metret, ikke stipulert. Det vanlige realiseringsavviket gjelder derfor ikke her, og besparelsen foeres opp uendret.",
"proposal_features": {
"affected_codes": ["ENERGI-TOTAL-EL"],
"measure_type": "LED-retrofit av kontorbelysning",
"claimed_saving_nok": 30000.0,
"description": ""
}
}
Svar 3 — avvist: tiltaket er ikke gjennomførbart her
Den viktigste dommen å ha et eksempel på, fordi den er den eneste som stopper noe. Validatoren har allerede sagt at tallene holder — du sier at virkeligheten rundt tallene ikke gjør det. Det er en dom bare et menneske kan avgi.
{
"id": "c91cb2fe1aa139a9",
"decision": "rejected",
"rationale": "Avvist. Regnestykket er internt konsistent, men forutsetningen om 3 000 driftstimer holder ikke for dette bygget: belysningen staar paa naermest kontinuerlig i fellesarealene og er allerede dagslysstyrt i kontorsonene, saa faktisk brenntid ligger langt fra timeplanen tiltaket er regnet paa. I tillegg ble armaturene skiftet i 2023 og er ikke avskrevet. Et nytt bytte naa gir en gevinst som ikke forsvarer kostnaden, uavhengig av at den modellerte besparelsen er feasibel.",
"proposal_features": {
"affected_codes": ["ENERGI-TOTAL-EL"],
"measure_type": "LED-retrofit av kontorbelysning",
"claimed_saving_nok": 30000.0,
"description": ""
}
}
Svar 4 — avvist: feil kostnadsgrunnlag
Bruk denne når tiltaket i seg selv er fornuftig, men det er regnet mot feil tall. Her sier du noe om grunnlaget, ikke om tiltaket — og det er en annen lærdom for systemet.
{
"id": "c91cb2fe1aa139a9",
"decision": "rejected",
"rationale": "Avvist paa grunnlaget, ikke paa tiltaket. Besparelsen er regnet mot byggets totale elforbruk, men belysning utgjoer bare ~18 % av det forbruket. Den paastaatte besparelsen tilsvarer over halvparten av hele belysningsposten, noe som ikke er oppnaaelig med et rent armaturbytte. Send tiltaket inn paa nytt regnet mot belysningsposten alene, saa er det sannsynligvis godkjennbart i redusert form.",
"proposal_features": {
"affected_codes": ["ENERGI-TOTAL-EL"],
"measure_type": "LED-retrofit av kontorbelysning",
"claimed_saving_nok": 30000.0,
"description": ""
}
}
Hva systemet gjør med dommen din
Legg fila i innboksen og kjør på nytt med --verdict-dir:
uv run python -m portfolio_optimiser.run BYGG-KONTOR-NORD \
--docs-dir shared/examples/bygg-energi-mikro \
--bundle-dir shared/examples/bygg-energi-mikro \
--scripted-replies replies.json \
--verdict-dir innboks
Dommen slås sammen inn i minnet før hypotesen lages, så neste forslag ser hva du sa forrige
gang. hitl pending er tom etterpå — forslaget er dømt.
Dommen din blir liggende i råt-laget: den er lest, men den er ikke skrevet inn i
kunnskapsbasen. Det siste skrittet er bevisst atskilt og krever en godkjenning
(verdicts.promote_verdict), slik at bare kunnskap et menneske har stått inne for havner i wikien.
En avvist dom kan ikke promoteres i det hele tatt — porten er lukket den veien, så rå agent-output
aldri kan skrive seg selv inn som lærdom.
Om du skriver dine egne
idgjengis ordrett frahitl pending. Endrer du den, blir dommen din hengende på et forslag som ikke finnes.decisionerapprovedellerrejected. Ingen tredje verdi på denne stien.proposal_featuresskal beskrive forslaget du dømte, ikke det du mener det burde vært. Feltene kopieres frarun-001-proposal.json.- Begrunnelsen er det eneste som bærer fagkunnskap videre. Skriv hvorfor, ikke hva — «avvist, ikke feasibelt» lærer systemet ingenting det ikke allerede visste.
- En ufullstendig eller halvskrevet fil hoppes stille over, ikke feiler. Sjekk med
hitl pendingat forslaget faktisk forsvant fra lista.