fix(evidence): resolve final review findings
This commit is contained in:
@@ -45,8 +45,19 @@ def _evaluation_workspace_root(cfg) -> Path:
|
||||
return root
|
||||
|
||||
|
||||
def _requires_candidate_evaluation(cfg) -> bool:
|
||||
evidence = cfg.evidence
|
||||
if evidence is None or evidence.schema_version != 2:
|
||||
return False
|
||||
return evidence.source_root is not None or any(
|
||||
source.type == "filesystem" for source in evidence.sources
|
||||
)
|
||||
|
||||
|
||||
def _candidate_evaluator(cfg, *, vector_store, embedder):
|
||||
"""Bind candidate publication to the same read-only retrieval evaluator as the CLI."""
|
||||
if not _requires_candidate_evaluation(cfg):
|
||||
return None
|
||||
from tht.evidence.canonical import load_curated_tree
|
||||
from tht.evidence.evaluation import evaluate_retrieval, load_evaluation_fixture
|
||||
|
||||
@@ -77,9 +88,7 @@ def _candidate_evaluator(cfg, *, vector_store, embedder):
|
||||
|
||||
def _validate_materialized_curated_corpus(cfg) -> None:
|
||||
"""Fail closed on a v2 pinned filesystem corpus before any vector write is possible."""
|
||||
if cfg.evidence is None or cfg.evidence.schema_version != 2:
|
||||
return
|
||||
if not any(source.type == "filesystem" for source in cfg.evidence.sources):
|
||||
if not _requires_candidate_evaluation(cfg):
|
||||
return
|
||||
from tht.evidence import validate_workspace_evidence
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import re
|
||||
import unicodedata
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
@@ -121,6 +122,7 @@ def legacy_formula_to_curated(
|
||||
formula: ConceptFormula,
|
||||
*,
|
||||
legacy_path: str,
|
||||
source_content: str | None = None,
|
||||
) -> CuratedEvidence | LegacyFormulaMigrationFailure | None:
|
||||
"""Convert one reviewed legacy formula into its deterministic curated counterpart.
|
||||
|
||||
@@ -129,10 +131,39 @@ def legacy_formula_to_curated(
|
||||
"""
|
||||
if formula.status != "reviewed":
|
||||
return None
|
||||
source_notes = tuple(formula.sources) or (
|
||||
"Legacy formula migrated without a recorded provenance note.",
|
||||
)
|
||||
source_sha256 = hashlib.sha256(formula.dump().encode("utf-8")).hexdigest()
|
||||
problems: list[str] = []
|
||||
normalized_source: str | None = None
|
||||
if source_content is None:
|
||||
problems.append("original_source_required")
|
||||
else:
|
||||
from tht.evidence.authoring import normalize_source_text
|
||||
|
||||
normalized_source = normalize_source_text(source_content)
|
||||
try:
|
||||
original_formula = ConceptFormula.parse(source_content)
|
||||
except (TypeError, ValidationError, ValueError, yaml.YAMLError):
|
||||
problems.append("original_source_invalid")
|
||||
else:
|
||||
if original_formula != formula:
|
||||
problems.append("original_source_mismatch")
|
||||
source_notes = tuple(formula.sources)
|
||||
if not source_notes:
|
||||
problems.append("supporting_excerpts_required")
|
||||
elif normalized_source is not None and any(
|
||||
unicodedata.normalize("NFC", note.replace("\r\n", "\n").replace("\r", "\n"))
|
||||
not in normalized_source
|
||||
for note in source_notes
|
||||
):
|
||||
problems.append("supporting_excerpt_unverified")
|
||||
if problems:
|
||||
return LegacyFormulaMigrationFailure(
|
||||
code="legacy_formula_requires_manual_review",
|
||||
legacy_path=legacy_path,
|
||||
formula=formula,
|
||||
problems=tuple(sorted(problems)),
|
||||
)
|
||||
assert normalized_source is not None
|
||||
source_sha256 = hashlib.sha256(normalized_source.encode("utf-8")).hexdigest()
|
||||
source_file = legacy_path if legacy_path.startswith("source/") else f"source/{legacy_path}"
|
||||
# The legacy path is the immutable identity of this unit during migration. Keeping
|
||||
# its full digest avoids a duplicate public ID when the same concept has reviewed
|
||||
|
||||
Reference in New Issue
Block a user