Commit graph

323 commits

Author SHA1 Message Date
5871e397a3 docs: presentasjonsmateriellet fra demoen 2026-08-13
Frysen er opphevet — demoen er avholdt, og disse to filene er det den ble holdt
på. De lå utrackede med vilje gjennom hele frys-vinduet, så `git status --short
--untracked-files=no` kunne stå TOM som gate.

- `2026-08-13-demo-presentasjon.html` — slide-decket som ble vist, 51 slides i
  åtte deler, 15 håndskrevne tema-bevisste SVG-figurer, ingen eksterne
  avhengigheter. Alle tall er grunnet mot `tests/golden/demo-transcript.stdout`
  før de ble skrevet: 2 100 000 · 1 769 915 · 445 500 · 3 tidligere dommer.
- `2026-08-13-presentasjon-ledelse.html` — utdypende underlag med
  verifiseringslogg, der de to viktigste radene står TOMME med vilje
  (pilotkostnad ikke estimert, gevinst ikke målt).

Det ble INGEN live kjøring i møtet; golden-transkriptet er derfor det eneste
beviset decket viser, og all «dere ser om litt»-formulering er skrevet om til
et eksempel løsningen ER testet på.

Begge filer er innholdssjekket før publisering til den offentlige `open/`-flaten:
null treff på endepunkt/tenant/nøkkel-mønstre, null eksterne avhengigheter,
`<meta charset="utf-8">` på plass i begge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkogKWsM489mCza1BLJdtW
2026-08-13 18:45:06 +02:00
d71a4e7b4e docs: stempler v1.0.0 — [Unreleased] blir [1.0.0] - 2026-08-12 v1.0.0
Datoen er LEST med `git log -1 --format=%cs` på Y, ikke skrevet på forhånd og
ikke tatt fra veggklokka. Re-leses på denne commiten før taggen settes (runbookens
§5 punkt 8): faller midnatt mellom Y og Z, står gårsdagens dato i commiten som
faktisk tagges. Denne commiten er Z.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWeYxduEnFQeynXbrtEA6o
2026-08-12 20:16:54 +02:00
2e17ea32b6 docs(P4.5): §0s to målte felt fylt ut — frosset commit X og generalprøve-tidspunkt
Generalprøve ×2 grønn på 777b9f7 (exit 0, 61/4 begge ganger, golden-diff TOM
begge ganger, kjøringene byte-identiske med hverandre). K1 distinkt = 8,
linje-telling 9 som forventet. K2: REJECTED 2100000 mot P90 1769915 →
VALIDATED 445500, samme kandidat. Rent tre målt FØR X ble notert.
Frys-gaten prøvekjørt begge armer: arm 1 tom per konstruksjon (lime-inn-sjekk
av hashen passerte), arm 2 mot c255662 ikke-tom (6 filer) — gaten diskriminerer.
Utfyllings-gaten TOM. Denne commiten er Y.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWeYxduEnFQeynXbrtEA6o
2026-08-12 20:16:23 +02:00
777b9f7225 docs(P4.5): min egen komprimering gjorde tag-kommandoen ukjørbar
Advisor felte en defekt DENNE ØKTA innførte. Forrige commit skrev
`git tag -a v1.0.0` i STATE og planens to rader — uten `-m`. Jeg fjernet
den for én-kopi-prinsippets skyld, men prinsippet gjelder MELDINGSTEKSTEN;
`-m` er ikke innhold, det er flagget som gjør `-a` ikke-interaktiv. Før
økta bar STATE en komplett kjørbar kommando. Etter bar den en ufullstendig.

Failure-moden er MÅLT, ikke arvet fra reviewet (som antok at den henger):
`GIT_EDITOR=true` er satt i sesjonsmiljøet, så kommandoen henger IKKE — den
gir `fatal: no tag message?`, exit 128, og INGEN tag. I et skall uten
`GIT_EDITOR` åpner den en editor. Begge veier: ukjørbar som skrevet, på
enveis-dagen, etter at frys-gaten alt har passert. Runbookens punkt 10 var
korrekt hele tiden — feilen satt kun i de to sammendragene.

Rettet til `-m "<ordrett fra runbookens §5 punkt 10>"`: `-m` er synlig og
obligatorisk, meldingsteksten bor fortsatt ett sted, og utfyllings-gaten
står på 2 (vinkelparentesene er enkle og små — de matcher ikke `<<[A-ZÆØÅ-]*>>`).

PUNKT 10 ER NÅ KJØRT EKSTRAHERT FRA FILA, ikke håndskrevet (økt 13s
presedens: en kommando som ser riktig ut kan lyve, og repoet har en
bash-3.2-multibyte-historie). Hentet ut av linje 281 via generert skript
(`eval` er hook-blokkert), kjørt mot engangs-repoet: exit 0, og
`git cat-file -p v1.0.0` gir meldingen byte-identisk med em-dash intakt.

TO PÅSTANDER FRA FORRIGE COMMIT VAR UMÅLTE, OG ER NÅ ERSTATTET AV MÅLINGER:

1. «vent et halvminutt» var et tall jeg aldri målte — jeg målte at porten
   svarte igjen, ikke hvor lenge den var stengt. Samme klasse som §1s
   `/tmp/po-sim-…`-sti økt 9 drepte. Erstattet av proben som FAKTISK ble
   observert virke: `ssh -T git@git.fromaitochitta.com` → `Hi there, ktg!`.
   En probe kan ikke bli foreldet slik et gjettet intervall kan.

2. «aldri re-push» var for absolutt. Målt: `git push` av en uendret tag gir
   `Everything up-to-date`, exit 0 — og hvis det var PUSH-en (punkt 10) som
   ble rate-limitet, ER retry den påkrevde utveien. Forbudet er nå snevret
   til det som faktisk er farlig: `git tag -f` + force. Uten force er selv
   det fail-closed — målt: `! [rejected] … already exists`.

Målt etter rettelsen: utfyllings-gaten 2 · §5 fortsatt elleve punkter ·
punkt 10 fortsatt på linje 281 og kjørbar · CHANGELOG urørt · planens to
rader uendret i linjeantall (705) og pipe-struktur (5/0 og 6/3) · frys-gaten
mot HEAD TOM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019nZQkAJytbaUAYxMAU2wk7
2026-08-11 22:33:58 +02:00
2319f04420 docs(P4.5): taggens FORM var onsdagens siste ufattede beslutning
Punkt 10 sa `git tag v1.0.0` — lettvekts. Repoets eneste andre tag er
ANNOTERT (målt: `git cat-file -t v0.1.0` → `tag`, melding
`v0.1.0 — first tagged release`), så hovedreleasen ville blitt den eneste
taggen uten forfatter, dato eller melding. Ingen gate ville stoppet det:
`describe --tags` og `tag -l` svarer likt for begge former (målt).

Onsdagen skal MÅLE og UTFØRE, ikke avgjøre. Slik den sto, måtte dagen
enten tagge lettvekts uten å se avviket, eller oppdage det og improvisere
en `-m`-melding på en enveis-dag. Meldingen står nå literalt i §5 punkt 10
— og KUN der; planens to rader peker dit, så det finnes ingen andre kopi
å drifte fra. Utfyllings-gaten står derfor fortsatt på 2: en placeholder
ville gjort meldingen til et tredje felt onsdag måtte fylle.

Formen er tørrkjørt i et engangs-repo, ikke resonnert: `-a` med em-dash gir
`tag -l` → v1.0.0, `describe --tags --exact-match HEAD` → v1.0.0, filtrert
`ls-remote` → 1 linje, og em-dashen overlevde skallet.

MIN FØRSTE HYPOTESE VAR FEIL, OG MÅLINGEN FELTE DEN: jeg trodde punkt 11s
«én linje» brakk for annoterte tagger, siden `ls-remote --tags origin` viser
den peelede `^{}`-refen. Målt mot EKTE origin: MED refspec-filter gir den
annoterte v0.1.0 én linje — `^{}` matcher ikke pattern-et. Punkt 11 var
robust hele tiden. Presisert i teksten, fordi neste leser vil ha samme tvil.

EN ANDRE DEFEKT FALT UT AV Å MÅLE MOT EKTE REMOTE: origin rate-limiter SSH
på burst. Målt: de to første ls-remote gikk igjennom, de fire neste ga
`Connection refused`, porten svarte igjen etter en pause, og Forgejo-weben
var oppe hele tiden (HTTP 303) — serveren var aldri nede. Punkt 11 kjører
to SSH-kall rett etter en push, altså nøyaktig et burst.

Alvorligheten ligger i at BEGGE utfall gir null linjer på stdout (målt):
taggen mangler = exit 0 + tom stderr; kom ikke fram = exit 128 + melding.
Et `| wc -l` kan ikke skille dem — så en rate-limitet bekreftelse leses som
«taggen landet ikke» dagen etter at push-en faktisk lyktes, på enveis-dagen.
Diskriminatoren er exit-koden; retteslen er vent-og-kjør-på-nytt, aldri
re-push eller re-tag. Samme klasse som §5 punkt 5s arm: en gate må kunne
feile på riktig grunn, og de to måtene den svikter på må se ulike ut.

Ingen nye punkter, ingen renummerering: begge endringene sitter PÅ punkt 10
og 11. Målt: §5 fortsatt elleve punkter · utfyllings-gaten 2 · CHANGELOG
urørt ([Unreleased] = 1, null link-refs) · kun to diff-hunks, begge i §5, så
§0/§1/§2/§3/§4/§6 er byte-urørt og økt 9s 67 målinger av §2 står · planens
to rader uendret i linjeantall og pipe-struktur (5/0 og 6/3, før = etter) ·
frys-gaten mot HEAD TOM og diskriminerende (c255662 = 6 filer).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019nZQkAJytbaUAYxMAU2wk7
2026-08-11 22:17:29 +02:00
1d30a47e68 docs(P4.5): punkt 5s nye arm hadde tvetydig failure-mode
Armen mot c255662 ble lagt til i c50fd2e for å bevise at frys-gaten kan
diskriminere. Men den fortalte ikke onsdagens operatør hvordan man skiller
de to måtene den kan svikte på — og begge ville stoppet sekvensen på en
enveis-dag:

