"""Structured engagement exports — the JSON is the source-of-truth artifact. ``exports/{engagement_id}.json`` — the full Engagement, serialized. ``exports/{engagement_id}.csv`` — one row per competency, for cross-engagement spreadsheet analysis (build spec §8). """ from __future__ import annotations import json from pathlib import Path import pandas as pd from .models import DiagnosticConfig, Engagement CSV_COLUMNS = [ "engagement_id", "client_name", "industry", "workshop_date", "competency_id", "dimension", "score", "evidence", "is_foundational", "is_binding_constraint", ] def engagement_json(engagement: Engagement) -> str: return json.dumps(engagement.model_dump(mode="json"), indent=2, ensure_ascii=False) def scores_dataframe(engagement: Engagement, config: DiagnosticConfig) -> pd.DataFrame: binding = set(engagement.computed_value.binding_constraints if engagement.computed_value else []) foundational = set(config.foundational_competencies) rows = [{ "engagement_id": engagement.engagement_id, "client_name": engagement.client_name, "industry": engagement.industry_config, "workshop_date": engagement.workshop_date.isoformat(), "competency_id": s.competency_id, "dimension": s.dimension, "score": s.score, "evidence": s.evidence, "is_foundational": s.competency_id in foundational, "is_binding_constraint": s.competency_id in binding, } for s in engagement.scores] return pd.DataFrame(rows, columns=CSV_COLUMNS) def write_exports(engagement: Engagement, config: DiagnosticConfig, exports_dir: Path) -> tuple[Path, Path]: """Write both artifacts; returns ``(json_path, csv_path)``.""" exports_dir.mkdir(parents=True, exist_ok=True) json_path = exports_dir / f"{engagement.engagement_id}.json" csv_path = exports_dir / f"{engagement.engagement_id}.csv" json_path.write_text(engagement_json(engagement), encoding="utf-8") scores_dataframe(engagement, config).to_csv(csv_path, index=False) return json_path, csv_path def load_engagement(json_path: Path) -> Engagement: """Reload a saved engagement for review (acceptance §10 nice-to-have).""" return Engagement.model_validate_json(json_path.read_text(encoding="utf-8"))