Aller au contenu

PD-253 — Review Gate 3 v2

Auditeur : Claude (review Gate 3 indépendante) Date : 2026-03-12 Documents audités : PD-253-specification.md (v2), PD-253-tests.md (v2)


Scores

Critère Score
completeness 8/10
testability 8/10
clarity 9/10
traceability 9/10

Score moyen : 8.5/10


Analyse par critère

Completeness (8/10)

La spec v2 couvre l'ensemble des invariants métier critiques (14 INV), la machine à états complète avec FAILED_TIMEOUT, les règles d'inclusion/exclusion, le modèle de données contractuel, les SLA temporels, les paramètres numériques et les codes d'erreur. La couverture est dense et cohérente.

Gaps résiduels identifiés :

  • La transition READY_FOR_DOWNLOAD → DOWNLOADED est documentée en spec (§5.5 flux 3), mais le mécanisme de "confirmation de téléchargement réussi" qui en est le trigger n'est pas défini : HTTP 200 S3 ? callback client ? endpoint de confirmation ? L'implémentation est laissée libre, avec risque d'incohérence ou de blocage si la confirmation n'arrive pas.
  • La politique de purge post-téléchargement (PC-253-02) reste ouverte. Un package en état DOWNLOADED n'a pas de rétention contractuelle définie. Si DOWNLOADED est terminal et que le package reste en staging indéfiniment, c'est une fuite de stockage. À trancher avant Gate 5.
  • La reprise après FAILED_TIMEOUT (PC-253-05) n'est pas contractualisée : libération de quota non confirmée explicitement, mode de relance (manuel vs automatique) absent. La définition de "export actif" (§3) exclut implicitement FAILED_TIMEOUT, mais la libération explicite du quota n'est pas contractualisée.
  • Le schéma complet de destruction-log.json n'est pas contractualisé. Seul destruction_act_hash est défini en §5.1. Les autres champs (document_id, date, motif légal, référence PD-250) sont absents. Risque d'interopérabilité et de non-conformité NF Z42-013 §13.1.
  • Le champ failure_reason (ex: PROOF_ENVELOPE_INCOMPLETE) est référencé dans §6 et dans TC-ERR-06 comme "observable dans les métadonnées de l'export", mais son format (enum ? string libre ?), son emplacement (colonne DB ? champ API GET ?) et ses valeurs contractualisées ne sont pas définis dans le modèle §5.1.

Testability (8/10)

Les tests v2 sont bien structurés dans l'ensemble : Given/When/Then déterministes, matrice de couverture exhaustive, tests négatifs et adversariaux pertinents (TC-NEG-01 à TC-NEG-08). L'explicitation de l'asynchronisme (TC-ERR-06, TC-NOM-10) est correcte. L'existence de TC-INV-11 et TC-INV-12 pour les invariants non fonctionnels est appréciable.

Gaps résiduels :

  • Aucun test dédié ne couvre la transition READY_FOR_DOWNLOAD → DOWNLOADED. TC-NOM-09 est générique ("un export dans chaque état, tentative de transitions autorisées puis interdites") mais ne documente pas le mécanisme de confirmation de téléchargement ni l'atteinte effective de l'état DOWNLOADED. C'est un gap fonctionnel central compte tenu du flux 3 de §5.5.
  • TC-NOM-14 (annulation depuis ASSEMBLING) prévoit deux branches (worker pas encore terminé vs déjà terminé), mais ne précise pas comment contrôler de manière déterministe dans quel état se trouve le worker au moment de l'appel DELETE. Sans hook de synchronisation ou chaos test déterministe, ce test risque d'être non-reproductible.
  • TC-INV-11 (chiffrement artefacts temporaires) mentionne "instrumentation sécurité activable" sans définir le mécanisme d'observation concret. Le test n'est pas reproductible par une équipe tierce sans définition de l'observable.
  • TC-INV-12 couvre "crash simulé" générique mais ne modélise pas explicitement le crash OOM/kill-signal qui bypasse le finally block — cas le plus critique pour INV-253-12. Gap de couverture sur le scénario précisément visé par le pattern purgeStale().
  • CA-253-12 est marqué "Partielle" dans la matrice de couverture des tests (§2) avec "bloquant" dans §9, mais n'est pas annoté [CONDITIONNEL] dans le tableau §7 de la spec. Incohérence de qualification entre les deux documents.
  • TC-NOM-13 accepte "200 ou 204" pour l'annulation réussie, sans que la spec contractualise un seul code HTTP de succès. La disjonction rend le test partiellement non-déterministe.