- stille tomt  = pathspec-en er ødelagt (det armen finnes for)
- fatal: bad revision = hashen er feilskrevet

MÅLT, ikke antatt:

    $ git diff --stat deadbeef..HEAD -- . ':(exclude)docs/' ':(exclude)CHANGELOG.md'
    fatal: bad revision 'deadbeef..HEAD'

Git roper altså på feil hash. En tom utskrift er derfor ALDRI «feil hash»,
og det står nå i punktet — så «ikke gå videre før armen er ikke-tom» kan
handles på uten å gjette.

Samme klasse som defekten c50fd2e lukket, ett nivå ned: en gate hvis
utfall er tvetydig blir under tidspress resolvert ved gjetning. c255662 er
nå load-bearing i runbooken, så hashen navngis i selve feilbeskrivelsen.

Målt: utfyllings-gaten 2 · §5 elleve punkter · frys-gaten mot HEAD TOM ·
kun §5 endret. Ingen suite-kjøring: identisk innholdsklasse som c50fd2e,
der 810/4 + ruff + format + mypy allerede ble målt rene.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192WLzngWK5aFDYpkXWuLVh
2026-08-11 21:57:06 +02:00
c50fd2edb4 docs(P4.5): §5s frys-gate ved X kunne aldri feile
Punkt 5 kjørte frys-gaten mot <X> rett etter at punkt 4 leste X som
`git rev-parse HEAD`. På det tidspunktet ER X lik HEAD, og ingenting er
committet imellom — så <X>..HEAD er tom uansett hva treet inneholder.

Målt, ikke resonnert: med en endret src/-fil liggende i arbeidstreet
(` M src/portfolio_optimiser/__init__.py`) sto gaten fortsatt tom. Den
måler ingen tilstand.

Økt 7s begrunnelse for to kjøringer sa «den første måler en tilstand som
ikke lenger finnes når taggen settes». Det er for snill: den finner ingen
tilstand å måle. Dette er repoets egen defektklasse, anvendt på repoets
egen runbook — «en gate som bare kan bli grønn beviser ingenting» er
standarden hver load-bearing test måles mot.

Alvorlighet, uttalt presist: falsk trygghet, ikke falsk grønt. Punkt 3
(rent tre) og punkt 9 (etter Y og Z) dekker den faktiske risikoen, så
ingenting ved onsdagen blir rødt av dette. Men en gate operatøren ser
grønn ved X kan under tidspress gjøre punkt 9 til en gjentakelse man
hopper over — samme argument som ga §6 steg 1 sin `--untracked-files=no`.

Punktet er BEHOLDT, ikke fjernet: fjerning renummererer 6→5 … 11→10 og
bryter fem kryssreferanser (§0s «punkt 10» og «punkt 6», punkt 9s
tilbakereferanse, STATEs «elleve punkter», planens ons-12-rad) — på
frys-eve. I stedet har punkt 5 fått en arm den kan feile på:

    git diff --stat c255662..HEAD -- . ':(exclude)docs/' ':(exclude)CHANGELOG.md'

→ ikke tomt (målt: 6 filer). Den beviser at kommandoen kan diskriminere
FØR punkt 9 hviler på at den er tom. Uten den ville en feilskrevet
':(exclude)…' eller en quoting som ikke overlevde skallet (MULTIOS,
08-09) gitt grønn gate på feil grunnlag, og et utestet tre tagget.
c255662 ligger fast bak både Y og Z, så armen forblir ikke-tom uansett
hvor HEAD står onsdag.

To rettelser i samme pass, begge nødvendige for at teksten ikke skal lyve
på en ny måte:

- punkt 9 sa «Punkt 5 målte en tilstand som ikke lenger finnes» — under
  det nye punkt 5 er det galt på en ny måte, siden punkt 5 ikke målte noe
- §5s ingress sa «Fila skrives ÉN gang onsdag (punkt 6)», mens punkt 4
  instruerer om å skrive X inn i §0. Den bærende egenskapen er at
  ingenting skrives ETTER Y, ikke antallet skrivinger — nå sagt slik.
  Punkt 4 er operasjonelt riktig: å bære en hash i hodet gjennom tre
  gate-kjøringer er verre.

Begge gate-kommandoene er EKSTRAHERT LITERALT fra runbooken og kjørt
(ikke gjenskapt for hånd — repoets MULTIOS-lærdom): arm 1 tom, arm 2
seks filer.

Målt: utfyllings-gaten 2 · §5 elleve punkter · §0/§1/§2/§3/§4/§6/vedlegg
byte-urørt mot 24b5ed2 (kun §5 endret, så økt 9s 67 målinger av §2 står) ·
planens kalender-rader 3 usiterte pipes · frys-gaten mot HEAD TOM ·
810 passed / 4 skipped · ruff + format + mypy rene.

Pre-flighten er re-målt HELT på 24b5ed2, ikke arvet fra 4b9e5d9:
stale tag 0/0 · [Unreleased] 1, null link-refs · frys-gaten d0e8bb0..HEAD
TOM og diskriminerende (c255662..HEAD = 6 filer) · demo exit 0, golden-diff
TOM, 61 linjer, K1 distinkt 8 / linjer 9.

Åttende defekt i denne dokumentfamilien på åtte økter. Ny klasse: ikke
«feil tidspunkt» og ikke «implisitt steg», men en gate hvis utfall var
avgjort av sin egen plassering i sekvensen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0192WLzngWK5aFDYpkXWuLVh
2026-08-11 21:51:23 +02:00
24b5ed29df docs(P4.5): §5 navnga to commits den aldri opprettet
Y og Z navngis fem steder i §5 — punkt 3s parentes, punkt 8, punkt 9 og
ingressen — men ingen av de elleve punktene opprettet dem. Punkt 6 sa
«Runbooken fylt ut», punkt 7 «CHANGELOG-overskriften stemplet»; ingen sa
git commit, og punkt 8 forutsatte at Z fantes.

Konsekvenskjeden er målt mot gate-definisjonene, ikke resonnert:

- frys-gaten unntar BÅDE docs/ og CHANGELOG.md, så to ucommitterte endringer
  passerer punkt 5 og 9 stille
- punkt 11s anker passerer også, fordi HEAD da fortsatt er X og X ER det
  taggede
- v1.0.0 ville blitt tagget med `## [Unreleased]` fortsatt i CHANGELOG — en
  release-defekt, ikke bare en gate-defekt
- først torsdagens §6 steg 1 ville ropt, foran demoen

Rettet som klausuler PÅ punkt 6 og 7, ikke som nye punkter: commiten er det
som gjør handlingen varig, og å skille dem er nøyaktig defekten. Fortsatt
elleve punkter. Punkt 6→7→8 lenker nå: Y committet → dato lest på Y → stempel
→ Z committet → re-lest på Z → tag Z.

Klassen er ny for uka. De åtte foregående var «kommandoen var riktig,
tidspunktet var det ikke». Denne er «handlingen var riktig, steget som gjør
den varig var implisitt» — og den overlevde både gjennomlesningen og
propagerings-passen i 4b9e5d9, fordi begge lette etter tall og referanser,
ikke etter fravær.

Målt: utfyllings-gaten 2 · §5 elleve punkter · §1 og §2 byte-urørt mot
63a167a · frys-gaten d0e8bb0..HEAD TOM.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfdfrMcEtkmZXPkzt7APQU
2026-08-11 14:16:14 +02:00
4b9e5d9520 docs(P4.5): §0s tag-felt var sirkulært, og begge utveier gjorde torsdagen rød
§0s tag-rad hentet verdien fra `git tag -l v1.0.0` ETTER push (§5 punkt 10),
mens §5 punkt 6 krever at utfyllings-gaten er TOM — altså FØR. Punkt 6 var
gatet på informasjon som først finnes etter punkt 10.

Ingen utvei holdt. Fylt ærlig krever den en commit ETTER taggen: HEAD forlater
Z, og torsdagens §6 steg 2 — identitets-ankeret økt 10 vant — blir rødt på
demo-morgenen. Ufylt bryter den gaten i punkt 6. Sekvensen modellerer heller
ingen tredje commit (X → Y → Z → tag). Lokal tag før utfylling hjelper ikke
(taggen står fortsatt på Z); --amend etter taggen flytter Zs sha ut under den.

Tvillingen: §5s haker settes i selve fila, og punkt 7-10 skjer ETTER
runbook-commiten Y. Målt: en redigert runbook gir « M docs/plan/…», altså rød
§6 steg 1 — eller en commit etter taggen, altså rød §6 steg 2. Samme
motsigelse, samme to gater.

Løsningen bevarer identiteten: §0 mistet tag-raden med begrunnelsen skrevet
inn, §5 fikk et ellevte punkt som bekrefter taggen der den settes (git tag -l ·
git ls-remote --tags origin · git describe --tags --exact-match HEAD — det
siste er torsdagens anker kjørt et døgn tidlig), og §5s ingress sier at hakene
aldri settes i fila. Ingenting skrives etter taggen.

