portfolio-optimiser/docs/2026-09-02-read-bundle-kontekstkostnad.md
Kjell Tore Guttormsen 37547fe292
refactor(examples): replace sector-specific example material with generic, fictitious examples
The context sets, the packaged knowledge bases and the example bundles are
replaced by one fictitious example set about IT operations in an invented
organisation: three context sets (serverrom-2027, driftsavtale-2027 and the
two-base drift-og-avtale-2027), two synthetic knowledge bases under
src/portfolio_optimiser/data/kunnskapsbaser and two example bundles under
src/portfolio_optimiser/data/bundles. Numbers, codes and structural values in
tests and fixtures are kept; names, ids and wording change. Dated measurement
documents that only recorded runs on the replaced material are deleted.

Gate figures measured on the new set are not comparable with earlier ones.
The exclusion gate from the previous commit is green: 0 tracked files hit
outside the shared/ subtree.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 15:04:21 +02:00

11 KiB
Raw Blame History

S2c / MAJOR-3 — read_bundles kontekstkostnad: målingen

Ordre: 20260902T151931Z-250257273-from-.claude. Bindende ordretekst: ordreutkast M3 i docs/2026-09-02-misjonsreview-v2.md § 7. Regelen ordren gir: MÅL FØRST, så ÉN søm. Denne fila er tallene med nevner — skrevet og committet FØR noe ble endret, og utvidet med ETTER-tabellen i sømmens egen commit.

0. Instrumentet, og hvorfor det er troverdig

Efemert, i /tmp/claude-s2c/ — utenfor repoet, som forrige gang (misjonsreview-v2 § 8): et måleinstrument i tests/ ville vært en beslutning om å beholde det, og ordren ba om en måling, ikke en ny produksjonsflate. Tokens telles med tiktokens o200k_base, kjørt med uv run --with tiktoken (tiktoken er fortsatt IKKE en prosjekt-avhengighet).

Kjent-positiv kontroll FØR noe ble målt (Verifiseringsloven ansikt 4 — en spørring skal bevises å KUNNE finne): instrumentet ble kjørt mot de tre eksempelbundlene som den gang lå i commons (bygg-energi-mikro og to energi-eksempler, her energi-a og energi-b; de to siste er i dag erstattet av de fiktive klientpark-energi og driftssenter-kjoling, og tallene her er målt på de gamle) og reproduserte commons' egne publiserte fasittall for okf.bundle_context eksakt — 3 861 / 10 406 / 12 595. Et instrument som ikke treffer en kjent fasit måler seg selv.

Prompten måles som tekst + function_call + function_result, ALDRI .text alene. Den skriptede klientens egen sink samler kun .text, og en prompt hvis hele nyttelast er et verktøyresultat måles da til noen få tegn. Den fella er dokumentert i misjonsreview-v2 vedlegg A og er unngått her ved en egen wrapper på ScriptedChatClient._inner_get_response.

Kjøringen er ekte, ikke rekonstruert: hver rad er én run.main([... --explore ...]) gjennom CLI-døra, med navigatøren skriptet som list_bundles → read_bundle → tekst (trinn-manuset fra økt 67, MAJOR-1 b). At navigatøren faktisk ÅPNET basen er lest av kjøringens eget artefakt ({run_id}-exploration.jsons tool_calls), ikke antatt.

Ærlighetsgrense, uttalt: kopi-telleren er en 160-tegns skive fra MIDTEN av read_bundles nyttelast (samme sonde som misjonsreview-v2 § 4). Skiva finnes i dag i BEGGE de to strengene kjøringen sender — utforskningens function_result OG debattens okf.bundle_context — fordi de er den samme strengen. Kolonnene under skiller dem derfor på ROLLE, som er det eneste som skiller dem: manager/navigator/hypothesiser er utforskningen (sømmen denne ordren rører), proposer/checker er debatten (som ordren forbyr å røre).

1. FØR — hva read_bundle koster, og hvor mange prompts det rir med i

Per base, én CLI-kjøring med --explore:

Base read_bundle-nyttelast Prompts totalt Prompt-tokens totalt Utforsknings-kopier Tokens i dem Debatt-kopier Tokens i dem
bygg-energi-mikro 12 005 tegn / 3 861 tok 15 35 773 5 22 013 3 11 738
energi-a 32 201 tegn / 10 406 tok 19 88 881 5 54 623 3 31 376
energi-b 39 583 tegn / 12 595 tok 19 106 519 5 65 698 3 37 943

