Pin dae0bd1a -> v0.3.1 (=692f2df) on the public Forgejo mirror; uv.lock pins the exact commit behind the tag. - Drop the mypy override: the library ships py.typed from v0.2.0, so strict mode now follows its real types instead of follow_untyped_imports. - Migrate 8 library-error assertions from pytest.raises(match=...) to exc.value.code — message text is explicitly unstable from v0.3.0, the codes are the stability contract. - Fix a real breakage the bump surfaced: IngestResult gained a required `stamp` field (d3a3bcc), which the delegation fake did not construct. - The read-only SQL test loses resolution under the code contract (`sql_failed` is generic), so it now proves read-onlyness by effect — the write never lands — instead of by message wording. - Correct the guard plan: G1's persist-gate anchor (ingest.py:372-387) died with the 2026-07-16 adoption. Door A is ungated by the library's own README, so gating stays our responsibility at the call site. Verified: 426 tests green, golden output byte-exact unchanged, full gate clean (ruff + format + mypy strict). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RmNAgbRXUgvoSKxVK4Bevv
9.8 KiB
Plan — når/hvor llm-ingestion-guard wires inn i dette repoet
Status: PLAN (ikke wiret). Forfattet 2026-07-16 etter guard-repoets adopsjons-brief (
~/repos/llm-ingestion-pipeline-security/docs/ADOPTION-BRIEF.md, guardv0.2alpha). Dette dokumentet KLASSIFISERER repoets ingest-flater mot briefens §7-checklist og fastsetter NÅR/HVOR guarden skal wires — det IMPLEMENTERER ingenting. Maskinlesbar status iSTATE.md(markørlinjenllm-ingestion-guard: planned — …).Ærlighets-regelen (metode-spec §1) gjelder også her: en grønn guard-scan er IKKE «trygt». Guarden er write-time defense-in-depth FORAN validator/checker/kostbaseline — ikke en erstatning.
1. Hvorfor dette repoet er i målgruppen
Guarden hardner write-time-formen: untrusted innhold som flyter gjennom et enrichment-/ekstraksjons-steg og persisteres i en artefakt en downstream agent senere leser som betrodd kontekst. Dette repoet ER den formen:
- Ingest-laget materialiserer en OKF-bundle (markdown-konseptfiler +
index.md) —ingest.py:348-391 materialize. - Loopens Steg 1 navigerer bundelen og renderer den som read-context rett inn i
hypotese-/debatt-prompten —
okf.py:122-134 bundle_context→loop.py:119-133(contexti proposer/checker-promptene). Bundelen leses altså som betrodd kontekst. - Den lange lærings-sløyfa (Steg 7) folder ekspert-verdikter inn i samme prompt:
experience.py:157-171 fold_experiencebygger linjer- {id} [{decision}]: {rationale}—decisionogrationalenår prompten verbatim (experience.py:3,6).
Bundelen/verdikt-storen er trust-grensen: en forgiftet konsept- eller verdikt-linje skrevet ved write-time leses senere som betrodd. Provenansen er kun kjent ved write-gaten.
2. Trust-grense-kartlegging (briefens §7 mot dette repoet)
| # | Inngang | Klassifisering | Belegg (verifisert) | Guard-relevans |
|---|---|---|---|---|
| 1 | ingest.py file-kilde (lokal CSV under root) |
Førstepart i D7-scope | Operatør peker manifest mot lokal CSV; boundary-sjekket fail-closed (ingest.py:264-276); null modellkall, ingen nett (ingest.py:1-6); celler rendres verbatim (ingest.py:164-185) |
Ikke mål som scopet. Forbehold (trust følger opphav, ikke kanal): hvis CSV-radene selv er eksternt hentet, blir cellene en untrusted bærer inn i Steg-1-prompten |
| 2 | ingest.py sql-kilde (lokal sqlite, read-only) |
Førstepart i D7-scope | connection_ref → env, read-only URI, verbatim typing (ingest.py:230-268) |
Samme som (1): opphavs-forbeholdet gjelder |
| 3 | ingest.py http-kilde |
DORMANT untrusted-sti (avvist i dag) | type:"http" avvises fail-fast av discriminated union (ingest.py:129) — bevisst ikke bygd (extending.md:128-160; sesjonsplan §4). Ingen egress-call-sites i src/ (grep: 0 treff) |
DEN avgjørende untrusted-grensen når den går live — auto-fetch av web/vendor-innhold → materialiseres i bundelen → leses av loopen. Guardens hovedplass |
| 4 | inbox.py verdikt-inbox |
Live injeksjonsflate, men tiltenkt førstepart | decision valideres kun som ikke-tom streng; ingen sjekk på merge-stien (inbox.py:102-132); rationale verbatim til prompten (§1). C-F7: kjørt bevis at injeksjonstekst når prompten. Ennå ikke wiret til noen kjøresti (C-N2, merge_inbox_into_store kalles fra ingen leverbar sti) |
Depth-komplement til den alt planlagte C2.5-herdingen — ikke primærbehovet (forfatteren er førstepart; C2.5-allowlist lukker den kjørte injeksjonen) |
| 5 | Mottatt tredjeparts OKF-bundle | Ikke en sti i dag | Repoet PRODUSERER sin egen bundle (ingest); ingen import_bundle-inngang finnes |
okf.import_bundle er det eksakte verktøyet HVIS en bundle-utvekslings-sti åpnes (delt D-E: klynge/flerbruker) |
| 6 | Kuraterte / promoterte konseptfiler | Førstepart | Håndforfattet (golden) / gated promoterings-gate (promotion.py) |
Utenfor guardens trusselmodell (in-place trusted-author-edits, brief §7) |
LLM-steget: i dag sitter modell-steget (loop) MELLOM bundelen og proposal-output — ikke mellom en untrusted kilde og storen. Ingest→bundle er deterministisk (null modellkall). Den klassiske «untrusted → LLM-enrich → persist»-formen oppstår FØRST når http-kilden (rad 3) går live. Det er derfor guarden er «når, ikke hvis».
3. Klassifisering + status: planned
- Repoet HAR en OKF-bundle-store som leses som betrodd (rad 1–2, 6 mater den; loop leser den).
- Ingen live untrusted-ingest-sti i en leverbar kommando i dag: http er avvist fail-fast og bevisst utsatt (rad 3); inbox-injeksjonen er reell men tiltenkt førstepart OG ikke wiret til noen kjøresti ennå (rad 4 / C-N2).
- → Ingenting å integrere nå, men klart applikabelt.
not-applicableville vært feil (repoet ER en OKF-second-brain med en designet-inn untrusted utvidelse + en kjørt-bevist inbox-injeksjonsflate).integratedville vært feil (ingen wiring; briefen ber oss ikke implementere).
4. Integrasjonspunkter (persist-gaten) + minimal wiring — NÅR
Tre trigger-gatede wiringer, hver forankret i en eksisterende roadmap-beslutning:
G1 — http-kilden går live · gate: D-B-utvidelse (i dag IKKE på D7-roadmap)
- Persist-gate: MELLOM http-fetch og skriving av
ingest-{id}.md. - KORRIGERT 2026-07-20 (pin-bump til v0.3.1): den opprinnelige forankringen
(
_read_extraction/materializeiingest.py:372-387) er DØD — adopsjonen 2026-07-16 flyttet den koden tilllm-ingestion-okf; lokalingest.pyer nå en 63-linjers adapter. Biblioteket bekrefter selv at dør A er ugatet («What is gated today: nothing» — README): null runtime-avhengigheter, ingen guard-kall før skriving. Gating er derfor VÅRT ansvar på kallstedet. To mulige forankringer når http går live: (a) wrap i vår egen seam (ingest.materialize) rundt bibliotekkallet, eller (b) løft gaten inn i biblioteket via operatør-køen. Valget er IKKE tatt — det hører til D-B. - Minimal wiring: ingest har intet modell-steg, så bookend-formen kollapser til
sanitér+scan over den hentede ekstraksjons-kroppen:
prepared = prepare_input(fetched_body)→ deterministisk render →screen_output(rendered, PRESET_…);FAIL_SECURE→ ikke skriv konseptfila, alert med gate-kode (decision.reasons), ingen innhold i alert. Provenance-frontmatteret (§5) bærer alleredesource_system/ingested_at— behold som er. - Dette er guardens hovedplass. Utsettes nøyaktig så lenge http er utsatt.
G2 — inbox-herding · gate: sesjon C2.5 (byggbar nå) — DEPTH, ikke påkrevd
- Persist-gate:
merge_inbox_into_store/load_inbox, FØRstore.add(inbox.py:122-132). - C2.5s primære fiks (sesjonsplan §2) = vokabular-allowlist {approved, rejected, approved_with_adjustment} + tak på rationale-lengde/antall. Den lukker den kjørte C-F7- injeksjonen alene.
- Guard-komplement (valgfritt depth):
scan_output(rationale + " " + decision, PRESET_USER_UPLOAD)over fritekst-rationale(injeksjons-bæreren). MÅ beholde inboxens tolerante semantikk: scan-treff → SKIP den verdikten (aldri raise) — konsistent medload_inboxs skip-never-raise (inbox.py:102-119). Merkes «vurder ved C2.5», ikke blokkerende.
G3 — mottatt tredjeparts OKF-bundle · gate: delt D-E (klynge/flerbruker) eller enhver receive-bundle-sti
- Wiring:
okf.import_bundle(bundle, origin=Origin.EXTERNAL, channel=…); per-konseptFAIL_SECURE/c.error→ ikke merge det konseptet.result.links= kryss-lenke-graf (dormant-injeksjons-signal). - Trigger: hvis/når en kryss-prosjekt-bundle-utveksling åpnes (delt D-E-retning). Ikke en sti i dag.
5. Forutsetninger å avklare FØR en wiring
- Guard er
v0.2alpha — public API kan endres. Ved wiring: pin + versjonsvakt, SAMME disiplin som SDK-pinnen (C-N3/C2.5):>=0.2,<0.3+ test som tvinger re-verifisering ved bump. - Offline/no-egress-invarianten består: guard-core er stdlib-only, gjør ingen nettkall,
parser ingen filer (brief §6) → «testsuiten kjører uten nøkkel og uten nettverk» (S5-invariant)
holder. Verifiseres eksplisitt ved wiring (guard-core i
[dev]/core, ikke[ml]/[judge]). - Ærlighets-grensene (brief §8) som betyr mest for et kostbesparings-wiki:
semantisk/faktisk poisoning er usynlig for lexicon+entropi — feil join-path/metrikk/tall
passerer rent. For dette repoet er nettopp plausible-men-feil
claimed_saving_nok/koder den farligste klassen; guarden fanger den IKKE. Det er validatorens/checkerens/kostbaselinens (C4.0) jobb. Guarden legges FORAN dem, ikke i stedet for.
6. Hva som IKKE gjøres nå (per inclusion-prompt)
- Ingen guard-avhengighet i
pyproject.toml, ingen import, ingen wiring, ingen kode. - http-kilden forblir avvist fail-fast (uendret).
- Kun: dette plandokumentet + markørlinjen i
STATE.md.
7. Verifisering NÅR en wiring engang skjer (ikke nå)
python -m llm_ingestion_guard.coverageexit 0 før man stoler på guarden (brief §5).- Load-bearing test (§11): detach guard-gaten → en injeksjons-fixture MÅ da nå bundelen/storen → testen RØD. Grønn-men-død er feilmoden.
- Full gate grønn (
pytest/ruff/mypy); golden-bytene uendret; offline-invarianten består (ingen nettkall introdusert i suiten).
8. Sekvens-forankring
- G2 vurderes SAMMEN med C2.5 (byggbar nå) — men C2.5-allowlist er den nødvendige delen; guard-depth er additiv.
- G1 materialiseres når/hvis D-B åpner en live-kilde-utvidelse som inkluderer http
(i dag eksplisitt IKKE på D7-roadmap,
extending.md:128-160). - G3 materialiseres hvis delt D-E-retning åpner bundle-utveksling.
Ingen av de tre er live i dag → status planned. Oppdater markørlinjen til integrated når
en av dem faktisk wires (og legg load-bearing detach-beviset ved).