En åttende defekt falt ut av gjennomlesningen, og den er økt 11s egen bom: §5
punkt 9 sa «Steg 2 målte en tilstand som ikke lenger finnes», mens første
frys-gate-kjøring er punkt 5. Verifisert mot 818b55a: da linja ble skrevet var
frysen TO kommandoer og gaten var nr. 2. Økt 11 gjorde den til tre, men
grep-passen lette etter strengen «to kommandoer», så «Steg 2» slapp forbi —
og økt 11 konkluderte eksplisitt at ingen kryssreferanse pekte på den gamle
nummereringen. Nå forankret i §5s egen nummerering.

Målt: utfyllings-gaten 3 → 2 · §5 ti → elleve punkter · §0-tabell 4 pipes per
rad · §1 og §2 byte-urørt (shasum likt før/etter — økt 9s 67 målinger er gjort
mot de bytene) · fire diff-hunks, alle i §0/§5 · alle 20 numeriske
kryssreferanser sveipet · frys-gaten d0e8bb0..HEAD TOM · ingen test leser
dokumentene.

Propagert til fem levende steder i planen og STATE; GJORT-blokkenes «3» står
som historikk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FfdfrMcEtkmZXPkzt7APQU
2026-08-11 14:11:47 +02:00
63a167a8d8 docs(P4.5): frys-gaten er commit-til-commit, men prøven leser arbeidstreet
To en-linjes herdinger av onsdagen og torsdagen. Null kodeendring.

1) §5 manglet en arbeidstre-sjekk ved X. Frys-gaten er
   `git diff <X>..HEAD` — commit-til-commit — mens generalprøven kjører
   fra arbeidstreet. En ucommittet endring i src/ ved prøvetidspunktet
   gjør X til en beskrivelse av noe som aldri ble prøvd, og BEGGE
   kjøringene av gaten står tomme: de kan ikke se den. Verre om
   endringen er dét som gjør prøven grønn — da er den taggede koden rød,
   som er nøyaktig hullet kriterium 6 ikke dekker. Samme argument som ga
   §6 steg 1 sin plass (økt 10): rent tre er en REGEL, ikke et
   øyeblikksbilde. Punktet sier også hva man gjør ved ikke-tomt — commit
   eller forkast, og kjør så prøven OM IGJEN, siden en commit flytter
   HEAD og X ellers ville pekt på et tre prøven aldri så.

2) §3s abortsti brukte relativ sti til fasit-fila, og prosaen rett under
   navngir «feil katalog» som sannsynlig årsak. Målt: fra en annen
   katalog gir den `cat: tests/golden/…: No such file or directory`.
   En abortsti som deler failure-mode med det den aborterer fra, gjør
   ett synlig problem til to. Nå absolutt sti — målt kjørbar fra
   vilkårlig cwd (61 linjer).

Samme defektklasse som de fem forrige i denne dokumentfamilien:
kommandoen var riktig, konteksten var det ikke.

Klon-tørrkjøring av hele sekvensen ble VURDERT og forkastet: en lokal
klons `origin` peker på dette repoet, så §5 steg 10 (`git push origin
v1.0.0`) ville skapt nøyaktig den stale taggen økt 8 pre-flightet mot —
og den måtte vært stoppet ett steg for tidlig på eve-en av en enveis-dag.

Grep-passen fant fem kopier av «to kommandoer»; de to levende
instruksene er rettet til tre, de to i GJORT-blokkene er historikk og
står. Tir-11-raden sa TRE ØKTER (drift, samme klasse som økt 10 fant).

Målt: utfyllings-gaten 3 (uendret — ingen ny placeholder) · §5 ni → ti
avkryssinger · frys-blokka to → tre punkter · tabell-integritet 3
usiterte pipes per rad (ons-12s tre escapede er K1-kommandoens) ·
frys-gaten mot HEAD TOM (kjørestien urørt) · 810 passed / 4 skipped ·
ruff + format + mypy rene.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0186tGdSmqQZUfy4emjSFNy7
2026-08-11 13:50:13 +02:00
8e7fa54267 docs(P4.5): torsdagens anker var arvet, og arvet gjorde det fail-open
§6 landet i 859be2a med frys-gatens to unntak (`docs/`, `CHANGELOG.md`)
kopiert inn i tag-ankeret. Unntakene er ikke generelle: de er begrunnet i
at ONSDAGEN skriver nøyaktig dem. Torsdag skriver ingenting, så riktig
forventning er IDENTITET — og arvet dit gjorde `docs/`-unntaket gaten
blind for den ene skriveren vi vet er aktiv i repoet, den parallelle
sesjonen som eier docs/presentasjon-portfolio-optimiser.html.

Samme klasse som da frys-gaten selv ble snudd fra positiv liste til
eksklusjonsform: en gate arvet uten at begrunnelsen ble re-utledet.

Ankeret er nå `git describe --tags --exact-match HEAD` -> `v1.0.0`.
MÅLT fail-closed begge veier: `no tag exactly matches '<sha>'` (exit 128)
når HEAD ikke er tagget, `bad revision` når taggen mangler. Ingen av dem
kan forveksles med grønt.

Feiler ankeret er det en BESKJED, ikke en abort: `git diff --stat
v1.0.0..HEAD` UTEN unntak skiller kjøresti-endring (-> §3) fra ren
`docs/` (demoen upåvirket, men da vitende).

Steg 1 var også et øyeblikksbilde, ikke en regel: «kun den fremmede
HTML-fila» slutter å stemme i det den sesjonen committer eller legger
igjen en fil til, og en gate som roper på noe operatøren ikke eier lærer
ham å ignorere gaten. Nå `git status --short --untracked-files=no`
-> TOMT (målt).

Lagt til én setning om at en `Resolved`/`Audited`/`Installed`-linje fra
uv er miljø-sjekken, ikke en feil — målt at `uv run` er STILLE på varmt
miljø (stderr = de fire linjene §1 beskriver), men en første kjøring for
dagen kan si fra.

Målt: utfyllings-gaten uendret på 3 · 810 passed / 4 skipped · ruff +
format + mypy rene · kalendertabellens pipe-telling intakt.

Planens to beskrivelser av gaten rettet i samme pass (P4.5-blokka +
tor-13-raden) — de beskrev et design som ikke lenger står.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143ESVxVd5srp9PGshHCdi4
2026-08-11 13:14:03 +02:00
859be2acfc docs(P4.5): runbooken manglet sjekken som kjøres FØR demoen
Golden-transkriptet ble sjekket inn nettopp for å fange «regresjon mellom
onsdag og torsdag» (egnethetsreview-planen P4 pkt. 3) — selv-identitet
fanger ikke-determinisme, men ikke at noe flyttet seg over natta.
Mekanismen fantes altså. Men i runbooken sto kommandoen under overskriften
«Hvis du vil vise at outputen er den frosne», altså som et show-element
UNDER demoen, og kjørt der oppdager den regresjonen samtidig med publikum.

Samme defektklasse som frys-gaten (x1 -> x2) og CHANGELOG-datoen (lest på
feil HEAD): kommandoen var riktig, tidspunktet var det ikke.

§6 flytter den til før rommet fylles og legger til tag-ankeret
`git diff --stat v1.0.0..HEAD` med frys-gatens to unntak. MÅLT at ankeret
er fail-CLOSED: en manglende v1.0.0 gir `fatal: bad revision` (exit 128),
ikke tomt — en gate mot en tag som ikke finnes kunne ellers vært stille
grønn. Kommandoen står fortsatt kun ÉN gang i dokumentet (§6 peker på
§1-blokka), så det er ikke laget en andre kopi å drifte fra.

Tatt tirsdag med vilje: onsdagen skal måle og utføre, ikke avgjøre.

Målt: demo på HEAD golden-diff TOM (61 linjer, exit 0) · to kjøringer
byte-identiske · 810 passed / 4 skipped · ruff + format + mypy rene ·
utfyllings-gaten uendret på 3 · kalendertabellens pipe-telling intakt.

Én påstand ble drept av måling: pre-flighten varmer IKKE venv-en
(2,67 s vs 2,77 s), så den setningen ble ikke skrevet.

Planen lukket i samme pass (grep-passen fant tre steder): P4.5-blokka,
tor-13-raden, og tir-11-raden — «TOM — GÅ RETT PÅ ONSDAG» var sant da den
ble skrevet mandag og sluttet å være det samme uke.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143ESVxVd5srp9PGshHCdi4
2026-08-11 13:03:34 +02:00
c6d7ea7c1b docs(P4.5): §1 lovet en stderr-sti som aldri kan vises
Runbookens §1 sa `(arbeidskopi: /tmp/po-sim-…)`. Målt: `mkdtemp` følger
`TMPDIR`, som på macOS er `/var/folders/…/T/` — `tempfile.gettempdir()`
bekrefter det. Strengen `/tmp/po-sim-` kan altså aldri stå på skjermen.

Det er den dyre varianten av defekten: operatøren ser en lang
`/var/folders`-sti der runbooken lovet `/tmp`, og et sekunds tvil om
miljøet er ett sekund fra en unødvendig abortsti på scenen.

Rettet til FORMEN, ikke til denne maskinens sti — en hardkodet
`/var/folders/xc/…` ville gjenskapt defekten ett nivå ned. Fasiten gjør
allerede nøyaktig dette skillet: temp-katalogen tilhører miljøet,
`po-sim-`-prefikset tilhører programmet.

Funnet ved å måle §1s stderr-INNHOLD mot fasiten (testens egen
`normalise_stderr`) i stedet for bare å telle fire linjer — den ene §1-
påstanden økt 9s pass hadde tallfestet uten å innholds-sammenligne.

