64 lines
2.7 KiB
Python
64 lines
2.7 KiB
Python
"""D15 granularity (a): `tht decision retract` tombstones the last substantive decision.
|
|
|
|
Wires the step-granularity rollback ("re-ask current widget, discard last answer") to a
|
|
reachable CLI command. The data model (decision_retracted + retracts, honored by
|
|
effective_decisions) already existed; this pins the command that emits it.
|
|
"""
|
|
from pathlib import Path
|
|
|
|
from tht.cli.decision_cmd import retract_cmd
|
|
from tht.decisions import append_decision, list_decisions
|
|
from tht.phase import current_phase, effective_decisions
|
|
|
|
|
|
def _walk_to_phase(session: Path, target: int) -> None:
|
|
while current_phase(session) < target:
|
|
append_decision(session, type="phase_approved", subject=f"phase:{current_phase(session)}")
|
|
|
|
|
|
def test_retract_drops_last_substantive_decision(tmp_path, monkeypatch):
|
|
s = tmp_path / "2026-01-01-000000-x"
|
|
s.mkdir(parents=True)
|
|
_walk_to_phase(s, 4)
|
|
append_decision(s, type="table_promoted", subject="phase:4", detail="dim_pazienti")
|
|
append_decision(s, type="table_promoted", subject="phase:4", detail="fact_ricoveri")
|
|
|
|
# stub config + session loading (the command only needs a session dir)
|
|
import tht.cli.decision_cmd as mod
|
|
import tht.cli.session_cmd as session_mod
|
|
from tht.session.models import SessionManifest, SessionSnapshot
|
|
|
|
class _Cfg:
|
|
class paths:
|
|
sessions = tmp_path
|
|
|
|
monkeypatch.setattr(mod, "_load_config_or_exit", lambda _c: _Cfg())
|
|
monkeypatch.setattr(mod, "load_session_or_exit", lambda _cfg, _s: None)
|
|
class _Repository:
|
|
def get(self, session_id):
|
|
return SessionSnapshot(
|
|
manifest=SessionManifest(id=session_id, created_at="2026-01-01T00:00:00Z", question="q", database="d", schema="s"),
|
|
decisions=list_decisions(tmp_path / session_id),
|
|
)
|
|
|
|
def append_decisions(self, session_id, decisions):
|
|
from tht.decisions import append_decisions
|
|
|
|
return append_decisions(tmp_path / session_id, list(decisions))
|
|
|
|
repository = _Repository()
|
|
monkeypatch.setattr(mod, "load_snapshot_or_exit", lambda _cfg, sid: repository.get(sid))
|
|
monkeypatch.setattr(mod, "session_repository", lambda _cfg: repository)
|
|
monkeypatch.setattr(session_mod, "load_snapshot_or_exit", lambda _cfg, sid: repository.get(sid))
|
|
|
|
retract_cmd(session="2026-01-01-000000-x", config=Path("x"))
|
|
|
|
eff = effective_decisions(s)
|
|
promoted = [d for d in eff if d.type == "table_promoted"]
|
|
assert len(promoted) == 1 # the last one was retracted
|
|
assert promoted[0].detail == "dim_pazienti"
|
|
# the audit log keeps everything (append-only): 2 promotions + the retract marker
|
|
raw = [d.type for d in list_decisions(s)]
|
|
assert raw.count("table_promoted") == 2
|
|
assert "decision_retracted" in raw
|