feat(ingest): I5 — SQL D7-speil, bygget fra commons-spec alene
Speiler MAF I4 fra shared/ingest-spec.md alene: manifest → SQL-konnektor → materialisert OKF-bundle, byte-identisk med den delte golden-fasiten. Gaten I4→I5 verifisert løst mot ground truth (MAF-commits d7e5f2f/4f45fe6/1b7612b) før arbeidet startet. Spec byte-identisk delt, ingen spec-endring (I4). - ingest.py: SqlSource (type: sql, id, connection_ref); ManifestContract.source er nå diskriminert union FileSource | SqlSource på type (http/ukjent tag → fail-fast). _render_sql_cell (§5 typed: NULL→"", int→decimal, float→korteste round-trip, str→verbatim m/ delt _escape_cell, annet→fail — aldri stille coercion). _resolve_connection_ref (env-oppslag §4/§8, usatt → fail-fast). _read_sql (read-only sqlite file:?mode=ro, ett SELECT, max_rows §8). _read_extraction dispatcher på source.type; materialisering/index/replacement uendret fra I3. - examples/ingest-golden-sql/: repo-lokal golden (byte-frossen kopi av I4s fasit). - Speiltester (I4s load-bearing-sett, gjennom SQL-konnektoren, detach-bevist røde): sql-golden byte-fasit + mutasjonskontroller · typed-cell/NULL (NY §I5-søm) · provenance/navigability/verdict-reservasjon/re-ingest-safety · SqlSource-kontrakt/ typed-rendering/connection_ref/max_rows/read-only · spec-integritet utvidet med connection_ref. Stale type:"sql"-avvisningscase erstattet (sql er gyldig post-I5). - docs/2026-07-04-I5-brief.md: brief + premiss-verifisering. Suite 265 passed uten nøkkel/nettverk (239 + 26 nye) · ruff + mypy --strict rene. [skip-docs] README + docs/extending.md er bevisst utsatt til I7 per sesjonsplan (programmet batcher ingest-doc der, avgrenset til det D7 faktisk har — CSV + SQL nå, HTTP/MCP kun pekere). Dokumentert i docs/2026-07-04-I5-brief.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017MM6BWb1hWmJZuXFZ7rjxT
This commit is contained in:
parent
e03bd79876
commit
32640deffc
13 changed files with 615 additions and 9 deletions
74
docs/2026-07-04-I5-brief.md
Normal file
74
docs/2026-07-04-I5-brief.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# 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).
|
||||
Loading…
Add table
Add a link
Reference in a new issue