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
125 lines
7.1 KiB
Markdown
125 lines
7.1 KiB
Markdown
# 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.
|