feat(evidence): add table-free v3 and design guidance
This commit is contained in:
@@ -121,7 +121,7 @@ def pipeline(tmp_path, source, *, embedder=None, vectors=None, model="model-a",
|
||||
def test_pipeline_embeds_validated_curated_evidence_as_semantic_fragments(tmp_path):
|
||||
evidence = CuratedEvidence.model_validate(
|
||||
{
|
||||
"schema_version": 2,
|
||||
"schema_version": 3,
|
||||
"id": "evidence:fascia-pediatrica",
|
||||
"title": "Fascia pediatrica",
|
||||
"kind": "formula",
|
||||
|
||||
@@ -350,12 +350,12 @@ def test_prepare_changed_source_uses_one_model_call_and_applies_a_valid_batch(tm
|
||||
assert restructurer.requests[0].previous_units[0].id == "evidence:fascia-pediatrica"
|
||||
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
||||
curated = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
||||
assert curated.schema_version == 2
|
||||
assert curated.schema_version == 3
|
||||
assert "# Fascia pediatrica\n" in curated_path.read_text(encoding="utf-8")
|
||||
assert validate_workspace_evidence(tmp_path).publishable is True
|
||||
|
||||
|
||||
def test_migrate_workspace_evidence_rewrites_v1_units_without_a_model_call(tmp_path):
|
||||
def test_migrate_workspace_evidence_rewrites_v1_units_as_v3_without_a_model_call(tmp_path):
|
||||
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
||||
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
||||
|
||||
@@ -365,7 +365,7 @@ def test_migrate_workspace_evidence_rewrites_v1_units_without_a_model_call(tmp_p
|
||||
migrated = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
||||
assert report.migrated == ("evidence:fascia-pediatrica",)
|
||||
assert report.unchanged == ()
|
||||
assert migrated.schema_version == 2
|
||||
assert migrated.schema_version == 3
|
||||
assert migrated.payload.rule == "La fascia pediatrica comprende i minori."
|
||||
assert "## Regola\n\nLa fascia pediatrica comprende i minori." in curated_path.read_text(
|
||||
encoding="utf-8",
|
||||
@@ -373,6 +373,26 @@ def test_migrate_workspace_evidence_rewrites_v1_units_without_a_model_call(tmp_p
|
||||
assert report.findings == ()
|
||||
|
||||
|
||||
def test_migrate_workspace_evidence_rewrites_v2_units_as_table_free_v3(tmp_path):
|
||||
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
||||
evidence = _evidence(source_text).model_copy(update={"schema_version": 2})
|
||||
_write_workspace(tmp_path, evidence, source_text)
|
||||
|
||||
first = migrate_workspace_evidence(tmp_path, git_status=lambda _: ())
|
||||
second = migrate_workspace_evidence(tmp_path, git_status=lambda _: ())
|
||||
|
||||
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
||||
text = curated_path.read_text(encoding="utf-8")
|
||||
migrated = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
||||
assert first.migrated == ("evidence:fascia-pediatrica",)
|
||||
assert first.unchanged == ()
|
||||
assert second.migrated == ()
|
||||
assert second.unchanged == ("evidence:fascia-pediatrica",)
|
||||
assert migrated.schema_version == 3
|
||||
assert text.startswith("<!-- tht:metadata:")
|
||||
assert not any(line.startswith("|") for line in text.splitlines())
|
||||
|
||||
|
||||
def test_migrate_workspace_evidence_rejects_dirty_curated_files_in_a_nested_workspace(tmp_path):
|
||||
subprocess.run(["git", "init", "--quiet", str(tmp_path)], check=True)
|
||||
workspace_root = tmp_path / "psd-clinical"
|
||||
@@ -546,7 +566,7 @@ def test_prepare_marks_an_omitted_prior_unit_for_human_review(tmp_path):
|
||||
"supporting_excerpt_missing", "unresolved_review_item",
|
||||
]
|
||||
retained = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
||||
assert retained.schema_version == 2
|
||||
assert retained.schema_version == 3
|
||||
assert retained.review_items[0].code == "source_no_longer_supports_unit"
|
||||
|
||||
|
||||
|
||||
@@ -221,6 +221,79 @@ def _domain_evidence_v2() -> CuratedEvidence:
|
||||
})
|
||||
|
||||
|
||||
def _domain_evidence_v3() -> CuratedEvidence:
|
||||
return CuratedEvidence.model_validate({
|
||||
**COMMON,
|
||||
"schema_version": 3,
|
||||
"title": "Dominio Ablazione",
|
||||
"kind": "domain",
|
||||
"purposes": ["disambiguation", "schema_linking", "rewriting"],
|
||||
"applies_to": {
|
||||
"concepts": ["ablazione", "studio elettrofisiologico", "SEE"],
|
||||
"tables": ["clinical.fact_ablazione"],
|
||||
"columns": ["clinical.fact_ablazione.patient_id"],
|
||||
},
|
||||
"payload": {
|
||||
"rule": (
|
||||
"Il dominio Ablazione rappresenta la procedura transcatetere.\n\n"
|
||||
"La fact centrale è `clinical.fact_ablazione`."
|
||||
),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
def test_v3_curated_markdown_replaces_frontmatter_tables_with_readable_sections(tmp_path):
|
||||
evidence = _domain_evidence_v3()
|
||||
path = tmp_path / "curated" / "domain" / "dominio-ablazione.md"
|
||||
|
||||
text = dump_curated_markdown(evidence)
|
||||
parsed = parse_curated_markdown(text, path=path)
|
||||
|
||||
assert text.startswith("<!-- tht:metadata:")
|
||||
assert not text.startswith("---\n")
|
||||
assert not any(line.startswith("|") for line in text.splitlines())
|
||||
assert "> **Dominio** · Italiano" in text
|
||||
assert "**Scopi:** Disambiguazione · Collegamento allo schema · Riscrittura" in text
|
||||
assert "## Ambito di applicazione" in text
|
||||
assert "### Concetti\n\n- ablazione\n- studio elettrofisiologico\n- SEE" in text
|
||||
assert "### Tabelle\n\n- `clinical.fact_ablazione`" in text
|
||||
assert "### Colonne\n\n- `clinical.fact_ablazione.patient_id`" in text
|
||||
assert "<summary>Dettagli tecnici e provenienza</summary>" in text
|
||||
assert parsed == evidence
|
||||
|
||||
|
||||
def test_v3_curated_markdown_renders_enum_values_as_a_list_instead_of_a_table(tmp_path):
|
||||
evidence = CuratedEvidence.model_validate({
|
||||
**COMMON,
|
||||
"schema_version": 3,
|
||||
"kind": "enum",
|
||||
"payload": {
|
||||
"column": "clinical.episode.discharge_status",
|
||||
"values": {"D": "dimesso", "T": "trasferito | altra struttura"},
|
||||
},
|
||||
})
|
||||
|
||||
text = dump_curated_markdown(evidence)
|
||||
|
||||
assert "## Valori\n\n- `D`: dimesso\n- `T`: trasferito | altra struttura" in text
|
||||
assert not any(line.startswith("|") for line in text.splitlines())
|
||||
assert parse_curated_markdown(
|
||||
text,
|
||||
path=tmp_path / "curated" / "enum" / "discharge-status.md",
|
||||
) == evidence
|
||||
|
||||
|
||||
def test_v3_curated_markdown_rejects_visible_metadata_that_drifted_from_canonical_data():
|
||||
text = dump_curated_markdown(_domain_evidence_v3()).replace(
|
||||
"**Scopi:** Disambiguazione",
|
||||
"**Scopi:** Testo alterato",
|
||||
1,
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError, match="not canonical"):
|
||||
parse_curated_markdown(text)
|
||||
|
||||
|
||||
def test_v2_curated_markdown_renders_domain_content_in_the_markdown_body(tmp_path):
|
||||
evidence = _domain_evidence_v2()
|
||||
path = tmp_path / "curated" / "domain" / "dominio-ablazione.md"
|
||||
|
||||
Reference in New Issue
Block a user