portfolio-optimiser/.claude/projects/2026-07-04-i4-ingest-sql-maf/brief.md
Kjell Tore Guttormsen 1b7612b22d docs(i4): brief + plan + golden fixture builder (I4)
Session brief (scope, non-goals, pinned SQL type/number decisions, verification) + TDD plan + build_fixture.py (regenerates the sqlite golden; the committed db bytes need not reproduce — the golden compares the derived bundle).
2026-07-04 06:56:08 +02:00

4.6 KiB
Raw Blame History

I4 — SQL-kilde på MAF-siden (brief)

Økt-type: kode-økt, offline, IKKE gatet (lokalt/offline; driftsmodellens klarsignal dekker den). Andre kildetype i ingest-programmet, mot I1s polymorfe manifest-skjema UTEN spec-endring. Speiler I2 (file/CSV) for sql.

Kilder: ingest-spec (normativ, FROSSET) · målbilde ingest · sesjonsplan §I4.

Mål (én lukket leveranse)

sqlite-konnektor på MAF-siden mot det polymorfe manifest-skjemaet: manifest (source.type: sql) → read-only sqlite-uttrekk → materialisert OKF-bundle (samme §5§7 provenance + §6 index som file), hele veien load-bearing- og golden-testet. materialize() går fra å avvise alt ≠ FileSource til å dispatche FileSource → read_csv, SqlSource → read_sql (http forblir I6-avvist).

Suksesskriterier (hver = verifiserbar)

  1. read_sql(connection_ref, query, *, max_rows) eksekverer et read-only SELECT mot en sqlite-fil resolvet fra env-varen connection_ref navner, med §5-typet celle-rendering.
  2. materialize() materialiserer et sql-manifest til en bundle bit-identisk med en golden (examples/ingest-golden-sql/), idempotent ved re-run.
  3. Nye load-bearing-tester (SQL-navigerbarhet + §5-type-sømmer) er RØDE ved detach (bevist).
  4. Full suite grønn uten nøkkel/nettverk; okf.py/shared//run.py urørt; ruff+format+mypy grønne; null modellkall.

Non-goals (bygg IKKE)

  • Ingen spec-/commons-endring (spec FROSSET; oppdages drift → STOPP, egen GATET runde).
  • Ingen http-konnektor (I6), ingen python -m-CLI, ingen live-DB, ingen ORDER-BY-håndhevelse i kode (manifest-forfatters SHOULD, §4), ingen per-rad-filsplitting, ingen inkrementell re-ingest, ingen index-typing-RFC (åpen, utsatt).
  • Ingen søsken-repo-endring (I5, GATET).

Låste beslutninger — SQL §5-type/tall-regler (delegert HIT av STATE; pinnes i kode+golden)

STATE: «CSV-celle-verbatim-regelen utsatte tall-/type-håndtering eksplisitt til sql/I4 → SQL-kolonners type/tall-regler avgjøres HER.» Konsistente med §5, ikke en spec-endring:

Python-type (sqlite default) §5-tekst Begrunnelse
None (SQL NULL) "" (tom) §5 «SQL NULL as the empty string»
int (INTEGER) str(v) plain decimal §5 «integers in plain decimal»
float (REAL) repr(v) korteste round-trip §5 «non-integral numbers … shortest round-trip decimal form»; repr er Pythons korteste round-trip (ekstrem magnitude → E-notasjon, akseptert som korteste form)
str (TEXT) verbatim (escapes i render_table) §5 «text verbatim»
bool IngestError sqlite emitter den ikke; guard hindrer str(True)"True" silent-coercion
bytes (BLOB) / annet IngestError §5 «any other value type MUST fail (never silent coercion)»

Konnektor-regler:

  • connection_ref = env-var-NAVN → verdi = sti til sqlite-fil (I4-scope: sqlite-fixture). Env-var usatt → IngestError fail-fast; fil mangler → IngestError (speiler read_csv).
  • Read-only: åpnes file:{quote(path)}?mode=ro med uri=True → et skrive-forsøk feiler på DB-nivå (§4 «SHOULD enforce read-only», robust — ikke skjør streng-parsing).
  • Single-statement: Connection.execute avviser flere statements naturlig (§4 «one statement»).
  • max_rows: streaming-tak, IngestError ved overskridelse (§8, aldri silent truncation — speiler read_csv).
  • sqlite3-feil (syntaks, skrive-forsøk, korrupt db) → wrappes som IngestError (fail-fast, ærlig — som read_csvs FileNotFoundError-wrapping).

Antakelser (med test)

  • A1: sqlite3 default-typing gir int/float/str/bytes/None (ingen registrerte konvertere) → testet i test_ingest_sql.py (typet fixture-db, én rad per type).
  • A2: mode=ro håndhever read-only → test: skrive-query mot ro-connection raiser.
  • A3: golden-db-bytene påvirker ikke bundle-determinismen (kun DB-INNHOLD via query; env-sti lekker aldri inn i frontmatter) → golden bit-deterministisk uansett checkout-sti.

Verifisering (kommandoer)

  • uv run pytest -q — 211+ passerer, ingen ny skip, ingen nett/nøkkel.
  • Detach-bevis (manuelt, revertert): bryt hver ny load-bearing-søm → bekreft RØD → revert.
  • uv run ruff check . && uv run ruff format --check . && uv run mypy src — grønne.
  • git diff --statsrc/portfolio_optimiser/okf.py, shared/, src/portfolio_optimiser/run.py IKKE i diffen.
  • MAF-fri: test_ingest_module_is_maf_free_and_context_layer_pure grønn (kun stdlib lagt til).