portfolio-optimiser/docs/plan/2026-07-20-f1-freetext-connector-direction.md
Kjell Tore Guttormsen 8a86f2ab6d Squashed 'shared/' changes from 7aa53fc..a2b57d2
a2b57d2 docs(plan): V1 — «de 5 linjene» var ikke homogene; :214 er ikke en literal
d63e45d docs(plan): okf-versjonssjekken utført — hypotesen falsifisert på to stale premisser
ef31dda docs(plan): V1 §4.2 — pin + id + sitering avgjort, og ratifiseringsgaten funnet
35220f7 docs(plan): V1 §4.1 — serialiseringsformen er bundet av :158, så 6 sider er invariant
8a7d430 docs(plan): operatøren avgjorde V1 (O2) og B1 (O1) — B1 utført, V1 gated
f306c7b docs(plan): V1 §5.1 — konsument-kostnaden målt @ 8a14137, O3-raden priset
ab0ea8f docs(plan): innboksrunden — V1 utvidet med tre målte funn, §7.2-siteringen ref-bundet
84a3010 docs(plan): §7.2 — MCP-spørsmålet er avgjort av frossen tekst, S2.2 og S2.4 er ugated
e984d51 docs(plan): D-B ankret, D-A#3s årsak er repo-avhengig, V1 utvidet med oppstrøms-evidens
3de702b docs(plan): V1 §6 — rekkevidde-forbeholdet korrigert, og funnet under funnet
249425b docs(plan): amendment-underlag — D-A#3s ÅRSAK rettet, drift ikke avvik
4876970 docs(plan): V1-underlag — generated-feltets form etter OKF v0.2
3f18ca7 docs(plan): B1/D4 operator question — nav-golden's normative status, four costed options
29ad8ca docs(plan): amendment-underlag — frossen tekst per køpunkt, med målt fasit-effekt
a67a243 docs(plan): ordering-axes ruling — three distinct axes, as an interpretation record
381d9e5 docs(plan): guard adoption plan pins no version — v0.2 header was stale
54ca0ff docs(plan): D3 ratified — status vocabulary landed in coord register
fe6b998 docs(plan): D3 status vocabulary — canonical 7-token set for roll-up register
c66ccc3 docs(plan): D2 register-form fix — two-output model resolves ÅS#5
b641741 docs(examples): nav-golden fixture class — bundle → read-context goldens
9801d35 docs(spec): method-spec §3 Step 1 — Q3 navigation contract (hierarchy)
bfa5a9b docs(spec): ingest-spec — land ratified D1 stamp model
5f046ab docs(plan): Q3 finding — method-spec §3 silently forbids hierarchical bundles
a013e8b docs(plan): F1 direction — free-text sources belong in ingest-spec door A
84191c6 docs(plan): record commons↔implementation-repo coordination boundary
cae9972 docs(plan): llm-ingestion-guard adoption — planned at future untrusted ingest boundaries

git-subtree-dir: shared
git-subtree-split: a2b57d20fc0953c19776c21ce1311f234386a590
2026-07-31 18:37:48 +02:00

