test(spec-guard): ingest contract field cross-check vs spec §12 (I2)
This commit is contained in:
parent
6236f2fb78
commit
dbf5dc5c13
1 changed files with 41 additions and 0 deletions
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue