okr/docs/llm-ingestion-okf-fase4-kartlegging-2026-07.md
Kjell Tore Guttormsen 29401bcd60 docs(okr): fase-4-kartlegging for llm-ingestion-okf (planned, ingen kode)
Forarbeid mot fase 4: all OKF-kode (okf-check/okf-index/innboks-ingest,
lib/okf-*.mjs, lib/innboks-*.mjs, lib/convert/) lest mot ground truth og
skilt i generelt vs. okr-spesifikt. Kravliste for at okr skal kunne vendore
en delt Node-utgave, samt okrs faktiske bruk av okf_version (ekko-tekst i
rot-index.md, kb-layout-2026-06) og hvorfor avviket mot spec-ens 0.1 er et
felt-type-avvik, ikke bare en verdiforskjell.

Ingen kode endret, ingenting wiret. Markørlinje satt til planned i STATE.md
(local-only). Meldt avvik: bibliotekets koordineringsvedlegg er utdatert.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AGkEqS3Zxf7rVuUQHrsQG2
2026-07-20 07:23:04 +02:00

10 KiB

llm-ingestion-okf — fase 4-kartlegging (okr-siden)

Status: planned — kartlegging og kravgrunnlag. Ingen kode endret, ingenting wiret. Dato: 2026-07-20. Grunnlag: ground-truth-lesing av all OKF-kode i dette repoet (suite 149/149 grønn ved kartleggingstidspunkt).

Node-halvdelen av llm-ingestion-okf finnes ikke ennå. Dette dokumentet er forarbeid: hva okr faktisk har, hva som er generelt vs. okr-spesifikt, og hva et delt bibliotek må oppfylle før okr kan vendore det i stedet for å eie egen kode.


1. Kartlegging — hva finnes i dag

Zero-runtime-dependency Node/ESM. Alle moduler er både importerbare (named exports) og CLI-kjørbare (import.meta.url === process.argv[1]-vakt). Node >= 22.

Modul Linjer Rolle Løftbarhet
lib/frontmatter.mjs 70 Flat FM-parse/skriv. BOM+CRLF-tolerant, siterte verdier bevarer intern #, multi-linje list-verdier tolereres Generell
lib/okf-links.mjs 39 Den ENE lenke-allow-listen: trygg bundle-lenke = leading /, .md, ingen scheme/../backslash/NUL. resolveBundleLink re-sjekker confinement Generell
lib/okf-vocab.mjs 73 Lukket TYPE/TAGS-vokab + routeLevel(type) okr-spesifikk data, generell mekanisme
lib/innboks-split.mjs 100 Ren funksjon: #/##-heading-split → konsepter. Preamble bevares, flat-fallback Generell (én no-detalj)
lib/innboks-frontmatter.mjs 96 Regelbasert FM-projeksjon. timestamp = kilde-mtime (idempotens by construction) Blandet
lib/innboks-relations.mjs 49 Relasjoner innen kjøringens sett, exact-title-substring → root-lenker. Assert zero-dangling Generell
lib/innboks-write.mjs 186 Atomisk skriv (temp+rename), path-confinement, realpath/symlink-guard, reservert-navn-guard, kuratert-fil-vern (kilde: innboks), kryss-kilde-claimed-register Generell (én okr-konstant)
lib/convert/index.mjs 132 docx/eml/pdf/txt/md → md. Lenke-nøytralisering i alle fem lenkeformer Generell
scripts/okf-check.mjs 160 Bundle-validering. Default tolerant (kun type kreves); --strict-ingest = vokab + lenke-allow-liste + files-scoping Generell
scripts/okf-index.mjs 162 Per-nivå index.md, idempotent, sanitizeEntry (C0/C1, zero-width, bidi, Unicode-tags, link-nøytralisering), atomisk Generell
scripts/innboks-ingest.mjs 240 Orkestrator: discover → per-dok staging → gate → discard-on-fail → relasjoner → index → sluttsjekk Generell arkitektur

Arkitektur-invarianter verdt å bevare i et løft:

  • Ingen LLM. Fil-settet er en funksjon av (drop-zone-innhold + mtime) alene → run1 og run2 byte-identisk. Veggklokke brukes aldri.
  • Per-dokument-isolasjon (Map-Reduce): ett fiendtlig dokument discardes alene og forgifter ikke de andre. Relasjoner emitteres ETTER gaten, så hvert mål garantert er på disk.
  • Strict-gaten scopes til kjøringens skrevne filer, ALDRI hele roten — ellers feller den legitimt håndkuratert innhold med lovlige eksterne lenker.
  • Ikke-destruktiv: originalene blir liggende i drop-zonen; hver original får en peker-fil.

