refactor(harness): route workflow persistence through repositories

This commit is contained in:
User
2026-07-16 18:01:29 +02:00
parent 259f021313
commit c1cddaa667
30 changed files with 925 additions and 348 deletions
+27 -24
View File
@@ -8,7 +8,6 @@ commands. All read workflow facts from load_workflow() (no mirrored constants).
from __future__ import annotations
import json
from pathlib import Path
import typer
@@ -22,16 +21,12 @@ from tht.workflow import load_workflow
phase_app = typer.Typer(help="Fase del workflow HITL (gate di avanzamento/ritorno)")
def session_dir(cfg, session_id: str) -> Path:
"""Where a session's artifacts live. Mirror of session_cmd.session_dir (kept
here to avoid a circular import: session_cmd imports phase helpers too)."""
return cfg.paths.sessions / session_id
def require_phase_or_exit(cfg, session: str, min_phase: int) -> None:
"""Refuse with exit 1 if the session hasn't reached min_phase yet. The phase
name in the message comes from workflow.yaml (load_workflow), not a constant."""
cur = current_phase(session_dir(cfg, session))
from tht.cli.session_cmd import load_snapshot_or_exit
cur = current_phase(load_snapshot_or_exit(cfg, session))
if cur < min_phase:
wf = load_workflow()
nome = wf.phase_name(min_phase)
@@ -89,21 +84,24 @@ def advance_cmd(
),
) -> None:
"""Approva la fase corrente e passa alla successiva (persiste phase_approved)."""
from tht.decisions import append_decision
from tht.cli.session_cmd import load_snapshot_or_exit, session_repository
sdir = session_dir(_cfg(), session)
cur = current_phase(sdir)
cfg = _cfg()
snapshot = load_snapshot_or_exit(cfg, session)
cur = current_phase(snapshot)
wf = load_workflow()
if cur > wf.max_phase:
typer.secho("Sessione già alla fase terminale.", fg=typer.colors.YELLOW)
raise typer.Exit(0)
if auto:
if not auto_advance_eligible(sdir):
problems = advance_problems(sdir, cur)
if not auto_advance_eligible(snapshot):
problems = advance_problems(snapshot, cur)
for p in problems:
typer.echo(p)
raise typer.Exit(6) # needs human confirmation (gate contract)
append_decision(sdir, type="phase_approved", subject=f"phase:{cur}")
session_repository(cfg).append_decisions(
session, [{"type": "phase_approved", "subject": f"phase:{cur}"}]
)
typer.echo(f"Fase {cur} ({wf.phase_name(cur)}) approvata → Fase {cur + 1}.")
@@ -113,16 +111,21 @@ def reopen_cmd(
phase: int = typer.Option(..., "--phase", help="Fase a cui tornare (1..fase corrente -1)."),
) -> None:
"""Torna a una fase precedente (persiste phase_reopened + teardown artefatti)."""
from tht.decisions import append_decision
from tht.teardown import teardown_to_phase
from tht.cli.session_cmd import load_snapshot_or_exit, session_repository
sdir = session_dir(_cfg(), session)
cur = current_phase(sdir)
cfg = _cfg()
snapshot = load_snapshot_or_exit(cfg, session)
cur = current_phase(snapshot)
if phase < 1 or phase >= cur:
typer.secho(f"Target non valido (fase corrente {cur}).", fg=typer.colors.RED, err=True)
raise typer.Exit(1)
report = teardown_to_phase(sdir, target_phase=phase)
append_decision(sdir, type="phase_reopened", subject=f"phase:{phase}")
from tht.teardown import teardown_snapshot
repository = session_repository(cfg)
report = teardown_snapshot(repository, snapshot, phase)
repository.append_decisions(
session, [{"type": "phase_reopened", "subject": f"phase:{phase}"}]
)
for f in report.deleted_files:
typer.echo(f" eliminato artefatto: {f}")
typer.echo(f"Tornati alla Fase {phase} ({load_workflow().phase_name(phase)}).")
@@ -133,13 +136,13 @@ def show_cmd(
session: str = typer.Option(..., "--session"),
) -> None:
"""Mostra stato, fase corrente e ultime decisioni della sessione."""
from tht.decisions import list_decisions
from tht.cli.session_cmd import load_snapshot_or_exit
sdir = session_dir(_cfg(), session)
cur = current_phase(sdir)
snapshot = load_snapshot_or_exit(_cfg(), session)
cur = current_phase(snapshot)
wf = load_workflow()
typer.echo(f"Fase corrente: {cur}/{wf.max_phase} ({wf.phase_name(min(cur, wf.max_phase))})")
decisions = list_decisions(sdir)
decisions = snapshot.decisions
if decisions:
typer.echo(f"Decisioni registrate: {len(decisions)}")
for d in decisions[-5:]: