refactor(evidence): migrate runtime consumption (#29)

This commit is contained in:
2026-08-24 02:10:06 +02:00
parent 8b63715b56
commit d5e78febd3
8 changed files with 128 additions and 58 deletions
+7 -11
View File
@@ -54,18 +54,16 @@ def search_cmd(
from rich.table import Table
from tht.cli.vector_cmd import make_embedder, open_searcher, require_vector_cfg
from tht.evidence import active_searcher, validate_corpus_workspace
from tht.lshindex import LshIndexError, load_index, query_index
from tht.search import combined_search
cfg = _load_config_or_exit(config)
from tht.search.evidence import validate_corpus_workspace
workspace_id = workspace_id_for_config(cfg, config)
validate_corpus_workspace(cfg, workspace_id)
dwh_snapshot = _leased_dwh_snapshot(cfg, ctx)
require_vector_cfg(cfg)
from tht.search.evidence import active_searcher
runtime_searcher = active_searcher(
cfg, open_searcher(cfg),
workspace_id=workspace_id,
@@ -255,13 +253,17 @@ def pack_cmd(
from sqlalchemy.exc import OperationalError
from tht.cli.vector_cmd import make_embedder, open_searcher, require_vector_cfg
from tht.evidence import (
active_searcher,
build_retrieval_entries,
validate_corpus_workspace,
)
from tht.ports.vector import VectorReadUnavailable, VectorStoreError
from tht.search import combined_search, schema_tables
from tht.memory import SOLVED_KIND
from tht.vectorstore.embeddings import EmbeddingsError
cfg = _load_config_or_exit(config)
from tht.search.evidence import validate_corpus_workspace
workspace_id = workspace_id_for_config(cfg, config)
validate_corpus_workspace(cfg, workspace_id)
@@ -277,8 +279,6 @@ def pack_cmd(
vec = None
searcher = embedder = None
try:
from tht.search.evidence import active_searcher
searcher = active_searcher(
cfg, open_searcher(cfg),
workspace_id=workspace_id,
@@ -314,11 +314,7 @@ def pack_cmd(
top=PACK_EVIDENCE_TOP, rrf_k=cfg.search.rrf_k,
kinds=KIND_MAP["evidence"], query_vec=vec,
)
evidence = [
{"title": r.label, "status": r.status,
"excerpt": r.content[:PACK_EXCERPT_CHARS]}
for r in ev
]
evidence = build_retrieval_entries(ev, excerpt_chars=PACK_EXCERPT_CHARS)
except degrade as e:
warnings.append(f"ricerca evidence fallita ({e})")
try:
+2 -2
View File
@@ -518,7 +518,7 @@ def finalize_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OP
from tht.execute import ExecutionError
from tht.execute.warnings import plan_warnings, runtime_warnings, static_warnings
from tht.report import extract_reviewer_notes, render_validation_report
from tht.session.artifacts import build_evidence_entries
from tht.evidence import project_session
from tht.phase import cte_plan as effective_cte_plan
from tht.phase import effective_decisions
from tht.session.models import SchemaLinking
@@ -614,7 +614,7 @@ def finalize_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OP
linking = SchemaLinking.model_validate(
json.loads(snapshot.artifacts["schema_linking"])
)
entries = build_evidence_entries(decisions, linking, cfg.paths.artifacts / "evidence")
entries = project_session(decisions, linking, cfg.paths.artifacts / "evidence")
evidence = json.dumps(entries, ensure_ascii=False, indent=2)
# --- manifest + riepilogo ---
+49 -3
View File
@@ -55,6 +55,18 @@ def validate_corpus_workspace(cfg, workspace_id: str) -> None:
legacy_validate(cfg, workspace_id)
def build_retrieval_entries(results, *, excerpt_chars: int) -> list[dict]:
"""Project ordered Evidence search hits into the existing retrieval-pack shape."""
return [
{
"title": result.label,
"status": result.status,
"excerpt": result.content[:excerpt_chars],
}
for result in results
]
def resolve_citation(
store: "CorpusStore",
evidence_id: str,
@@ -71,15 +83,48 @@ def resolve_citation(
)
def _resolve_session_citation(evidence_root: Path, evidence_id: str) -> str:
# New deployments resolve only immutable materialized files from ACTIVE. Keep the
# curated-tree fallback for sessions created before a canonical corpus exists.
corpus_root = evidence_root.parent.parent / "corpus"
if corpus_root.exists():
from tht.corpus.store import CorpusStore
return resolve_citation(
CorpusStore(corpus_root),
evidence_id,
materialized_root=evidence_root.parent / ".materialized-evidence",
)
for match in evidence_root.rglob(f"{evidence_id}.md"):
return str(match)
return ""
def project_session(
decisions: list["DecisionRecord"],
linking: "SchemaLinking",
evidence_root: Path,
) -> list[dict]:
"""Project cited and reviewed Evidence into the existing session artifact shape."""
from tht.session.artifacts import build_evidence_entries
return build_evidence_entries(decisions, linking, evidence_root)
entries: dict[str, dict] = {}
for candidate in linking.candidates:
for evidence_id in candidate.evidence:
entries.setdefault(evidence_id, {
"id": evidence_id,
"file": _resolve_session_citation(evidence_root, evidence_id),
"esito": "usata",
"decision_seq": candidate.decision_seq,
})
for decision in decisions:
if decision.type not in ("evidence_accepted", "evidence_rejected"):
continue
entries[decision.subject] = {
"id": decision.subject,
"file": _resolve_session_citation(evidence_root, decision.subject),
"esito": "accettata" if decision.type == "evidence_accepted" else "scartata",
"decision_seq": decision.seq,
}
return list(entries.values())
__all__ = [
@@ -90,6 +135,7 @@ __all__ = [
"SourceObject",
"acquire",
"active_searcher",
"build_retrieval_entries",
"discover",
"project_session",
"resolve_citation",
+6 -38
View File
@@ -1,49 +1,17 @@
"""Legacy session-artifact entrypoints retained during the Evidence migration."""
from pathlib import Path
from tht.decisions import DecisionRecord
from tht.session.models import SchemaLinking
def _find_evidence_file(evidence_root: Path, evidence_id: str) -> str:
# New deployments resolve only immutable materialized files from ACTIVE. Keep
# the legacy curated-tree fallback for sessions created before a corpus exists.
corpus_root = evidence_root.parent.parent / "corpus"
if corpus_root.exists():
from tht.corpus.store import CorpusStore
from tht.search.evidence import resolve_evidence_file
return resolve_evidence_file(
CorpusStore(corpus_root), evidence_id,
materialized_root=evidence_root.parent / ".materialized-evidence",
)
for match in evidence_root.rglob(f"{evidence_id}.md"):
return str(match)
return ""
def build_evidence_entries(
decisions: list[DecisionRecord],
linking: SchemaLinking,
evidence_root: Path,
) -> list[dict]:
"""Elenco {id, file, esito, decision_seq}: evidence citate nello schema linking
(esito 'usata') e decisioni esplicite del reviewer (accettata/scartata, che
prevalgono sul linking)."""
entries: dict[str, dict] = {}
for candidate in linking.candidates:
for evidence_id in candidate.evidence:
entries.setdefault(evidence_id, {
"id": evidence_id,
"file": _find_evidence_file(evidence_root, evidence_id),
"esito": "usata",
"decision_seq": candidate.decision_seq,
})
for d in decisions:
if d.type not in ("evidence_accepted", "evidence_rejected"):
continue
entries[d.subject] = {
"id": d.subject,
"file": _find_evidence_file(evidence_root, d.subject),
"esito": "accettata" if d.type == "evidence_accepted" else "scartata",
"decision_seq": d.seq,
}
return list(entries.values())
"""Compatibility shim for callers not yet migrated to ``tht.evidence``."""
from tht.evidence import project_session
return project_session(decisions, linking, evidence_root)