2. Hva er okr-spesifikt vs. generelt

Generelt (kan løftes tilnærmet uendret)

frontmatter.mjs, okf-links.mjs, innboks-split.mjs, innboks-relations.mjs, okf-index.mjs, okf-check.mjs-kjernen, convert/-adapterne, og hele skrive-/ confinement-maskineriet i innboks-write.mjs. Ingenting her vet at domenet er OKR.

okr-spesifikt (må parametriseres før løft)

  1. TYPE_VOCAB/TAGS_VOCAB/LEVEL_BY_TYPE (okf-vocab.mjs) — norske, lukkede, OKR-domene. Mekanismen (lukket vokab + type→nivå-ruting) er generell; innholdet er ikke. Må inn som konfigurasjon, ikke kode. Merk at spec-en er engelskspråklig konvensjon mens vokabet er norsk — eierskapet (bibliotek-default vs. konsument-profil) må avklares.
  2. HOME_ORG-konstanten (innboks-write.mjs:44, ~/.claude/okr/org) — okrs to-rot- modell. Generaliseres til en «forbudte skriverøtter»-liste fra kaller.
  3. Type-utledningen (deriveType, innboks-frontmatter.mjs) — matcher vokab-termer som helt ord i tittel + kilde-basename, med \p{L}\p{N}-lookaround fordi \b ikke håndterer æ/ø/å. Regelen er generell, vokabet ikke.
  4. slugifys æ→ae/ø→oe-translitterering (innboks-split.mjs:15-25) — nordisk, ikke universelt. NFKD dekomponerer ikke æ/ø, så uten dette faller bokstaven bort. Et delt bibliotek trenger en pluggbar translitterasjonstabell, ellers regresserer norsk input.
  5. Faste nivånavn (strategisk-kontekst/historikk/dokumenter) og .claude/okr/innboks/ som drop-zone. Rene konfig-verdier.
  6. Norske feilmeldinger og kilde: innboks-provenansnøkkelen. Meldingsspråk må være pluggbart hvis biblioteket skal tjene ikke-norske konsumenter; kilde-nøkkelen er en OKF-extension key okr er avhengig av for kuratert-fil-vernet.

lib/convert/ spesielt

Adapterne er domene-agnostiske og det mest direkte gjenbrukbare i repoet. Men:

  • Fire exact-pinnede deps (mammoth 1.12.0, turndown 7.2.4, postal-mime 2.7.5, unpdf 1.6.2). okrs zero-dep-posisjon er bevart ved at de er lazy-importert med norsk installasjonshint, og at txt/md kjører helt dependency-fritt. Et delt bibliotek må bevare denne egenskapen — deps må være valgfrie (peer/optional), aldri obligatoriske. Vendored-vs-peer er en åpen beslutning som må tas sammen, ikke arves.
  • turndown er pinnet til headingStyle: 'atx'. Default er setext, som heading-splitten aldri ser. Denne koblingen mellom konverter og splitter må dokumenteres i kontrakten, ellers reintroduseres bugen i en delt utgave.
  • unpdf kalles med eksplisitt isEvalSupported: false (CVE-2024-4367), selv om det er default i 1.6.2. Belte + seler — må overleve løftet.
  • PDF gir flat tekst uten headings (kjent v1-caveat): PDF-dokumenter blir alltid ett konsept.
  • neutralizeExternalLinks er sikkerhetskritisk og hører sammen med okf-links.mjs. Emit-siden og validerings-siden deler allow-liste nettopp for at de aldri skal divergere. Splittes de i et løft, er divergens et spørsmål om tid.

3. Forutsetninger for at okr kan vendore en delt utgave

