feat(explore): katalogkallet koster O(baser), ikke O(korpus) (ORDRE 20260825T213645Z)

list_bundles returnerte hele rot-indeksens body for HVER konfigurert base samtidig,
pluss ett JSON-objekt per ufulgt kryss-lenke. Begge vokser med korpuset, saa prisen
paa aa finne ut HVILKE baser som finnes ble satt av hvor mye de INNEHOLDER - progressiv
disclosure snudd paa hodet.

Maalt med o200k_base, instrumentet foerst validert mot commons' egne fasittall:
  tre flate Vegnormal-baser   112 116 -> 362 tokens   (-99,7 %)
  171 grenbaser               124 942 -> 21 448       (-82,8 %)
Grenformen (vegnormal-okf 8145c23) lukket bundle-siden og gjorde katalogsiden verre,
noeyaktig som det repoet forutsa.

Et premiss ble felt FOER noe ble bygget paa det: "indeksbodyen forteller hva basen
handler om" er usant for maskin-importerte baser - grenbasenes index.md er en ren
lenkeliste uten frontmatter og prosa, saa feltet var dyrt OG innholdsloest der.

Fast vindu (200 tegn), aldri en andel av basen. Avkorting annonseres som FELT
(index_truncated), og en base som passer blir ikke merket avkortet. En ufulgt lenke
overlever som ANTALL; per-lenke-detaljen blir liggende der den er handlingsbar.
Hele indeksen er fortsatt ett read_file(id, "index.md") unna.

Taket (500 tegn/base) bor i TESTEN, ikke i explore.py.

Load-bearing MAALT: tests/test_catalogue_cost_loadbearing.py, 7 armer, ni mutasjoner
alle roede mot HELE suiten + groenn kontroll 1066/5 og golden demo-transcript.stdout
byte-uendret (ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

Ogsaa: MINOR-1 i syretest-rapporten rettet - flatheten er Doer C sin
(llm-ingestion-okf importer.py, §6-index-blokka), ikke vegnormals emitterform.
Verifisert mot kilden, ikke mot meldingen.

Maaling: docs/2026-08-26-katalogkostnaden.md
This commit is contained in:
Kjell Tore Guttormsen 2026-08-26 14:45:16 +02:00
commit a1f8522bdf
6 changed files with 421 additions and 11 deletions

View file

@ -84,6 +84,13 @@ enkelt katalogkall bruker mer enn et normalt tak. En 128k-modell kan ikke ta N20
er den harde grensen for vei A/B live, og den var ikke målt før i dag.
**Fil:linje:** `src/portfolio_optimiser/explore.py:419-438` (`list_bundles`), `:444-445` (`read_bundle`).
> **Oppdatert 2026-08-26 (økt 65, ordre `20260825T213645Z-9019120455`):** katalog-halvdelen er
> **lukket**. `list_bundles()` over de samme tre basene koster nå **362 tokens** (fra 112 116), og
> over alle 171 grenbaser **21 448** (fra 124 942). `read_bundle`-halvdelen ble lukket på korpussiden
> av `vegnormal-okf` `8145c23` (grener som egne baser). Måling og gate:
> [docs/2026-08-26-katalogkostnaden.md](2026-08-26-katalogkostnaden.md). Setningen over står som
> den ble målt 25.08 — den er historikk, ikke en gjeldende tilstand.
### MAJOR-1 — gjentatt `--bundle-dir` forkastes STILLE; kjøringen ser ut som multi-base og er det ikke
Ordrens pkt. 3 forutsatte at CLI-en tar tre baser. Målt:
@ -172,9 +179,21 @@ som kontekst») er en **annen form**, og den finnes allerede — bare ikke i dis
### MINOR-1 — importformen legger alt på ett nivå, så progressiv disclosure gir null lettelse
0 underkataloger, 0 nestede `index.md`, 1733 av 1733 konsepter lenket direkte fra rot. Navigasjonen
har ingenting å utsette; hele korpuset er ett flatt nivå. Dette er en egenskap ved **kilden**
(vegnormal-okf sin importform), ikke ved `okf.py`. Det er også hele grunnen til BLOCKER-1: med
nestede indekser kunne manageren åpnet én gren om gangen.
har ingenting å utsette; hele korpuset er ett flatt nivå. Dette er en egenskap ved **kilden**, ikke
ved `okf.py`.
> **Rettet 2026-08-26 (økt 65): tilskrivelsen var feil, og `vegnormal-okf` har rett.** Flatheten er
> **Dør C** sin, ikke vegnormals emitterform. Verifisert mot kilden, ikke mot deres melding:
> `llm-ingestion-okf` `src/llm_ingestion_okf/importer.py` (§6-index-blokka) kaller
> `link_in_index(bundle, entry.path.name, _index_label(entry.concept_path))` per merget oppføring —
> altså én flat lenke i rot-`index.md` for hvert konsept, uansett hvor nestet konseptstien er.
> Vegnormals emitter skriver allerede et tonivåtre. Setningen over sto uendret som «vegnormal-okf
> sin importform» til dette punktet.
Dette var også hele grunnen til BLOCKER-1: med nestede indekser kunne manageren åpnet én gren om
gangen. Løsningen ble en annen — grener som **egne baser** (`vegnormal-okf` `8145c23`), med den
målte begrunnelsen at basegrensen er der OKF-navigasjonen stopper, så ingen indeksstruktur INNE i en
base senker prisen på å åpne den.
### NICE-1 — `read_bundle` nekter ukjent base ved navn, som lovet

