portfolio-optimiser/docs/2026-08-25-syretest-vei-ab.md
Kjell Tore Guttormsen 98cbb80a45 docs: syretesten vei A/B — tre Vegnormal-baser MAALT gjennom po (ORDRE 20260825T111038Z)
MAAL, IKKE BYGG: ingen fil under src/ er endret. 1021 passed / 5 skipped (166 s),
golden demo-transcript byte-uendret (ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

Alle seks maalepunkter dekket, hvert tall fra en kommando kjoert i oekten.
Instrumentet er validert mot commons' tre fasittall (3861/12595/10406) foer
Vegnormal-tallene ble konsumert.

Kjernetall: 446/1017/270 konsepter; 93 422 / 250 785 / 85 937 o200k_base-tokens
(sum 430 144); list_bundles() = 112 116 tokens i ETT verktoeykall; 0 av 3 baser
har validator-input.json eller cost-baseline.json; 0 nestede index.md av 1733.

Funn: BLOCKER-1 kontekstkostnaden gjoer live utforskning ugjennomfoerbar som
korpuset staar · MAJOR-1 gjentatt --bundle-dir forkastes STILLE, exit 0
(run.py:1581-1583 + :2070) · MAJOR-2 --explore --scripted-replies krasjer med
KeyError: 'navigator' (run.py:1531) · MAJOR-3 multi-base = N PROSJEKTER, ikke
1 prosjekt x N referansebaser (okf.py:433 via run.py:1491) · MINOR-1 flat
importform · NICE-1 ukjent base nektes ved navn.

Punkt 5 delvis vakuoest, som ordren forutsaa: sloeyfa FULLFOERER offline mot tre
baser og produserer et rutet mandat (bundle_id, stop=None), men 0 verktoeykall og
0 quick_validate - navigatoren aapnet aldri en base. Plumbing bevist, verdi ikke.
Syretesten trenger en levende modell.

Eksponerings-grensen holdt: ingen bundle kopiert, ingen kravtekst gjengitt,
rapporten baerer kun tall/stier/kommandoer/egne observasjoner. Ingen Azure-
handling, ingen live modellkall, ingen push til open.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4zGuDG2X7FQHMWBTDPLxF
2026-08-25 14:35:15 +02:00

16 KiB
Raw Blame History

Syretesten vei A/B — de tre Vegnormal-basene gjennom portfolio-optimiser

Ordre: 20260825T111038Z-1174613178-from-.claude (programplanens spor 3, gap G12). Dato: 2026-08-25 (økt 60). Mandat: MÅL, IKKE BYGG. Ingen fil under src/ er endret; uv run pytest -q1021 passed / 5 skipped (166 s), identisk med tallet før økten.

Eksponerings-grense (ordrens harde krav, holdt): dette repoet pusher til open/. Rapporten bærer derfor kun tall, stier, kommandoer og egne observasjoner. Ingen bundle-fil er kopiert, og ikke én linje kravtekst fra et konsept er lest inn eller gjengitt — alle konsept-tall under er lengdemålinger, ikke innhold.

Stopp-betingelsen var oppfylt: multi-base-ordren 20260825T080753Z-103813595 lå i orders/archive/ (commit 18af86e + 785261f) da økten startet. Multi-base-formen er lest slik den faktisk landet (run.py, explore.py, mandate.py, README), ikke slik planens § C.7 omtalte den.


1. Sammendrag — én setning per målepunkt

# Punkt Status Kjernetall
1 Katalogen (index_summary, konsepter, cost-baseline, verdicts) MÅLT 446 / 1017 / 270 konsepter; 0 av 3 har cost-baseline.json; 0 av 3 har validator-input.json; 0 type: verdict-filer i alle tre
2 Kontekstkostnad (bundle_context(navigate_bundle(...))) MÅLT 93 422 / 250 785 / 85 937 o200k_base-tokens — sum 430 144 mot 3861/12595/10406 for de tre eksempelbundlene (instrumentet reproduserte commons' tall eksakt)
3 Dry-run med tre baser i multi-base-formen MÅLT — og formen finnes ikke fra CLI-en Fire --bundle-dir gir exit 0 og en kjøring mot ÉN base (siste vinner, stille); bibliotekdøra run_mandate_across_bundles ruter korrekt men feiler i dispatch: FileNotFoundError @ okf.py:433
4 Offline-simuleringen med samme oppsett MÅLT Golden demo-transcript.stdout BYTE-UENDRET (ea8c534773acdbe41ae68f2c55724d69aaf8be4f), stderr 4 linjer; demoen kan ikke peke på en Vegnormal-base (samme okf.py:433)
5 --explore med full seks-felts --explore-config MÅLT — delvis vakuøst, som ordren forutså Sløyfa fullfører offline mot tre baser og returnerer et rutet mandat (bundle_id='B-n100-…', stop=None); men 0 verktøykall og 0 quick_validate — navigatoren åpnet aldri en base. Fra CLI-en er utforskningen ikke kjørbar offline i det hele tatt (KeyError: 'navigator')
6 G14: navigasjon inn i nestede index.md IKKE PRØVBAR HER — nevner oppgitt 0 nestede index.md av 1733 konsepter i alle tre basene (0 underkataloger); kjent-positiv kontroll nav-golden-hierarchy/bundle finner 2 nestede index og 2 dypt-nådde kontekstfiler, så instrumentet kan se dem

2. Tabellen (punkt 1 + 2)

Kommando bak hver rad: okf.navigate_bundle(d)okf.bundle_context(bundle), med tiktoken.get_encoding("o200k_base") (kjørt via uv run --with tiktoken; tiktoken er ikke lagt til som prosjekt-avhengighet).

Base Konsepter Kontekstfiler index_summary (tegn / tokens) bundle_context tegn bytes o200k_base-tokens verdicts cost-baseline validator-input skipped links
B-n100-2023-uten-sources-importert 446 446 51 214 / 28 289 221 916 226 430 93 422 0 nei nei 0
B-n200-2024-uten-sources-importert 1017 1017 116 879 / 64 764 616 179 626 034 250 785 0 nei nei 0
B-n500-2024-uten-sources-importert 270 270 30 974 / 17 197 240 714 245 251 85 937 0 nei nei 0
Sum, tre baser 1733 1733 199 067 / 110 250 1 078 809 1 097 715 430 144 0 0
kontroll: veglys-fv-soer 6 5 3 646 / — 32 201 32 884 10 406 1 ja ja 1
kontroll: tunnel-hauglia 6 5 4 763 / — 39 583 40 475 12 595 1 ja ja 1
kontroll: bygg-energi-mikro 5 4 1 884 / — 12 005 12 270 3 861 1 nei ja 1

Instrumentet er validert mot kjent fasit (Verifiseringsloven ansikt 4): de tre kontrollradene reproduserer commons' egne tall — 3861 / 12 595 / 10 406 — eksakt. Uten den kontrollen ville Vegnormal-tallene vært en måling ingen visste kunne treffe.

Ordrens tall bekreftet mot ground truth før noe ble bygget på dem: 447 / 1018 / 271 .md-filer på disk = 446 / 1017 / 270 konsepter + index.md i hver. Hver index.md har nøyaktig like mange lenker som det er konsepter (446 / 1017 / 270), alle unike, alle fulgt — skipped = 0.

Det manageren faktisk ser. Ett list_bundles()-kall (explore.py:419-438) returnerer hele index_summary for alle baser samtidig:

tegn bytes o200k_base-tokens
list_bundles() over de tre basene 201 196 201 196 112 116

Dette er ett verktøykall, og det er katalogverktøyets eneste form.

Hva tallene sier om .claudes § 9.1-analyse

.claude sin docs/okf-bundle-prosessen.md § 9.1 («en fil uten lenke finnes ikke; alt som lenkes leses helt») er bekreftet mot et ekte korpus, og den er kostbar her: alle 1733 konsepter er lenket fra rot-index.md, skipped = 0, og «leses helt» betyr 430 144 tokens for de tre basene. Progressiv disclosure gir ingen lettelse på denne bundle-formen, fordi importformen legger alt på ett nivå — se funn MINOR-1.


3. Funn

BLOCKER-1 — kontekstkostnaden gjør en live utforskning mot disse basene ugjennomførbar som de står

list_bundles() = 112 116 tokens i ett kall; read_bundle("B-n200-…") = 250 785 tokens. ExplorationContract.max_tokens (explore.py:70) er ledgeren BudgetMiddleware håndhever, og et enkelt katalogkall bruker mer enn et normalt tak. En 128k-modell kan ikke ta N200 i det hele tatt.

Dette er ikke en defekt i rammeverket — det er korpusets form møtt av § 9.1-kontrakten. Men det er den harde grensen for vei A/B live, og den var ikke målt før i dag. Fil:linje: src/portfolio_optimiser/explore.py:419-438 (list_bundles), :444-445 (read_bundle).

MAJOR-1 — gjentatt --bundle-dir forkastes STILLE; kjøringen ser ut som multi-base og er det ikke

Ordrens pkt. 3 forutsatte at CLI-en tar tre baser. Målt:

uv run python -m portfolio_optimiser.run VEGLYS-FV-SOER \
  --docs-dir shared/examples/veglys-fv-soer \
  --bundle-dir <N100> --bundle-dir <N200> --bundle-dir <N500> \
  --bundle-dir shared/examples/veglys-fv-soer --live-dry-run
→ EXIT 0, "VEGLYS-FV-SOER: LIVE-DRY-RUN OK (…)"

Exit 0. De tre Vegnormal-basene ble droppet uten ett ord. Bytter man rekkefølgen slik at en Vegnormal-base står sist, feiler samme kommando i stedet (live-dry-run refused: IR projection not found in bundle: 'validator-input.json') — altså siste --bundle-dir vinner, som er argparse sin default når action="append" mangler.

Dette er repoets egen defektklasse, anvendt på operatørflaten: hosting-whitelisten nekter ukjente felt ved navn nettopp fordi stille dropping er uleselig utenfra, og multi-base-invarianten avviser en andre bundle_dirrun_project-signaturen fordi den ville tvunget «et stille velg-en». Her er det et stille velg-en — bare i argv i stedet for i signaturen.

Fil:linje: src/portfolio_optimiser/run.py:1581-1583 (add_argument("--bundle-dir", default=None…), ingen action="append"), konsumert run.py:2070 (bundle_dirs=(args.bundle_dir,)) og run.py:607-610. Minste ærlige rettelse (ikke bygget — ordren er MÅL, IKKE BYGG): nekt et gjentatt --bundle-dir ved navn, på linje med de åtte eksisterende utforskningsnektene. STATE fører allerede «repeterbart --bundle-dir» som en åpen operatørbeslutning fra økt 58; denne målingen sier at inntil den er tatt, er stillheten selv problemet — ikke fraværet av funksjonen.

MAJOR-2 — --explore --scripted-replies krasjer med rå traceback: KeyError: 'navigator'

Den ene offline-døra CLI-en har til --explore er ubrukelig. _SCRIPTED_ROLES = ("proposer", "checker") er debattens to roller; utforskningen trenger i tillegg navigator, hypothesiser og manager. _load_scripted_replies er eksplisitt fail-fast for de to den kjenner («a missing role would otherwise surface as a KeyError deep inside scripted_factory's lookup, mid-run») — og så inntreffer nøyaktig det den advarer mot, for de tre den ikke kjenner:

File ".../explore.py", line 576, in fresh_exploration_workflow
    client_factory(role),
File ".../simulation.py", line 470, in factory
    reply = replies[role]
KeyError: 'navigator'

Ingen run refused:-linje, ingen rc-1 med forklaring — en traceback, som er den kanalen økt 57 betalte for å holde konfigurasjonsfeil UTE av.

Positivt målt i samme kjøring: finally-blokka holdt. {run_id}-exploration.json ble skrevet selv om kjøringen krasjet, med "completed": false og "stop": null — nøyaktig det completed-feltet finnes for.

Fil:linje: src/portfolio_optimiser/run.py:1531 (_SCRIPTED_ROLES), :1559-1564 (fail-fast-listen), krasjer i src/portfolio_optimiser/simulation.py:470. Merk: simulation.scripted_exploration_factory (simulation.py:713-736) dekker allerede alle fem rollene. Sømmen finnes; CLI-en når den bare ikke.

MAJOR-3 — regelverksbaser kan ikke være baser i multi-base-dispatchen (arkitektonisk, ikke en bug)

Bibliotekdøra run_mandate_across_bundles ble målt direkte med de tre basene og et mandat med én approach per base:

STEG 1  route_by_bundle → B-n100…: ['a0']   B-n200…: ['a1']   B-n500…: ['a2']     ✅ korrekt partisjon
STEG 2  run_mandate_across_bundles → FileNotFoundError @ okf.py:433
        "IR projection not found in bundle: 'validator-input.json'"

Partisjonen virker perfekt. Dispatchen gjør det ikke, fordi run.py:1491 leser hver bases prosjekt fra den basens egen IR-projeksjon — som er selve multi-base-invariantens designvalg («en kaller-oppgitt konstant kunne uansett bare vært riktig for én base av N»).

Konsekvensen er den viktigste innsikten i hele syretesten: multi-base betyr N prosjekter, ikke 1 prosjekt × N referansebaser. Vegnormal-basene er regelverk — de har verken prosjekt eller kostbaseline, og skal ikke ha det. Ordrens mentale modell («ett veglysprosjekt + tre normalbaser som kontekst») er en annen form, og den finnes allerede — bare ikke i dispatchen:

Dør bundle_dirs betyr Passer regelverk?
run.run_mandate_across_bundles (run.py:1388) N prosjektbaser → N kjøringer Nei — krever validator-input.json per base
explore.explore (explore.py:~840) N lesekilder for navigator/hypothesiser Ja — målt, se under

Fil:linje: src/portfolio_optimiser/okf.py:431-433, kalt fra run.py:1491 (dispatchen), run.py:609 (enkeltkjøringen) og simulation.py (demoen) — alle tre feiler på samme sted.

MINOR-1 — importformen legger alt på ett nivå, så progressiv disclosure gir null lettelse

0 underkataloger, 0 nestede index.md, 1733 av 1733 konsepter lenket direkte fra rot. Navigasjonen har ingenting å utsette; hele korpuset er ett flatt nivå. Dette er en egenskap ved kilden (vegnormal-okf sin importform), ikke ved okf.py. Det er også hele grunnen til BLOCKER-1: med nestede indekser kunne manageren åpnet én gren om gangen.

NICE-1 — read_bundle nekter ukjent base ved navn, som lovet

read_bundle("finnes-ikke") → ExplorationError: unknown knowledge base 'finnes-ikke';
                             configured: B-n100-2023-…, B-n200-2024-…, B-n500-2024-…

Nekten navngir det konfigurerte settet. Fil:linje: explore.py:390-393.


4. Hva punkt 5 faktisk viste — og hvor grensen for offline går

Ordren ba om at vakuiteten skulle måles, ikke antas. Målt, med scripted_exploration_factory (alle fem roller) mot de tre basene:

Arm Utfall
B — hypotese uten bundle_id, tre baser HypothesisParseError @ explore.py:732 — «a marked hypothesis must name its knowledge base when several are configured». Multi-base-nekten fyrer korrekt mot et ekte korpus.
C — hypotese med bundle_id, tre baser stop=None, 1 approach, bundle_id='B-n100-2023-uten-sources-importert', 2 ledger-runder, 6 modell-prompts. Sløyfa fullfører og produserer et rutet mandat.

Og så det ærlige forbeholdet, som er poenget:

  • quick_validate-kall: 0
  • Prompt-strøm-forekomster av basenavnene: N100 2, N200 0, N500 0 — begge fra instruksjonene, ingen fra et verktøyresultat.

Navigatoren åpnet aldri en base. Den scriptede klienten returnerer tekst og emitterer ingen verktøykall — nøyaktig den grensen økt 56s måling allerede slo fast, nå bekreftet mot et eksternt korpus. Lesesømmen selv er derimot bevist mot disse basene, ved direkte kall (samme kontroll økt 56 måtte innføre da den oppdaget at armen lå utenfor gaten): list_bundles() → 3 baser, read_bundle() → 221 916 / 616 179 / 240 714 tegn.

Konklusjon for punkt 5, uten pynt: plumbingen er bevist ende-til-ende mot ekte eksterne baser — ruting, nekt, mandatform, artefaktskriving. Verdien er ikke bevist, og kan ikke bli det offline. Syretesten trenger en levende modell. Det er et funn, ikke en feil.


5. Hva som MÅ til for en live-kjøring

Målt i denne økten, ikke antatt:

# Mangler Målt tilstand Konkret
1 Kontekstbudsjettet list_bundles() = 112 116 tokens; read_bundle(N200) = 250 785 Den harde blokkeringen. Enten en modell med svært stort vindu, eller — mer realistisk — en bundle-form med nestede indekser slik at manageren kan åpne én gren. Kilden eies av vegnormal-okf.
2 Foundry-endepunkt PORTFOLIO_FOUNDRY_PROJECT_ENDPOINT ikke satt, FOUNDRY_PROJECT_ENDPOINT ikke satt Én av de to må eksporteres. Låst av operatørbeslutningen om DisableLocalAuth (ordre 20260821T094949Z, docs/2026-08-18-vurdering-azure-omdoeping.md). Ikke rørt her.
3 Modell-map PORTFOLIO_MODEL_MAP ikke satt; src/portfolio_optimiser/data/model_map.json bærer REPLACE-WITH-FOUNDRY-DEPLOYMENT for alle azure-roller resolve_model("azure", r) nekter for alle fem roller, inkl. manager/navigator/hypothesiser. Under local faller alle fem til qwen3:4b via default — utforskningsrollene er fortsatt ikke eksplisitt mappet (kjent ærlighets-grense fra økt 56).
4 En prosjektbase 0 av 3 Vegnormal-baser har validator-input.json eller cost-baseline.json Kjøringen trenger et prosjekt å optimere. Vegnormal-basene er regelverket det optimeres innenfor. Riktig oppsett: --bundle-dir <prosjektbase> for pipelinen + de tre normalbasene som explore(bundle_dirs=…)-lesekilder — men det krever MAJOR-1 løst, siden CLI-en i dag sender én base til begge.
5 Offline-generalprøve KeyError: 'navigator' MAJOR-2 må lukkes før en betalt kjøring, ellers er første live-kjøring også første gjennomkjøring. Repoets egen måleprotokoll: bevis så mye som mulig gratis, så en feil er attribuerbar.

Rekkefølge, uten å foregripe operatørens valg: 5 → 1 → 2/3 → 4. Punkt 5 er gratis, punkt 1 avgjør om vei A/B i det hele tatt er mulig med denne bundle-formen, og punktene 23 koster penger og er Azure-gatet.


6. Kommandologg

Hver tabellverdi over stammer fra én av disse, kjørt i denne økten:

# pkt 1: konsepter, index-lenker, verdicts, cost-baseline
find <base> -name '*.md' | wc -l ; grep -oE '\]\([^)]+\)' <base>/index.md | wc -l
grep -lE '^type: *verdict' <base>/*.md | wc -l

# pkt 1+2: navigasjon, kontekst, tokens (instrument validert mot commons' tre fasittall)
uv run --with tiktoken python  # okf.navigate_bundle / okf.bundle_context / o200k_base

# pkt 3: CLI, fire --bundle-dir, begge rekkefølger
uv run python -m portfolio_optimiser.run VEGLYS-FV-SOER --docs-dir … --bundle-dir … --live-dry-run

# pkt 3: bibliotekdøra
python  # mandate.route_by_bundle + run.run_mandate_across_bundles

# pkt 4: golden-regresjon
uv run python -m portfolio_optimiser.simulation | shasum   # ea8c534773acdbe41ae68f2c55724d69aaf8be4f

# pkt 5: CLI-en, og deretter explore() direkte med alle fem roller scriptet
uv run python -m portfolio_optimiser.run … --explore … --explore-config … --scripted-replies …

# pkt 6: nestede index, med nav-golden-hierarchy som kjent-positiv kontroll

# regresjon
uv run pytest -q   # 1021 passed, 5 skipped, 166.00s