generate_via_llm consumed each validator Rejection internally (`last`), fed it into the next attempt's prompt, and dropped it. So Step 5 was real but unobservable: a caller could see THAT a proposal validated, never that it validated on attempt 2 after the deterministic validator falsified attempt 1. It was the one step of the eight with no output to show. The seam is a typed return value -- GenerationResult(outcome, refinements) -- rather than an out-parameter or a callback: a returned value cannot be silently lost by a caller that forgets to pass a collector, and mypy forces every call site to acknowledge it. refinements carries ONLY rejections that were actually fed back. When the attempt budget runs out the final rejection IS outcome; counting it here would be double-counting, and the bounded control test goes red on the collect-everything implementation that gets this wrong. The loop's bound is untouched: max_attempts and meter.tick_round stand, and `last` still drives the prompt alone, so prompt growth is unchanged. run.py accumulates across _evaluate calls, so _evaluate_mandate is untouched; RunResult.refinements defaults (the coverage precedent) and is concatenated across approaches rather than keyed per approach -- stated as an honesty limit. The simulation now shows it: the scripted proposer overclaims 250000, which the validator falsifies against P90 = 90000, and the corrected 30000 validates. Only the overclaim is scripted -- the rejection is computed. scripted_factory takes a per-role reply selector so this needs no second scripted client body. README records the two accuracy changes only (Step 5 is now inspectable; the simulation trace shows the correction). The level-2 publishing claim stays deferred until after the demo (O4). Load-bearing MEASURED against the full suite with a control, four mutations all red: detach the returned history (4 tests) - collect-everything (control only) - detach the run wiring (2 tests) - revert the simulation's proposer to a constant (the demo-protection test). Control: 759 passed / 4 skipped; ruff, format and mypy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017CcWFcREUi6YPjEpN3ACDP
8.8 KiB
Demo-uke — alle åtte steg live torsdag 13. august 2026
Grunnlag:
2026-08-06-intensjons-qa.md(påstander A1–C8, funn G1–G6, beslutninger O1–O4). Rammene A/B/C fra briefen står. Denne planen legger til dagsrekkefølge, den ene kodejobben, og et go/no-go-punkt som gjør uka robust mot at innholdet ikke kommer.
0. Låst — ikke gjenåpne
| Beslutning | |
|---|---|
| A | «Live» = sanntids-gjennomgang, skriptet under panseret. Preflight/Foundry er UTE av kritisk sti. |
| B | MAF-siden alene. Søsken-repoet er parkert. |
| C | Det realistiske eksemplet bygges i commons, i en egen tab. |
| O1 | Ferdigbygd eksempel. Fabrikken (D-G/T0 okf-toolkit) er eksplisitt utsatt. |
| O2 | Steg 5 bygges og vises live. |
| O3 | Bestilt commons 2026-08-06 med frist 11. august; reserve planlagt. |
| O4 | README oppdateres ETTER demoen (14.–15. august), ikke før. |
Bestillingen er levert: 20260806T112037Z-2648131757-from-portfolio-optimiser.md.
1. Hva demoen ÆRLIG er — formuleringen er avtalt på forhånd
D-I setter publiserings-påstanden til nivå 2: realistisk case, modellerte tall, aldri salgsspråk over beleggsnivået. Tre ting sies høyt i demoen, ikke i en fotnote:
- Agent-svarene er skriptet. Dette beviser dataflyten, den deterministiske ryggraden og at læringssløyfa lukkes — ikke at en levende modell ville produsert nettopp dette forslaget. (Banneret sier det allerede i dag; det skal stå, ikke pyntes bort.)
- Innholdet er håndkuratert, ikke fabrikkert. Den besluttede demo-stien (D-H pkt. 4) går via en bundle-fabrikk som ikke er bygget. Vi viser «last ned → kjør», men et menneske lagde innholdet.
- Tallene er modellerte, ikke målte. Ingen pilot har validert dem i drift.
Dette er ikke en unnskyldning som svekker demoen — det er selve grunnregelen repoet er bygget på (A5: koden får ikke påstå mer enn den gjør). En demo som overselger bryter med det den demonstrerer.
2. De åtte stegene → hva som faktisk vises
RunResult bærer allerede retrieved, debate_output, checker_verdict, outcome
(ValidatedProposal | Rejection), verdict og coverage. Presentasjonen er ~30 print-linjer
(simulation.py:295–326). Derfor er sju av åtte steg presentasjonsarbeid, og ett er ekte bygg:
Steg (method-spec §3) |
Vises som | Status i dag | Arbeid |
|---|---|---|---|
| 1 — Forstå konteksten | navigerte filer + ExpeL-folden (retrieved) |
markør-linja antyder det | print |
| 2 — Hypotese | forslaget med parametere | data finnes, printes ikke | print |
| 3 — Debatt (maker-checker) | begge deltakere + checker_verdict |
checker printes | print |
| 4 — Valider / falsifiser | validator-linja med P90 | printes ✔ | — |
| 5 — Forbedre, informert og bundet | avvisning → korrigert forslag | bygget 7. aug ✔ | — |
| 6 — Forkast eller foreslå | typet outcome |
data finnes, printes ikke | print |
| 7 — Svar på tilbakemelding | persona-dom + fil-innboksen | dommen printes | print |
| 8 — Promoter godkjent kunnskap | promotert fil + index-lenke | printes ✔ | — |
Steg 5 er den eneste ekte kodejobben. generate_via_llm forbruker den mellomliggende
avvisningen internt (last) og returnerer bare sluttresultatet — og i dagens demo-kjøring
validerer forslaget på FØRSTE forsøk, så forbedringsløkka trigges aldri. Det kreves to ting:
en søm som slipper avvisnings-historikken ut, og et nytt skriptet forløp der forslaget først
blir avvist og deretter korrigert.
3. Dagsplan
Fredag 7. august — steg 5-sømmen (den ene kodejobben). ✔ GJORT.
Slipp avvisnings-historikken ut av generate_via_llm uten å endre løkkas tak (max_attempts +
meter.tick_round står urørt — «forbedre til god nok» uten tak er forbudt). Nytt skriptet
avvis-så-korriger-forløp. Ny load-bearing-test: RØD når sømmen kobles fra. Ligger først i uka
med vilje — det er den eneste jobben som kan overraske, og den har fem dagers slakk bak seg.
Utfall: den åpne beslutningen ble egen returtype —
generate_via_llmreturnererGenerationResult(outcome, refinements), ogRunResult.refinementsbærer den ut av kjøringen. En returverdi kan ikke bli stille tapt slik en out-parameter kan, og mypy tvinger hvert kallsted til å ta stilling.refinementsbærer KUN avvisninger som faktisk ble matet tilbake (den siste avvisningen ved uttømt budsjett ERoutcome). Simuleringens proposer overklager 250 000 NOK, som den deterministiske validatoren felt mot P90 = 90 000; det korrigerte forslaget på 30 000 validerer. Fire mutasjoner målt røde mot hele suiten, med kontroll.
Lørdag 8. – søndag 9. august — presentasjonslaget.
De fem print-tilleggene over, formet som én lesbar gjennomgang med steg-nummer i margen.
Ingen ny logikk. Målet er at en tilhører kan følge hvert steg uten at du forklarer hva de ser på.
Mandag 10. august — gjør manuset innholds-drevet.
ScriptedChatClient tar en reply_selector over (prompt_blob, role) — den ser altså prompten
og KAN nøkle svaret på kandidaten i stedet for å ha ett hardkodet svar. Bygg det nå, før
innholdet kommer: da er et nytt prosjekt en data-oppføring, ikke et nytt manus skrevet for hånd
under tidspress. Dette er ukas viktigste risikoreduksjon.
Tirsdag 11. august — GO/NO-GO på innholdet.
Er commons-leveransen hentbar? git subtree pull --prefix=shared commons main --squash, så
kjør. JA: pek simulate_learning_loop på den nye bundelen, utvid selector-dataene, mål
rendret kontekst-størrelse per bundle. NEI: lås mikro-eksemplet som demo-innhold og si det i
ærlighets-avsnittet. Beslutningen tas tirsdag, ikke onsdag kveld.
Onsdag 12. august — generalprøve, så fryse. Kjør hele gjennomgangen to ganger. Identisk output begge ganger (determinisme er et poeng, ikke en detalj). Full suite grønn. Etter generalprøven: ingen endringer i kjørestien.
Torsdag 13. august — demo.
Fredag 14. – lørdag 15. august — README (O4). Nivå-2-påstanden løftes ETTER at beviset finnes.
4. Risiko
| Risiko | Utslag | Tiltak |
|---|---|---|
| Commons rekker ikke 11. august | Tynt innhold | Reserve låst tirsdag; bestillingen sier eksplisitt at det er en reserve, ikke en krise |
| Nytt innhold krever nytt manus | 2 dager håndarbeid under press | Innholds-drevet reply_selector bygges mandag, FØR innholdet kommer |
| Prompten sprenges av stor bundle | Token-tak slår inn midt i demoen | Bestillingen er størrelses-kappet på målt grunnlag (~25 000 tegn/bundle); mål på nytt tirsdag |
| Steg 5-sømmen tar lengre tid | Ett steg mangler | Ligger fredag; fallback er testbevis-varianten (vurdert og valgt bort, men den finnes) |
docs/presentasjon-*.html eies av annen sesjon |
Konflikt | Røres aldri; alltid eksplisitt filliste ved git add |
5. Verifisering
Konkrete kriterier, ikke «sjekk at det virker»:
uv run python -m portfolio_optimiser.simulation→ exit 0, og outputen har én merket linje per steg 1–8. Verifiseres med... | grep -cE "^ *Steg [1-8]"→ 8.- Steg 5 er synlig som to forslag: ett avvist med grunn, ett korrigert som validerer.
Verifiseres ved at outputen inneholder både en
REJECTED- og enVALIDATED-linje for samme kandidat. - Ny load-bearing-test for steg 5-sømmen blir RØD når sømmen kobles fra. Måles mot HELE suiten,
med kontroll, restaurert fra scratchpad-kopi +
shasum -c. uv run pytest -qgrønn (baseline i dag: 759 kollektert, 755 passed / 4 skipped).uv run ruff check .+uv run mypy srcrene.- Generalprøve onsdag: to kjøringer, byte-identisk output (
diff <(kjøring1) <(kjøring2)tom). - Ved commons-leveranse: rendret kontekst per bundle måles med
okf.bundle_contextog skal ligge under ~25 000 tegn. Over det → bruk færre bundles, ikke større prompt. shared/examples/bygg-energi-mikro/ognav-golden-*er uendret etter subtree-pull (git diff --statpå de stiene → tomt). Goldenene er load-bearing.
6. Nøkkelantakelser som skal testes, ikke antas
- «Sju av åtte steg er ren presentasjon.» Testes fredag/lørdag: hvis et av de fem
print-tilleggene viser seg å kreve ny logikk, er det samme klasse funn som C7 og skal meldes med en gang. - «
reply_selectorkan nøkle på kandidaten.» Signaturen er(prompt_blob, role) -> str, så prompten er tilgjengelig — men at kandidaten er entydig identifiserbar i blobben er ikke verifisert. Testes mandag, på mikro-eksemplet, før innholdet kommer. - «Ny bundle plugges inn som parameter.»
simulate_learning_loop(bundle_dir, work)tar katalogen som argument (simulation.py:183, kalt:293) — verifisert i dag. Det som IKKE er verifisert, er at en bundle med flere kandidater kjører gjennom uendret; det er S3.2-stien, og den testes tirsdag.