Aller au contenu

Je procède à l'audit complet du plan PD-103 contre la spec, les tests et les code contracts.

PD-103 — Plan d'implémentation : Revue

1. Références

  • Spécification : PD-103-specification.md (v3)
  • Tests contractuels : PD-103-tests.md (v3)
  • Plan d'implémentation : PD-103-plan.md
  • Code contracts : PD-103-code-contracts.yaml
  • Date de revue : 2026-04-03
  • Reviewer : Claude (auditeur PMO Gate 5)

2. Constatations (écarts)

# Type Référence (Spec/Test/Plan) Description Impact Gravité
ECT-01 Non-conformité Spec Spec §10.1 / Plan §2.1 step 4 La spec v3 §10.1 exige react-native-quick-crypto pour SHA3-256. Le plan utilise @noble/hashes/sha3 (pur JS) comme choix primaire et documente react-native-quick-crypto seulement comme hypothèse incertaine (HT-103-01). Le plan devrait utiliser la lib obligatoire de la spec ou documenter explicitement la dérogation avec justification technique vérifiée. Risque P95 capture > 3s (hash pur JS sur images volumineuses), non-conformité stack contractuelle. MAJEUR
ECT-02 Hypothèse implicite Spec §5.5 / Plan §2.2 step 1 Aucun contrat API explicite pour la demande d'URL pré-signée S3 (ni dans la spec, ni dans le plan). Le mobile appelle "le backend" pour obtenir une URL, mais l'endpoint, les paramètres requis, le format de réponse et la sémantique (single vs multipart) ne sont pas définis. De même, upload_object_key (champ requis du payload canonique §5.12) n'a pas d'origine documentée côté mobile. Ambiguïté d'intégration mobile/backend. L'agent M4 ne peut pas implémenter sans spécification de l'endpoint. MAJEUR
ECT-03 Couverture manquante Spec §5.6 / §5.8 / Plan §2.3 La spec distingue explicitement capture_events (table DB) et journal probatoire append-only comme deux artefacts séparés (§5.6 step 1, §5.8). Le plan et la migration M13 ne décrivent qu'une table capture_events. Le mécanisme d'append-only journal (table séparée ? event store ? WAL ?) n'est ni décrit ni migré. Rupture d'auditabilité : l'immutabilité du journal probatoire n'est pas garantie par la seule table capture_events (qui autorise les UPDATE). INV-103-25 exige persistance dans le journal append-only. MAJEUR
ECT-04 Code Contract — Invariant CC invariants_mapping vs Plan §3 INV-103-01 (fidelity) et INV-103-02 (no-transform) sont mappés à [CC-2] dans le code contracts, mais le plan §3 les mappe à M6 (orchestrator) et M6/M8 (UI). CC-2 (crypto pipeline) ne porte pas la responsabilité d'intégrité image — c'est l'orchestrateur (CC-6) et l'UI (CC-8) qui doivent garantir l'absence de transformation. CC-6 et CC-8 ne listent pas ces invariants. Responsabilité d'intégrité image mal attribuée : aucun agent ne sera explicitement chargé de vérifier l'absence de transcodage implicite. MAJEUR
ECT-05 Contrainte technique non documentée Plan §12 / Learnings ESM/CJS @noble/hashes est un package ESM-only. Le plan choisit Jest comme framework de test (CC-14) sans documenter la compatibilité ESM/CJS. Jest nécessite une configuration spécifique (--experimental-vm-modules ou transform) pour les modules ESM-only. Ce pattern a causé des échecs sur des stories précédentes. Tests non exécutables sans configuration ESM explicite du runner. MAJEUR
ECT-06 Hypothèse implicite Plan §2.3 / INV-103-11 Le job de réconciliation M12 (cron 10 min) ne dispose d'aucun mécanisme de lock de job pour environnement multi-instance. Si le backend tourne sur N instances, N réconciliations concurrentes s'exécutent simultanément. Le plan utilise pg_advisory_xact_lock pour les transitions individuelles, mais pas pour le job lui-même. Risque de double-suppression d'orphelins S3 ou double-positionnement de SEAL_DELAYED. Race condition sur réconciliation concurrente en production multi-instance. MAJEUR
ECT-07 Contrainte technique non documentée Plan §8 HT-103-03 Les dépendances PD-56 (Merkle), PD-55 (TSA/worker), PD-41 (blockchain) sont mentionnées comme STUB mais leur statut actuel (DONE / TODO / In Progress) n'est pas documenté. Le plan §9 point 5 dit "documenter comme STUB avec stories de destination" mais ne le fait pas formellement. Impossible de déterminer la faisabilité des tests E2E PENDING_SEAL → ANCHOR_CONFIRMED sans connaître l'état de ces dépendances. MAJEUR
ECT-08 Hypothèse implicite Spec §5.6 / Plan mapping CA-103-10 Le plan dit "Notification push iOS via expo-notifications déclenchée par SSE/polling backend à SEALED". Le mécanisme de trigger est ambigu : SSE/polling exige que l'app soit active au premier plan. La spec exige un push iOS (APNs), qui fonctionne même app fermée. Le plan ne spécifie pas le mécanisme serveur→APNs pour déclencher le push. Notification SEALED potentiellement non reçue si app en arrière-plan ou fermée. INV-103-12 exige "notification obligatoire". MAJEUR
ECT-09 Code Contract — Invariant CC-9 / INV-103-08 CC-9 (capture-ingest) liste INV-103-08 (sealed guard) dans ses invariants. Mais M9 est le service d'ingestion (POST /documents/capture), pas le worker de scellement. La garde PENDING_SEAL → SEALED est dans le pipeline backend existant, pas dans M9. Cette attribution est trompeuse : l'agent de CC-9 n'implémentera pas cette garde. L'invariant INV-103-08 n'est couvert par aucun code contract du périmètre PD-103 (délégué au pipeline existant sans vérification). MINEUR
ECT-10 Non-conformité Spec Spec §5.1 ocr_text / CC-9, CC-10 La spec v3 §5.1 exige pour ocr_text : "normalisation NFC + suppression des control chars C0/C1 (hors TAB, LF, CR) + longueur max". Ni CC-9 (validation DTO), ni CC-10 (idempotence) ne mentionnent explicitement la sanitisation NFC / control chars. La validation DTO class-validator standard ne couvre pas NFC ni le filtrage C0/C1. Données OCR non conformes acceptées en base sans sanitisation contractuelle. MINEUR
ECT-11 Hypothèse implicite Plan §2.1 step 2 Le plan utilise expo-screen-capture pour la capture d'écran. Ce module Expo est principalement conçu pour contrôler les permissions de screenshot (bloquer/autoriser les captures système), pas pour capturer programmatiquement le contenu de l'écran. Le mécanisme de capture réel (ex: react-native-view-shot, captureRef) n'est pas spécifié. Le format de sortie (URI vs buffer brut) impacte directement INV-103-01/02. Si la lib ne fournit pas un buffer PNG brut, un transcodage intermédiaire sera nécessaire, violant potentiellement INV-103-01/02. MINEUR
ECT-12 Code Contract — Cohérence Plan §2bis / Wave 3 La description "Wave 3 (3 agents)" suggère un parallélisme, mais M12 dépend de M9 (CC-12 depends_on: [CC-9]). M6 et M9 peuvent être parallèles, M12 doit être séquentiel après M9. La description est ambiguë. Risque d'ordonnancement incorrect si l'orchestrateur multi-agents parallélise M12 avec M9. MINEUR
ECT-13 Contrainte technique non documentée Plan §12 / CI Les variables d'environnement CI nécessaires aux tests d'intégration backend (M14) ne sont pas documentées : DATABASE_URL, credentials Vault pour S3, configuration rate-limit Redis. Tests d'intégration non reproductibles en CI sans documentation des prérequis environnementaux. MINEUR
ECT-14 Couverture manquante Spec §5.12 / Code Contracts Le champ upload_object_key est un champ requis du payload canonique d'idempotence (§5.12) mais n'apparaît dans aucun DTO d'entrée documenté, aucun code contract inputs, et aucun mécanisme du plan ne décrit sa génération ou transmission. Le fingerprint canonique d'idempotence ne pourra pas être calculé sans ce champ. MAJEUR

