# I5 — D7-speil av ingest (SQL-kilde) — brief > Forankret i hovedrepoets sesjonsplan > `~/repos/portfolio-optimiser/docs/plan/2026-07-03-sesjonsplan-ingest.md` §I5 og dette > repoets STATE. Bygget **fra `shared/ingest-spec.md` alene** — aldri ved reverse-engineering > av MAF-koden. Golden-**bytene** (den delte fasiten fra MAF I4) er lest, siden spec §11 gjør > dem til konformanskravet begge stacker reproduserer. Gaten I4→I5 ble verifisert løst mot > ground truth (MAF-commits `d7e5f2f`/`4f45fe6`/`1b7612b`, «I4») før arbeidet startet. ## Mål (§I5) Andre kildetype konsumert **uendret** fra samme delte kontrakt i søskenrepoet: D7s uavhengige SQL-konnektor reproduserer MAF I4s golden **byte-identisk** fra spec alene. Scope = `sql` (lokal SQL-database, sqlite-fixture, null nettverk). `file` var I3; `http` = ikke i D7 (målbildet: HTTP/MCP demonstreres MAF-only, I6). ## Premiss-verifisering (før impl) - **Spec byte-identisk delt:** `diff -q shared/ingest-spec.md` mot MAF = IDENTISK. Spec dekker `sql` fullt (§4 `connection_ref`, §5 typed-cell/NULL, read-only SELECT). I4 gjorde **ingen spec-endring** (sesjonsplan §I4) → subtree-pull er no-op (bekreftet, ikke kjørt — ingen drift). - **Golden-stamp:** SHA-256(manifest)[:16] = `a4b891aea55df97b` reprodusert lokalt → matcher `ingest_manifest: manifest@a4b891aea55df97b` i forventet bundle. - **Ingen nye operatør-beslutninger:** I3s to avgjørelser (golden repo-lokal kopi; okf relaksert for frontmatterløs index) bærer uendret inn i I5. Én lukket økt, ingen commons-runde. ## Leveranse - `examples/ingest-golden-sql/` — repo-lokal golden (byte-frossen kopi av MAF I4s; `diff -r` tomt): `manifest.json`, `fixture/portefolje.sqlite`, `ingested-at.txt`, `expected-bundle/`. - `src/portfolio_optimiser_claude/ingest.py` — SQL-utvidelse: - `SqlSource`-modell (`type: "sql"`, `id`, `connection_ref`); `ManifestContract.source` er nå en **diskriminert union** `FileSource | SqlSource` på `type` (ukjent/`http`-tag → fail-fast). - `_render_sql_cell` — §5 typed rendering: `None`(NULL)→`""`, `int`→plain decimal, `float`→ korteste round-trip (`repr`), `str`→verbatim (§5-escaping via delt `_escape_cell`), annet (BLOB o.l.)→**fail** (aldri stille coercion). - `_resolve_connection_ref` — env-var-oppslag (§4/§8: referanse ved navn, secret aldri i manifest; usatt ref → fail-fast). - `_read_sql` — read-only sqlite (`file:…?mode=ro`), ett SELECT (driver håndhever én-statement), `max_rows` fail-fast (§8). - `_read_extraction` — dispatch på `source.type` (`file`→CSV, `sql`→SQL); `materialize` kaller den (materialisering/index/replacement uendret fra I3). - Speiltester (I4s load-bearing-sett, gjennom SQL-konnektoren): - `test_ingest_sql_golden.py` — byte-fasit + idempotens + 3 mutasjonskontroller (endret rad / timestamp / manifest-bytes). - `test_ingest_sql_loadbearing.py` — typed-cell/NULL (NY §I5-søm) · provenance · navigability · verdict-reservasjon (fail-fast før DB åpnes) · re-ingest-safety. - `test_ingest_sql.py` — `SqlSource`-kontrakt, `_render_sql_cell`-enheter, connection_ref fail-fast, `max_rows`-tak, read-only-håndhevelse. - `test_ingest_spec_loadbearing.py` — `connection_ref` lagt til kontrakt-felt-guarden (D7s sql-impl avhenger nå av at spec dokumenterer feltet). - `test_ingest.py` — stale `type:"sql"`-avvisningscase erstattet (sql er gyldig post-I5) med `http`/ukjent-diskriminator-avvisning (honesty-regelen). ## SDK-kroker (STATE steg 4 — søk-først) I5 (SQL) introduserer **ingen SDK-flate**: ingest er deterministisk, null modellkall. Søk-først SDK-krok-reverifisering (API-drift på `create_sdk_mcp_server`) er relevant for I6 (HTTP/MCP), ikke I5 — utsatt dit kroken faktisk brukes. Eksisterende SDK-klient uendret og grønn i suiten. ## Verifisering (kjørt, grønn) - Golden **byte-identisk** konsumert (5/5, inkl. idempotens + mutasjonskontroller). - Speiltester **røde ved detach** — de nye sømmene bevist load-bearing (detach-bevis-skript): typed-cell/NULL · connection_ref fail-fast · sql-dispatch · spec-integritet (`connection_ref`). - Søskensuite **grønn uten nøkkel/nettverk**: 265 passed (239 + 26 nye). - `ruff check` + `ruff format` rene · `mypy --strict src`: no issues (16 filer). ## Åpent (forslag, ikke utført — utenfor I5-scope) - **Standard-evolusjon:** «typet index overalt» som bevisst OKF-endring forblir en egen koordinert commons-RFC (begge specs/golden/okf). Dagens permissive okf er forover-kompatibel. - **Åpent-speil-synk:** I3/I5-koden er ikke pushet til det offentlige `open/`-speilet (outward-facing → egen operatør-handling).