test(spec-guard): ingest contract field cross-check vs spec §12 (I2)

This commit is contained in:
Kjell Tore Guttormsen 2026-07-03 18:38:35 +02:00
commit dbf5dc5c13

View file

@ -16,6 +16,7 @@ import json
import re
from pathlib import Path
from portfolio_optimiser.ingest import Extraction, FileSource, HttpSource, ManifestV1, SqlSource
from portfolio_optimiser.verdicts import ProposalFeatures, capture_verdict, verdict_to_dict
REPO_ROOT = Path(__file__).resolve().parents[1]
@ -172,3 +173,43 @@ def test_ingest_spec_exists_with_required_structure() -> None:
assert "promoted-verdict-" in text, "ingest spec must state the reserved filename namespace"
# The determinism anchor: the explicit-timestamp rule must be visible at field level.
assert "`ingested_at`" in text, "ingest spec must document the explicit timestamp field"
def test_ingest_spec_documents_every_contract_field() -> None:
"""Test 5 (I2 — discharges test 4's deferred note): every field of the REAL ingest manifest
contract is documented in the ingest spec driven from the pydantic models' ``model_fields``
(all three polymorphic source variants + the extraction shape), the seven §5/§7 provenance
frontmatter keys, and the §11 golden-case entries. Mirrors test 3: the test goes RED the
moment the contract code and the spec's §12 cross-check table drift apart (a new model field
without a spec entry, a renamed frontmatter key, a changed golden layout)."""
text = INGEST_SPEC_PATH.read_text(encoding="utf-8")
def documented(field: str, source: str) -> None:
assert f"`{field}`" in text, f"ingest spec does not document {source} field `{field}`"
for field in ManifestV1.model_fields:
documented(field, "manifest top-level")
for model, source in (
(FileSource, "file source"),
(SqlSource, "sql source"),
(HttpSource, "http source"),
(Extraction, "extraction"),
):
for field in model.model_fields:
documented(field, source)
# The §5/§7 provenance layer — exactly the keys the materializer stamps.
for key in (
"type",
"title",
"source_system",
"source_query",
"ingested_at",
"ingest_manifest",
"generated",
):
documented(key, "provenance frontmatter")
# The §11 golden extraction case layout.
for entry in ("manifest.json", "fixture/", "ingested-at.txt", "expected-bundle/"):
documented(entry, "golden extraction case")