View file

@ -0,0 +1,120 @@
# Katalogkallet — `list_bundles()` fra 112 116 til 362 tokens
**Ordre:** `20260825T213645Z-9019120455-from-.claude`. **Dato:** 2026-08-26 (økt 65).
**Kode:** `src/portfolio_optimiser/explore.py` (`_index_excerpt`, `navigator_tools`).
**Gate:** `tests/test_catalogue_cost_loadbearing.py` (7 tester). **Suite:** 1066 passed / 5 skipped.
**Golden `demo-transcript.stdout` byte-uendret** (`ea8c534773acdbe41ae68f2c55724d69aaf8be4f`).
**Eksponerings-grense (arvet fra syretesten, holdt):** dette repoet pusher til `open/`. Rapporten
bærer kun tall, stier, kommandoer og egne observasjoner. Ingen bundle-fil er kopiert, og ingen
kravtekst er gjengitt — alle konsept-tall er lengdemålinger, ikke innhold.
---
## 1. Instrumentet, validert før noe tall ble trodd
`tiktoken.get_encoding("o200k_base")` over `json.dumps(list_bundles(), ensure_ascii=False)`, kjørt
med `uv run --with tiktoken` (`tiktoken` er fortsatt **ikke** en prosjekt-avhengighet). Samme
instrument som syretesten 25.08.
**Kjent-positiv kontroll (Verifiseringsloven ansikt 4):** de tre flate Vegnormal-basene målte
**201 196 tegn / 112 116 tokens** før endringen — tallet syretesten publiserte, reprodusert eksakt.
Uten den kontrollen ville «etter»-tallet vært en måling ingen visste kunne treffe.
## 2. Før og etter, med nevner
| Katalog | Baser (nevner) | Tegn før | **Tokens før** | Tegn etter | **Tokens etter** | Endring |
|---|---:|---:|---:|---:|---:|---:|
| Tre flate baser (syretestens sett) | 3 | 201 196 | **112 116** | 877 | **362** | **99,7 %** |
| Grener, N100:2023 | 40 | 63 375 | **33 889** | 11 679 | **5 017** | 85,2 % |
| Grener, N200:2024 | 99 | 134 667 | **71 726** | 28 894 | **12 396** | 82,7 % |
| Grener, N500:2024 | 32 | 36 569 | **19 329** | 9 408 | **4 037** | 79,1 % |
| **Alle grener samlet** | **171** | 234 611 | **124 942** | 49 981 | **21 448** | **82,8 %** |
| *kontroll:* commons' tre eksempelbaser | 3 | 11 050 | 3 472 | 989 | 321 | 90,8 % |
Per base: **731 → 125 tokens** i grenformen, **37 372 → 121** i den flate.
**Nevner-avvik mot ordren, uttalt:** ordren oppgir 34 grener for N100:2023. Målt på disk
(`ls ~/repos/vegnormal-okf/build | grep -c '^B-n100-2023-gren-.*-importert$'`) er tallet **40**.
N200:2024 = 99 og N500:2024 = 32 stemmer. Tallene over bruker den målte nevneren, ikke ordrens.
**Ordrens hypotese bekreftet:** grenformen lukket bundle-siden og gjorde katalogsiden **verre**
124 942 tokens over 171 grener mot 112 116 over tre flate baser. Etter endringen er hele
maksimal-konfigurasjonen 21 448 tokens, altså under en femtedel av ett 128k-vindu.
## 3. Hva som ble endret, og hvorfor akkurat det
`list_bundles` returnerte `Bundle.index_summary`**hele** rot-indeksens body — for **hver**
konfigurert base samtidig, pluss ett JSON-objekt per ufulgt kryss-lenke. Begge vokser med korpuset.
Prisen på å finne ut *hvilke baser som finnes* ble altså satt av hvor mye de basene *inneholder*.
Det er progressiv disclosure snudd på hodet (målbilde §2/§4): katalogen er stigens billigste trinn,
og den var loopens dyreste kall.
Hver oppføring er nå bundet ved konstruksjon: `id`, en **ordrett prefiks** av indeksbodyen på maks
`_CATALOGUE_EXCERPT_CHARS` (200) tegn, `index_truncated`, `documents`, `verdict_count`,
`cost_baseline`, `unreachable_links`. Kostnaden er **O(baser), aldri O(korpus)**.
**Et premiss ble felt FØR noe ble bygget på det.** «Indeksbodyen forteller en manager hva basen
handler om» er **usant** for maskin-importerte baser: grenbasenes `index.md` har verken frontmatter
eller prosa — den er en ren lenkeliste (målt: `B-n200-2024-gren-1-1-importert/index.md`, 959 bytes,
første tegn er `-`). Feltet var altså ikke bare dyrt, det var dyrt **og** innholdsløst der. En
avkortet prefiks taper ingenting en manager brukte.
Tre valg, hvert med sin begrunnelse:
- **Fast vindu, ikke en andel av basen.** En andel ville skalert med korpuset igjen — bare med en
mindre konstant. Mutasjon M8 (`body[:len(body)//10]`) er rød mot nettopp den formen.
- **Avkorting ANNONSERES, som felt.** `index_truncated` står **ved siden av** utdraget, ikke som en
markør limt inn i det — samme grunn som `BudgetExceeded` bærer trippelen sin som felt (kø-(y)):
en konsument som må re-parse prosa for å vite om den holder helheten, har fått en diagnostikk den
ikke kan handle på. En base som **passer** blir ikke merket avkortet og får hele bodyen —
omisjon, aldri en løgn i noen av retningene (M3 og M4 er begge røde, hver sin vei).
- **En ufulgt kryss-lenke overlever som ANTALL.** Fakta fra økt 51 («et hopp er tolerert, men ikke
lenger taust») står; per-lenke-detaljen blir liggende der den er handlingsbar — på
`RunResult.skipped_links` / `DryRunReport.skipped_links` — og rir ikke med i et kall hvis hele
jobb er å være billig.
Hele indeksen er fortsatt **ett** `read_file(id, "index.md")` unna. Dette er et disclosure-nivå,
ikke datatap.
## 4. Gaten
Taket (500 tegn per base) bor i **testen**, ikke i `explore.py`: en test som importerte
implementasjonens budsjett ville flyttet seg med det, og å heve budsjettet er nøyaktig den
regresjonen fila finnes for.
Syv armer: (a) taket over mange store baser · (b) kostnaden sporer **ikke** korpus-størrelse ·
(c) katalogen identifiserer fortsatt hver base — anti-vakuitets-armen, uten den består «returner
bare id-ene» (a) perfekt · (d) avkorting annonsert, utdraget ordrett, begge retninger · (e) stigen
er intakt, hele indeksen er ett kall unna · (f) ufulgte lenker overlever som antall ·
(g) **kontrollen** — én bases rå indeksbody alene sprenger taket for hele katalogen, så en grønn (a)
betyr at bindingen fyrte, ikke at fixturen var liten.
**Ni mutasjoner, alle røde mot HELE suiten, hver med sin egen signatur** (grønn kontroll 1066/5):
| # | Mutasjon | Røde tester |
|---|---|---:|
| M1 | ingen binding i det hele tatt (tilbake til hele bodyen) | 4 |
| M2 | bundet, men vakuøst (utdraget tømt) | 2 |
| M3 | avkorting ikke annonsert (stille kutt) | 1 |
| M4 | over-annonsert (en hel indeks meldt avkortet) | 1 |
| M5 | per-lenke-lista rir med igjen | 1 |
| M6 | det ufulgte faktumet slettet | 1 |
| M7 | bundet, men suffiks i stedet for ordrett prefiks | 2 |
| M8 | en andel av basen i stedet for et fast vindu | 2 |
| M9 | størrelses-signalet (`documents`) gjort konstant | 1 |
M9 ble kjørt fordi `documents` var et felt uten gate — et felt ingen test kan se, råtner.
## 5. Grenser, uttalt
- **MAJOR-1 (repeterbart `--bundle-dir`) var ikke nødvendig for dette.** Bindingen sitter i
verktøykroppen, bak en uendret CLI-flate. Operatørbeslutning 26.08: repeterbart `--bundle-dir`
er **nei** — multi-base forblir bibliotek-partisjonen (`run_mandate_across_bundles`).
- **`navigate_bundle` kalles fortsatt per base per katalogkall**, altså leses hver fil på disk for å
telle dokumenter og dommer. Det er I/O og veggklokke, ikke tokens, og er utenfor denne
bestillingen — men det er ikke gratis ved 171 baser, og det er ikke målt her.
- **Ingen levende modell har kalt det nye verktøyet.** Formen er bevist offline; at en manager
faktisk velger bedre med et utdrag enn med hele indeksen er ikke målt (samme klasse som
structured-output-grensen).
- **N101 er ikke berørt** — utenfor bestillingen (operatørpresisering 26.08).