feat: redesign persisted session summaries

This commit is contained in:
2026-07-23 15:35:31 +02:00
parent 12c7a976d7
commit 0db85e4e4e
12 changed files with 1090 additions and 71 deletions
+182 -1
View File
@@ -1,10 +1,13 @@
"""Tests for `tht session documents --json` and build_documents."""
import json
from datetime import datetime
from typer.testing import CliRunner
from tht.config import DatabaseConfig
from tht.session.store import build_documents, create_session
from tht.decisions import DecisionRecord
from tht.session.models import SessionSnapshot
from tht.session.store import build_documents, build_snapshot_documents, create_session
from tht.cli.session_cmd import session_app
@@ -38,6 +41,184 @@ def test_build_documents_includes_existing_artifacts_only(tmp_path):
assert "validation_report" not in docs # not written
def _decision(seq: int, type_: str, subject: str, detail: str = "", rationale: str = ""):
return DecisionRecord(
seq=seq,
ts=datetime(2026, 1, 1),
type=type_,
subject=subject,
detail=detail,
rationale=rationale,
)
def _rich_session(tmp_path):
manifest = create_session("domanda originale", _db(), tmp_path)
session_dir = tmp_path / manifest.id
question = (
"# Domanda\n\n"
"Conta i pazienti con **ablazione**.\n\n"
"## Assunzioni\n\n"
"- Considera solo gli adulti\n"
"- Usa l'ultima procedura disponibile\n"
)
report = (
"# Validation report\n\n"
"## Parsing e read-only\n\n- parsing: OK\n\n"
"## Preview / aggregato\n\n"
"- tempo di esecuzione: 12 ms (limit 10)\n\n"
"| count |\n|---|\n| 42 |\n\n"
"## Note del reviewer\n\nRisultato verificato.\n"
)
decisions = [
_decision(1, "concept_clarified", "paziente attivo", "`flag_attivo = TRUE`"),
_decision(2, "memory_promotion_declined", "paziente attivo", "seq:1"),
_decision(
3,
"concept_clarified",
"ablazione valida",
"Procedura con stato **completato**.",
"Definizione approvata dal reviewer.",
),
_decision(4, "memory_promoted", "ablazione valida", "seq:3"),
_decision(5, "phase_approved", "phase:1"),
_decision(6, "table_promoted", "fact_procedure"),
_decision(7, "column_promoted", "fact_procedure.status"),
_decision(8, "column_excluded", "fact_procedure.note", "Non pertinente"),
]
(session_dir / "question.md").write_text(question)
(session_dir / "sql_final.sql").write_text("SELECT COUNT(*) FROM fact_procedure")
(session_dir / "validation_report.md").write_text(report)
(session_dir / "schema_linking.json").write_text(
'{"question":"q","candidates":[],"joins":[],"excluded":[],"open_questions":[]}'
)
(session_dir / "review_decisions.jsonl").write_text(
"\n".join(d.model_dump_json() for d in decisions) + "\n"
)
return manifest, session_dir, question, report, decisions
def test_build_documents_projects_the_approved_summary_order_and_sections(tmp_path):
manifest, session_dir, _question, _report, _decisions = _rich_session(tmp_path)
docs = build_documents(manifest, session_dir)
assert [doc["key"] for doc in docs] == [
"question",
"sql",
"preview",
"revised_question",
"assumptions",
"memories",
"schema_linking",
"validation_report",
"decisions",
]
by_key = {doc["key"]: doc for doc in docs}
assert by_key["preview"]["format"] == "markdown"
assert "tempo di esecuzione: 12 ms" in by_key["preview"]["content"]
assert "| 42 |" in by_key["preview"]["content"]
assert "Parsing e read-only" not in by_key["preview"]["content"]
assert by_key["revised_question"]["content"] == (
"# Domanda\n\nConta i pazienti con **ablazione**."
)
assert by_key["assumptions"]["content"] == (
"## Assunzioni\n\n- Considera solo gli adulti\n"
"- Usa l'ultima procedura disponibile"
)
assert "Preview / aggregato" not in by_key["validation_report"]["content"]
assert "Parsing e read-only" in by_key["validation_report"]["content"]
assert "Note del reviewer" in by_key["validation_report"]["content"]
def test_build_documents_groups_memories_and_filters_summary_decisions(tmp_path):
manifest, session_dir, _question, _report, _decisions = _rich_session(tmp_path)
by_key = {doc["key"]: doc for doc in build_documents(manifest, session_dir)}
memories = json.loads(by_key["memories"]["content"])
assert memories == [
{
"status": "approved",
"subject": "ablazione valida",
"detail": "Procedura con stato **completato**.",
"rationale": "Definizione approvata dal reviewer.",
},
{
"status": "declined",
"subject": "paziente attivo",
"detail": "`flag_attivo = TRUE`",
"rationale": "",
},
]
decisions = by_key["decisions"]["content"]
assert "column_excluded" in decisions
for hidden in (
"concept_clarified",
"memory_promoted",
"memory_promotion_declined",
"phase_approved",
"table_promoted",
"column_promoted",
):
assert hidden not in decisions
def test_build_documents_keeps_validation_report_when_it_has_no_preview(tmp_path):
manifest = create_session("q", _db(), tmp_path)
session_dir = tmp_path / manifest.id
report = "# Validation report\n\n## Parsing\n\n- OK\n"
(session_dir / "validation_report.md").write_text(report)
by_key = {doc["key"]: doc for doc in build_documents(manifest, session_dir)}
assert "preview" not in by_key
assert by_key["validation_report"]["content"] == report.strip()
def test_memory_projection_does_not_repeat_detail_as_marker_rationale(tmp_path):
manifest = create_session("q", _db(), tmp_path)
session_dir = tmp_path / manifest.id
decisions = [
_decision(1, "concept_clarified", "termine", "Definizione in **Markdown**."),
_decision(
2,
"memory_promoted",
"termine",
"seq:1",
"Definizione in **Markdown**.",
),
]
(session_dir / "review_decisions.jsonl").write_text(
"\n".join(d.model_dump_json() for d in decisions) + "\n"
)
by_key = {doc["key"]: doc for doc in build_documents(manifest, session_dir)}
assert json.loads(by_key["memories"]["content"])[0] == {
"status": "approved",
"subject": "termine",
"detail": "Definizione in **Markdown**.",
"rationale": "",
}
def test_filesystem_and_snapshot_builders_share_the_same_projection(tmp_path):
manifest, session_dir, question, report, decisions = _rich_session(tmp_path)
snapshot = SessionSnapshot(
manifest=manifest,
artifacts={
"question": question,
"schema_linking": (session_dir / "schema_linking.json").read_text(),
"sql_final": (session_dir / "sql_final.sql").read_text(),
"validation_report": report,
},
decisions=decisions,
)
assert build_snapshot_documents(snapshot) == build_documents(manifest, session_dir)
def test_cli_documents_json(tmp_path, monkeypatch):
m = create_session("q", _db(), tmp_path)
from tht.cli import session_cmd