111 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# F1 — fritekst-kilder i ingest-spec: retningsvurdering
**Status:** vurdering, ikke vedtak. Spec-en er IKKE endret. Beslutning tas av operatøren.
**Foranledning:** `llm-ingestion-okf` v0.3.1 har ingen fritekst-connector; `file` er en streng
CSV-leser og §5-body rendres som markdown-tabell med newline-kollaps. To uavhengige repo
(`claude-playlist-corpus`, `claude-code-llm-wiki`) blokkeres. Spørsmålet stilt til commons:
løses dette i `ingest-spec.md` (dør A) eller i bibliotekets dør B (innboks, ikke spec-styrt)?
---
## 1. Retning: løses i spec-en, i dør A
Fire grunner, i synkende vekt:
1. **Arkitekturregelen krever det.** §1: *«data reaches the model ONLY via OKF bundles»*, og
bundlen materialiseres deterministisk FØR loopen. Fritekst er data. Ingenting i §1§3
skiller tabulært fra ustrukturert — utelukkelsen er et artefakt av at v1s `file`-connector
ble en CSV-leser, ikke en prinsipiell grense. Skyves den vanligste kunnskapsbase-kilden ut
til dør B, faller den samtidig utenfor provenance-stemplingen (§7), verdict-reservasjonen
(§3), golden-regimet (§11) og determinismen (§10) — spec-ens dekning uthules der den betyr
mest.
2. **Sitatkravet peker samme vei.** Method-spec §9 krever *«file + exact text span +
snippet»*. En span inn i en tabell-rendret, newline-kollapset body er i praksis ubrukelig;
en verbatim dokument-body er det naturlige span-målet. Fritekst gjennom dør A gjør
sitatkjeden bedre, ikke svakere.
3. **Determinismen er lettere, ikke vanskeligere.** Verbatim bytes har ingen typekoercion,
ingen tallformatering, ingen NULL-semantikk — hele §5s tabell-fallgruvefelt forsvinner.
Det finnes ikke noe determinisme-argument for å holde fritekst ute.
4. **Spec-en har allerede render-modusen — feilplassert.** §5 sier for `http`: *«the response
body verbatim inside a fenced code block»*. Verbatim-render finnes altså, men er bundet til
**transport** (`http`) i stedet for til **innholdsform**. Det er den faktiske defekten: §5
konflaterer kildetype og body-form. F1 er symptomet.
**Grensen mot dør B holder likevel — men den går ikke ved innholdsform.** Den går ved
*adresserbarhet + re-eksekverbarhet*: en kilde med manifest-deklarert, repeterbar `query` mot
en adresserbar kilde hører i dør A (en transkripsjonsfil under `root` kvalifiserer). Materiale
uten re-eksekverbar kilde-query — limt inn tekst, en e-post, et engangsdropp — hører i dør B.
Bruker vi innholdsform som grense i stedet, havner halve kunnskapsbasen utenfor spec-en av en
grunn som ikke er prinsipiell.
### Foreslått form (retning, ikke spec-tekst)
Ikke en ny kildetype `document` — den ville duplisere `file`s `root`- og
grensesjekk-logikk. I stedet: **skill body-form fra kildetype.** Et nytt påkrevd
extraction-felt (arbeidsnavn `render`) med `table` | `verbatim`. `file`+`table` = dagens
CSV-leser; `file`+`verbatim` = fritekst-dokumentet som mangler; `http` beskrives retroaktivt
som `verbatim` og blir dermed konsistent i stedet for et unntak. Ett felt, én rad i §12s
kryssjekk-tabell, ingen ny kildetype.
## 2. Hva §5 må si om verbatim body-render
Seks punkter. De fire første er ikke valgfrie — dagens `http`-render mangler dem alle, så
dette lukker et latent hull samtidig som det løser F1.
- **Bytes og dekoding.** Innholdet leses som bytes og dekodes som UTF-8, strengt. Dekodefeil
er en ERROR — aldri erstatningstegn, aldri lossy koercion. Samme disiplin som §5s *«any
other value type MUST fail (never silent coercion)»*.
- **Linjeskift — her er «verbatim» nødt til å vike.** §5 krever LF-only og nøyaktig én
avsluttende newline. CRLF/CR MÅ derfor normaliseres til LF, og etterfølgende blank plass ved
EOF kollapses til nøyaktig én LF. Uten denne regelen motsier «verbatim» og «LF-only»
hverandre, og golden-ekstraksjoner blir plattformavhengige. Spec-en MÅ si rett ut at
renderen dermed er lossy mot kildens eksakte bytes — og at en eventuell kildehash regnes
over **kildens** bytes, ikke de rendrede.
- **Fencing — obligatorisk, med deterministisk bredde.** Fence-lengde =
`max(3, lengste backtick-run i innholdet + 1)` (CommonMark-standard, deterministisk).
- **Fencing er sikkerhetsbærende, ikke kosmetikk.** Ufenset markdown-passthrough er IKKE v1.
Grunnen er konkret: method-spec §3 Step 1 navigerer ved å følge body-lenker
(`](target.md)`), så et ufenset ingested dokument kan injisere navigasjonskanter utenom
`index.md` og forsøke bundle-escape-stier. I tillegg rendres read-context som
`## {type}: {title}`-seksjoner — et dokument med egne `##`-overskrifter visker ut
seksjonsgrensene, og en ledende `---` kan leses som et nytt frontmatter-blokk. Fenset
innhold har ingen av delene. (Ufenset passthrough = utvidelsespunkt.)
- **`max_rows` for dokumenter.** Feltet er radorientert og meningsløst for fritekst. Enkleste
konsistente lesning: for `verbatim` teller `max_rows` LF-delimiterte linjer, og overskridelse
er ERROR (§8, aldri stille trunkering). **Åpen underbeslutning:** en 40 MB transkripsjon
passerer en linjegrense lenge før den blir håndterbar — trengs et valgfritt `max_bytes` i
tillegg? Anbefaling: ja, valgfritt, men dette er verdt et eksplisitt operatørvalg.
- **`source_query` og provenance ellers:** uendret — relativ sti, whitespace-kollapset (§5/§7).
### `ingested_at`-determinismen bevares — med én felle å lukke eksplisitt
Verbatim-render leser ingen klokke. `ingested_at` forblir et eksplisitt påkrevd argument,
stemplet ordrett; §5s regel er urørt. Fellen er en fristende «forbedring»: å stemple kildefilens
mtime eller størrelse som ekstra provenance. Det MÅ forbys — git bevarer ikke mtime, så et
golden-fixture ville gi ulikt resultat ved frisk utsjekking, og §11s byte-for-byte-krav brytes.
Verdt en eksplisitt MUST NOT.
### §11 — nye seams
- Ny golden-case, konvensjon `examples/ingest-golden-verbatim/`. Fixturet MÅ inneholde et
dokument med CRLF, en backtick-run ≥ 3, en ledende `---`, og ikke-ASCII — så escape-reglene
fryses av golden i stedet for å leve i prosa.
- Ny load-bearing rad: testen MÅ feile når fence-bredden slutter å vokse med innholdets
lengste backtick-run (dvs. når ingested innhold kan bryte ut av fencen).
## 3. Sikkerhetsobservasjon (til operatøren, ikke en spec-endring)
Dette er første gang dør A materialiserer innhold som er **untrusted av opphav** selv om
transporten er lokal og first-party: `root` eies av operatøren, men en transkripsjon eller
artikkel under `root` er tredjeparts tekst. Guard-adopsjonsplanen
([2026-07-16](2026-07-16-llm-ingestion-guard-adoption.md) §4) definerte Trigger A som «når
`http`/MCP-kildetypen bygges». En fritekst-connector treffer samme untrusted-grense uten å gå
via `http` — så Trigger A bør trolig omformuleres fra *transport* til *opphav*, og kan dermed
inntreffe tidligere enn planen antar. Flagget her, ikke besluttet.
## 4. Hva dette IKKE avgjør
- Ingen spec-tekst er skrevet. §4, §5, §11 og §12 er urørt.
- `render`-feltnavnet er et arbeidsnavn.
- `max_bytes`-spørsmålet står åpent (§2).
- Dør B (innboks) berøres ikke: den beholder materiale uten re-eksekverbar kilde-query.