feat(synthesis): F-13 synthesis/lead-engine — grounded leads + conjecture quarantine #3

Merged
user2595 merged 2 commits from feat/F-13-synthesis-engine into main 2026-06-14 06:54:51 +00:00
2 changed files with 22 additions and 7 deletions
Showing only changes of commit 59763105a5 - Show all commits

View File

@@ -102,6 +102,13 @@ class Lead:
# Derived: claim-level grounding decisions (empty for conjectures). # Derived: claim-level grounding decisions (empty for conjectures).
claims: list[Claim] = field(default_factory=list) claims: list[Claim] = field(default_factory=list)
def __post_init__(self) -> None:
if not self.provenance:
raise ValueError(
f"Lead '{self.id}' must carry at least one Provenance entry. "
"For gap leads with no chunks, use a topic-marker Provenance."
)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Protocols # Protocols
@@ -432,7 +439,7 @@ def find_gaps(
f"The retrieval layer returned no chunks for topic '{topic}'.\n" f"The retrieval layer returned no chunks for topic '{topic}'.\n"
"No grounded statement is possible; this is the absence itself." "No grounded statement is possible; this is the absence itself."
), ),
provenance=[], provenance=[Provenance(bibkey="(none)", locator=f"topic:{topic}")],
confidence=1.0, confidence=1.0,
status="unverified", status="unverified",
suggested_validation=( suggested_validation=(
@@ -797,12 +804,7 @@ def write_leads(leads: list[Lead], leads_dir: str) -> None:
def _update_index(root: Path) -> None: def _update_index(root: Path) -> None:
"""Re-build ``root/INDEX.md`` from the on-disk files. """Re-build ``root/INDEX.md`` from the on-disk files (full rebuild, not append-only)."""
Append-only semantics: previously listed ids that no longer have a
file are still recorded under "Removed" so the index never silently
loses provenance.
"""
grounded_dir = root / "grounded" grounded_dir = root / "grounded"
conj_dir = root / "conjectures" conj_dir = root / "conjectures"
grounded_files = sorted(grounded_dir.glob("*.md")) if grounded_dir.exists() else [] grounded_files = sorted(grounded_dir.glob("*.md")) if grounded_dir.exists() else []

View File

@@ -78,6 +78,19 @@ def test_lead_missing_provenance_field_raises() -> None:
) )
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: def test_lead_id_format_helper() -> None:
"""The internal _make_lead_id helper produces zero-padded L-XXXX strings.""" """The internal _make_lead_id helper produces zero-padded L-XXXX strings."""
from codex.synthesis import _make_lead_id from codex.synthesis import _make_lead_id