# 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.