Deltakelse i den koordinerte OKF-adopsjonsrunden (ni repo). Varig innhold festet i eget repo per postkasse-regel 2; svaret selv ligger i den midlertidige postkassen. Nytt i §6: primitiv-hypotesen bekreftet mot egen kode, med forbehold om at orkestreringen (gate-foer-relasjoner, gate-scoping, claimed-register, per-dokument-rollback) er den dyre delen og maa foelge med som referanse- orkestrator. Flat-vs-hierarkisk indeks: format kan deles, kontrakt ikke -- to lenkekonvensjoner i samme bundle kollapser i en flat modell. Konvergens med to andre repo paa writer-primitivet (frontmatter-passthrough, som vi allerede har). Bundle-plassering: compliant, men cwd-binding flytter lekkasjeflaten uten aa fjerne den. Ingen kodeendring. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AGkEqS3Zxf7rVuUQHrsQG2
14 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)
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.HOME_ORG-konstanten (innboks-write.mjs:44,~/.claude/okr/org) — okrs to-rot- modell. Generaliseres til en «forbudte skriverøtter»-liste fra kaller.- Type-utledningen (
deriveType,innboks-frontmatter.mjs) — matcher vokab-termer som helt ord i tittel + kilde-basename, med\p{L}\p{N}-lookaround fordi\bikke håndterer æ/ø/å. Regelen er generell, vokabet ikke. 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.- Faste nivånavn (
strategisk-kontekst/historikk/dokumenter) og.claude/okr/innboks/som drop-zone. Rene konfig-verdier. - 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.
turndowner pinnet tilheadingStyle: '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.unpdfkalles med eksplisittisEvalSupported: 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.
neutralizeExternalLinkser sikkerhetskritisk og hører sammen medokf-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:
- Vokabet er data, ikke kode. Bibliotekets API tar TYPE/TAGS/
routeLevelsom argument. Uten dette må okr forke uansett. - 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).
- 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. - Idempotens by construction. mtime-basert timestamp, deterministisk sortering, stabil kryss-kilde-disambiguering. Et bibliotek som introduserer veggklokke er ubrukelig for okr.
- Pluggbar slugify-translitterering (æ/ø/å), ellers regresjon på norsk input.
- Pluggbar meldingsstreng/språk, eller minst en
onNotice-seam som i dag. - Versjonspinning etter polyrepo-disiplinen. okr vendorer mot en tag, ikke mot main.
- Guard-grensen respekteres. Dør A er ugatet;
llm-ingestion-okfer 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 viallm-ingestion-guardpå 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 somOKF_VERSION). - Den bor som markdown-tekstlinje i rot-
index.md, ikke i frontmatter —index.mder OKF-reservert og bærer aldri frontmatter. Kun rot-index; undernivåer har den aldri (testet eksplisitt). okf-check.mjsekkoer 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.mjsbevarer 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.mjssom 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) ogokr-second-brain-search-skillen — ren plugin-UX. - Alt sikkerhetsansvar. Guard-grensen står:
llm-ingestion-guardeier sikkerhet,llm-ingestion-okfer plumbing, og okr reimplementerer ingen av delene.
6. Tillegg fra adopsjonsrunden 2026-07-20 (trinn C)
Skrevet etter deltakelse i den koordinerte runden (ni repo, postkasse ~/repos/_okf-interim/,
midlertidig). Svaret vårt ligger i svar/okr.md der; det varige innholdet er dette:
6.1 Primitiv-modellen er riktig — men orkestreringen er den dyre delen
okr er allerede primitiver + én komponerende kaller: splitConcepts, projectFrontmatter,
resolveRelations, writeConcepts, generateIndexes, checkBundle, convert,
isSafeBundleLink — og innboks-ingest.mjs som gjør ingenting primitivene ikke eksponerer.
Fire orkestrerings-invarianter er ikke-åpenbare og ble kjøpt dyrt (B5, B2). De må følge med et delt bibliotek som referanse-orkestrator, ikke bare som primitiver:
- Gate FØR relasjoner (ellers dangling lenker fra discardede dokumenter).
- Gate scopet til kjøringens skrevne filer (ellers felles håndkuratert innhold).
- Kryss-kilde-
claimed-register (kollisjon er en egenskap ved kjøringen, ikke en primitiv). - Per-dokument-rollback (derfor returnerer
writeConcepts{concepts, pointers}).
Begrensning i vår stemme: okr har ingen pull-sti (no-network by design), så vi kan ikke uttale oss om henting-som-primitiv.
6.2 Flat vs. hierarkisk indeks — format deles, kontrakt gjør det ikke
Dør A produserer flate bundles; vår form er hierarkisk. Forskjellen er ikke kosmetisk:
- To lenkekonvensjoner i samme bundle: index-entries er nivå-relative, body-relasjoner er
bundle-rot-relative (leading
/). I en flat bundle kollapser de til det samme — en port fra en flat kontrakt får dette stille galt. okf_versionkun i rot-index forutsetter en rot distinkt fra andre nivåer.routeLevel(type)gjør nivået semantisk avledet; flat materialisering har ingen tilsvarende operasjon.
Posisjon: flat = degenerert hierarkisk (dybde 1). Kontrakten må formuleres som «én
index.md per nivå», ellers kan ikke Node konformere uten å brekke okr. Krav til
cross-runtime-fixtures: minst én hierarkisk fixture, ellers beviser parity-testing ingenting.
6.3 Konvergens med to andre repo på writer-primitivet
portfolio-optimiser-claude og ms-ai-architect ber begge om frontmatter-som-input uten
connector. Vi har det bygget: writeConcepts tar concept.frontmatter som ferdig
serialisert streng og skriver verbatim (fileContent = frontmatter + body, ingen
re-serialisering — dokumentert designvalg). Tre av ni konvergerer; løses F1 som en
markdown-connector i dør A, får ingen av de tre noe.
6.4 Bundle-plassering — vi er compliant, men cwd-binding er en svak garanti
Ingen bruker-eid bundle ligger i plugin-treet (.claude/okr/ er cwd-relativ i brukerens eget
prosjekt; ~/.claude/okr/org/ er home; KB-referansene er plugin-eide og blir). Org-profil-
migreringen i 1.6.x er vår egen referanse for konfigurerbar sti-oppløsning.
Åpent, meldt videre: cwd-binding flytter lekkasjeflaten, den fjerner den ikke —
.claude/okr/ lander i hvilket som helst repo brukeren står i, inkludert offentlige.
Grensetilfelle: tillitsmodellen vår er asymmetrisk innenfor én bundle (innboks fiendtlig,
resten kuratert — derfor kilde: innboks-guarden). Blir hele bundlen dør C-«eksternt
innhold», må den grensen tegnes på nytt.
7. Neste steg (ikke utført)
- Operatør melder kartleggingen inn til biblioteket som kravgrunnlag (§3 er kravlisten).
- Catalog avklarer
okf_version-semantikken (§4) — blokkerer løftet. - Parser-sett + vendored-vs-peer avgjøres i samråd (§2,
lib/convert/). - 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.