Én kopi: planen var allerede korrekt («`TMPDIR`-rota maskeres»).
Utfyllings-gaten står uendret på 3 placeholders; kjørestien er urørt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NaBAXKK1ippN8Zi62DMNoS
2026-08-11 12:50:06 +02:00
4f1c19dfb2 docs: CHANGELOG-datoen må RE-LESES etter stempel-commiten, ikke bare før
Sekvensen onsdag er X → Y (runbook) → les `%cs` → stempel → Z → tag Z.
Ved lesningen står HEAD på Y — og Y blir aldri tagget; verdien skrives inn
i Z. Det holder når Y og Z lander samme dag, men brekker ved midnatt MELLOM
dem: da bærer den taggede commiten gårsdagens stempel. Det er nøyaktig det
tilfellet setningen påberopte seg («også hvis dagen sklir til torsdag morgen»).

Retteslen er ett steg, ikke en omskriving: `git log -1 --format=%cs` én gang
til ETTER commit av Z og FØR `git tag`, med `--amend` ved avvik. §5 har nå ni
avkryssinger. Samme klasse som frys-gaten selv (amendert økt 7): kommandoen
var riktig, tidspunktet var det ikke.

Begge kilder rettet i samme pass — runbookens §5 og planens frys-blokk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LefsEziBhiJgLFbBqTZxnK
2026-08-11 06:44:29 +02:00
818b55ae09 docs: frys-gaten kjøres TO ganger, og CHANGELOG-datoen leses av commiten
Tre retteser fra advisor-review, alle propagert til BEGGE kilder (runbook +
plan + STATE) — en oppskrift som står ulikt to steder er nøyaktig drift-klassen
denne økta har lukket.

1. GATEN KJØRES TO GANGER. Sekvensen er X (prøve) -> Y (runbook) -> Z
   (CHANGELOG-stempel) -> tag. En gate kjørt kun ved X måler en tilstand som
   ikke lenger finnes når taggen settes; bare et andre kall RETT FØR git tag
   beviser at det TAGGEDE treet er det prøvde. Samme kommando, annet tidspunkt.

2. DATOEN LESES AV COMMITEN SOM TAGGES: git log -1 --format=%cs, ikke date +%F.
   Veggklokka er ikke etterprøvbar og kan avvike fra commiten på en sen
   kveldsøkt; %cs gjør CHANGELOG, tag-objektet og commiten enige også hvis
   dagen sklir til torsdag morgen. Målt: %cs på HEAD gir 2026-08-10.

3. PORTEFØLJE-SVARET SNEVRET INN. Raden lovet "ja, den kan kjøre en hel
   portefølje" med et forbehold om CLI-taket. Spørsmålet den besvarer er
   bredere enn det vi har prøvekjørt denne uka: run_portfolio er testet, men
   demoen kjører ett prosjekt og CLI-porteføljestien er ikke prøvd. Raden sier
   nå hva biblioteket har, at demoen ikke viser det, og at porteføljestien ikke
   skal tilbys som live demonstrasjon.

Verifisert: null "date +%F" igjen i noen av de tre kildene; %cs-oppskriften i
alle tre; placeholders fortsatt 3; docs/-gaten grønn (10 passed).
2026-08-10 21:24:48 +02:00
eb631d6ba9 docs(plan): P4.5 lukket i planen — den instruerte om en runbook som nå er skrevet
Samme drift-klasse som økt 4, 5 og 6 hver for seg fant, og derfor lukket i SAMME
økt som arbeidet: planen er dokumentet operatøren følger onsdag under tidspress.

Grep-passen (økt 4s mottiltak) over "runbook|P4.5" fant FEM levende steder, ikke
ett:
- P4.5-blokka: ☐ -> ✔ SKREVET, med amendementet som forklarer hvorfor gaten
  ("VED frysen ... så den matcher frosset output") dekker målingene og ikke
  forfatterskapet
- ons-12-raden: "skriv runbooken" -> "FYLL UT runbooken", med utfyllings-gaten
- Spor 2 (§0): mandat-setningen merket ✔ — den sto der som en PLASSHOLDER for en
  beslutning, ikke som en beslutning
- Spor 2-oppsummeringen linje 63: "VED frysen" -> "SKREVET man 10., FYLLES UT"
- man-10-raden: nytt punkt (7)

Ett premiss rettet i samme pass: raden sa "SEKS ØKTER" og er nå syv.

Historiske oppføringer står urørt med vilje: I5-registeret i §6 og frys-blokkas
"runbook (commit Y)" beskriver beslutninger og en sekvens som fortsatt stemmer —
onsdag committer fortsatt den utfylte runbooken som Y.

Tabell-integritet verifisert etter redigering: hver kalenderrad har nøyaktig tre
usiterte pipes; de tre escapede på ons-12-raden er K1-kommandoens og er
uendret. docs/-gaten grønn (10 passed).
2026-08-10 21:18:41 +02:00
c7a57d8c76 docs(P4.5): demo-runbooken skrevet — beslutningene mandag, målingene onsdag
Runbooken var gatet til "VED frysen onsdag". Gaten gjelder hashen X og verbatim
output-utdrag — ikke forfatter-dømmekraften. Planens egen onsdags-regel er at
dagen skal MÅLE og UTFØRE, ikke avgjøre; en runbook skrevet fra bunnen på en
enveis-dag under tidspress er nøyaktig det den regelen forbyr. Derfor to-trinns
med vilje: alt kjennbart nå, tre målte felt onsdag.

Samler de fire spredte kildene I5 navnga (demo-uke-plan §1 · innholdsgate §5
JA-varianten · P4 pkt. 4 · §0 Spor 2) og forankrer hver setning i en LINJE i det
pinnede transkriptet, så operatøren finner stedet uten å lete.

MANDAT-SETNINGEN ER SKREVET. Den sto i Spor 2 som "én muntlig setning" og fantes
ikke som tekst noe sted — en udraftet setning til en live demo. Nå formulert mot
docs/bestille-en-kjoring.md: bestillingen styrer hva som VURDERES, aldri hva som
GODKJENNES.

UTFYLLINGEN ER GJORT TIL EN SJEKKET STEG, ikke en husket. Tre placeholders med
greppbar form, og grep-en er SELV-SIKKER: monsteret '<<[A-ZÆØÅ-]*>>' matcher
ikke sin egen tekst (målt: 3 treff, ingen av dem kommandolinjene). Et uutfylt
felt er samme drift-klasse som plan-radene økt 4, 5 og 6 hver for seg fant.

VEDLEGGET FELLER TRE STATE-PREMISSER. Alle tre "scene-kosmetiske" punkter er
målt mot det pinnede transkriptet, og INGEN er synlige:
- 23700 NOK/aar: rationale er 389 tegn, beløpet står ca. tegn 370, demoen
  klipper på 300 -> linja ender "pga. overes…". grep -c "23700" -> 0.
  STATEs "printes fortsatt ordrett" var et premiss, ikke en måling.
- 0.82 hører til bygg-goldenen, ikke veglys. grep -c -> 0.
- docs/ekspert-svar.md leses ikke av demoen.
Torsdagen slipper altså tre setninger den var fortalt at den måtte bære.

CHANGELOG-DATOEN GJORT TIL EN MÅLING: sjekklista sier "les datoen på dagen"
(date +%F), ikke det forhåndsskrevne 2026-08-12 — samme premiss-klasse som
hashen planen allerede nekter å skrive ned.

Frysen er IKKE flyttet fram. Tirsdagen er tom og fristet, men onsdag er en
dato-beslutning på en enveis-handling (tag + frys), og risikoen den ville hedget
er allerede retirert: økt 6 målte samme kjøresti grønn, og d0e8bb0..HEAD er
dokumenter alene.

Målt: 810 passed / 4 skipped uendret. docs/-gaten passert via datert sti.
Kjørestien urørt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GtvZy6hn3k2iTFGjRVzLi
2026-08-10 21:16:10 +02:00
c4b0e08cc5 docs(plan): tirsdagen lukket i PLANEN — den instruerte om arbeid som var gjort
Planen er dokumentet operatøren FØLGER onsdag under tidspress, og etter
persona-pullen instruerte tir-11-raden fortsatt om en betinget subtree pull med
abortsti og 18:00-frist — arbeid som er utført og pushet. Samme drift-klasse økt
4 felte, så samme mottiltak: én grep-pass FØR redigering
(`persona|kontorbygg|tilsvarende anlegg|I4|18:00` over `docs/plan/` +
CHANGELOG), amendering med attribusjon (§6-mønsteret), aldri omskriving.

Grep-passen fant FIRE steder, ikke ett — som er hele grunnen til å kjøre den:
- tir-11-raden: betinget pull-instruks → **TOM, gå rett på onsdag**, med
  utfallet og de fire målingene som lukket den
- frys-blokkas X-note: «lander tirsdagens persona-pull, flytter X seg» →
  pullen ER landet (`d0e8bb0`); X leses fortsatt av `git rev-parse HEAD` etter
  grønn prøve, aldri skrevet ned her
- P4 pkt. 1s fersk-klon-måling: sto på `c9787cf`, altså to commits bak etter
  pullen. HOLDBARHETEN sagt eksplisitt i stedet for underforstått — delta er
  prosa i `shared/` + regenerert fasit, `pyproject.toml`/`uv.lock` MÅLT urørt,
  så målingen står; onsdagens generalprøve ×2 er bekreftelsen
- P3s I4-abortsti (i `<details>`): stemplet HISTORISK, med den ene målingen
  verdt å bære videre — den harde reset-formen blokkeres av hooken, `--keep`
  slipper igjennom

CHANGELOG: én Changed-linje for persona-formuleringen, slik at onsdagens
`[Unreleased]` → `[1.0.0]`-stempel ikke beskriver en artefakt-tekst som har
endret seg siden. Beslutningen tas her, ikke på en enveis-dag.