Rangert, alle må være oppfylt:

  1. Vokabet er data, ikke kode. Bibliotekets API tar TYPE/TAGS/routeLevel som argument. Uten dette må okr forke uansett.
  2. Zero-dep-kjerne bevart. txt/md-stien må kjøre uten npm-installasjon. Binærformat-deps optional/lazy med samme feilmeldings-kvalitet (klar hint, aldri traceback).
  3. Sikkerhetsegenskapene er testbart bevart. Path-confinement, realpath/symlink-guard, reservert-navn-guard, kuratert-fil-vern, sanitizeEntry-settet (C0/C1, ZWSP, bidi, Unicode tag-blokk), lenke-nøytralisering i alle fem former, --strict-ingest-scoping. Alle 149 testene her er tilgjengelige som seed; et løft som ikke porter dem er ikke ferdig. Særlig: gate-scoping (files) og discard-on-fail-isolasjon er lærte lekser fra B5/B2 — de er ikke kosmetikk.
  4. Idempotens by construction. mtime-basert timestamp, deterministisk sortering, stabil kryss-kilde-disambiguering. Et bibliotek som introduserer veggklokke er ubrukelig for okr.
  5. Pluggbar slugify-translitterering (æ/ø/å), ellers regresjon på norsk input.
  6. Pluggbar meldingsstreng/språk, eller minst en onNotice-seam som i dag.
  7. Versjonspinning etter polyrepo-disiplinen. okr vendorer mot en tag, ikke mot main.
  8. Guard-grensen respekteres. Dør A er ugatet; llm-ingestion-okf er plumbing. okrs egen strict-gate er ikke en sikkerhetsguard i guard-repoets forstand og skal ikke forveksles med en. Vil vi ha guard-gating, går det via llm-ingestion-guard på kallstedet — og det er en separat beslutning, ikke en del av fase 4.

4. okf_version — hvordan okr bruker feltet i dag (kjent avvik)

Faktisk bruk, verifisert:

  • Verdien er kb-layout-2026-06 (scripts/okf-index.mjs:27, eksportert som OKF_VERSION).
  • Den bor som markdown-tekstlinje i rot-index.md, ikke i frontmatter — index.md er OKF-reservert og bærer aldri frontmatter. Kun rot-index; undernivåer har den aldri (testet eksplisitt).
  • okf-check.mjs ekkoer verdien for menneskelig sammenligning. Den validerer den ikke, sammenligner den ikke mot noe, og feiler aldri på den. Hooks/scripts er no-network, så auto-fetch mot en standard er utelukket by design.
  • okf-index.mjs bevarer eksisterende verdi ved re-kjøring; en eksplisitt --okf-version <ver> vinner (bump-mekanismen). Begge grener er testet.
  • Feltet er per rot: prosjekt-.claude/okr/ og home-~/.claude/okr/org/ har hver sin.

Avviket: spec-en sier 0.1; okr sier kb-layout-2026-06. Dette er ikke bare ulik verdi — det er to ulike typer felt. okrs verdi navngir hvilket layout-mønster treet følger (datert konvensjons-snapshot); spec-ens 0.1 er et spec-versjonsnummer. De kan begge være riktige og likevel uforenlige i ett felt.

okrs posisjon: dette avgjøres av catalog som konvensjonseier, ikke av okr og ikke av biblioteket. okr har lav byttekostnad — feltet er ren ekko-tekst uten validerings-semantikk, så en verdiendring koster én konstant + fixture-oppdateringer. Men hvis begge betydningene skal bæres, trenger vi to felt (f.eks. okf_version = spec-versjon, okf_layout = layout-snapshot), og det er en spec-endring som må gå via commons/catalog.


5. Hva som aldri bør flyttes til biblioteket

  • okf-vocab.mjss innhold — norsk OKR-domenevokab hører hjemme i konsumenten eller i en profil, aldri som bibliotek-default.
  • Orkestratoren innboks-ingest.mjs som helhet — fase-rekkefølgen er generell og verdt å dele som mønster, men den konkrete drop-zone-plasseringen, to-rot-modellen og peker-filkonvensjonen er okrs. Del kjeden, ikke policyen.
  • Hook-integrasjonen (inject-okr-context.mjs, coaching-hook.mjs) og okr-second-brain-search-skillen — ren plugin-UX.
  • Alt sikkerhetsansvar. Guard-grensen står: llm-ingestion-guard eier sikkerhet, llm-ingestion-okf er plumbing, og okr reimplementerer ingen av delene.

6. Neste steg (ikke utført)

  1. Operatør melder kartleggingen inn til biblioteket som kravgrunnlag (§3 er kravlisten).
  2. Catalog avklarer okf_version-semantikken (§4) — blokkerer løftet.
  3. Parser-sett + vendored-vs-peer avgjøres i samråd (§2, lib/convert/).
  4. Først når Node-halvdelen finnes med §3 oppfylt: vurder adopsjon i egen sesjon.

Ingen av disse stegene endrer kode i okr. Markørlinjen i STATE.md står på planned.