PD-275 — Rapport de confrontation (Étape 8 — Clôture)¶
Ce rapport est produit par l'orchestrateur Claude avant la gate PMO 8 (CLOSURE). Il confronte les documents produits pour identifier convergences, divergences et zones d'ombre.
1. Sources confrontées¶
| Document | Étape d'origine | Version |
|---|---|---|
| PD-275-specification.md | Étape 1 (spécification) | Post-Gate 3 v3 |
| PD-275-tests.md | Étape 2 (tests) | Post-Gate 3 v3 |
| PD-275-plan.md | Étape 4 (plan) | Post-Gate 5 v2 |
| PD-275-acceptability.md | Étape 7 (acceptabilité) | v1 |
2. Convergences¶
2.1 Invariants — Alignement intégral sur les 12 invariants¶
Les 4 documents s'accordent sur les 12 invariants (INV-275-01 à INV-275-12). La spécification les définit, les tests les couvrent (matrice §2 : 24 TC mappés sur les 12 INV), le plan les mappe sur des mécanismes concrets (§3 : 12/12 mappings), et l'acceptabilité confirme 11/12 PASS + 1 PASS avec réserve (INV-275-08, vacuously satisfied).
2.2 Sémantique fail-closed¶
Spécification (INV-275-01), tests (TC-NOM-02, TC-NOM-06, TC-NOM-07, TC-ERR-03/04), plan (§3 : "Les trois gardes lancent une exception avant toute mutation"), acceptabilité (0 bypass détecté par pentester) : convergence complète sur le deny-by-default pour finalizeBatch, submitBatch et revokeSigner.
2.3 Sérialisation par verrou pessimiste¶
Les 4 documents s'accordent sur SELECT ... FOR UPDATE comme mécanisme de sérialisation (spec INV-275-11, tests TC-NOM-10/11, plan C4/C6 avec lock: { mode: 'pessimistic_write' }, acceptabilité S-03 confirmant le pattern double-fenêtre by design).
2.4 Machine à états signer¶
Convergence complète : ACTIVE -> REVOKED (autorisée), REVOKED -> * (interdite, état terminal). Couvert par INV-275-06/07, testé par TC-INV-06/07A, implémenté par enum SignerStatus + constante VALID_SIGNER_STATUS_TRANSITIONS, confirmé par acceptabilité.
2.5 Autorisation et anti-usurpation¶
Les 4 documents convergent sur : seuls ADMIN ou SIGNER_ADMIN peuvent révoquer (INV-275-09), revokedBy dérivé du JWT sub exclusivement (INV-275-10). Le plan implémente @Roles('ADMIN', 'SIGNER_ADMIN') + double garde (controller + service), l'acceptabilité confirme le fonctionnement (tentative de bypass bloquée).
2.6 Codes d'erreur¶
Les 8 codes d'erreur métier sont définis dans la spec (§6), testés dans les TC (ERR-01 à ERR-09), implémentés dans le plan (C10 + §6) et vérifiés par l'acceptabilité (260/260 tests passing).
2.7 Bornes numériques confirmation_count¶
Convergence sur [0, 2_147_483_647] entier, défaut 0. Spec (§10.2), tests (TC-ERR-01, TC-NEG-01/02), plan (C1 migration DDL CHECK + C5 validation applicative), acceptabilité (tests passing).
2.8 Couverture tests → invariants¶
La matrice tests (§2) couvre les 12 invariants avec 24+ TC. Le plan (§5) mappe chaque TC sur un mécanisme et un observable. L'acceptabilité confirme 260/260 tests passing, coverage >= 80% (avec détails par fichier).
2.9 Migration réversible¶
Spec (CA-08), tests (TC-NOM-09), plan (C1 : up/down), acceptabilité implicite (tests passing) : convergence sur l'exigence de réversibilité DDL.
3. Divergences¶
⚠️ Les conflits ne doivent JAMAIS être lissés. Chaque divergence est rendue visible.
DIV-01 — Anti-spoofing revokedBy : comportement non-déterministe dans le document de tests¶
- Spécification (§8, T11) : "la valeur persistée revokedBy vaut actor-A (ou la requête est refusée avec ERR-REVOKEDBY-SPOOFING selon contrat API), jamais actor-B"
- Tests (TC-ERR-09) : "La requête est refusée avec ERR-REVOKEDBY-SPOOFING ou le champ revokedBy est ignoré"
- Plan (C7) : "si le body contient un champ
revokedBy, retournerERR-REVOKEDBY-SPOOFING(400 Bad Request)" — choix déterministe : refus strict - Acceptabilité (E-04, T-02) : "L'implémentation choisit le refus strict (400). Documenté dans le controller." / "L'ambiguïté est dans le document de tests, pas dans le code."
- Impact : Le code est déterministe (refus strict 400), mais la spécification et les tests autorisent deux comportements contradictoires ("refus OU ignore"). Le document
PD-275-tests.mdet la section T11 de la spec doivent être mis à jour pour refléter le choix implémenté. Criticité : MINEUR (documentation uniquement, pas d'impact code).
DIV-02 — Sonar Phase 1.5 BLOQUANTE contournée¶
- Règle de gouvernance (
.claude/rules/procedures.md, §Étape 7) : "Phase 1.5 (Sonar local) est BLOQUANTE. Si Sonar QG ERROR → STOP avant reviews LLM." - Acceptabilité (§Phase 1.5) : "Quality Gate : NON DISPONIBLE — Raison : Token Sonar absent du Vault (
kv/data/ci/sonarvide). Atténuation : lint + tsc + tests 260/260 + coverage >= 80%" - Impact : L'acceptabilité a procédé aux reviews LLM (Phase 2) malgré l'absence de Sonar, ce qui contrevient à la règle BLOQUANTE issue des rétrospectives (8 stories avec corrections post-Gate 8 causées par Sonar QG FAILED). L'atténuation est documentée mais ne constitue pas une dérogation formelle. Criticité : MAJEUR (violation procédurale, atténuation partielle par lint+tsc+tests).
DIV-03 — Machine à états batch : couverture partielle dans spec/tests vs résolue dans le plan¶
- Spécification (§5, Q-02) : "Liste canonique complète des états
anchor_batchhorsFINALIZED" — question ouverte - Tests (TC-INV-07B) : Teste uniquement
NON_FINALIZED -> FINALIZEDautorisée etFINALIZED -> *interdite — couverture partielle - Plan (C6, §3 INV-275-07) : Utilise l'enum réel
BatchStatus(PENDING, BUILDING, SUBMITTED, PENDING_FINALITY, FINALIZED, FAILED) et référence la constanteVALID_ANCHOR_STATUS_TRANSITIONSexistante (PD-55) - Acceptabilité (E-01) : "L'enum
BatchStatusTypeORM EST la liste canonique. Q-02 était une question ouverte en spec, résolue par l'implémentation. L'enum est vérifié formellement par TLA+ (StatusValues ⊆ RealStates)." - Impact : La spec et les tests utilisent
NON_FINALIZEDcomme état abstrait, alors que l'implémentation utilise les états réels du domaine (dontPENDING_FINALITY). Q-02 est de facto résolue par le code mais pas rétropropagée dans la spec. Criticité : MINEUR (résolu dans les faits, documentation spec non mise à jour).
DIV-04 — Codes HTTP sur erreurs internes (worker BullMQ)¶
- Plan (§6, table erreurs) :
ERR-SIGNER-REVOKED → HTTP 409,ERR-SIGNER-NOT-FOUND → HTTP 404 - Plan (§6, stratégie propagation) : "Les erreurs internes (worker BullMQ) sont loguées via Logger et le batch passe à FAILED via failBatch()"
- Plan (FT4) : Le flux
submitBatch()est dans un worker BullMQ (BlockchainAnchorProcessor.process), pas dans un endpoint HTTP - Impact : La table d'erreurs attribue des codes HTTP à des erreurs qui, dans le flux de soumission, ne passent jamais par HTTP (worker BullMQ). Les codes HTTP s'appliquent uniquement au flux de révocation (endpoint REST). Incohérence de présentation, pas d'impact fonctionnel. Criticité : INFORMATIF.
4. Zones d'ombre¶
ZO-01 — Valeur de FINALITY_DEPTH par environnement (Q-01 — non résolue)¶
Question ouverte dans la spec (Q-01), le plan (HT-03) propose un défaut configurable, mais aucune valeur officielle n'est validée pour dev/staging/prod. L'acceptabilité ne mentionne pas ce point. Les tests sont exécutés en paramétrique mais la conformité numérique en production reste indéterminée.
ZO-02 — Provisionnement du rôle SIGNER_ADMIN dans Keycloak¶
Le plan (§7.1) mentionne : "Le rôle SIGNER_ADMIN est un nouveau rôle à créer dans Keycloak. Si ce rôle n'existe pas encore, il doit être provisionné avant déploiement." Aucun document ne confirme que ce provisionnement est effectué ou planifié. Si absent au déploiement, seul ADMIN pourra révoquer (fonctionnel mais ne couvre pas le besoin de délégation).
ZO-03 — Seed initial du registre signer (Q-05 — non résolu)¶
Le plan (§9.1) identifie un risque critique : registre vide → toute soumission bloquée fail-closed. Il recommande un script de seed mais aucun artefact de seed n'est livré dans PD-275. L'acceptabilité ne vérifie pas ce point. Risque opérationnel au déploiement.
ZO-04 — Format canonique de revokedBy (Q-04 — non résolu)¶
La spec laisse Q-04 ouverte. Le plan dit "JWT sub" et l'implémentation utilise request.user.sub, mais le format exact stocké (UUID, email, identifiant technique) n'est pas contractualisé. Risque d'hétérogénéité de l'audit trail si des service accounts ont des formats de sub différents des utilisateurs humains.
ZO-05 — Normalisation des adresses signer (Q-03 — partiellement résolu)¶
Le plan (§9.4, HT-07) recommande la normalisation EIP-55 systématique. La migration DDL (C1) utilise VARCHAR(42) compatible EIP-55. Mais ni la spec ni les tests ne contractualisent explicitement la normalisation à l'insertion/requête. Risque de collision si une adresse est insérée en lowercase et requêtée en checksum (ou inverse).
ZO-06 — Token Sonar dans Vault¶
L'acceptabilité note que kv/data/ci/sonar est vide. Aucun plan d'action avec échéance pour configurer ce secret. Impact : la Phase 1.5 BLOQUANTE restera contournée sur les prochaines stories tant que non résolu.
ZO-07 — Atomicité audit event dans la transaction de révocation¶
La spec (INV-275-05) exige que "les écritures d'audit de révocation sont dans la même transaction que la transition d'état signer". Le plan (FT3) montre AuditService.logEvent('SIGNER_REVOKED') à l'intérieur du callback dataSource.transaction(). Mais si AuditService écrit dans une table séparée (module audit), la transaction couvre-t-elle bien les deux tables ? L'acceptabilité mentionne TC-ERR-06 (ERR-AUDIT-TRAIL-MISSING) passing, ce qui suggère que oui, mais le mécanisme exact (même connexion DB, propagation EntityManager) n'est pas documenté.
5. Recommandation¶
- Procéder — convergence confirmée, aucun conflit bloquant
- Rework nécessaire — divergences à résoudre avant de continuer
- Escalade — décision humaine requise sur un point structurant
Justification¶
DIV-02 (Sonar BLOQUANTE contournée) est la divergence la plus significative. La règle de gouvernance est explicite : Phase 1.5 est BLOQUANTE. L'atténuation (lint+tsc+tests+coverage) couvre partiellement les axes Sonar mais ne constitue pas une dérogation formelle. Deux options :
- Dérogation explicite : Le PO/architecte accepte formellement la dérogation Sonar pour PD-275, documentée dans le verdict. La réserve "configurer le token Sonar" est portée comme action post-story.
- Blocage : Installer sonar-scanner + configurer le token Vault, exécuter Sonar, puis reprendre la Gate 8.
DIV-01 et DIV-03 sont des écarts de documentation (MINEUR) qui peuvent être corrigés post-gate ou portés comme réserves du verdict.
ZO-01/02/03 sont des risques opérationnels de déploiement, pas des non-conformités de code. Ils doivent être documentés dans le verdict comme conditions pré-déploiement.