De fem utforsknings-kopiene, navngitt (energi-b-tall): navigatørens egen prompt etter kallet (12 770) · managerens tre progress-ledger-/final-prompts (13 527 / 13 549 / 13 075) · hypotesiserens ene tur (12 777). Ett read_bundle-kall gjør hele basen til et function_result, og det resultatet rir med i hver senere prompt i samme samtale — deltakerne deler samtalehistorikk, så ingen av dem betaler for å be om det.

Selve nyttelasten, som andel av alt: 5 kopier × nyttelast = 19 305 / 52 030 / 62 975 tokens, altså 54 % / 59 % / 59 % av ALLE prompt-tokens i kjøringen. Debattens tre kopier (11 738 / 31 376 / 37 943 = 33 % / 35 % / 36 %) kommer fra run.pys okf.bundle_context og er en EGEN beslutning (PM) — de er med i tabellen som nevner og som ETTER-kontroll, ikke som mål.

Nevneren for «hvor mange prompts»: 15 / 19 / 19 prompts i alt, hvorav 8 bærer konteksten. Tallet 5 gjelder DETTE manuset (én navigatør-tur, én hypotesiser-tur, tre manager-prompts). misjonsreview-v2 § 4 målte 7× på bibliotek-armen med et annet manus (to hypotesiser-turer, fire navigatør-prompts); begge er sanne om sitt eget manus, og ingen av dem er en påstand om hva en LEVENDE manager gjør. Multiplikatoren er en egenskap ved samtalehistorikken, ikke ved manuset: den er antall prompts etter kallet, og den er ≥ 1 uansett.

2. Hva basene faktisk inneholder — premisset for formen

Base Filer navigert Konseptfiler type: verdict Rot-index.md (body)
bygg-energi-mikro 6 4 1 1 884 tegn
energi-a 7 5 1 3 646 tegn
energi-b 7 5 1 4 763 tegn

Ett premiss felt før noe ble bygget på det: «basens indeks er selve navigasjonsprosaen, så den hører hjemme i read_bundle». Energi-b-basens rot-indeks er alene 4 763 tegn ≈ 1 400 o200k-tokens — altså nesten hele ordrens tak på 1 500 for HELE kallet. Å legge den inn ville brukt opp budsjettet på et felt katalogen alt gir et bundet utdrag av (_CATALOGUE_EXCERPT_CHARS), og som fortsatt er nøyaktig ett read_file(id, "index.md") unna. read_bundle bærer derfor konseptlista og ikke indeksbodyen.

3. Hva prefiks-caching ville kjøpt — notert, IKKE bygget

Ordren ber om notatet, ikke mekanismen. Regnet av prompt-prefiksene i misjonsreview-v2 § 4 (ikke av en fakturering — leverandørens faktiske cache-treff er UMÅLT): ≈ 60 % av debattens og ≈ 40 % av utforskningens prompt-tokens er prefiks-cachebart som koden står i dag, uten én kodeendring, fordi prefiksene allerede er byte-stabile. Caching virker på KOPIENE; et kontekstbudsjett virker på GRUNNTALLET de multipliserer. De to utelukker ikke hverandre, og denne ordren gjør bare det siste.

4. Verifiseringslogg (FØR-halvdelen)

# Påstand Kommando → resultat
1 Instrumentet treffer en kjent fasit uv run --with tiktoken python /tmp/claude-s2c/measure.py <repo> → 3 861 / 10 406 / 12 595 = commons' publiserte tall
2 Kjøringen ÅPNET basen (ikke bare listet den) measure-exploration.jsons tool_calls → list_bundles, read_bundle(<base>)
3 Prompt-størrelse inkluderer verktøyresultatet wrapper på _inner_get_response serialiserer contents (function_call/function_result), ikke .text
4 Nevner 15 / 19 / 19 prompts per kjøring; 8 bærer konteksten i alle tre
5 Indeksbodyen alene sprenger nesten hele taket len(navigate_bundle(energi_b).index_summary) → 4 763 tegn ≈ 1 400 tok

5. ETTER — samme instrument, samme kommandoer, samme baser

read_bundle returnerer nå katalogformen: én oppføring per konseptdokument (name, type, title, chars), med read_file som neste trinn.