Clarity (9/10)

La machine à états v2 est complète : les 8 états sont explicités avec leurs transitions autorisées/interdites et leur caractère terminal. La note v2 sur FAILED_TIMEOUT vs FAILED est pertinente et justifiée. §5.5 documente l'annulation avec la règle d'idempotence du checkpoint worker. §5.6 clarifie l'atomicité multi-composant avec la table sync/async. §5.7 contractualise les contrôles d'accès pour les trois opérations (GET status, download URL, DELETE).

Seul gap résiduel :

  • La relation entre l'état DOWNLOADED et la rétention package reste implicite. La spec §5.5 dit "Si non téléchargé avant TTL: EXPIRED" — confirmant que seul READY_FOR_DOWNLOAD → EXPIRED est possible. Mais la purge du package après DOWNLOADED n'est pas tranchée. Mérite une note explicite pour éviter une implémentation divergente.

Traceability (9/10)

La matrice de couverture §2 des tests est complète et cohérente avec la spec : chaque INV pointe vers des CA et des TC. Les codes d'erreur sont cohérents entre §6 spec et §4 tests. La suppression du 422 est confirmée dans §8 observabilité des tests. Les IDs INV/CA/TC sont stables et traçables. Le lien entre 504 EXPORT_TIMEOUT (code HTTP, §6 spec) et l'état FAILED_TIMEOUT (async) est couvert par TC-ERR-09.

Seul gap résiduel :

  • L'ambiguïté entre 504 EXPORT_TIMEOUT comme code HTTP et FAILED_TIMEOUT comme état asynchrone n'est pas explicitement résolue : un client qui fait un GET de statut sur un export en FAILED_TIMEOUT reçoit-il un 504 ou un 200 avec status: FAILED_TIMEOUT dans le body ? Les deux mécanismes sont différents et non précisés.

Écarts résiduels

  • ECT-01 [MAJEUR] : Transition READY_FOR_DOWNLOAD → DOWNLOADED non testée explicitement. Aucun TC dédié ne couvre la confirmation de téléchargement et l'atteinte effective de l'état DOWNLOADED. DIV-03 v1 partiellement résolu (flux documenté en spec §5.5), mais les tests ne couvrent pas ce point. À corriger avant soumission.

  • ECT-02 [MAJEUR] : Schéma complet de destruction-log.json non contractualisé. Seul destruction_act_hash est défini en §5.1. Les autres champs obligatoires pour la traçabilité NF Z42-013 §13.1 sont absents. TC-NOM-08 ne peut pas valider l'exhaustivité du schéma sans définition complète.

  • ECT-03 [MAJEUR] : Champ failure_reason non modélisé dans le modèle de données contractuel §5.1. Format (enum/string), emplacement (colonne DB/champ API) et valeurs contractuelles (PROOF_ENVELOPE_INCOMPLETE, autres ?) absents. TC-ERR-06 s'y réfère comme "observable" sans que l'observabilité soit garantie par contrat.

  • ECT-04 [MINEUR] : Mécanisme de "confirmation de téléchargement réussi" non défini. Trigger de la transition READY_FOR_DOWNLOAD → DOWNLOADED non contractualisé. Risque d'implémentation divergente ou de blocage.

  • ECT-05 [MINEUR] : Politique de purge post-téléchargement (PC-253-02) non tranchée. Fuite de stockage staging possible sur packages DOWNLOADED. À résoudre avant Gate 5.

  • ECT-06 [MINEUR] : Reprise après FAILED_TIMEOUT (PC-253-05) non contractualisée. Libération explicite du quota et mode de relance absents. À résoudre avant Gate 5.

  • ECT-07 [MINEUR] : TC-NOM-14 potentiellement non-déterministe. Contrôle de l'état du worker au moment de l'appel DELETE nécessite un mécanisme d'injection déterministe non défini.

  • ECT-08 [MINEUR] : TC-INV-11 : observabilité concrète non définie ("instrumentation sécurité activable" sans précision du mécanisme). Test non reproductible par une équipe tierce.

  • ECT-09 [MINEUR] : TC-INV-12 ne modélise pas le crash OOM/kill-signal (bypass finally). Sous-couverture du cas le plus critique pour INV-253-12.

  • ECT-10 [MINEUR] : CA-253-12 non annoté [CONDITIONNEL] dans §7 spec alors que les tests §9 le qualifient de "bloquant" si métriques absentes.

  • ECT-11 [MINEUR] : TC-NOM-13 accepte "200 ou 204" sans que la spec contractualise un seul code HTTP de succès pour l'annulation. Test partiellement non-déterministe.

  • ECT-12 [MINEUR] : Ambiguïté 504 EXPORT_TIMEOUT : code HTTP synchrone (retourné sur quel endpoint ?) vs état asynchrone FAILED_TIMEOUT (visible via GET status). Le mécanisme d'émission du 504 n'est pas explicité.


Convergences v2

  • Correction DIV-01 (FAILED_TIMEOUT absent de la machine à états) : vérifiée. L'état FAILED_TIMEOUT est présent en §5.4, documenté avec note explicative distinguant timeout infrastructure vs échec fonctionnel, et couvert par TC-ERR-09.
  • Correction DIV-02 (422 sync/async ambigu) : vérifiée. Le 422 est supprimé ; la détection de ProofEnvelope invalide est asynchrone avec état FAILED + failure_reason: PROOF_ENVELOPE_INCOMPLETE. Confirmé dans TC-ERR-06 et §8 observabilité tests.
  • Correction DIV-03 (transition DOWNLOADED non testée) : partiellement vérifiée. La spec documente le flux en §5.5 flux 3. Aucun TC dédié ne teste la transition READY_FOR_DOWNLOAD → DOWNLOADED (voir ECT-01 MAJEUR).
  • Correction DIV-04 (fallback export.sig strong→standard non contractualisé) : vérifiée. TC-NOM-06 couvre explicitement le fallback "le package reste au minimum standard si vérification strong indisponible". INV-253-06 et H-253-06 sont cohérents.
  • Correction DIV-05 (accès inter-utilisateur non contractualisé) : vérifiée. §5.7 contractualise les trois endpoints (GET status, download URL, DELETE) avec 403 FORBIDDEN_EXPORT_ACCESS. TC-SEC-01 couvre les trois opérations.
  • Correction ZO-08 (flux annulation non documenté) : vérifiée. §5.5 flux 4 documente l'annulation complète avec règles d'idempotence, transitions et traçage audit fail-closed. TC-NOM-13 et TC-NOM-14 couvrent les deux cas.

Verdict

RESERVE

La spec v2 et les tests v2 atteignent un niveau de maturité élevé. Les six corrections de la v1 sont toutes confirmées, dont cinq entièrement et une partiellement (DIV-03). Trois écarts MAJEURS résiduels (ECT-01, ECT-02, ECT-03) bloquent le GO.

Conditions pour passage GO (v3) :

  1. ECT-01 [MAJEUR] : Ajouter un TC dédié à la transition READY_FOR_DOWNLOAD → DOWNLOADED avec définition du mécanisme de confirmation de téléchargement.
  2. ECT-02 [MAJEUR] : Contractualiser le schéma complet de destruction-log.json dans §5.1 (champs obligatoires pour traçabilité NF Z42-013).
  3. ECT-03 [MAJEUR] : Modéliser failure_reason dans §5.1 (format, emplacement API, valeurs enum contractualisées).

Les écarts MINEURS (ECT-04 à ECT-12) sont des améliorations souhaitables. ECT-05 et ECT-06 doivent être résolus avant Gate 5 (plan). Les autres peuvent être adressés en v3 de spec/tests ou lors de l'étape 4.