1
0
Fork 0

docs(plan): Q3 finding — method-spec §3 silently forbids hierarchical bundles

Answering question 3 from the OKF round (flat vs hierarchical bundles) turned
up a conflict that is real in code, not just between two spec texts:

  method-spec.md:66-69   skip any link target containing a path separator
  okf.py:123-125         `if "/" in target: continue` — implemented as written
  okf-index.mjs:110      okr emits `${sd}/index.md`
  okf-links.mjs:23       okr *requires* a leading `/`

So every link okr produces is skipped by the navigator, and okr cannot write a
flat bundle at all (routeLevel always returns a subdirectory). Worse, the
robustness rule at :72-73 mandates that the skip be silent — a hierarchical
bundle yields a read-context of the root index and nothing else, with no error.
On okr's own okf-realistic fixture all 8 concept files vanish.

The separator ban is the wrong proxy for the security property it wants: it
conflates "contains a separator" with "escapes the bundle". Method-spec already
carries the precise rule two lines below (:73, boundary-checked, fail-closed),
and okr has correct prior art (okf-links.mjs:20-26).

Direction: let navigation traverse hierarchy; keep door A flat in v1. This is
also what makes a shared Python/Node fixture suite possible at all.

Neither spec is edited. Decision is the operator's.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HBJNsFsBRaAhqGKjjiGjoQ
This commit is contained in:
Kjell Tore Guttormsen 2026-07-20 08:53:33 +02:00
commit 5f046abcf4

View file