Tabell-integritet verifisert (pipe-telling; ons-12-radens seks er tre escaped
`\|` i grep-kommandoen, urørt). `test_doc_constant_sync_loadbearing` grønn.
Kalenderen: man 10. er nå SEKS økter.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017og6HMcP1WQcABRDogUMfx
2026-08-10 20:56:19 +02:00
d0e8bb058f test(golden): demo-transkriptet re-målt etter commons' persona-pull
Subtree-pullen (71b7b66) landet commons' domene-nøytrale formulering i
persona-artefaktets `rationale` («i kontorbygg» → «i tilsvarende anlegg»;
commons 73136eb — én fil, én linje, verifisert av OSS mot commons/main FØR
pullen). Linja printes ordrett i demoens Steg 7, så det pinnede transkriptet
sto rødt i pullens egen commit. Mellomtilstanden er uunngåelig: squash-commiten
kan ikke amendes (den bærer git-subtree-trailerne pullen leser neste gang).

Regenereringen er en RE-MÅLING, ikke en kopiering (testens egen docstring:
«whoever regenerates re-takes those measurements»). Den nye linja ble PREDIKERT
fra det innkommende artefaktet FØR pullen, og er byte-identisk med det
programmet faktisk skrev. Prediksjonen var bærende: `_clip(..., 300)` kapper på
fast bredde, og byttet er +8 tegn, så HALEN flytter seg også («overestimerte …»
→ «overes…»). Uten en nedskrevet prediksjon kan en regenerering ikke skille den
forventede forskyvningen fra drift — den ville bare vært «kopier det demoen
skriver nå».

MÅLT:
- rød-settet var NØYAKTIG én test (809 passed / 1 failed / 4 skipped) — ingen
  annen assertion matcher en delstreng av `rationale`; commons advarte om
  nøyaktig den klassen, og prediksjonen var at kun goldenen ville falle
- gammel vs ny fasit: KUN linje 32
- K1 distinkt 8 (linjer 9 — kjent, dokumentert avvik) · K2 hypotese #1 REJECTED
  2 100 000 mot P90 1 769 915 → VALIDATED 445 500, samme kandidat · K6
  selv-identitet: to kjøringer byte-identisk stdout, eneste stderr-diff er
  po-sim-suffikset · K8 bygg-energi-mikro + nav-golden-* uendret · 61/4 linjer
- stderr-goldenen URØRT · `pyproject.toml` og `uv.lock` urørt av pullen, så
  fersk-klon-målingen (P4 pkt. 1) står — delta er prosa i `shared/` + fasit
- 810 passed / 4 skipped · ruff check + ruff format + mypy rene

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017og6HMcP1WQcABRDogUMfx
2026-08-10 20:46:46 +02:00
71b7b66718 Merge commit '3ee70b01a6' 2026-08-10 20:39:06 +02:00
3ee70b01a6 Squashed 'shared/' changes from 27cdce9..73136eb
73136eb fix(persona): example-verdict begrunnet domene-nøytralt — «i tilsvarende anlegg»

git-subtree-dir: shared
git-subtree-split: 73136eb6eacd1825608d6b9c43e1e91bc230920c
2026-08-10 20:39:06 +02:00
5135f099e3 docs(plan): frys-gaten snudd til eksklusjonsform — den feilte OPEN
Første form listet kjørestien positivt (src/ tests/ shared/ pyproject.toml
uv.lock). En slik gate er blind for alt den ikke rakk å regne opp: målt på
1522e2a^..1522e2a rapporterer den to filer og slipper README.md OG CLAUDE.md
rett igjennom, mens eksklusjonsformen tar alle fire. På en enveis-dag skal en
gate feile lukket — en ny fil skal trippe den, ikke passere fordi ingen forutså
den.

Unntakene er nøyaktig det onsdagen skal skrive: docs/ (runbooken) og
CHANGELOG.md (stemples i samme trekk som taggen, så en gate som dekket den kunne
aldri blitt grønn). STATE.md er gitignorert og kan ikke dukke opp i en diff.

Begge de opprinnelige målingene re-kjørt på begge former med samme svar —
c255662..HEAD gir fire filer, a41272d..HEAD tomt. Funnet i advisor-review.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVmQfqWWEVTQnv7PkuLE9U
2026-08-10 14:59:28 +02:00
6ae3bc7c49 docs(plan): P4-hashen inn i ✔-en (planens egen regel, linje 10)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVmQfqWWEVTQnv7PkuLE9U
2026-08-10 14:53:57 +02:00
d306929c28 docs(plan): frysedagens to udefinerte steg lukket — FRYS gjort kjørbar, P4 lukket
«FRYS» hadde ingen operasjonell definisjon (40 treff i åtte plandokumenter; eneste
forsøk er demo-uke-planen linje 93, som er en regel, ikke en handling). Sekvensen er
prøve (X) → runbook (Y) → stempel+tag (Z), så taggen lander på Z mens prøven målte X.
Frysen er nå to kommandoer: noter X, og kjør frys-gaten før taggen. Gaten er målt at
den diskriminerer — c255662..HEAD gir fire filer (versjonssynken landet ETTER
generalprøve nr. 0), a41272d..HEAD gir tomt. CHANGELOG.md bevisst utenfor gaten.

P4 lukket: onsdagsraden sa «P4 re-målt» uten å si hva. Målt var det fersk-klon-
kriteriet (pkt. 1), stående på ab7f45a — elleve commits tilbake, før subtree-pullen,
P3/GO, det pinnede transkriptet, innholdsgaten (ny runtime-dep) og versjonssynken
(endret uv.lock). Re-målt på c9787cf: uv sync exit 0 med treet urørt, 810 passed /
4 skipped, ruff+mypy rene, demo-stdout byte-identisk mot goldenen, 61/4 linjer,
K1 distinkt 8.

Onsdagen har dermed fire steg, alle kjørbare. Null kodeendring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LVmQfqWWEVTQnv7PkuLE9U
2026-08-10 14:53:07 +02:00
c9787cf10c docs(plan): frysedagens instrument gjort sant — to open/-instrukser felt, P2 lukket
Planen er dokumentet operatøren følger onsdag under tidspress. Den instruerte
fortsatt om en beslutning som ble felt 08-10, og på TO steder — nøyaktig
drift-klassen der en retting i én fil etterlater den i en annen:

- §0 S1.c-raden: «tag v1.0.0 på begge remotes» → taggen går til `origin` ALENE.
  Felt med målingen som felte den (open/main = 520e741 = v0.1.0; 26 commits =
  53 filer / 6087 innsettelser; seks plandokument-beslutninger, én åpen sak +
  fire aldri vurdert). Amendert i stedet for omskrevet, per §6-mønsteret.
- P4 pkt. 1s fresh-clone-notat: «publisering dit er S1.c onsdag» → korrigert,
  flyttet til P5-vinduet.

Bokføring i samme pass (planens egen regel, linje 10):
- P2/S1.b ☐ → ✔ (2026-08-09, c255662), både overskrift og Spor 1-tabellen;
  JA-varianten i ærlighets-teksten markert som den som gjelder.
- Kalenderen: man 10. = tre økter (var: kun generalprøven) · tir 11. = P3 er
  gjort søndag, tirsdag er commons-svaret eller tom · ons 12. = frysesekvensen
  i rekkefølge, med distinkt-tellingen (8, ikke 9) og taggen sist.

«ETT trekk» på tag-dagen er MÅLT inn i dokumentet, ikke antatt: `## [Unreleased]`
er verbatim og unik (1 treff, kun to `## `-overskrifter), ingen link-refs å
følge med. Sto den to steder, ble frysedagens ene trekk improvisasjon.

Null kodeendring; ingen test rørt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QLpSfvCgBLmc3tPRMnr1JA
2026-08-10 05:15:36 +02:00
9708c15d07 docs(plan): S1.c synk + CHANGELOG lukket — taggen står igjen, frys-gatet
Forskuttert fra onsdag kveld, fordi den delen ikke er frys-gatet: kun taggen er.
Raden bærer nå de tre tingene målingen avgjorde — hvorfor overskriften står på
[Unreleased], hvorfor uv lock måtte kjøres eksplisitt og diffes før noen test, og
at fire versjonssteder ER alle fire.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ue1AnPZYsC9Tk7e5Tyv8Fv
2026-08-10 04:50:01 +02:00
a41272def5 chore(release): 1.0.0 version sync + the six undocumented feat commits, tag deliberately withheld
Version 1.0.0 across the four sites that carry it — pyproject.toml, __init__.py,
uv.lock, test_smoke.py. Measured that these are the only four: README carries no
version badge, and CHANGELOG's `## [0.1.0]` is history rather than a bump site.

The heading stays `[Unreleased]`. STATE authorises the CHANGELOG CONTENT now and
holds the TAG until after Wednesday's freeze, so stamping `## [1.0.0] - <date>`
today would be a future-dated claim about an event that has not happened — and
one to rewrite if the dress rehearsal fails or the freeze slips. `pyproject` at
1.0.0 with `[Unreleased]` populated is the release-prep state, not an
inconsistency; nothing machine-reads the CHANGELOG (measured). The global
versjonssync rule is read as CONTENT, not heading. Tag day is then one atomic
move: rename the heading, stamp the date, tag.

The re-lock was the hazard, and it was gated rather than assumed. Bumping the
version stales `uv.lock`, and the next `uv run` would have re-locked it
invisibly against a RANGE dependency (`agent-framework-core>=1.9.0,<2`) — while
the two ExperimentalWarning lines are pinned byte-for-byte in the stderr golden,
and STATE's own okf note records that a bare sync is enough for a guard to stop
guarding with no local diff. So: bump, then `uv lock` EXPLICITLY, then diff
before any test ran. The diff is the single `portfolio-optimiser` version line;
agent-framework-core, llm-ingestion-okf (v0.3.2) and llm-ingestion-guard
(v0.3.4) are untouched, and uv.lock was re-checked AFTER the suite to confirm no
silent re-lock.

