portfolio-optimiser/docs/plan/2026-08-09-innholdsgate-og-aerlighet.md
Kjell Tore Guttormsen 295e9665fe docs(plan): the content gate and the honesty sentence, on a track that does not touch the freeze
The demo shows "download and run". Implying you can point this at your own sources and build a
knowledge base claims three things the code does not carry -- and A5 (the code may not claim more
than it does) binds the presenter too, not just the source.

Measured first, and one measurement changed the plan: the guard is NOT v0.2 alpha. That figure came
from our own 2026-07-16 inclusion plan, which is a premise rather than a fact. It is v0.3.4, seven
published tags, `dependencies = []` -- stdlib only. Our okf pin (v0.3.2) declares no dependencies
either, so the guard is not coupled to it, and the 0.3.5-vs-0.4.0 release argument concerns the
release AFTER v0.3.4. Adoption moved from risky to tractable on that one reading.

The three claims, made precise: the demo bundle was hand-curated (honesty), the ingest path writes
unscanned (buildable), and the generic bundle factory does not exist (deferred at O1, not buildable
in four days). Two close with code, one with a sentence.

The two tracks are separated on a measured fact: `simulation.py` does not import `ingest`, so Door A
work cannot disturb what Wednesday freezes. Criterion 5 is the one that proves it -- the walkthrough
must stay byte-identical.

Four decisions are named as decisions rather than settled silently: which policy preset, fail-closed
versus flag-and-write, where the guard's report lands in provenance, and keeping `--strict`
meaningful across a seam that ships no py.typed. The honesty paragraph is written in BOTH variants
up front, so Wednesday is an observation and not a judgement call on stage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XoHJCKBTjFKcjsfEQyGbzh
2026-08-06 19:49:13 +02:00

9.1 KiB

Innholdsgate og ærlighet — plan fram til demoen 13. august

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» FEILv0.3.4, syv publiserte tagger git -C ~/repos/llm-ingestion-pipeline-security tag
Guarden er tung å adoptere FEILdependencies = [], stdlib-only pyproject.toml i guard-repoet
Vår okf-pin drar inn guarden NEIv0.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 NEIsimulation.py importerer ikke ingest grep "^from portfolio_optimiser" simulation.py
Ingesten skanner innhold i dag NEIingest.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 Neimaterialize 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

  1. Hvilken policy-preset? Guarden eksporterer PRESET_TRUSTED_SOURCE og PRESET_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.
  2. Fail-closed eller flagg-og-skriv? Repoets presedens er entydig — promote_verdict er fail-closed, write_concept_file validerer og reparerer aldri. Forslag: avvist dokument skrives IKKE, og materialize raiser en typet feil på linje med IngestStampError. 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.
  3. Hvor havner guardens Report? Provenance er en invariant her. Funnene skal ikke kastes — de hører i ingest_manifest, ved siden av eierskaps-stempelet. Avgjør felt-navn og form.
  4. mypy --strict over sømmen. Guarden shipper ingen py.typed, så symbolene ankommer som Any. 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 --strict meningslø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 materialize et 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

  1. uv sync grønn med guarden som deklarert dep; uv run python -c "import llm_ingestion_guard as g; print(g.__version__)"0.3.4.
  2. Ny load-bearing-test grønn; tre mutasjoner målt røde mot hele suiten, med kontroll.
  3. uv run pytest -q grønn — og antallet skal ha økt, ikke bare være grønt.
  4. uv run ruff check . + uv run mypy src rene, med --strict fortsatt meningsfull over sømmen (adapter, ikke bare override).
  5. Demoens kjøresti byte-uendret: uv run python -m portfolio_optimiser.simulation gir 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.
  6. git diff --statshared/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.2 gjennom 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