3. Synthèse

Nombre d'écarts par gravité :

Gravité Nombre
BLOQUANT 0
MAJEUR 9
MINEUR 5

Points critiques :

  1. Intégration mobile/backend sous-spécifiée (ECT-02, ECT-14) : L'API de génération d'URL pré-signée et le champ upload_object_key ne sont contractualisés nulle part. L'agent M4 et le fingerprint M10 ne peuvent pas être implémentés sans cette spécification.

  2. Journal probatoire append-only absent (ECT-03) : La table capture_events n'est pas un journal append-only (elle autorise UPDATE pour signature_status, seal_delayed, etc.). L'auditabilité exigée par INV-103-25 nécessite un mécanisme distinct d'immutabilité.

  3. Stack crypto mobile incertaine (ECT-01, ECT-05) : Le choix de @noble/hashes/sha3 (ESM-only, pur JS) vs react-native-quick-crypto (natif, contractuel) a des implications cascadées : performance P95, compatibilité Jest, conformité §10.1.

  4. Résilience multi-instance (ECT-06) : Le job de réconciliation n'est pas protégé contre l'exécution concurrente.

  5. Attribution d'invariants dans les code contracts (ECT-04) : INV-103-01/02 sont attribués au mauvais composant, créant un angle mort sur la garantie d'intégrité image.

4. Verdict de la revue

  • Statut : ⚠️ Accepté avec réserves
  • Motif synthétique : Le plan couvre l'ensemble des 39 invariants et 28 critères d'acceptation avec des mécanismes identifiés. Les 15 modules sont bien découpés avec des waves d'exécution cohérentes. Aucun écart n'est structurellement bloquant. Cependant, 9 écarts MAJEUR doivent être corrigés avant Gate 5 GO, dont 3 clusters critiques : (1) l'API presigned URL + upload_object_key non contractualisés, (2) le journal append-only non décrit dans le plan/migration, (3) la conformité stack crypto §10.1 et sa compatibilité ESM/Jest. Ces corrections sont localisées et n'invalident pas l'architecture globale.