feat: complete evidence restructuring worktree
This commit is contained in:
@@ -1,63 +1,14 @@
|
||||
"""D14b wiring: status=auto, search_formulas, and evidence loader skips formula files.
|
||||
"""L1: Formula Evidence search uses only the typed, published Evidence surface."""
|
||||
|
||||
Completes the formula layer beyond the store: the `auto` status the spec requires
|
||||
(§4.7.2), the concept-substring retrieval that `tht search find --kind formula` uses,
|
||||
and the guarantee that load_evidence_dir does NOT choke on *.sql.md formula files when
|
||||
they live under the evidence root.
|
||||
"""
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from tht.cli import app, search_cmd
|
||||
from tht.evidence import formula_store
|
||||
from tht.evidence.formula_store import ConceptFormula, save_formula, search_formulas
|
||||
from tht.evidence.model import EvidenceDoc, load_evidence_dir
|
||||
from tht.evidence.search import EvidenceSearchOutcome
|
||||
|
||||
|
||||
def test_status_auto_is_valid():
|
||||
f = ConceptFormula(concept="x", sql="SELECT 1", status="auto")
|
||||
assert f.status == "auto"
|
||||
# round-trips through parse/dump
|
||||
assert ConceptFormula.parse(f.dump()).status == "auto"
|
||||
|
||||
|
||||
def test_search_formulas_substring_case_insensitive(tmp_path):
|
||||
save_formula(tmp_path, ConceptFormula(concept="fascia pediatrica", sql="SELECT 1"))
|
||||
save_formula(tmp_path, ConceptFormula(concept="indice di Charlson", sql="SELECT 2"))
|
||||
hits = search_formulas(tmp_path, "PEDIATRICA")
|
||||
assert len(hits) == 1
|
||||
assert hits[0].concept == "fascia pediatrica"
|
||||
assert search_formulas(tmp_path, "charlson")[0].concept == "indice di Charlson"
|
||||
|
||||
|
||||
def test_load_evidence_dir_skips_formula_files(tmp_path):
|
||||
# a real evidence doc + a formula file under the same root
|
||||
(tmp_path / "ev1.md").write_text(
|
||||
"---\nid: ev1\ntitle: T\n---\nbody text\n"
|
||||
)
|
||||
save_formula(tmp_path, ConceptFormula(concept="ablazione", sql="SELECT 1"))
|
||||
docs = load_evidence_dir(tmp_path)
|
||||
ids = [d.id for d in docs]
|
||||
assert ids == ["ev1"] # the .sql.md formula file is skipped, no crash
|
||||
assert all(isinstance(d, EvidenceDoc) for d in docs)
|
||||
|
||||
|
||||
def test_unreviewed_legacy_formulas_cannot_become_curated_evidence():
|
||||
for status in ("auto", "draft"):
|
||||
formula = ConceptFormula(
|
||||
concept="fascia pediatrica",
|
||||
columns=["clinical.patient.birth_date"],
|
||||
sql="CASE WHEN age < 18 THEN 'pediatrica' ELSE 'adulta' END",
|
||||
status=status,
|
||||
)
|
||||
assert formula_store.legacy_formula_to_curated(
|
||||
formula, legacy_path="formulas/pediatric-1.sql.md",
|
||||
) is None
|
||||
|
||||
|
||||
def test_formula_search_uses_typed_evidence_with_a_formula_constraint():
|
||||
class Searcher:
|
||||
vector_generation = "gen:" + "a" * 32
|
||||
@@ -68,8 +19,11 @@ def test_formula_search_uses_typed_evidence_with_a_formula_constraint():
|
||||
def search(self, embedding, **kwargs):
|
||||
self.calls.append((embedding, kwargs))
|
||||
return [SimpleNamespace(
|
||||
id="fragment:formula", similarity=0.9, content="formula excerpt",
|
||||
title="Fascia pediatrica", metadata={
|
||||
id="fragment:formula",
|
||||
similarity=0.9,
|
||||
content="formula excerpt",
|
||||
title="Fascia pediatrica",
|
||||
metadata={
|
||||
"evidence_id": "evidence:fascia-pediatrica",
|
||||
"evidence_kind": "formula",
|
||||
"document_id": "doc:formula",
|
||||
@@ -89,16 +43,26 @@ def test_formula_search_uses_typed_evidence_with_a_formula_constraint():
|
||||
)
|
||||
|
||||
assert outcome.status == "available"
|
||||
assert [result.evidence_id for result in outcome.results] == ["evidence:fascia-pediatrica"]
|
||||
assert [result.evidence_id for result in outcome.results] == [
|
||||
"evidence:fascia-pediatrica",
|
||||
]
|
||||
assert searcher.calls[0][1]["metadata_filter"]["required_kinds"] == ["formula"]
|
||||
|
||||
|
||||
def test_formula_search_json_is_pristine_while_human_output_warns_about_legacy_store(monkeypatch):
|
||||
monkeypatch.setattr(search_cmd, "_load_config_or_exit", lambda _path: SimpleNamespace(embeddings=object()))
|
||||
def test_formula_search_json_is_pristine_and_human_output_uses_only_published_evidence(
|
||||
monkeypatch,
|
||||
):
|
||||
monkeypatch.setattr(
|
||||
search_cmd,
|
||||
"_load_config_or_exit",
|
||||
lambda _path: SimpleNamespace(embeddings=object()),
|
||||
)
|
||||
monkeypatch.setattr(search_cmd, "workspace_id_for_config", lambda _cfg, _path: "workspace-a")
|
||||
monkeypatch.setattr(search_cmd, "search_formula_evidence", lambda *args, **kwargs: EvidenceSearchOutcome(
|
||||
"available", "gen:" + "a" * 32,
|
||||
))
|
||||
monkeypatch.setattr(
|
||||
search_cmd,
|
||||
"search_formula_evidence",
|
||||
lambda *args, **kwargs: EvidenceSearchOutcome("available", "gen:" + "a" * 32),
|
||||
)
|
||||
monkeypatch.setattr("tht.cli.vector_cmd.require_vector_cfg", lambda _cfg: None)
|
||||
monkeypatch.setattr("tht.cli.vector_cmd.open_searcher", lambda _cfg: object())
|
||||
monkeypatch.setattr("tht.cli.vector_cmd.make_embedder", lambda _cfg: object())
|
||||
@@ -114,6 +78,6 @@ def test_formula_search_json_is_pristine_while_human_output_warns_about_legacy_s
|
||||
|
||||
assert json_result.exit_code == 0
|
||||
assert json.loads(json_result.stdout) == []
|
||||
assert "ATTENZIONE" not in json_result.stdout
|
||||
assert human_result.exit_code == 0
|
||||
assert "ATTENZIONE" in human_result.output
|
||||
assert "ATTENZIONE" not in human_result.output
|
||||
assert "Nessuna formula" in human_result.output
|
||||
|
||||
Reference in New Issue
Block a user