portfolio-optimiser/shared/docs/plan/2026-07-20-f1-freetext-connector-direction.md

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.