From dbf5dc5c13fea77484933300c01e401ec4b28365 Mon Sep 17 00:00:00 2001 From: Kjell Tore Guttormsen Date: Fri, 3 Jul 2026 18:38:35 +0200 Subject: [PATCH] =?UTF-8?q?test(spec-guard):=20ingest=20contract=20field?= =?UTF-8?q?=20cross-check=20vs=20spec=20=C2=A712=20(I2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_method_spec_loadbearing.py | 41 +++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/test_method_spec_loadbearing.py b/tests/test_method_spec_loadbearing.py index 93903b7..c270316 100644 --- a/tests/test_method_spec_loadbearing.py +++ b/tests/test_method_spec_loadbearing.py @@ -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")