feat(synthesis): Lead/Provenance model + grounded leads + conjecture generator
- codex/synthesis.py: Lead/Provenance dataclasses, find_connections/gaps/improvements, propose_conjectures (status=unverified, quarantined in leads/conjectures/), write_leads (grounded→leads/grounded/, conjectures→leads/conjectures/ HARD invariant) - codex/cli.py: synthesis leads/conjectures/report command group - codex/config.py: F-13 settings (leads_dir, synthesis_llm_*, synthesis_top_k, synthesis_min_grounded_ratio, synthesis_gap_min_coverage) - tests/synthesis/: 42 tests covering model, grounding, conjecture invariant, quarantine, CLI - spike/: F-13 spike script + output (live run attempted) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
124
tests/synthesis/conftest.py
Normal file
124
tests/synthesis/conftest.py
Normal file
@@ -0,0 +1,124 @@
|
||||
"""Shared synthesis fixtures — keep DB/LLM/embed fully mocked."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
# Shared corpus fixture used across the test suite.
|
||||
FIXTURE_CHUNKS: list[dict[str, Any]] = [
|
||||
{
|
||||
"id": 1,
|
||||
"paper_id": "springborn-2008",
|
||||
"ord": 16,
|
||||
"content": (
|
||||
"For an ideal tetrahedron with dihedral angles the hyperbolic volume is "
|
||||
"V = L(gamma1) + L(gamma2) + L(gamma3). "
|
||||
"The volume function V0 is strictly concave on the angle domain."
|
||||
),
|
||||
"bibkey": "Springborn2008",
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"paper_id": "bps-2015",
|
||||
"ord": 3,
|
||||
"content": (
|
||||
"A discrete conformal map is defined by logarithmic scale factors u_i "
|
||||
"at each vertex such that the edge lengths satisfy a compatibility condition."
|
||||
),
|
||||
"bibkey": "BobenkoPinkallSpringborn2015",
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"paper_id": "luo-2004",
|
||||
"ord": 0,
|
||||
"content": (
|
||||
"The combinatorial Yamabe flow drives the edge lengths towards a target "
|
||||
"curvature on a triangulated surface."
|
||||
),
|
||||
"bibkey": "Luo2004",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class StubLLM:
|
||||
"""Deterministic mock LLM that returns a preset response."""
|
||||
|
||||
def __init__(self, response: str | list[str]) -> None:
|
||||
if isinstance(response, str):
|
||||
self._responses = [response]
|
||||
else:
|
||||
self._responses = list(response)
|
||||
self._calls: list[tuple[str, str]] = []
|
||||
|
||||
def generate(self, prompt: str, model: str) -> str:
|
||||
self._calls.append((prompt, model))
|
||||
if not self._responses:
|
||||
return ""
|
||||
if len(self._responses) == 1:
|
||||
return self._responses[0]
|
||||
return self._responses.pop(0)
|
||||
|
||||
@property
|
||||
def calls(self) -> list[tuple[str, str]]:
|
||||
return list(self._calls)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def stub_llm() -> StubLLM:
|
||||
"""Default stub returning empty string (override per test as needed)."""
|
||||
return StubLLM("")
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fixture_chunks() -> list[dict[str, Any]]:
|
||||
return [dict(c) for c in FIXTURE_CHUNKS]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_retrieve(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Patch _retrieve_chunks to return deterministic fixture chunks (no DB)."""
|
||||
monkeypatch.setattr(
|
||||
"codex.synthesis._retrieve_chunks",
|
||||
lambda queries, top_k: [dict(c) for c in FIXTURE_CHUNKS],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_paper_titles(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
"""Patch _list_paper_titles to return a deterministic three-paper corpus."""
|
||||
monkeypatch.setattr(
|
||||
"codex.synthesis._list_paper_titles",
|
||||
lambda db_conn: [
|
||||
("Springborn2008", "A variational principle for weighted Delaunay triangulations"),
|
||||
(
|
||||
"BobenkoPinkallSpringborn2015",
|
||||
"Discrete conformal maps and ideal hyperbolic polyhedra",
|
||||
),
|
||||
("Luo2004", "Combinatorial Yamabe Flow on Surfaces"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_settings(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> Path:
|
||||
"""Settings stub pointing leads_dir at tmp_path/leads."""
|
||||
from codex.config import Settings
|
||||
|
||||
leads_path = tmp_path / "leads"
|
||||
|
||||
mock = MagicMock(spec=Settings)
|
||||
mock.leads_dir = str(leads_path)
|
||||
mock.synthesis_llm_model = "test-model"
|
||||
mock.synthesis_llm_url = None
|
||||
mock.ollama_base_url = "http://localhost:11434"
|
||||
mock.synthesis_top_k = 6
|
||||
mock.synthesis_min_grounded_ratio = 0.5
|
||||
mock.synthesis_gap_min_coverage = 2
|
||||
mock.wiki_dir = str(tmp_path / "wiki")
|
||||
|
||||
monkeypatch.setattr("codex.synthesis.get_settings", lambda: mock)
|
||||
return leads_path
|
||||
Reference in New Issue
Block a user