portfolio-optimiser/tests/test_provenance.py

47 lines
1.5 KiB
Python

"""Step 6 tests — first-class Pydantic provenance stamp.
At least one citation is mandatory (the load-bearing NFR); a valid stamp exposes the
proposal's provenance fields; the annotation adapter yields MAF citation dicts for display.
Pattern: tests/spikes/test_c_validator.py (pydantic raises + field assertions).
"""
import pytest
from pydantic import ValidationError
from portfolio_optimiser.provenance import Citation, ProvenanceStamp
from portfolio_optimiser.retrieval import TextSpan
def _stamp() -> ProvenanceStamp:
return ProvenanceStamp(
citations=[Citation(file="asphalt.txt", locator=TextSpan(0, 10), snippet="0123456789")],
model="qwen3:4b",
role="proposer",
validator_decision="validated",
token_usage=42,
)
def test_zero_citations_is_rejected() -> None:
with pytest.raises(ValidationError):
ProvenanceStamp(
citations=[],
model="m",
role="proposer",
validator_decision="validated",
token_usage=1,
)
def test_valid_stamp_exposes_provenance_fields() -> None:
stamp = _stamp()
assert len(stamp.citations) >= 1
assert stamp.model and stamp.role
assert stamp.validator_decision in {"validated", "rejected"}
assert isinstance(stamp.token_usage, int) and stamp.token_usage > 0
def test_to_annotations_yields_citation_dicts() -> None:
anns = _stamp().to_annotations()
assert anns and all(a["type"] == "citation" for a in anns)
assert anns[0]["annotated_regions"][0]["type"] == "text_span"