fix(dashboard,worker): vérité produit P0 — dashboard+worker+VWB export
Some checks failed
tests / Lint (ruff + black) (push) Failing after 1m46s
tests / Tests unitaires (sans GPU) (push) Failing after 2m0s
tests / Tests sécurité (critique) (push) Has been skipped

War-room clôture DGX 2026-06-18 (recadrage Dom : graphe/apprentissage/mémoire/dashboard = surface produit P0).
Le dashboard et le statut worker affichaient des états faux ; corrige pour refléter la vérité du produit.

- dashboard FAISS: distingue index brut / metadata HMAC invalide / runtime / absent (plus de faux "inactif")
- dashboard process-mining: 503 explicite missing_dependency (plus de message trompeur)
- dashboard /api/workflows + system/status: lecture DB VWB v3 canonique (total réel = 24, plus de 0)
- worker /processing/status: véridique (lit _worker_health.json) + statut "idle/armé (lazy)" distinct de "dégradé (échec)"
- VWB export: N steps -> N actions/edges (dernière action n'est plus perdue)
- tests: dashboard routes, worker status truthfulness, export VWB

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-06-18 17:50:12 +02:00
parent 6d5ef51c60
commit ec1fb81054
8 changed files with 626 additions and 56 deletions

View File

@@ -480,21 +480,24 @@ def convert_vwb_to_core_workflow(
now = datetime.now().isoformat()
wf_id = workflow_data.get("id", f"wf_{uuid.uuid4().hex[:12]}")
# Créer les nodes : un node par étape (chaque étape = un état écran)
# Les actions sont portées par les edges. N étapes VWB doivent donc donner
# N edges core, et N+1 états écran (avant chaque action + terminal).
nodes = []
edges = []
for idx, step in enumerate(steps_data):
node_count = len(steps_data) + 1 if steps_data else 0
for idx in range(node_count):
step = steps_data[idx] if idx < len(steps_data) else {}
node_id = f"node_{idx:03d}"
action_type = step.get("action_type", "click_anchor")
params = step.get("parameters", {})
label = step.get("label", action_type)
label = step.get("label", action_type) if idx < len(steps_data) else "Fin du workflow"
# Créer le node (template minimal)
node = {
"node_id": node_id,
"name": label,
"description": f"Étape {idx + 1} : {label}",
"description": f"Étape {idx + 1} : {label}" if idx < len(steps_data) else "État terminal",
"template": {
"window": {
"title_pattern": params.get("window_title"),
@@ -518,7 +521,7 @@ def convert_vwb_to_core_workflow(
},
},
"is_entry": idx == 0,
"is_end": idx == len(steps_data) - 1,
"is_end": idx == node_count - 1,
"variants": [],
"primary_variant_id": None,
"max_variants": 5,
@@ -529,12 +532,13 @@ def convert_vwb_to_core_workflow(
"metadata": {
"vwb_step_id": step.get("id", ""),
"visual_type": _action_type_to_visual(action_type),
"terminal": idx >= len(steps_data),
},
}
nodes.append(node)
# Créer l'edge vers le node suivant (sauf pour le dernier)
if idx < len(steps_data) - 1:
# Créer un edge/action pour chaque step VWB, y compris la dernière.
if idx < len(steps_data):
next_node_id = f"node_{idx + 1:03d}"
# Convertir l'action VWB → action core