Planens §3 sa at `ingest.materialize` er repoets ENE skrivepunkt på Door A, og det premisset ble felt av måling FØR bygging: `materialize` er en ren delegasjon til pinnet llm_ingestion_okf v0.3.2s `materialize_bundle`, som stager i minnet og utfører sin egen disk-fase. Det finnes ingen callback mellom de to, så en gate plassert der kunne bare kjørt ETTER at bytene landet — en opprydding, ikke en gate. Sømmen ble i stedet kopier bundelen → materialiser inn i kopien → skann det som ble generert → publiser eller forkast. Kopien er bærende, ikke bekvemmelighet: bibliotekets §3 eierskaps-skann, kollisjonsgaten mot kuratert innhold og §6 index-merge leser alle den EKSISTERENDE bundelen. Staging i tom katalog mister alle tre og publiserer en bundle uten kuraterte naboer — datatap forkledd som sikkerhetsfiks. De fire §4-beslutningene, tatt og målt: (1) ingen av guardens to preset — Origin.EXTERNAL/AUTOMATIC, fordi trust_for utleder policy fra origin alene og PRESET_USER_UPLOAD bærer en quarantine-semantikk Door A ikke har; (2) utfall per BUNDLE, diagnostikk per DOKUMENT — delvis publisering ville etterlatt bundle + index som svarer til intet manifest, men import_bundle itererer forbi første avvisning; (3) Report til log.md, aldri konsept-frontmatter, der fire golden-suiter pinner bytene; (4) mypy-override OG adapter, siden override alene gjør sømmen type-blind i stedet for type-sikker. `materialize` forblir ugatet med vilje — goldenene pinner den, og en kaller som vil ha gaten ber om den ved navn. Fem mutasjoner alle røde + grønn kontroll (hele suiten, ~120 s hver): detach gaten · la den fyre ETTER publisering · Origin.INTERNAL · tom staging-katalog · rapporter kun første avvisning. Målingen felte en VAKUØS test først: en hard injeksjon scorer fail_secure under BEGGE trust-tierene, så Origin.INTERNAL-mutasjonen lot alle tre avvisningstestene stå grønne — beslutning 1 så dekket ut uten å være testet. Båndet der tieren faktisk avgjør er høy-entropi-innhold (quarantine_review vs warn), og testen ble skrevet mot nøyaktig det før mutasjonen ble re-målt. Mutasjon 4 ble på sin side felt av KUN én test; 809 andre merket ikke at bundle-kopien forsvant. Laveste disposition er `warn`, ikke `allow` — `allow` finnes ikke i guarden. En gate skrevet mot == allow ville avvist hvert dokument som noensinne ingestes. Kriterium 5 står: demo-stdout er byte-identisk med tests/golden/demo-transcript.stdout, målt både i suiten og ved eksplisitt kjøring. shared/ er urørt. 801 -> 810 passed / 4 skipped. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DDu94KoyxAmhJsG2n63X8Q
14 KiB
Innholdsgate og ærlighet — plan fram til demoen 13. august
✅ SPOR B LANDET 2026-08-09 — alle seks kriterier grønne
materialize_gatedisrc/portfolio_optimiser/ingest.py; gate-pinv0.3.4. 801 → 810 tester. Fem mutasjoner målt røde mot HELE suiten + grønn kontroll.§3s premiss var FEIL, og målingen felte det før byggingen. Planen plasserer gaten i
ingest.materialize, «repoets ENE skrivepunkt på Door A». Målt ermaterializeen ren delegasjon til det pinnedellm_ingestion_okfv0.3.2smaterialize_bundle, som stager i minnet og utfører sin egen disk-fase. Ingen callback finnes mellom de to — en gate plassert der kunne bare kjørt ETTER at bytene hadde landet, altså en opprydding, ikke en gate. Sømmen ble i stedet: kopier bundelen → materialiser inn i kopien → skann det som ble generert → publiser eller forkast.Kopien er bærende, ikke bekvemmelighet. Bibliotekets §3 eierskaps-skann, kollisjons-gaten mot kuratert innhold og §6 index-merge leser ALLE den EKSISTERENDE bundelen. Staging i en tom temp-katalog ville mistet alle tre og publisert en bundle uten kuraterte naboer og deres index-lenker — et datatapsbug forkledd som en sikkerhetsfiks. Mutasjon 4 beviser det.
De fire beslutningene i §4, tatt og målt
# Beslutning Utfall Begrunnelse 1 Policy-preset Ingen av dem — Origin.EXTERNAL+Channel.AUTOMATICimport_bundletar ikke et preset;trust_forutleder policy fra origin alene.PRESET_USER_UPLOADbærerquarantine_default=True(opplastings-semantikk Door A ikke har);PRESET_TRUSTED_SOURCEgir en tier en manifest-navngitt ekstern kilde ikke har fortjent2 Fail-closed, per dokument eller per bundle Utfall per BUNDLE, diagnostikk per DOKUMENT materialize_bundleer allerede alt-eller-ingenting per manifest — den sletter hver stemplet fil og regenerererindex.md. Delvis publisering ville etterlatt en bundle + index som svarer til INTET manifest. Planens motargument («ett av femti avvist gir en halv bundle») er argumentet FOR: per-bundle gir ingen halv bundle.import_bundleitererer likevel forbi første avvisning, så visibiliteten taper ingenting3 Hvor havner Reportlog.md(OKF §7), ALDRI konsept-frontmatterKonseptbytene er det pinnede bibliotekets, og fire golden-suiter pinner dem. Et gate-felt i frontmatter ville brutt alle fire. test_gated_output_is_byte_identical_to_ungated_materializeer vakten som holder det ute4 mypy --strictover sømmenOverride OG adapter, som planen krevde Override alene gjør sømmen type-BLIND, ikke type-sikker: alt ankommer som Any._stamp_line+ koersering iverdictsstopperAnyved grensenKriterier (§6)
uv syncgrønn;llm_ingestion_guard.__version__→0.3.4✅- Load-bearing-test grønn; fem mutasjoner røde (planen krevde tre) + kontroll ✅
uv run pytest -qgrønn, antall økt 801 → 810 ✅ruff check+ruff format --check+mypy srcrene ✅- Demo-stdout BYTE-IDENTISK med
tests/golden/demo-transcript.stdout✅ — gaten lekket ikke inn i det som fryses. Målt både av golden-testen i suiten og ved eksplisitt kjøringgit diff --stat shared/tomt ✅Mutasjons-manifest (alle mot HELE suiten, ~120 s hver)
# Mutasjon Utfall 1 Detach gate-kallet ( if False)🔴 4 tester 2 Gaten fyrer ETTER publisering (advarsel, ikke gate) 🔴 3 tester 3 Origin.INTERNALsom default🔴 2 tester 4 Staging i TOM katalog i stedet for kopi 🔴 1 test — og KUN den; 809 andre merket ingenting 5 Rapporter kun FØRSTE avviste dokument 🔴 1 test — Kontroll: urørt kode 🟢 810 passed / 4 skipped Lærdom — mutasjon 3 avslørte en vakuøs test, og rettelsen kom av å måle. Første kjøring av mutasjon 3 felte KUN logg-testen; alle tre avvisnings-testene forble GRØNNE. Årsak: en hard injeksjon scorer
fail_secureunder BEGGE trust-tierene, så beslutning 1 så dekket ut uten å være testet. Målingen fant båndet der tieren faktisk avgjør — et høy-entropi-innhold girquarantine_reviewunder EXTERNAL ogwarnunder INTERNAL — ogtest_external_origin_refuses_what_internal_would_publish(med trusted-kontroll) ble skrevet mot nøyaktig det. Uten den re-målingen ville §4-beslutning 1 stått ubevist bak en grønn suite.Lærdom 2 — den lave dispositionen er
warn, ikkeallow. Et RENT konsept scorerwarn;Dispositionerwarn < quarantine_review < fail_secure, og noeallowfinnes ikke. En gate skrevet mot== allowville avvist hvert dokument som noensinne ingestes. Kontroll-testen er det som fanger den klassen.§5-ærlighetsavsnittet: bruk JA-varianten. Gaten er landet, så setningen som leses på scenen er «ingest-veien skanner nå innholdet før det skrives, med en egen sikkerhetskomponent». P1 og P3 (håndkuratert bundle, ingen generisk fabrikk) er UENDRET ærlighets-punkter.
Utløser. Demoen viser «last ned → kjør». Sier vi, eller antyder vi, at man kan peke systemet mot sine egne kilder og bygge en kunnskapsbase, påstår vi noe koden ikke bærer. Det er A5-brudd i muntlig form — koden får ikke påstå mer enn den gjør, og det gjelder også presentatøren.
Kjører parallelt med demo-uke-planen (
2026-08-06-demo-uke-plan.md), ikke i stedet for den. Den planen eier kjørestien og fryser den onsdag 12. Denne eier Door A, som ikke er på kjørestien.
0. Målte premisser (verifisert 2026-08-09, ikke gjenbrukt fra eldre dokument)
| Påstand | Målt | Kommando |
|---|---|---|
| Guarden er «v0.2 alpha» | FEIL — v0.3.4, syv publiserte tagger |
git -C ~/repos/llm-ingestion-pipeline-security tag |
| Guarden er tung å adoptere | FEIL — dependencies = [], stdlib-only |
pyproject.toml i guard-repoet |
| Vår okf-pin drar inn guarden | NEI — v0.3.2 har dependencies = [] |
git show v0.3.2:pyproject.toml |
| Vi må vente på release-nummer-striden | NEI — den gjelder utgivelsen etter v0.3.4 |
guard-repoets STATE |
| Door A er på demoens kjøresti | NEI — simulation.py importerer ikke ingest |
grep "^from portfolio_optimiser" simulation.py |
| Ingesten skanner innhold i dag | NEI — ingest.py:20-25 sier det selv |
modul-docstring |
Den første raden er grunnen til at denne planen finnes: inkluderingsplanen fra 16. juli
(2026-07-16-llm-ingestion-guard-inclusion.md) sier «v0.2 (alpha)», og det premisset gjorde
adopsjonen urimelig risikabel. Målt er den tre mindre-versjoner nyere og uten avhengigheter.
Den planen skal merkes som utdatert på dette punktet, ikke slettes.
1. De tre påstandene, presist — og hvilke som kan lukkes
Formuleringen «tre ting som ikke holder» var upresis. Målt er de:
| # | Påstand | Status | Til torsdag? |
|---|---|---|---|
| P1 | Bundelen i demoen ble laget av pipelinen | Nei — den er håndkuratert i commons | Ærlighet. Kan ikke bygges bort |
| P2 | Ingesten skanner innhold før skriving | Nei — materialize skriver det den får |
JA — bygges |
| P3 | Det finnes en generisk bundle-fabrikk (okf-toolkit, T0) |
Nei — eget repo, finnes ikke, utsatt ved O1 | Ærlighet. Nytt repo på fire dager er utelukket |
To av tre lukkes med kode, én med en setning. Å forsøke P3 før torsdag ville brutt scope-vaktet (O1 er en tatt beslutning) og satt demoen i spill for en gevinst ingen tilhører etterspør.
2. To spor, med vilje adskilt
Spor A — demoen. Eies av demo-uke-planen. Fryses onsdag 12. Rører ikke ingest.py.
Spor B — innholdsgaten. Denne planen. Rører KUN ingest.py + pyproject.toml + ny test.
Adskillelsen er ikke kosmetisk: simulation.py importerer ikke ingest (målt), så Spor B kan
lande etter frysen uten å røre det som fryses. Faller Spor B, står demoen uendret — den mister kun
retten til å si at gaten finnes, som er nøyaktig statusen i dag.
3. Dagsplan
Søndag 9. / mandag 10. — Spor B, byggingen.
Wire llm_ingestion_guard inn i ingest.materialize (ingest.py:167), som er repoets ENE
skrivepunkt på Door A. Fire beslutninger må tas, ikke antas — de er listet i §4.
Tirsdag 11. — GO/NO-GO på commons (Spor A, uendret). Spor B rører ikke commons; de to konkurrerer ikke om samme fil.
Onsdag 12. — generalprøve + frys (Spor A). Spor B skal være committet FØR frysen hvis den skal nevnes i demoen, men den er ikke en frys-betingelse. Er den ikke ferdig: si status som den er, ikke som den var planlagt.
Torsdag 13. — demo. Ærlighets-avsnittet leses opp som skrevet i §5.
4. Byggingen — fire beslutninger som må måles, ikke antas
- Hvilken policy-preset? Guarden eksporterer
PRESET_TRUSTED_SOURCEogPRESET_USER_UPLOAD. Door A henter fra eksterne kilder oppgitt i et manifest — det er ikke det samme som en fil en bruker laster opp, og ikke det samme som en kilde vi eier. Les begge presetene i installerte bytes før du velger. Feil preset gir enten en gate som slipper alt gjennom eller en som gjør ingest ubrukelig. - Fail-closed eller flagg-og-skriv? Repoets presedens er entydig —
promote_verdicter fail-closed,write_concept_filevaliderer og reparerer aldri. Forslag: avvist dokument skrives IKKE, ogmaterializeraiser en typet feil på linje medIngestStampError. Motargument som må avvises eksplisitt før valget: en bundle der ett av femti dokumenter avvises blir en halv bundle. Avgjør om avvisning er per dokument eller per bundle. - Hvor havner guardens
Report? Provenance er en invariant her. Funnene skal ikke kastes — de hører iingest_manifest, ved siden av eierskaps-stempelet. Avgjør felt-navn og form. mypy --strictover sømmen. Guarden shipper ingenpy.typed, så symbolene ankommer somAny. okf løser det med en[[tool.mypy.overrides]]-blokk (ignore_missing_imports = true) OG en adapter som koerserer hver verdi til konkret type. Kopier begge deler — kun overriden ville gjort--strictmeningsløs på vår side av sømmen.
Avhengigheten pinnes som okf gjør det, git-kilde + tagg:
llm-ingestion-guard = { git = "https://git.fromaitochitta.com/open/llm-ingestion-pipeline-security.git", rev = "v0.3.4" }.
Aldri en flytende ref på en sikkerhetskomponent.
Load-bearing-krav (ufravikelig). En test som bare er grønn beviser ingenting. Testen skal:
- mate
materializeet fikstur-dokument med kjent injeksjons-innhold, og kreve at det IKKE skrives; - ha en kontroll: et rent dokument som skrives uendret (ellers kan ikke testen skille «gaten virker» fra «ingenting skrives»);
- måles RØD ved minst tre mutasjoner: detach gate-kallet · gjør avvisningen til en advarsel · bytt til en preset som slipper alt gjennom.
- Måles mot HELE suiten, med restaurering fra scratchpad +
shasum -c.
5. Ærlighets-avsnittet — teksten som faktisk sies på scenen
Erstatter ingenting i demo-uke-planens §1; kommer i tillegg, og leses opp:
«To ting om innholdet dere ser. For det første: denne kunnskapsbasen er laget for hånd, ikke produsert av systemet. Det finnes en ingest-vei som henter eksterne kilder inn i formatet, men eksempelet her gikk ikke gjennom den, og den generiske fabrikken som skulle laget slike baser er ikke bygget — den er bevisst utsatt. For det andre, om sikkerhet: [HVIS SPOR B ER LANDET] ingest-veien skanner nå innholdet før det skrives, med en egen sikkerhetskomponent, slik at forgiftet kildeinnhold ikke havner i basen. [HVIS IKKE] ingest-veien skriver i dag det den får, uten innholds-skanning. Gaten er planlagt og komponenten finnes, men den er ikke koblet inn ennå. Peker dere dette mot upålitelige kilder i dag, er det deres ansvar, ikke systemets.»
De to variantene er skrevet på forhånd med vilje: valget mellom dem er en observasjon onsdag, ikke en vurdering torsdag morgen.
6. Verifisering — konkrete kriterier
uv syncgrønn med guarden som deklarert dep;uv run python -c "import llm_ingestion_guard as g; print(g.__version__)"→0.3.4.- Ny load-bearing-test grønn; tre mutasjoner målt røde mot hele suiten, med kontroll.
uv run pytest -qgrønn — og antallet skal ha økt, ikke bare være grønt.uv run ruff check .+uv run mypy srcrene, med--strictfortsatt meningsfull over sømmen (adapter, ikke bare override).- Demoens kjøresti byte-uendret:
uv run python -m portfolio_optimiser.simulationgir fortsatt åtte merkede steg og identisk stdout over to kjøringer. Dette er Spor B's viktigste kriterium — det beviser at gaten ikke lekket inn i det som fryses. git diff --statpåshared/examples/→ tomt. Goldenene er load-bearing.
7. Hva denne planen IKKE gjør
- Bygger ikke
okf-toolkit(T0/D-G). O1 står. Håndteres av §5. - Adopterer ikke okf
v0.4.0+. Vi står påv0.3.2gjennom demoen; v0.4.0+ gjør guarden til hard runtime-dep, og den koblingen tas etter demoen, ikke før. - Rører ikke commons. Den har sin egen frist 11. august og sin egen økt.
- Rører ikke
docs/presentasjon-portfolio-optimiser.html— eies av en annen sesjon. - Wirer ikke guarden på bundle-LESE-stien. Gaten sitter ved skriving (Door A). En bundle som allerede ligger i repoet er kuratert av et menneske; å skanne den ved lesing er en annen beslutning med en annen begrunnelse, og den er ikke tatt.
8. Risiko
| Risiko | Utslag | Tiltak |
|---|---|---|
| Preset-valget viser seg feil under bygging | Gate som slipper alt, eller blokkerer alt | §4.1: les begge i installerte bytes FØR valg; testen har både positiv og kontroll |
| Guarden avviser demo-bundelen ved en feil | Panikk onsdag | Gaten sitter kun på Door A; demo-bundelen leses, ikke ingestes. Kriterium 5 fanger lekkasje |
| Spor B tar lengre tid enn ventet | Ett løfte mindre i demoen | §5 har ferdigskrevet NEI-variant; ingen improvisasjon på scenen |
mypy --strict blir meningsløs over sømmen |
Stille typetap | §4.4: adapter OG override, som okf gjorde |