CHANGELOG prose for the six feat commits `[Unreleased]` did not cover — it
carried only Step 5 and the scripted registry. Console entry points and the
golden transcript are Added; the Step-7 inbox, the anchored walkthrough, the
stderr damping and the derived provenance sentence are Changed, scoped as the
OFFLINE SIMULATION rather than framework runtime, since they change what the
walkthrough exercises and not the library's behaviour. The content gate is
Security, and carries its opt-in qualifier: `materialize` stays ungated by
design and `materialize_gated` is asked for by name — an entry claiming "ingest
now scans content before writing" without that clause would overclaim, and it
sits next to the sentence read on stage Thursday. A Notes line names the two
open boundaries (ingest stamp spec divergence, D7 mirroring) so 1.0.0 reads as a
stable surface rather than a finished programme.

Measured, not asserted: 810 passed / 4 skipped unchanged · ruff + mypy clean (31
source files) · no `0.1.0` remaining outside .venv/shared · and the demo RUN, not
just tested — stdout byte-identical to tests/golden/demo-transcript.stdout, exit
0, 61 stdout / 4 stderr lines, matching dress rehearsal nr. 0. The version string
appears nowhere in either golden (0 hits), so the bump could not move the fasit.

Two STATE premises corrected by measurement: 24 commits since v0.1.0, not 23;
and eight feat commits exist since the tag, of which six were undocumented.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ue1AnPZYsC9Tk7e5Tyv8Fv
2026-08-10 04:46:39 +02:00
887a8be677 docs(plan): generalprøve nr. 0 bestått — og kriteriets telling er foreldet, ikke demoen
Prøven kjørte mot LEVERT VEGLYS-FV-SOER, ikke den forankrede reserven planen
forutsatte: P3 falt to døgn før fristen, så prøven målte demoinnholdet selv.
Det er en strengere prøve enn planlagt — reserven validerer mekanikk, aldri
presentasjon — og reserve-stien er fortsatt målt, i suiten.

Alt grønt, null kodeendring: golden-diffen tom for begge kjøringene, K6
selv-identitet tom på stdout med kun po-sim-suffikset ulikt på stderr,
810 passed / 4 skipped, ruff og mypy rene, goldens uendret.

Ett avvik, og det ligger i kriteriets bokstav: §5 pkt. 1 teller
`grep -cE "^ *Steg [1-8]"` = 8, men P1/S1.a ga Steg 7 to merkede linjer, én
per tidsskala, så tellingen gir 9. Åtte distinkte steg står — intensjonen er
oppfylt. Kriteriet rettes ikke her: en gate justert i samme økt som den
feiler er ikke lenger en gate. Onsdagens generalprøve ×2 bruker
distinkt-tellingen, og §5 pkt. 1 rettes etter frysen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATCeqRyvdL9qmk34o6HUCa
2026-08-10 04:34:05 +02:00
c255662802 feat(ingest): P2/S1.b — innholdsgaten står, rundt materialize og ikke i den
Planens §3 sa at `ingest.materialize` er repoets ENE skrivepunkt på Door A, og
det premisset ble felt av måling FØR bygging: `materialize` er en ren delegasjon
til pinnet llm_ingestion_okf v0.3.2s `materialize_bundle`, som stager i minnet og
utfører sin egen disk-fase. Det finnes ingen callback mellom de to, så en gate
plassert der kunne bare kjørt ETTER at bytene landet — en opprydding, ikke en gate.

Sømmen ble i stedet kopier bundelen → materialiser inn i kopien → skann det som
ble generert → publiser eller forkast. Kopien er bærende, ikke bekvemmelighet:
bibliotekets §3 eierskaps-skann, kollisjonsgaten mot kuratert innhold og §6
index-merge leser alle den EKSISTERENDE bundelen. Staging i tom katalog mister
alle tre og publiserer en bundle uten kuraterte naboer — datatap forkledd som
sikkerhetsfiks.

De fire §4-beslutningene, tatt og målt: (1) ingen av guardens to preset —
Origin.EXTERNAL/AUTOMATIC, fordi trust_for utleder policy fra origin alene og
PRESET_USER_UPLOAD bærer en quarantine-semantikk Door A ikke har; (2) utfall per
BUNDLE, diagnostikk per DOKUMENT — delvis publisering ville etterlatt bundle +
index som svarer til intet manifest, men import_bundle itererer forbi første
avvisning; (3) Report til log.md, aldri konsept-frontmatter, der fire golden-suiter
pinner bytene; (4) mypy-override OG adapter, siden override alene gjør sømmen
type-blind i stedet for type-sikker.

`materialize` forblir ugatet med vilje — goldenene pinner den, og en kaller som
vil ha gaten ber om den ved navn.

Fem mutasjoner alle røde + grønn kontroll (hele suiten, ~120 s hver): detach
gaten · la den fyre ETTER publisering · Origin.INTERNAL · tom staging-katalog ·
rapporter kun første avvisning.

Målingen felte en VAKUØS test først: en hard injeksjon scorer fail_secure under
BEGGE trust-tierene, så Origin.INTERNAL-mutasjonen lot alle tre avvisningstestene
stå grønne — beslutning 1 så dekket ut uten å være testet. Båndet der tieren
faktisk avgjør er høy-entropi-innhold (quarantine_review vs warn), og testen ble
skrevet mot nøyaktig det før mutasjonen ble re-målt. Mutasjon 4 ble på sin side
felt av KUN én test; 809 andre merket ikke at bundle-kopien forsvant.

Laveste disposition er `warn`, ikke `allow` — `allow` finnes ikke i guarden. En
gate skrevet mot == allow ville avvist hvert dokument som noensinne ingestes.

Kriterium 5 står: demo-stdout er byte-identisk med tests/golden/demo-transcript.stdout,
målt både i suiten og ved eksplisitt kjøring. shared/ er urørt.

801 -> 810 passed / 4 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DDu94KoyxAmhJsG2n63X8Q
2026-08-09 22:58:00 +02:00
50232fb88d feat(simulation): P4 pkt. 3+4 — demo-transkriptet pinnet, frø-setningen avledet [skip-docs]
Kriterium 6 er selv-identitet: to kjøringer av en regredert demo er like enige som
to av en riktig. Fasiten forlater derfor prosessen. stdout pinnes ORDRETT (og er
dermed demoens abortsti); stderr normaliseres på nøyaktig to MÅLTE miljø-spann —
site-packages-prefikset og temp-katalogen — med po-sim- holdt synlig, fordi det er
en egenskap ved programmet og ikke ved miljøet. Pinnet stderr = fire linjer.
Kontrollen som forbyr at masken vokser er load-bearing: en droppende normaliserer
med fasiten regenerert under seg holder BEGGE likhets-testene grønne.

Pkt. 4: planens forhåndsskrevne frø-setning sa «én av de TO tidligere dommene».
Målt mot levert VEGLYS-bundle henter Kjøring B TRE — én fulgte med kunnskapsbasen,
to er demoens egne, én per tidsskala. Splitten avledes derfor fra kjøringen; en
håndskrevet «én av tre» ville vært den andre kopien som drifter.

Fem mutasjoner alle røde + grønn kontroll (hele suiten hver gang): ett byte i en
stdout-linje · detach dempingen · over-normaliser stderr · literal splitt · detach
frø-setningens print. Byte- og detach-mutasjonene ble fanget av KUN golden-testen;
den literale splitten av KUN skille-testen.

793 -> 801 passed / 4 skipped.
2026-08-09 22:12:25 +02:00
7aef1feaa4 docs(plan): P3 lukket — GO, felt to døgn før fristen
Abortstien fulgt i rekkefølge, kriterium 8 målt to uavhengige veier, ingen reset.
Måletallene som avgjorde: P90 = 1 769 915, overdrivelsen 2 100 000 over begge terskler,
10 %-prøven mot LEVERT baseline feller i stage 0. Fem mutasjoner røde.

Planteksten slik den sto før utførelse er beholdt i en <details>-blokk — NO-GO-grenen er
død tekst nå, men reserven er fortsatt abortstien og skal kunne leses.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUjfw4eJdwwnqHSXhfcY6i
2026-08-09 21:32:57 +02:00
02ddc6735f feat(simulation): GO — demoen kjører levert VEGLYS-bundle, forankret på deres tall [skip-docs]
P3 a-c lukket. Pullen hentet commons 002f000+27cdce9: kriterium 8 grønt (nav-goldens
byte-uendret, målt både med git diff og shasum) og suiten uendret 785 — ingen abort.

Retningen på tallene er SNUDD (P3 b): manus-registerets kostlinjer er skrevet FRA
shared/examples/veglys-fv-soer/cost-baseline.json, ikke ved siden av den, og
baseline_from_scripted_candidate brukes ikke på denne stien — main() leser levert fil.
Overdrivelsen 2100000 er valgt utenfor commons' tall-inventar: målt fraværende fra
bundelen og over målt P90 1769915 (deres anslag var ~1770000). 600000/900000 ville
klarert gaten og aldri utløst Steg 5.

Målingen felte en defekt reserven skjulte: :g slår over i eksponentform ved 7. signifikante
siffer, så levert baseline printet 4.38615e+06. Reservens 300000 har seks siffer og nådde
aldri overgangen. _num erstatter :g begge steder.

