PD-275 — Retour d'expérience (REX)
1. Résumé exécutif
| Métrique | Valeur |
| Objectif initial | Conformité PV Anchor ANCHOR-16/17 (finality depth + signer revocation) — 32/32 checks Prolog |
| Résultat obtenu | Conforme avec réserves (Sonar non disponible, Q-01/Q-03/Q-04 non résolues) |
| Verdict final | GO (Gate 8 : 9.0/10) |
| Tests contractuels | 260/260 passés (13 suites) |
2. Métriques de convergence
2.1 Temps et itérations
| Étape | Durée estimée | Durée réelle | Itérations | Écart |
| 0 - Besoin | 30 min | 38 min | 1 | +27% |
| 1 - Spécification | 2h | 5 min | 1 | -96% |
| 2 - Tests | 1h | 4 min | 1 | -93% |
| 3 - Gate spec | 1h | 2h03 | 3 | +105% |
| 4 - Plan | 1h | 10 min | 1 | -83% |
| 5 - Gate plan | 1h | 17 min | 2 | -72% |
| 6 - Implémentation | 4h | 30 min | 1 | -88% |
| 7 - Acceptabilité | 2h | 13 min | 1 | -89% |
| 8 - Gate acceptabilité | 1h | 6 min | 1 | -90% |
| 9 - REX | 30 min | 30 min | 1 | 0% |
| TOTAL | ~14h | ~4h20 | 13 | -69% |
2.2 Scores de convergence par gate
| Gate | Score v1 | Score final | Delta | Itérations |
| Gate 3 | 7.875/10 | 9.062/10 | +1.187 | 3 |
| Gate 5 | 8.438/10 | 9.312/10 | +0.874 | 2 |
| Gate 8 | 9.0/10 | 9.0/10 | 0 | 1 |
2.3 Écarts par catégorie
| Catégorie d'écart | Gate 3 | Gate 5 | Gate 8 | Total |
| ECT (complétude/testabilité) | 1 | 0 | 0 | 1 |
| DIV (divergence spec/impl) | 3 | 7 | 4 | 14 |
| AMB (ambiguïté) | 1 | 0 | 1 | 2 |
| SEC (sécurité) | 0 | 0 | 1 | 1 |
| PERF (performance) | 0 | 0 | 0 | 0 |
| TOTAL écarts | 5 | 7 | 6 | 18 |
3. Points fluides
- Gate 8 GO en v1 : aucune itération nécessaire sur la gate de clôture ; la qualité d'implémentation était suffisante dès le premier passage.
- Implémentation rapide (30 min) : le plan détaillé avec 11 composants et les code contracts ont permis une exécution directe sans ambiguïté.
- Convergence Gate 5 (delta +0.874) : les corrections du plan (suppression C8 SignerActiveGuard, BLK-01 pré-check signer, MAJ-02 double protection rôles) ont résolu des écarts structurels en une seule itération.
- Coverage élevée : ~95% statements, ~82% branches sur les fichiers PD-275 sans effort de rattrapage.
- Pattern fail-closed éprouvé : la réutilisation du pattern PD-177/PD-238 pour les gardes sécurité a été fluide.
4. Points difficiles
- Gate 3 à 3 itérations : la spec initiale (8 INV) a nécessité l'ajout de 4 invariants (INV-275-09 à INV-275-12) pour couvrir l'autorisation, l'anti-usurpation, la concurrence et l'unicité d'audit — ces exigences n'étaient pas dans le besoin initial.
- Convergence Gate 3 v2 stagnante (delta=0.25, action STOP) : la v2 a corrigé les écarts v1 mais introduit de nouveaux écarts (IST-05, testability chutée à 7.0). Débloqué par une correction tests v2 alignant la matrice avec les 4 nouveaux invariants.
- Sonar Phase 1.5 indisponible : le token Sonar absent du Vault a forcé une dérogation de fait sur la phase BLOQUANTE. Atténuation par lint+tsc+tests+coverage, mais violation procédurale persistante.
- 5 questions ouvertes (Q-01 à Q-05) héritées de la spec : aucune n'a été résolue formellement durant le workflow. Q-02 résolue de facto par le code existant (enum BatchStatus).
5. Hypothèses révélées tardivement
- Double fenêtre de vérification signer (pré-check + re-check) — découverte à l'étape 5 : la spec décrit une fenêtre unique de sérialisation pour submitBatch(), mais le plan a introduit un pré-check hors transaction avant createBatch() pour éviter le travail inutile. Accepté comme optimisation by design (DIV-05 Gate 5).
- SignerActiveGuard HTTP non pertinent pour BullMQ — découverte à l'étape 5 : le plan v1 incluait un guard NestJS HTTP (C8) alors que submitBatch() est appelé depuis un worker BullMQ. Supprimé en v2 (MAJ-01/MAJ-03).
- Codes HTTP sur erreurs internes worker — découverte à l'étape 8 : les codes HTTP (409, 404) attribués aux erreurs signer ne transitent jamais par HTTP dans le flux de soumission (worker BullMQ). Incohérence de présentation documentée.
6. Invariants complexes
- INV-275-11 (signer-concurrency-serialization) — TC-NOM-10, TC-NOM-11 : la sérialisation par
SELECT ... FOR UPDATE entre revokeSigner() et submitBatch() concurrents nécessite des tests d'intégration PostgreSQL réels avec deux connexions parallèles. Pattern Promise.all([revoke, submit]) sur connexions distinctes. - INV-275-12 (single-revocation-audit-event) — TC-NOM-11 : prouver qu'un seul audit trail est émis lors de deux revocations concurrentes. Dépend directement du verrou pessimiste (INV-275-11) et de la vérification de statut sous verrou.
- INV-275-10 (revokedBy-auth-derived) — TC-ERR-09 : l'anti-usurpation nécessite une validation DTO qui rejette les champs non déclarés + extraction depuis le contexte auth. Complexité dans la couverture des trois vecteurs d'injection (body, query, header).
7. Dette technique
Token Sonar absent du Vault — ✅ RÉSOLU (2026-02-28) — Credentials présents dans Vault à kv/data/ci/sonarqube (login/password). URL corrigée dans Vault. Scripts de gouvernance mis à jour. probe-capabilities.sh confirme sonar: available. - Questions ouvertes non résolues (Q-01 FINALITY_DEPTH, Q-03 normalisation adresse, Q-04 format revokedBy) — impact: moyen — conformité numérique et audit trail hétérogène possibles en production.
- Seed initial signer_registry non livré — impact: élevé — toute soumission bloquée fail-closed si le registre est vide au déploiement. Script de seed à prévoir.
- Rôle SIGNER_ADMIN non provisionné dans Keycloak — impact: moyen — seul ADMIN peut révoquer tant que non configuré.
- Spec T11 et TC-ERR-09 avec ambiguïté "refus OU ignore" — impact: faible — le code est déterministe (refus strict 400) mais la documentation n'est pas alignée.
8. Risques résiduels
| Risque | Type | Probabilité | Impact | Mitigation |
| Registre signer_registry vide au déploiement → toute soumission bloquée | ops | élevé | élevé | Script de seed avec adresses wallet actives de production |
| FINALITY_DEPTH non configuré par environnement | tech | moyen | moyen | Valeur configurable via ConfigService, défaut conservateur 12 |
| Collision d'adresses signer (casse EIP-55) | tech | faible | moyen | Normalisation EIP-55 dans SignerRegistryService |
| Token Sonar absent → Phase 1.5 contournée durablement | ops | élevé | moyen | Configurer kv/data/ci/sonar dans Vault |
8bis. Matrice de délégation inter-PD
| Story | Direction | Statut | Nature de la dépendance | Problème rencontré |
| PD-177 | ← dépend de | DONE | AnchorBatch.signerAddress peuplé pour résolution signer | RAS — champ disponible |
| PD-55 | ← dépend de | DONE | finalizeBatch() existant avec verrou pessimiste et transitions d'état | RAS — intégration fluide |
| PD-52 | ← dépend de | DONE | ConfirmationTracker existant fournit les confirmations | RAS — interface stable |
| PD-264 | ← dépend de | DONE | Enum AnchorBatchStatus et constante VALID_ANCHOR_STATUS_TRANSITIONS | RAS |
8ter. Bugs de tests
Aucun bug de test rencontré.
8quater. Corrections post-Gate 8
Aucune correction post-Gate 8 nécessaire. Gate 8 GO en v1.
9. Patterns récurrents détectés
9.1 Patterns confirmés (déjà vus dans d'autres stories)
- Guard de sécurité fail-closed obligatoire — aussi dans PD-238, PD-240, PD-250, PD-251, PD-277, PD-276 (7e occurrence)
- Machine à états explicite avec transitions autorisées/interdites — aussi dans PD-82, PD-250, PD-264, PD-251, PD-277, PD-276 (7e occurrence)
- timingSafeEqual / opérations atomiques DB pour comparaisons crypto — pattern réutilisé via verrou pessimiste
SELECT ... FOR UPDATE pour la sérialisation signer - Stubs inter-PD acceptés en Gate 8 si documentés avec story destination — pattern validé (pas de stubs dans PD-275, dépendances déjà livrées)
- Sonar Phase 1.5 indisponible — dérogation de fait — aussi dans PD-277, PD-276 (3e occurrence consécutive)
- Format non contractualisé dans spec v1 bloque en Gate 3 — format
revokedBy (Q-04), autorisation revoke, vecteurs anti-spoofing non explicités dans spec v1
9.2 Nouveaux patterns identifiés
- Guard HTTP non pertinent pour flux BullMQ worker — le plan v1 a créé un guard NestJS HTTP (SignerActiveGuard) pour un flux exécuté depuis un worker BullMQ. Supprimé en Gate 5. À surveiller pour toute story avec flux worker.
- Double fenêtre de vérification (pré-check + re-check transactionnel) — optimisation by design pour éviter le travail inutile quand la vérification transactionnelle est coûteuse. Pattern documenté dans FT4.
- Convergence Gate 3 stagnante (delta=0.25) débloquée par correction tests — la correction de la spec seule ne suffit pas si les tests ne sont pas réalignés simultanément.
10. Améliorations du workflow
10.1 Améliorations des prompts/templates
| Fichier | Amélioration suggérée | Priorité |
templates/prompts/1 Specification.md | Ajouter checklist obligatoire pour stories blockchain/anchor : liste des états machine complets dès la spec (pas de Q-02 en questions ouvertes) | moyenne |
templates/prompts/1 Specification.md | Exiger la contractualisation des vecteurs d'injection (body, query, header) pour toute validation anti-spoofing | moyenne |
templates/prompts/4 Plan d'implémentation.md | Vérifier que les composants de type Guard sont pertinents pour le flux d'exécution réel (HTTP vs BullMQ worker) | haute |
10.2 Améliorations des agents
| Agent | Amélioration suggérée | Justification |
config/agents step 4 | Injecter un check "ce composant est-il appelé depuis un endpoint HTTP ou un worker ?" pour chaque guard/middleware | Guard HTTP inutile pour BullMQ (C8 supprimé) |
10.3 Améliorations du processus
- Configurer le token Sonar dans Vault : 3e story consécutive avec Phase 1.5 contournée. Bloquer le workflow si non résolu avant la prochaine story.
- Résoudre les questions ouvertes AVANT Gate 3 v2 : les Q-01 à Q-05 ont traversé tout le workflow sans résolution formelle. Le PO doit statuer avant la gate.
- Corriger spec ET tests simultanément en boucle de correction Gate 3 : la correction de la spec seule sans réalignement des tests provoque une stagnation (delta=0.25).
11. Enseignements clés
- Vérifier la pertinence HTTP/worker des guards — un guard NestJS HTTP est inutile et introduit un risque TOCTOU quand le flux passe par un worker BullMQ. La décision de sérialisation doit être dans le service layer avec transaction.
- Les questions ouvertes de spec doivent être bloquantes — 5 Q- ouvertes ont traversé 10 étapes sans résolution formelle, créant de la dette documentaire persistante.
- La convergence Gate 3 nécessite l'alignement simultané spec+tests — corriger la spec sans réaligner les tests provoque une stagnation (delta faible) car le revieweur voit de nouveaux invariants sans tests correspondants.
- Le pattern double fenêtre (pré-check + re-check) est un optimum pour les flux worker — le pré-check fail-fast évite le travail inutile, le re-check transactionnel garantit la sécurité. Documenter explicitement comme pattern by design dans le plan.
- Gate 8 GO en v1 corrèle avec une Gate 5 exigeante — les corrections structurelles (suppression C8, BLK-01, MAJ-02) effectuées en Gate 5 ont produit un plan suffisamment robuste pour une clôture sans itération.
12. Métriques cumulatives (auto-calculées)
| Métrique | Cette story | Moyenne projet | Tendance |
| Temps total | 4.3h | 4.1h | → |
| Itérations gates | 6 | 5.3 | ↑ |
| Écarts totaux | 18 | 20.3 | ↓ |
| Score convergence moyen | 9.125/10 | 8.53/10 | ↑ |