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).
4.6 KiB
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) forsql.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)
read_sql(connection_ref, query, *, max_rows)eksekverer et read-only SELECT mot en sqlite-fil resolvet fra env-varenconnection_refnavner, med §5-typet celle-rendering.materialize()materialiserer etsql-manifest til en bundle bit-identisk med en golden (examples/ingest-golden-sql/), idempotent ved re-run.- Nye load-bearing-tester (SQL-navigerbarhet + §5-type-sømmer) er RØDE ved detach (bevist).
- Full suite grønn uten nøkkel/nettverk;
okf.py/shared//run.pyurø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), ingenpython -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 →IngestErrorfail-fast; fil mangler →IngestError(speilerread_csv).- Read-only: åpnes
file:{quote(path)}?mode=romeduri=True→ et skrive-forsøk feiler på DB-nivå (§4 «SHOULD enforce read-only», robust — ikke skjør streng-parsing). - Single-statement:
Connection.executeavviser flere statements naturlig (§4 «one statement»). max_rows: streaming-tak,IngestErrorved overskridelse (§8, aldri silent truncation — speilerread_csv).- sqlite3-feil (syntaks, skrive-forsøk, korrupt db) → wrappes som
IngestError(fail-fast, ærlig — somread_csvsFileNotFoundError-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=rohå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 --stat—src/portfolio_optimiser/okf.py,shared/,src/portfolio_optimiser/run.pyIKKE i diffen.- MAF-fri:
test_ingest_module_is_maf_free_and_context_layer_puregrønn (kun stdlib lagt til).