portfolio-optimiser-claude/src/portfolio_optimiser_claude/ingest.py
Kjell Tore Guttormsen 5732d13369 feat(ingest): adopt llm-ingestion-okf as Door A implementation (first consumer)
Replace the local 391-line ingest implementation with a thin adapter over
the shared llm-ingestion-okf library (git-pinned dae0bd1a via Forgejo,
tool.uv.sources). The materialize() signature is preserved; error types are
now the library's typed hierarchy rooted in IngestError, re-exported from
the consumer seam.

- tests/test_ingest_adoption.py: new load-bearing seam tests (delegation,
  offline invariant — allow_network is never passed, error contract),
  detach-proven red twice.
- Golden suites (file + sql) pass UNCHANGED — byte-exact behaviour proven
  against the repo-local fixtures.
- 6 test files migrated to the library error hierarchy; escaping/typed-cell
  unit tests dropped (byte-bound by the ingest-edge.md golden, unit-owned by
  the library's own 189-test suite). Provenance stamp now asserted
  independently from the §5 rule.
- mypy override follow_untyped_imports for llm_ingestion_okf (no py.typed
  upstream yet — reported as a finding).

Suite: 386 passed; ruff + format + mypy --strict clean; shared/, examples/,
runs/s10/ and run_s10.py byte-untouched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 20:46:51 +02:00

63 lines
2.1 KiB
Python

"""Door A ingest — the consumer seam over the shared llm-ingestion-okf library.
An addition IN FRONT of the loop (ingest-spec §1): a deterministic step that couples the
framework to a real data source and materializes the extract as an OKF knowledge bundle,
which the existing 8-step loop then consumes UNCHANGED. Zero model calls; no network.
Since the first-consumer adoption (2026-07-16) the implementation IS the shared
``llm-ingestion-okf`` library (byte-compatible with the reference implementation; the
repo-local goldens under ``examples/`` remain the fasit). This module is the ONE place the
repo touches the library for Door A: it re-exports the library's typed surface and keeps
the historical ``materialize`` signature. The offline invariant lives at this seam — the
per-run network opt-in (``allow_network``) is NEVER passed, so an ``http`` source is
refused fail-fast at the library's network gate (§8, local-only default).
"""
from __future__ import annotations
from pathlib import Path
from llm_ingestion_okf import (
Extraction,
FileSource,
HttpSource,
IngestError,
IngestResult,
Manifest,
ManifestError,
MaterializationError,
NetworkGateError,
RenderError,
SourceError,
SqlSource,
load_manifest,
materialize_bundle,
)
__all__ = [
"Extraction",
"FileSource",
"HttpSource",
"IngestError",
"IngestResult",
"Manifest",
"ManifestError",
"MaterializationError",
"NetworkGateError",
"RenderError",
"SourceError",
"SqlSource",
"load_manifest",
"materialize",
"materialize_bundle",
]
def materialize(manifest_path: Path, bundle_dir: Path, ingested_at: str) -> list[Path]:
"""Materialize the manifest's extractions into ``bundle_dir`` (deterministic, §5).
``ingested_at`` is an EXPLICIT required argument (no wall-clock default, §5). Returns
the generated concept-file paths in extraction order. Delegates to the library with
its local-only defaults in force — no network opt-in, no transport injection.
"""
return list(materialize_bundle(manifest_path, bundle_dir, ingested_at).written)