refactor(harness): route workflow persistence through repositories
This commit is contained in:
@@ -130,6 +130,35 @@ def create_session(
|
||||
return manifest
|
||||
|
||||
|
||||
def new_session_manifest(
|
||||
question: str, db: DatabaseConfig, *, provider=None, model=None, thinking=None, name=None
|
||||
) -> SessionManifest:
|
||||
"""Create an unsaved UUIDv4 manifest for a repository-owned session."""
|
||||
now = datetime.now(UTC)
|
||||
return SessionManifest(
|
||||
id=str(uuid.uuid4()), created_at=now, question=question,
|
||||
database=db.database, schema=db.db_schema, author=current_author(),
|
||||
summary=_summarize(question), updated_at=now, updated_by=current_author(),
|
||||
provider=provider, model=model, thinking=thinking, name=name,
|
||||
)
|
||||
|
||||
|
||||
def build_snapshot_documents(snapshot) -> list[dict]:
|
||||
docs = [{"phase": "—", "key": "question", "title": "Original question", "format": "text", "content": snapshot.manifest.question}]
|
||||
spec = [
|
||||
("question", "F3", "revised_question", "Revised question", "markdown"),
|
||||
("schema_linking", "F4", "schema_linking", "Schema linking", "schema-linking"),
|
||||
("sql_final", "F7", "sql", "Final SQL", "sql"),
|
||||
("validation_report", "finalize", "validation_report", "Validation report", "markdown"),
|
||||
]
|
||||
for artifact, phase, key, title, fmt in spec:
|
||||
if artifact in snapshot.artifacts:
|
||||
docs.append({"phase": phase, "key": key, "title": title, "format": fmt, "content": snapshot.artifacts[artifact]})
|
||||
if snapshot.decisions:
|
||||
docs.append({"phase": "—", "key": "decisions", "title": "Decisions", "format": "decisions", "content": "\n".join(d.model_dump_json() for d in snapshot.decisions) + "\n"})
|
||||
return docs
|
||||
|
||||
|
||||
def touch_manifest(
|
||||
session_id: str, sessions_root: Path, *, updated_by: str | None = None
|
||||
) -> SessionManifest:
|
||||
@@ -227,6 +256,33 @@ def sync_schema_linking(session_id: str, sessions_root: Path) -> Path:
|
||||
return set_schema_linking(session_id, data, sessions_root)
|
||||
|
||||
|
||||
def sync_schema_linking_snapshot(snapshot) -> str:
|
||||
"""Repository projection of effective F4 decisions into schema_linking JSON."""
|
||||
from tht.phase import effective_decisions
|
||||
|
||||
existing = json.loads(snapshot.artifacts.get("schema_linking", "{}"))
|
||||
latest: dict[str, str] = {}
|
||||
for decision in effective_decisions(snapshot):
|
||||
if decision.type in {"table_promoted", "table_excluded", "column_promoted", "column_excluded"}:
|
||||
latest[decision.subject] = decision.type
|
||||
candidates, excluded = [], []
|
||||
for subject, kind in latest.items():
|
||||
entity = "column" if "." in subject else "table"
|
||||
if kind.endswith("promoted"):
|
||||
candidates.append({"kind": entity, "name": subject, "decision": "promoted"})
|
||||
else:
|
||||
excluded.append({"kind": entity, "name": subject})
|
||||
from tht.session.models import SchemaLinking
|
||||
|
||||
model = SchemaLinking.model_validate({
|
||||
"question": existing.get("question") or snapshot.manifest.question,
|
||||
"candidates": candidates, "excluded": excluded,
|
||||
"joins": existing.get("joins", []), "open_questions": existing.get("open_questions", []),
|
||||
"concept_formulas": existing.get("concept_formulas", []),
|
||||
})
|
||||
return json.dumps(model.model_dump(by_alias=True), indent=2, ensure_ascii=False)
|
||||
|
||||
|
||||
def load_session(session_id: str, sessions_root: Path) -> SessionManifest:
|
||||
path = sessions_root / session_id / MANIFEST
|
||||
if not path.exists():
|
||||
@@ -298,6 +354,30 @@ def delete_session(session_id: str, sessions_root: Path) -> None:
|
||||
shutil.rmtree(sessions_root / session_id)
|
||||
|
||||
|
||||
def persist_verified_finalization(
|
||||
repository,
|
||||
session_id: str,
|
||||
*,
|
||||
validation_report: str,
|
||||
evidence: str,
|
||||
) -> SessionManifest:
|
||||
"""Publish DWH-verified final artifacts and status at one repository boundary.
|
||||
|
||||
The caller must complete static validation, EXPLAIN and preview before this
|
||||
function is entered. It intentionally does not touch solved-question
|
||||
indexing: that derivative is best-effort and happens after the durable commit.
|
||||
"""
|
||||
snapshot = repository.get(session_id)
|
||||
manifest = snapshot.manifest.model_copy(deep=True)
|
||||
manifest.status = "finalized"
|
||||
manifest.updated_at = datetime.now(UTC)
|
||||
manifest.updated_by = current_author()
|
||||
return repository.finalize(
|
||||
manifest,
|
||||
{"validation_report": validation_report, "evidence": evidence},
|
||||
).manifest
|
||||
|
||||
|
||||
def build_documents(manifest: SessionManifest, session_dir: Path) -> list[dict]:
|
||||
"""Ordered, read-only document bundle for the UI panel. Only documents that exist
|
||||
on disk are returned. CTE artifacts (F6) are intentionally excluded (intermediate)."""
|
||||
|
||||
Reference in New Issue
Block a user