"""Tests for the Lead / Provenance datamodel (F-13).""" from __future__ import annotations from typing import get_args import pytest from codex.synthesis import Lead, LeadKind, LeadStatus, Provenance def test_provenance_requires_bibkey_and_locator() -> None: """Provenance has two required positional fields.""" p = Provenance(bibkey="Smith2020", locator="chunk 7") assert p.bibkey == "Smith2020" assert p.locator == "chunk 7" def test_provenance_missing_field_raises() -> None: """Provenance without locator must fail to construct (TypeError).""" with pytest.raises(TypeError): Provenance(bibkey="Smith2020") # type: ignore[call-arg] def test_lead_required_fields() -> None: """Lead requires id, kind, title, body, provenance, confidence.""" lead = Lead( id="L-0001", kind="connection", title="A connection", body="Some body text.", provenance=[Provenance(bibkey="X2020", locator="chunk 1")], confidence=0.8, ) assert lead.id == "L-0001" assert lead.kind == "connection" assert lead.status == "unverified" # default assert lead.suggested_validation == "" # default assert lead.claims == [] # default factory def test_lead_kind_literals_exact() -> None: """Lead kinds are exactly: connection, gap, improvement, conjecture.""" assert set(get_args(LeadKind)) == {"connection", "gap", "improvement", "conjecture"} def test_lead_status_literals_exact() -> None: """Lead statuses are exactly: unverified, spiking, go, no-go.""" assert set(get_args(LeadStatus)) == {"unverified", "spiking", "go", "no-go"} def test_lead_provenance_can_be_multiple() -> None: """A Lead may carry multiple provenance pointers.""" provs = [ Provenance(bibkey="A2020", locator="chunk 1"), Provenance(bibkey="B2021", locator="chunk 7"), ] lead = Lead( id="L-0002", kind="gap", title="t", body="b", provenance=provs, confidence=0.5, ) assert len(lead.provenance) == 2 def test_lead_missing_provenance_field_raises() -> None: """Constructing Lead without provenance is a TypeError.""" with pytest.raises(TypeError): Lead( # type: ignore[call-arg] id="L-0003", kind="connection", title="x", body="y", confidence=0.5, ) def test_lead_empty_provenance_raises() -> None: """Constructing Lead with empty provenance list raises ValueError.""" with pytest.raises(ValueError, match="at least one Provenance"): Lead( id="L-0004", kind="connection", title="x", body="y", provenance=[], confidence=0.5, ) def test_lead_id_format_helper() -> None: """The internal _make_lead_id helper produces zero-padded L-XXXX strings.""" from codex.synthesis import _make_lead_id assert _make_lead_id(1) == "L-0001" assert _make_lead_id(42) == "L-0042" assert _make_lead_id(9999) == "L-9999"