[skip-docs]
S2c / MAJOR-3, order 20260902T151931Z-250257273. The measurement landed first
in ce7f687; this commit is the one seam it authorised, plus the after-table.
read_bundle returned okf.bundle_context -- the WHOLE navigated base. Because
the exploration's participants share one conversation history, that single
function_result rode in FIVE later prompts at full price without anyone asking
for it again: 54-59 percent of every prompt-token in a CLI --explore run.
It now returns the catalogue form one rung down the ladder -- one entry per
concept document (name, type, title, chars) -- with read_file as the next rung.
Tunnel base: 12 595 -> 259 o200k tokens, exploration prompt-tokens -91 percent.
The listing is built from Bundle.context_files and never from files: that is
the property which drops the type: verdict layer at every level, and a listing
built from files would route prior verdicts in front of the navigator around
the gated ExpeL fold while every cost arm stayed green.
A premise was felled before anything was built on it: the tunnel base's root
index body is 4 763 chars alone, nearly the whole ceiling, for a field the
catalogue already excerpts and read_file still returns whole. So read_bundle
carries the listing and not the index.
The tool description and the navigator's instruction both claimed "read its
navigated context" and were updated in the same move -- a description that lies
about the body IS the model's instruction. Two pre-existing asserts would have
gone vacuously true against a list and were strengthened rather than left.
Ceiling lives in the test, not in explore.py. Deviation stated there and in the
docs: it bounds CHARACTERS, not tokens, because tiktoken is not a project
dependency and a gate that skips when an optional package is missing is a gate
that can be silently absent; the conversion was measured (2.89 chars/token) and
the order's own token criterion verified once by the instrument.
Load-bearing measured: seven mutations, all red against the WHOLE suite; green
control 1195 passed / 5 skipped (from 1189/5, strict superset); golden
demo-transcript.stdout byte-unchanged; and the debate's three bundle_context
copies are byte-identical before and after, which proves run.py and the
nav-goldens were not touched rather than asserting it.
10 KiB
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 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 |
veglys-fv-soer |
32 201 tegn / 10 406 tok | 19 | 88 881 | 5 | 54 623 | 3 | 31 376 |
tunnel-hauglia |
39 583 tegn / 12 595 tok | 19 | 106 519 | 5 | 65 698 | 3 | 37 943 |
De fem utforsknings-kopiene, navngitt (tunnel-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 |
veglys-fv-soer |
7 | 5 | 1 | 3 646 tegn |
tunnel-hauglia |
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». Tunnelbasens 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(tunnel).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 %) |
veglys-fv-soer |
10 406 → 237 tok | 5 → 5 | 52 030 → 1 185 | 56 314 → 5 742 (−90 %) | 88 881 → 38 309 (−57 %) |
tunnel-hauglia |
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 tunnelbasen 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». 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å veglys og tunnel. 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.
6. Ærlighetsgrenser, uttalt
- 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å tunnelbasen. En navigatør som deretter åpner k dokumenter betaler kread_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. - 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.
- Multiplikatoren 5 gjelder dette manuset. Se § 1.
- Debattens 3× står urørt og er PM-ens beslutning, ikke denne ordrens.
- 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 |