Base Nyttelast før → etter Kopier i utforsknings-prompts Nyttelast × kopier Utforsknings-prompts totalt Hele kjøringen
bygg-energi-mikro 3 861 → 163 tok 5 → 5 19 305 → 815 23 726 → 5 434 (−77 %) 35 773 → 17 481 (−51 %)
energi-a 10 406 → 237 tok 5 → 5 52 030 → 1 185 56 314 → 5 742 (−90 %) 88 881 → 38 309 (−57 %)
energi-b 12 595 → 259 tok 5 → 5 62 975 → 1 295 67 415 → 5 973 (−91 %) 106 519 → 45 077 (−58 %)

Ordrens eget kriterium, verifisert direkte: read_bundle over energi-b-basen er 748 tegn / 259 o200k-tokens — under taket på 1 500. Målt forhold 2,89 tegn/token for denne norske markdownen; det er dét som lar gaten bounde TEGN uten å gjette (se testens docstring, som uttaler avviket).

«Ikke utløs»-beviset er en MÅLING, ikke en forsikring. Ordren forbyr å røre okf.bundle_context, nav-goldenene og run.py. Debattens tre kontekstkopier kommer fra nettopp den sømmen, og de er byte-identiske før og etter i alle tre baser — 12 047 / 32 567 / 39 104 prompt-tokens, hver enkelt prompt uendret. Det er et sterkere utsagn enn «jeg rørte den ikke». Mekanismen, sagt én gang: identiteten er fastslått ved å sammenligne de per-prompt proposer/checker-tokentallene FØR og ETTER, ikke ved sondens carries-flagg — flagget svarer på «bærer denne prompten read_bundles nyttelast», og etter endringen er svaret naturlig nei for debatten, siden lista ikke finnes i debattens prompts. Et flagg som skifter av riktig grunn er ikke et bevis på uendrethet; tokentallene er. I tillegg: hele suiten grønn (1 195 passed / 5 skipped, mot 1 189/5 før — supersett, 0 fjernet), tre byte-fasiter OK, og golden demo-transcript.stdout UENDRET (ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

Et fravær som var et instrumentfeil, ikke et faktum (Verifiseringsloven ansikt 4). Den første ETTER-kjøringen rapporterte 0 kopier på energi-a og energi-b. Det var ikke sant: sonden var en 160-tegns skive fra MIDTEN av nyttelasten, og den nye nyttelasten er kort nok til at midten treffer norske tegn, som prompten serialiserer escaped (å) mens sonden holdt dem rå. Sonden ble byttet til et konseptfilnavn (ASCII, ordrett i begge), og svaret ble 5 — samme tall som før endringen. Et negativt resultat fra en ødelagt spørring er ikke en måling. Alle tre basene er re-målt med den rettede sonden (ikke bare de to som viste feilen): en tabellcelle som stammet fra et instrument man selv har erklært ødelagt, er nøyaktig dét dette avsnittet advarer mot.

6. Ærlighetsgrenser, uttalt

  1. Dette er ikke «−59 % kostnad». Det målte utsagnet er at read_bundles EGET bidrag faller fra 5 × 12 595 til 5 × 259 tokens på energi-b-basen. En navigatør som deretter åpner k dokumenter betaler k read_file-resultater, og en som åpner ALT betaler omtrent de samme bytene — bare per kall. Gevinsten er at den betaler for det den valgte, og at hvert resultat rir fra SITT eget kall og framover i stedet for at alt rir fra det første.
  2. At en LEVENDE modell velger BEDRE med en liste enn med hele konteksten er IKKE bevist. Samme klasse som structured-output-grensen: det som er bevist er formen og prisen, ikke dømmekraften.
  3. Multiplikatoren 5 gjelder dette manuset. Se § 1.
  4. Debattens 3× står urørt og er PM-ens beslutning, ikke denne ordrens.
  5. Prefiks-caching er notert (§ 3), ikke bygget — ordren ba om notatet.

7. Verifiseringslogg (ETTER-halvdelen)

# Påstand Kommando → resultat
6 Gaten er rød uten sømmen 7 mutasjoner mot HELE suiten, alle røde: se CLAUDE.md-raden
7 Grønn kontroll uv run pytest -q → 1 195 passed / 5 skipped (før: 1 189/5)
8 Golden uendret PYTHONIOENCODING=utf-8 uv run python -m portfolio_optimiser.simulation | shasum → ea8c5347…
9 Debatten urørt ETTER-kjøringens proposer/checker-prompts identiske med FØR-kjøringens, per prompt
10 Lint + typer uv run ruff check . → All checks passed; uv run mypy src → no issues, 35 files