@ -0,0 +1,125 @@
# Q3 — flate vs. hierarkiske bundles: en reell konflikt i method-spec §3
**Status:** funn + retningsvurdering. Spec-en er IKKE endret. Beslutning tas av operatøren.
**Foranledning:** spørsmål 3 fra `llm-ingestion-okf` (postkasse `_okf-interim`, trinn C):
dør A produserer flate bundles; second-brain-siden (okr, catalog) bruker hierarkisk form med
per-nivå-indekser. Sier spec-en noe om dette, og bør den?
---
## 1. Funnet: spec-en sier noe — og den forbyr hierarki, stilltiende
Spørsmålet var stilt som om spec-en er taus. Den er ikke det.
**method-spec.md:66-69 (§3 Step 1):**
> Navigation starts at `index.md` and follows its intra-bundle markdown cross-links
> (`](target.md)`). **Targets containing a path separator are out-of-bundle and MUST be
> skipped.**
Dette er verifisert implementert i MAF-halvdelen, `portfolio-optimiser/src/portfolio_optimiser/okf.py:123-125`:
```python
for target in _LINK_RE.findall(index.body):
if "/" in target or target in seen:
continue # only same-dir bundle files; de-dup repeated links
```
Og okr-siden produserer nøyaktig det som forkastes:
- `okr/scripts/okf-index.mjs:110` emitterer underkatalog-pekere som `` `${sd}/index.md` ``.
- `okr/lib/okf-links.mjs:23` **krever** ledende `/`: `if (!target.startsWith('/')) return false;`
— «maa vaere bundle-root-relativ».
Sammensatt: **hver eneste lenke okr produserer inneholder `/`, og hver eneste av dem forkastes
av navigatoren.** okr kan ikke engang skrive flatt — `routeLevel()` (`lib/okf-vocab.mjs:71`,
konsumert i `lib/innboks-frontmatter.mjs:74`) ruter alltid til en underkatalog. Dette er ikke
et kantttilfelle; det er okrs normaltilstand.
**Det verste er at feilen er stille.** method-spec.md:72-73 krever det: *«A broken or
bundle-escaping cross-link MUST be tolerated — skipped, never raised (OKF robustness rule).»*
En hierarkisk bundle gir altså ikke en feilmelding — den gir en read-context som inneholder
rot-indeksen og ingenting annet. På okrs eget fixture `tests/fixtures/okf-realistic/` forsvinner
alle 8 konseptfiler, fordi ingen av dem ligger i roten. Symptomet operatøren ville sett er
«modellen kjente ikke innholdet», ikke «bundelen er ugyldig».
**To spec-er kolliderer på samme paragrafnummer — ved et sammentreff.** `catalog`s svar siterer
«§3 MUST» for per-nivå-indeks. Det er `catalog/docs/okf-second-brain/spec.md:45`, et *annet*
dokument enn method-spec.md §3. De er ikke to lesninger av én regel; de er to normative regimer
som tilfeldigvis møtes på «§3». Verdt å holde fra hverandre i all videre diskusjon.
## 2. Hvorfor regelen er gal — den er feil proxy for riktig egenskap
Separator-forbudet ble åpenbart skrevet som en *sikkerhets*regel: hindre at en lenke rømmer
bundelen. Men den forveksler «inneholder separator» med «rømmer bundelen». `sub/index.md`
rømmer ingenting. `../../etc/passwd` gjør det.
Og method-spec **har allerede den riktige mekanismen**, to linjer lenger ned (:73):
> path resolution MUST be boundary-checked against the bundle directory, fail-closed.
Så §3 Step 1 bærer både den presise regelen og en grov proxy — og det er proxyen som gjør
skaden. Den presise regelen alene er tilstrekkelig.
**Den korrekte formen finnes allerede som fungerende prior art hos okr**
(`lib/okf-links.mjs:20-26`): avvis null-byte, backslash, URL-scheme, `..`-segment; krev `.md`;
krev bundle-rot-relativ form. Dette er resolve-og-grensesjekk gjort riktig. Retningen er derfor
ikke å oppfinne noe, men å løfte disse semantikkene inn i method-spec §3 Step 1 og la
separator-forbudet gå ut.
## 3. Retning: la navigatoren traversere hierarki; la dør A fortsatt produsere flatt
To beslutninger som med fordel holdes fra hverandre:
**(a) Navigasjon (method-spec §3 Step 1) bør støtte hierarki.** Alternativet — flat-only for
alltid — betyr at okr/catalogs output aldri kan mate optimiser-loopen, og at de to halvdelene
ikke kan dele fixture-suite i det hele tatt (se §4). Kostnaden ved å åpne er håndterbar; se
åpne punkter under.
**(b) Dør A (ingest-spec §5) bør forbli flat i v1.** `ingest-{id}.md` uten katalogkomponent,
extraction-id-grammatikken utelukker `/`. En flat bundle er et gyldig degenerert tre, så
ingenting brekker. Hierarkisk *produksjon* er et utvidelsespunkt, ikke v1 — og å holde det
utenfor gjør at F1 (fritekst) og Q3 (form) forblir uavhengige beslutninger. Det er navigatoren
som må lese begge former, ikke materialisereren som må produsere begge.
### Hva som må avklares hvis (a) velges — ikke gratis
- **Lenkesyntaks, normativt.** To former er i omløp: okr emitterer rot-relativt `/foo/bar.md`;
catalog spec.md:76 tillater både rot-relativt og relativt. Spec-en MÅ velge. Anbefaling:
støtt begge, med `/` = **bundle-rot-relativ, IKKE filsystem-absolutt**. Den lesningen er
nøyaktig der en naiv implementasjon blir en path traversal-sårbarhet (`open("/etc/passwd")`),
så den må være normativ og dekkes av en load-bearing test.
- **Traverseringsrekkefølge.** Dagens «index first, then links in first-seen order» er definert
for én flate. For et tre må dybde-først vs. bredde-først pinnes, ellers er read-context ikke
deterministisk og golden-suiten brekker.
- **Dedup på *resolvert* sti**, ikke rå target — ellers teller `./a.md` og `a.md` som to
oppføringer, og sykler (`a/index.md``b/index.md``a/index.md`) termineres ikke.
- **Verdict-eksklusjonen må holde på alle nivåer.** method-spec §3 Step 1 utelukker
`type: verdict` fra read-context; med hierarki må det gjelde rekursivt, ikke bare i roten.
Dette er lekkasjeflaten hvis den glemmes.
- **Read-context-rendering.** `## {type}: {title}`-seksjoner har ingen nivåforestilling.
Anbefaling: behold flat seksjonsrendering også for hierarkiske bundles (nivået er
navigasjonsstruktur, ikke presentasjonsstruktur) — men si det eksplisitt.
## 4. Konsekvens for delt fixture-suite (det spørsmålet egentlig gjaldt)
Direkte svar: **Python- og Node-halvdelen kan dele fixture-suite kun hvis traverserings-
kontrakten er én kontrakt.**
- Velges flat-only, er okrs `okf-realistic` ikke en gyldig input til Python-navigatoren, og de
to halvdelene deler ikke bundle-fixtures i det hele tatt — bare ingest-fixtures.
- Velges hierarki, MÅ fixture-suiten inneholde en hierarkisk case, og begge halvdeler MÅ
produsere **identisk read-context** fra den. okr har allerede kandidaten ferdig
(`tests/fixtures/okf-realistic/`, tre nivåer dypt, per-nivå-indekser), og et flatt
motstykke (`okf-minimal/`). De bør adopteres som delte fixtures, ikke gjenskapes.
Med andre ord: (a) er det som gjør delt fixture-suite mulig i første omgang. Det er
hovedargumentet, sterkere enn eleganse.
## 5. Løse tråder som ikke er mine å lukke
- **Versjonsdrift:** `catalog/docs/okf-second-brain/spec.md:47` oppgir rotmarkøren som «currently
`0.1`», mens `okr/scripts/okf-index.mjs:27` setter `OKF_VERSION = 'kb-layout-2026-06'`.
Spec og referanse-implementasjon er ikke i sync. Meldt, ikke rørt.
- **okrs lukkede vokabular håndheves kun på skrivestien** (`lib/okf-vocab.mjs:6-8`); lesesiden
aksepterer ukjente typer. Relevant for catalogs krav (i) — se svarfilen.