|
|
|
@@ -316,18 +316,18 @@ class _Restructurer(EvidenceRestructurer):
|
|
|
|
|
return tuple(self.candidates)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _candidate(*, title="Fascia pediatrica", existing_id=None):
|
|
|
|
|
def _candidate(*, title="Fascia pediatrica", existing_id=None, kind="domain", payload=None):
|
|
|
|
|
return RestructureCandidate.model_validate({
|
|
|
|
|
"schema_version": 1,
|
|
|
|
|
"existing_id": existing_id,
|
|
|
|
|
"title": title,
|
|
|
|
|
"kind": "domain",
|
|
|
|
|
"kind": kind,
|
|
|
|
|
"purposes": ["disambiguation"],
|
|
|
|
|
"applies_to": {"concepts": ["fascia pediatrica"]},
|
|
|
|
|
"language": "it",
|
|
|
|
|
"supporting_excerpts": ["I pazienti sotto i 18 anni sono pediatrici."],
|
|
|
|
|
"review_items": [],
|
|
|
|
|
"payload": {"rule": "La fascia pediatrica comprende i minori."},
|
|
|
|
|
"payload": payload or {"rule": "La fascia pediatrica comprende i minori."},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -378,6 +378,47 @@ def test_prepare_rejects_dirty_curated_state_before_model_call(tmp_path):
|
|
|
|
|
assert restructurer.requests == []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_prepare_refuses_an_incompatible_pipeline_version_without_writing(tmp_path):
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
manifest_path = tmp_path / "evidence" / "manifest.yaml"
|
|
|
|
|
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
|
|
|
|
manifest_path.write_text(
|
|
|
|
|
manifest_path.read_text(encoding="utf-8").replace("evidence-authoring-v1", "evidence-authoring-v2"),
|
|
|
|
|
encoding="utf-8",
|
|
|
|
|
)
|
|
|
|
|
original_manifest = manifest_path.read_text(encoding="utf-8")
|
|
|
|
|
original_curated = curated_path.read_text(encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
with pytest.raises(EvidencePreparationError, match="pipeline_upgrade_required"):
|
|
|
|
|
prepare_workspace_evidence(tmp_path, restructurer=_Restructurer([]), git_status=lambda _: ())
|
|
|
|
|
|
|
|
|
|
assert manifest_path.read_text(encoding="utf-8") == original_manifest
|
|
|
|
|
assert curated_path.read_text(encoding="utf-8") == original_curated
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_prepare_preserves_an_id_when_reclassified_and_allocates_a_new_id_for_a_split(tmp_path):
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
source_path = tmp_path / "evidence" / "source" / "domain" / "patient.md"
|
|
|
|
|
source_path.write_text(source_text + " I pazienti sopra i 18 anni sono adulti.\n", encoding="utf-8")
|
|
|
|
|
restructurer = _Restructurer([
|
|
|
|
|
_candidate(
|
|
|
|
|
existing_id="evidence:fascia-pediatrica",
|
|
|
|
|
kind="glossary",
|
|
|
|
|
payload={"definition": "Paziente con meno di 18 anni."},
|
|
|
|
|
),
|
|
|
|
|
_candidate(title="Fascia adulta"),
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
report = prepare_workspace_evidence(tmp_path, restructurer=restructurer, git_status=lambda _: ())
|
|
|
|
|
|
|
|
|
|
assert report.created == ("evidence:fascia-adulta",)
|
|
|
|
|
documents = {document.id: document for document in load_curated_tree(tmp_path / "evidence" / "curated")}
|
|
|
|
|
assert documents["evidence:fascia-pediatrica"].kind == "glossary"
|
|
|
|
|
assert documents["evidence:fascia-adulta"].kind == "domain"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_prepare_retains_units_from_a_removed_source_as_blocking_orphans(tmp_path):
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
@@ -437,3 +478,146 @@ def test_prepare_marks_an_omitted_prior_unit_for_human_review(tmp_path):
|
|
|
|
|
]
|
|
|
|
|
retained = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
|
|
|
|
assert retained.review_items[0].code == "source_no_longer_supports_unit"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_retires_an_orphan_and_updates_curated_content_and_manifest_atomically(tmp_path):
|
|
|
|
|
from tht.evidence import resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
source_path = tmp_path / "evidence" / "source" / "domain" / "patient.md"
|
|
|
|
|
source_path.unlink()
|
|
|
|
|
prepare_workspace_evidence(tmp_path, restructurer=_Restructurer([]), git_status=lambda _: ())
|
|
|
|
|
|
|
|
|
|
report = resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
retire=True,
|
|
|
|
|
git_status=lambda _: (),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert report.action == "retired"
|
|
|
|
|
assert report.evidence_id == "evidence:fascia-pediatrica"
|
|
|
|
|
assert not (tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md").exists()
|
|
|
|
|
manifest = load_manifest(tmp_path / "evidence" / "manifest.yaml")
|
|
|
|
|
assert manifest.orphans == ()
|
|
|
|
|
assert manifest.sources == {}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_relinks_an_unit_and_updates_its_manifest_membership(tmp_path):
|
|
|
|
|
from tht.evidence import resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
next_source = tmp_path / "evidence" / "source" / "domain" / "patient-age.md"
|
|
|
|
|
next_source.write_text(source_text, encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
report = resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
source="source/domain/patient-age.md",
|
|
|
|
|
git_status=lambda _: (),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert report.action == "relinked"
|
|
|
|
|
assert report.source_file == "source/domain/patient-age.md"
|
|
|
|
|
document = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
|
|
|
|
assert document.provenance.source_file == "source/domain/patient-age.md"
|
|
|
|
|
manifest = load_manifest(tmp_path / "evidence" / "manifest.yaml")
|
|
|
|
|
assert manifest.sources["source/domain/patient.md"].units == ()
|
|
|
|
|
assert manifest.sources["source/domain/patient-age.md"].units == ("evidence:fascia-pediatrica",)
|
|
|
|
|
assert validate_workspace_evidence(tmp_path).publishable is True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_relink_clears_an_unsupported_review_item_when_the_new_source_supports_it(tmp_path):
|
|
|
|
|
from tht.evidence import resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
source_path = tmp_path / "evidence" / "source" / "domain" / "patient.md"
|
|
|
|
|
source_path.write_text("La classificazione pediatrica non è documentata.\n", encoding="utf-8")
|
|
|
|
|
prepare_workspace_evidence(tmp_path, restructurer=_Restructurer([]), git_status=lambda _: ())
|
|
|
|
|
replacement_source = tmp_path / "evidence" / "source" / "domain" / "patient-revised.md"
|
|
|
|
|
replacement_source.write_text(source_text, encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
report = resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
source="source/domain/patient-revised.md",
|
|
|
|
|
git_status=lambda _: (),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert report.findings == ()
|
|
|
|
|
document = load_curated_tree(tmp_path / "evidence" / "curated")[0]
|
|
|
|
|
assert all(item.code != "source_no_longer_supports_unit" for item in document.review_items)
|
|
|
|
|
assert validate_workspace_evidence(tmp_path).publishable is True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_refuses_an_unsafe_relink_without_writing(tmp_path):
|
|
|
|
|
from tht.evidence import EvidencePreparationError, resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
|
|
|
|
manifest_path = tmp_path / "evidence" / "manifest.yaml"
|
|
|
|
|
original_curated = curated_path.read_text(encoding="utf-8")
|
|
|
|
|
original_manifest = manifest_path.read_text(encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
with pytest.raises(EvidencePreparationError, match="source_invalid"):
|
|
|
|
|
resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
source="../outside.md",
|
|
|
|
|
git_status=lambda _: (),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert curated_path.read_text(encoding="utf-8") == original_curated
|
|
|
|
|
assert manifest_path.read_text(encoding="utf-8") == original_manifest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_refuses_a_relink_through_a_symlinked_source_directory(tmp_path):
|
|
|
|
|
from tht.evidence import EvidencePreparationError, resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
|
|
|
|
manifest_path = tmp_path / "evidence" / "manifest.yaml"
|
|
|
|
|
original_curated = curated_path.read_text(encoding="utf-8")
|
|
|
|
|
original_manifest = manifest_path.read_text(encoding="utf-8")
|
|
|
|
|
source_root = tmp_path / "evidence" / "source"
|
|
|
|
|
outside_source = tmp_path / "outside-source"
|
|
|
|
|
source_root.rename(outside_source)
|
|
|
|
|
source_root.symlink_to(outside_source, target_is_directory=True)
|
|
|
|
|
|
|
|
|
|
with pytest.raises(EvidencePreparationError, match="source_invalid"):
|
|
|
|
|
resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
source="source/domain/patient.md",
|
|
|
|
|
git_status=lambda _: (),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert curated_path.read_text(encoding="utf-8") == original_curated
|
|
|
|
|
assert manifest_path.read_text(encoding="utf-8") == original_manifest
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_resolve_rejects_any_dirty_worktree_without_writing(tmp_path):
|
|
|
|
|
from tht.evidence import EvidencePreparationError, resolve_workspace_evidence
|
|
|
|
|
|
|
|
|
|
source_text = "I pazienti sotto i 18 anni sono pediatrici."
|
|
|
|
|
_write_workspace(tmp_path, _evidence(source_text), source_text)
|
|
|
|
|
curated_path = tmp_path / "evidence" / "curated" / "domain" / "fascia-pediatrica.md"
|
|
|
|
|
manifest_path = tmp_path / "evidence" / "manifest.yaml"
|
|
|
|
|
original_curated = curated_path.read_text(encoding="utf-8")
|
|
|
|
|
original_manifest = manifest_path.read_text(encoding="utf-8")
|
|
|
|
|
|
|
|
|
|
with pytest.raises(EvidencePreparationError, match="worktree_dirty"):
|
|
|
|
|
resolve_workspace_evidence(
|
|
|
|
|
tmp_path,
|
|
|
|
|
"evidence:fascia-pediatrica",
|
|
|
|
|
retire=True,
|
|
|
|
|
git_status=lambda _: (" M README.md",),
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
assert curated_path.read_text(encoding="utf-8") == original_curated
|
|
|
|
|
assert manifest_path.read_text(encoding="utf-8") == original_manifest
|
|
|
|
|