Load-bearing MÅLT mot hele suiten, fem mutasjoner alle røde + grønn kontroll:
detach main-wiringen · reverter _num til :g · drift registeret ETT siffer (4386151 —
innenfor 5 %-toleransen, fanget av ingenting i 792 tester bortsett fra den nye) ·
sett flip_key til et token som finnes i bundelen · detach forankringen på bundle-stien.

785 -> 793 passed / 4 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUjfw4eJdwwnqHSXhfcY6i
2026-08-09 21:27:43 +02:00
04ae3b1599 Squashed 'shared/' changes from ddaae5d..27cdce9
27cdce9 examples(tunnel): TUNNEL-HAUGLIA — strekkmål nummer to, på et korrigert premissgrunnlag
002f000 examples(veglys): VEGLYS-FV-SOER komplett — den forpliktede leveransen til 11.08 18:00
b3f4789 docs(plan): SS12-underlaget — konsument-måling skiller «tilføy» fra «erstatt»
838a4b1 fix(spec): §7-raden siterte framework-nøytraliteten til feil sted
aa9eaa9 docs(plan): V1-etterspill — §12 mangler rader for `by`/`at`, presedens målt begge veier
54e0ec7 spec(ingest): V1 — `generated` til O2-formen, ratifisert 2026-08-02

git-subtree-dir: shared
git-subtree-split: 27cdce9eb2bc1199120de3c8e03af9711f3cca79
2026-08-09 20:59:13 +02:00
ce892be855 Merge commit '04ae3b1599' 2026-08-09 20:59:13 +02:00
7acd331e31 docs(plan): P4 pkt. 5, 2 og 1 lukket — og pinningen i pkt. 3 har fått sin egen måling
Punkt 5 (entry points), 2 (stderr) og 1 (fresh-clone) er merket ✔ med en UTFØRT-blokk
som bærer beslutningen og belegget, ikke bare utfallet.

Punkt 2 var øktas åpne beslutning, og den ble avgjort ved måling framfor preferanse:
rund-taks-linjene dempes, ExperimentalWarning-paret gjør det ikke — de fyrer før
simulation i det hele tatt importeres, så demping ville krevd et warnings-filter inne
i bibliotekpakken.

Punkt 3 får en konsekvens fra fresh-clone-målingen: fasiten kan ikke være literal.
De to gjenstående stderr-linjene bærer en absolutt sti inn i site-packages, som er
ulik i klon og arbeidskopi — normaliser på BÅDE den og po-sim-suffikset. Pinnet
stderr blir fire linjer, ikke to.

[skip-docs]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2bxLcCRguxXzpM4priTMn
2026-08-09 15:21:20 +02:00
ab7f45aa95 feat(cli): console entry points + the demo's stderr damping (P4 pkt. 5 og 2)
Two commands are now part of the install surface a fresh clone gets from `uv sync`:
`portfolio-optimiser` (run:main) and `portfolio-optimiser-demo` (simulation:main).
Deliberately two of five main()s — costsim/hitl/preflight stay module-invoked; every
name here is a name the freeze has to carry. Pinned against the INSTALLED distribution's
metadata, not the TOML: a [project.scripts] line that has never been synced is a claim,
not a command. Measured: stdout is byte-identical across both invocation forms.

stderr (P4 pkt. 2), the session's open decision, resolved by measurement rather than by
preference. Damped: the round-cap notice only, via a filter on the emitting logger, keyed
on the message and installed by main() — never at import, so a library consumer keeps its
own logging config. NOT damped: the two ExperimentalWarnings. They fire while the package
__init__ imports run -> agent_framework, always before simulation's own imports and under
both invocation forms, so silencing them would mean filtering warnings inside the library
package on every consumer's behalf; they are pinned in pkt. 3 instead. A console-script
wrapper was rejected for a second reason: the two forms would then write different stderr,
and a byte-fasit would pin the command rather than the program. stderr 6 -> 4 lines.

A first implementation wrapped simulation's own agent_framework import in a scoped mute.
Measurement showed it can never fire — the package __init__ has already imported
agent_framework by then — so it was removed rather than left as a green-but-dead seam.

Load-bearing MEASURED against the whole suite, five mutations all red + green control:
remove [project.scripts] · typo the target · detach the main() call · make the filter drop
everything · install the filter at import time. The typo mutation also felled a test: the
resolve-assert re-checked the expected constant against itself, and now resolves what the
distribution actually installs. 775 -> 785 passed / 4 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01C2bxLcCRguxXzpM4priTMn
2026-08-09 15:13:09 +02:00
1522e2aaaa feat(simulation): the demo's gate is anchored to real cost lines (P4 pkt. 0)
The validator can reconcile a proposal against the project's actual cost lines
(S4.0 stage 0), but only when the knowledge base ships a cost-baseline.json —
and no bundle under shared/ has one. So on stage the gate reasoned only about
numbers the proposal supplied itself.

The reserve can never receive the file in shared/ (pull-only subtree, and demo
criterion 8 requires the goldens byte-unchanged). That is a placement
constraint, not an impossibility: materialize_anchored_bundle copies the bundle
and adds the file outside shared/, and the run path reads it through exactly
the seam a delivered bundle would use.

The baseline is DERIVED IN CODE from the scripted register, never typed beside
it — two sources of the same numbers drift, and drift is precisely what the
10 % probe models. On GO day the direction reverses (plan P3 b). Both scripted
replies must state the same cost lines or ValueError: were they to differ,
hypothesis #1 would be falsified by stage 0 instead of by P90 — the same
REJECTED line on screen, a different mechanism behind it.

10 % probe, measured: baseline x 1.10 -> FORKASTET at stage 0, before the
solver; corrected -> FORESLÅTT. Criterion 6 re-measured (stdout byte-identical
across two runs); stderr unchanged at 6 lines. The ONLY diff against the
un-anchored demo is the new KUNNSKAPSBASE block — everything else is
byte-identical, which is the problem: an anchoring nobody can see is one nobody
can check. Hence it is printed, and hence `provenance` is a required argument.
769 -> 775 passed.

Five mutations red + green control. The measurement failed the TEST first:
"ingen kostbaseline erklært" CONTAINS "kostbaseline erklært", and
ENERGI-TOTAL-EL already appears in the Step-2 line, so both assertions survived
the detach mutation. The two branches now share no wording.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GD6Y2Y23NZZxPYtSRoCmst
2026-08-09 14:35:07 +02:00
1e11dcb96c feat(simulation): the demo now RUNS the Step-7 file inbox it narrates (P1/S1.a)
The Step-7 trace line said "lang fil-løkke" while the verdict arrived as a
function argument (`verdict_input`) — the short, in-run capture. The long loop
was tested but never exercised by the thing on stage.

An expert now drops a real verdict FILE (`write_verdict`) into an inbox between
the runs, and Run B is given `verdict_dir=`, so `run_project` merges it into the
store before the Step-1 fold.

