The report's strongest evidence is that the debate's three context copies are byte-identical before and after. It was established by comparing the per-prompt proposer/checker token lists, NOT by the probe's carries flag -- which after the change correctly reports no, because the listing's text is not in the debate's prompts. A flag that flips for the right reason is not a proof of sameness; the token counts are. Said once, where the claim is made. And bygg's copy count was carried over from the middle-slice probe that the section immediately below declares broken. All three bases are now re-measured with the corrected ASCII probe; bygg confirms five copies and the same exploration total. A cell sourced from an instrument you yourself retired is what that paragraph exists to refuse.
158 lines
11 KiB
Markdown
158 lines
11 KiB
Markdown
# S2c / MAJOR-3 — `read_bundle`s kontekstkostnad: målingen
|
||
|
||
**Ordre:** `20260902T151931Z-250257273-from-.claude`. Bindende ordretekst: ordreutkast M3 i
|
||
[`docs/2026-09-02-misjonsreview-v2.md`](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 `tiktoken`s `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.json`s `tool_calls`), ikke antatt.
|
||
|
||
**Ærlighetsgrense, uttalt:** kopi-telleren er en 160-tegns skive fra MIDTEN av `read_bundle`s
|
||
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.py`s `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.json`s `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». **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_bundle`s 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å 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. **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_bundle`s EGET bidrag faller fra
|
||
5 × 12 595 til 5 × 259 tokens på tunnelbasen. 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 |
|