"""Chargement des livrables audités (sortie `out/` des modules voisins). L'audit 5D est un audit de SECOND NIVEAU : sa matière première est le hand-off JSON déjà commité par chaque générateur. On ne relance pas les générateurs — on lit leur produit tel qu'il sera importé côté VPS. Chaque artefact absent lève une erreur explicite (un audit sur un livrable manquant serait mensonger). """ from __future__ import annotations import json import os from typing import Any _HERE = os.path.dirname(os.path.abspath(__file__)) _DELIVERABLES = os.path.normpath(os.path.join(_HERE, "..", "..", "..")) # id logique → chemin relatif au dossier 05_deliverables_mvp ARTIFACT_PATHS: dict[str, str] = { "workflow": os.path.join("crm", "workflow_vente", "out", "workflow.json"), "dossier": os.path.join("crm", "dossier_vente", "out", "doctype_oto_dossier_vente.json"), "commissions": os.path.join("crm", "commissions", "out", "commission_plan.json"), "ecf": os.path.join("fiscal", "ecf_dgii", "out", "ecf_plan.json"), "confotur": os.path.join("legal", "confotur", "out", "doctype_confotur_application.json"), } def _load(rel: str) -> Any: path = os.path.join(_DELIVERABLES, rel) if not os.path.exists(path): raise FileNotFoundError( f"Artefact audité introuvable : {rel} — le générateur amont doit " f"avoir écrit son `out/` avant l'audit 5D (aucun audit à vide)." ) with open(path, encoding="utf-8") as fh: return json.load(fh) def load_artifacts() -> dict[str, Any]: """Charge les 5 livrables. Le workflow est une liste ; on expose l'objet.""" raw = {aid: _load(rel) for aid, rel in ARTIFACT_PATHS.items()} wf = raw["workflow"] if not isinstance(wf, list) or not wf: raise ValueError("workflow.json attendu = liste non vide de Workflow.") raw["workflow"] = wf[0] return raw def known_ids() -> frozenset[str]: return frozenset(ARTIFACT_PATHS)