Les steps needsAnchor des workflows importés par le pont R1 (import_core_workflow_to_db) affichaient « Ancre requise » car R1 laissait _anchor_image_base64 dans params sans créer le VisualAnchor ni poser anchor_id. La route HTTP import_learned_workflow faisait ce travail mais en dupliquait ~50 lignes inline. Fix GÉNÉRAL et réutilisable (mandat Dom), pas une rustine click_anchor : - helper unique services/anchor_image_service.materialize_anchor_from_b64 : crée VisualAnchor + fichier PNG + pose step.anchor_id + retire le b64 de params ; ne commit pas (transaction gérée par l'appelant) ; tolérant (crop invalide → anchor_id NULL, pas de crash) ; générique pour TOUS les action_type needsAnchor. - branchement dans import_core_workflow_to_db (flux R1) ; - route HTTP refactorée pour réutiliser le même helper (dé-duplication réelle, -48 lignes) → source unique de vérité. - source canonique needsAnchor côté backend : services/anchor_action_types.py (miroir de frontend_v4/src/types.ts, garde-fou anti-divergence testé). - script tools/backfill_anchors_r1.py (--dry-run par défaut / --apply) : filtre source=learned_import ET action_type ∈ NEEDS_ANCHOR ET anchor_id NULL ET crop présent ; DB résolue depuis la config runtime VWB (pas en dur) ; dry-run affiche le chemin DB résolu + estime PNG/disque ; idempotent. NON exécuté en --apply (backup + arbitrage Dom requis avant, jamais la DB clinique DGX). TDD : tests rouges d'abord puis verts. 20 tests neufs (matérialisation 6 types d'ancre, b64 retiré, sans-crop→NULL, R1 clic, ré-import idempotent, dé-dup route, backfill apply/idempotent/dry-run/filtre manual+hors-needsAnchor, canonique). 24 tests unit VERTS, 0 régression (test_import_core_workflow_to_db intact). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.5 KiB
8.5 KiB