Not done as the plan point was worded, and the difference is load-bearing:
routing the PERSONA verdict through the inbox would have put ONE marker on two
paths — Step 7 (inbox) and Step 8 (promotion) both end in Run B's prompt, so
either could carry it alone and `test_simulation_loadbearing.py`'s promotion
assertion would have stayed green with promotion detached. A second verdict with
its own marker keeps both seams independently red-able; `simulate_learning_loop`
raises when the two markers are equal. The inbox sits beside the bundle copy,
never inside it, and the id is an explicit sentinel (a minted id would collide
with the promoted verdict's, and `VerdictStore.add` is first-write-wins).

766 -> 769 passed (773 collected). Criterion 6 re-measured: stdout byte-identical
across two runs; stderr unchanged at 6 lines. Mutations measured against the full
suite, four red + a green control: detach `verdict_dir=` · point Run B at an empty
folder while the file is still written · marker set to `realization_rate: 0.82`
(measured present in the verdict seed) · marker set to `energy performance gap`
(measured present in a navigated concept file) · benign rename of the inbox dir.

Honesty limit found while measuring: the last two mutations fell on the causality
assertion, not the Run A control — generation prompts carry the debate output, not
the bundle context. The pair holds, but each assert defends a different property.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FVYDeJ9evZicgU5r3roZVW
2026-08-09 13:13:21 +02:00
d0571ca408 docs(plan): six objections measured, all taken in — the anchoring risk moves to the weekend
I1: Funn 1 was measured one directory wide; the repo ships a working S4.0
baseline fixture and run.py:516 reads it. The anchored dry-run + the 10%%
deviation test move from Tuesday to the weekend (P4 pt 0); Tuesday becomes a
re-measurement with an explicit abort path (I4: pre-pull hash, reset rule,
18:00 NO-GO). I2: stderr damping decided YES, in the weekend BEFORE pinning —
measured today stderr is six lines, one deliberately non-deterministic. I3:
[project.scripts] moves off freeze day to before the fresh-clone measurement.
I5: a demo runbook post (P4.5) at the freeze. I6: every §4 claim re-measured
today on HEAD bb3df79; the 08-09 datings were commits from 2026-08-06.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDHSsyMuBASJcRapddciHL
2026-08-07 16:55:30 +02:00
bb3df79204 docs(plan): six objections to the week plan, as a prompt the next session must measure before acting
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M1rEDj3QLNasKSceWFyE6k
2026-08-07 16:39:42 +02:00
f49a4d263b docs(plan): work starts Friday with full quota — front-load everything that needs no new content
Operator directive: full week available, weekend included, new quota,
high priority. The calendar now starts Friday with P1, pulls the whole
P4 advance (fresh-clone criterion, golden transcript, stderr muting,
both honesty sentences) into the weekend against the micro reserve, and
makes Monday dress rehearsal #0 — the NO-GO outcome is fully verified
BEFORE Tuesday's GO gate, leaving Tuesday/Wednesday thin: pull+measure,
re-measure, freeze, release cut, tag.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019xhQpH4oQBaf8dxCkXuB8Z
2026-08-07 08:20:06 +02:00
33f0a6857d docs(plan): §0 splits the week into two tracks — complete v1 by Thursday, and the demo
Operator decision 2026-08-09. Track 1 (complete v1, incl. other repos):
S1.a = P1 step-7 inbox, S1.b = P2 content gate, S1.c = release cut
(1.0.0 synced in four places, CHANGELOG, [project.scripts] moved in from
P9, tag only AFTER a green dress rehearsal). Other-repo accounting is
measured: commons already ordered with the Tuesday deadline and a
reserve, okf/guard/po-claude need nothing — no new coord message. Each
post carries a named degradation so v1 stays honestly complete at every
level. Track 2 (convincing demo): P3 + P4 + rehearsal + one spoken
mandate sentence, optional stderr-noise muting before the freeze. The
O4-vs-tag conflict is flagged for the operator, not decided.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019xhQpH4oQBaf8dxCkXuB8Z
2026-08-06 23:30:01 +02:00
0eb0f3d72b docs(plan): the review's findings as a ranked plan the NESTE block walks, one point per session
Fable-review 2026-08-09 made durable: P1-P10 in plain language with the
commands behind every number (evidence table §4). Pre-demo: step-7 inbox
wired into the walkthrough (P1), Spor B sharpening (P2), the stage-0
first-contact check on Tuesday's GO (P3), fresh-clone/stderr/golden
criteria plus two honesty sentences on Wednesday (P4). Post-demo: CLI
portfolio cap (P6), one consolidated commons amendment (P7), method
skill [Voyage] (P8), and an explicit NULL for orchestration swaps (P10).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019xhQpH4oQBaf8dxCkXuB8Z
2026-08-06 23:13:23 +02:00
c96ef9032d docs(plan): the Fable prompt, with the feature set as its main track and quota as its output
A prompt that lives only in a conversation dies at /clear, so it goes in the repo.

Three tracks, in the order the operator weighted them: the MAF feature set, the demo, and -- as
the actual deliverable rather than an appendix -- a ranked list of what the week's quota should
buy. Each item carries a mechanism, a hard [FØR TORSDAG]/[ETTER DEMOEN] tag, a cost in SESSIONS
rather than hours, and what would go red if the item were done. An item nothing can falsify is an
opinion, not a finding.

The measured starting points are embedded so the session does not re-derive them wrongly: two
debate agents rather than three, one orchestration in use out of the installed surface, a
hand-rolled portfolio fan-out, and a capability map organised by NEED that therefore never
compares TOPOLOGIES. The map is not stale on version -- 1.9.0/1.0.0 is what is installed -- which
matters, because "the map is old" would be the easy wrong conclusion.

The prompt carries its own discipline because Fable runs without an advisor: every figure must be
produced by a command shown beside it, and premises in STATE and in plan documents are named as
premises. This repo has measured at least three of them wrong, most recently today.

It is also forbidden from smuggling feature work in front of the demo. The demo is a hard date;
the feature set is not. Arguing otherwise is allowed -- but only out loud, with the consequence
spelled out.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 20:01:53 +02:00
295e9665fe docs(plan): the content gate and the honesty sentence, on a track that does not touch the freeze
The demo shows "download and run". Implying you can point this at your own sources and build a
knowledge base claims three things the code does not carry -- and A5 (the code may not claim more
than it does) binds the presenter too, not just the source.

Measured first, and one measurement changed the plan: the guard is NOT v0.2 alpha. That figure came
from our own 2026-07-16 inclusion plan, which is a premise rather than a fact. It is v0.3.4, seven
published tags, `dependencies = []` -- stdlib only. Our okf pin (v0.3.2) declares no dependencies
either, so the guard is not coupled to it, and the 0.3.5-vs-0.4.0 release argument concerns the
release AFTER v0.3.4. Adoption moved from risky to tractable on that one reading.

The three claims, made precise: the demo bundle was hand-curated (honesty), the ingest path writes
unscanned (buildable), and the generic bundle factory does not exist (deferred at O1, not buildable
in four days). Two close with code, one with a sentence.

The two tracks are separated on a measured fact: `simulation.py` does not import `ingest`, so Door A
work cannot disturb what Wednesday freezes. Criterion 5 is the one that proves it -- the walkthrough
must stay byte-identical.

Four decisions are named as decisions rather than settled silently: which policy preset, fail-closed
versus flag-and-write, where the guard's report lands in provenance, and keeping `--strict`
meaningful across a seam that ships no py.typed. The honesty paragraph is written in BOTH variants
up front, so Wednesday is an observation and not a judgement call on stage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 19:49:13 +02:00
688ee24973 feat(sim): the demo script is keyed on the project the prompt names, so a new project is data
The scripted proposer answered one hard-coded pair of proposals. A second project meant a second
hand-written selector, written under demo-week time pressure -- the risk the week plan names
explicitly (§4, risk 2). It is now a registry: `ScriptedCandidate` entries selected by
`scripted_proposer`, plus `project_id` as an argument to `simulate_learning_loop`.

The open decision was WHAT identifies the candidate in the prompt blob; the plan flagged it as
unverified, so it was measured. Two prompt shapes reach the selector: the debate prompt carries the
whole bundle context, the generation prompt carries `Project: {id} - {name}` plus -- as its context
-- the debate output, which is the selector's own earlier reply. So the cost code and the measure
name are present in the generation prompt only because the script put them there; keying on them
would key the script on its own output. The project id is the one identifier both shapes carry and
the framework stamps.

Validation, never repair: no match, or more than one, raises `ScriptedCandidateError`. A default
reply would answer an unregistered project with another project's numbers, which on screen is
indistinguishable from a correct run; an ambiguous blob is a data problem that must surface at the
rehearsal rather than be decided by registry order.

Load-bearing MEASURED against the whole suite, five mutations all red plus a green control: detach
the project keying - one global flip key - fall back on an unknown project - first-match on an
ambiguous prompt - detach the `project_id` argument. The flip-key test was rewritten mid-measurement
because its first form asserted on the FIRST registry entry, where "the matched candidate's key" and
"candidates[0]'s key" coincide -- it could not separate the two implementations, and proved nothing.

766 passed / 4 skipped. Simulation still exits 0, still prints eight labelled steps, still
byte-identical across two runs.

[skip-docs] README is deliberately untouched: O4 defers the README rewrite to 14-15 August, after
the demo has produced the evidence for the level-2 claim. CLAUDE.md carries the invariant.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 16:43:29 +02:00
e93e921b1f docs(sim): the console trace walks all eight steps, one labelled line each
The simulation proved the loop but printed only four of its eight steps, so a
listener could not follow what they were looking at without narration. This is
presentation only: every value printed is read off the RunResult the run already
returned -- nothing is recomputed against the bundle, nothing is inferred, and
the run path is untouched. The week plan's assumption ("seven of eight steps are
pure presentation") therefore held; no new logic was needed.

Run A walks steps 1-7, the promotion between the runs IS step 8, and Run B is
not re-numbered -- it shows only what changed, which is the marker reaching the
hypothesis prompt. Two honesty limits are visible in what is printed rather than
papered over: `retrieved` is the post-hoc proposal-keyed retrieval, not the
Step-1 fold (the marker line is what evidences the fold reaching the prompt),
and the run carries the checker's DECISION, not its prose -- the decision is
what gates, so it is what is shown.

The working-copy path moves to stderr: mkdtemp is the one non-deterministic
value in the output, and stdout must be byte-identical across runs for the dress
rehearsal's diff check. Status tokens stay VALIDATED/REJECTED in English on
purpose -- the same vocabulary as provenance.validator_decision, which the
Step-6 line prints verbatim.

Verified: `... | grep -cE "^ *Steg [1-8]"` -> 8; two runs byte-identical on
stdout; both a REJECTED and a VALIDATED line for the same candidate; suite
759 passed / 4 skipped; ruff + mypy clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 16:08:28 +02:00
d6f3359fae feat(step5): the falsification that informed the next hypothesis now leaves the loop
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
2026-08-06 15:12:06 +02:00
cd011c4ac7 docs(plan): demo week, with the one real build separated from the presentation
Seven of the eight steps already have their data in RunResult and need a print;
one does not exist at all. Putting that distinction in a table is the point of
this plan -- it turns "show all eight steps" from an unbounded week into one
build on Friday and presentation work over the weekend.

The go/no-go on Tuesday is deliberate. The content is being built in another
repo on a deadline nobody here controls, so the week is designed to survive it
not arriving rather than to hope it does. The content-keyed reply selector
lands Monday, before the content, for the same reason: a new project should
then be a data entry rather than a hand-written script under time pressure.

Honesty framing is section 1 rather than a footnote, because the demo's own
subject is a system that refuses to claim more than it proves.
2026-08-06 13:23:19 +02:00
3313e9dcaa docs(qa): the four decisions the QA surfaced, with what constrains them
The 20 claims went un-corrected, so they stand as confirmed. What the operator
actually decided were the four choices the QA exposed: hand-built example with
the factory path explicitly deferred, step 5 built and shown live, commons
ordered with a fallback, README after the demo rather than before.

Two measurements are recorded because they bound the order, not because they
are interesting: bundle_context renders every navigated file's full body, and
summary-first reading is not built -- so the full 15-30 measure library would
put 40-90k characters into every hypothesis prompt. The order is size-capped
for that reason and says so.

Also recorded: simulate_learning_loop already takes the bundle directory as a
parameter, so new content plugs into an existing seam. The cost is the scripted
replies, which are written against the LED case.
2026-08-06 13:20:52 +02:00