PD-284 — Plan d'implémentation : Revue (Gate 5 v1)¶
1. Références¶
- Spécification : PD-284-specification.md (v3)
- Tests contractuels : PD-284-tests.md (v3)
- Plan d'implémentation : PD-284-plan.md
- Code contracts : PD-284-code-contracts.yaml
- Specification Review (Gate 3 v2) : PD-284-specification-review.md
- Date de revue : 2026-03-13
- Reviewer : Claude (mode factuel, Gate 5 AMBIGUITY)
2. Constatations (écarts)¶
E-01 — Contradiction HT-03 vs code contract seal-sse-client : lib tierce à la fois mitigation et interdite¶
| Champ | Valeur |
|---|---|
| Type | Hypothèse implicite |
| Référence | Plan §8 HT-03 / CC seal-sse-client forbidden |
| Description | HT-03 admet que Expo SDK 54 peut ne pas supporter fetch en mode streaming (pour SSE custom). La mitigation proposée est « nécessiterait une lib native tierce ». Or le code contract du module seal-sse-client interdit explicitement « Utiliser une lib EventSource tierce (implémentation fetch-based custom) ». Si HT-03 est invalidée, la seule mitigation documentée viole le contrat du module. Aucune alternative contractuellement autorisée n'est prévue. |
| Impact | Plan non exécutable si l'hypothèse HT-03 est invalidée — impasse architecturale sans issue contractuelle. |
| Gravité | MAJEUR |
E-02 — Mapping 7 états → 5 étapes visuelles non documenté¶
| Champ | Valeur |
|---|---|
| Type | Ambiguïté |
| Référence | Plan §1 C9, CC seal-progress-card / Spec §5.7 (7 états) |
| Description | Le plan et le code contract de seal-progress-card déclarent 5 étapes visuelles : « Capture, TSA, Merkle, Blockchain, Scellé ». La spec §5.7 définit 7 états (RECEIVED, QUEUED_PRIORITY, TSA_PENDING, TSA_SEALED, ANCHOR_PENDING, SEALED, FAILED_TIMEOUT). Le mapping états → étapes visuelles n'est documenté ni dans le plan, ni dans les code contracts, ni dans la spec. Exemples d'ambiguïtés : RECEIVED et QUEUED_PRIORITY correspondent-ils tous deux à « Capture » ? ANCHOR_PENDING correspond-il à « Merkle » ou « Blockchain » ? FAILED_TIMEOUT est-il une 6e étape visuelle ou un overlay sur l'étape courante ? |
| Impact | L'implémenteur doit inventer le mapping état↔étape visuelle sans contrat — risque d'incohérence entre composants C2 et C9. |
| Gravité | MAJEUR |
E-03 — failure_reason (FAILED_TIMEOUT) : champ contractuel non exploité¶
| Champ | Valeur |
|---|---|
| Type | Couverture manquante |
| Référence | Spec §5.12 (payload FAILED_TIMEOUT) / Plan §1-§6 |
| Description | La spec §5.12 liste failure_reason comme champ obligatoire additionnel pour l'état FAILED_TIMEOUT. Le plan §6 mentionne « message de contact support » pour cet état terminal mais ne référence jamais failure_reason. Aucun composant (C9, C10, C14), aucun code contract, aucun mapping §3-§5 ne consomme ni n'affiche ce champ. Le code contract seal-types (C1) ne le liste pas dans ses interfaces. |
| Impact | Donnée contractuelle obligatoire reçue et ignorée — l'utilisateur ne voit pas la raison d'échec fournie par le backend. |
| Gravité | MAJEUR |
E-04 — Absence de purge proactive (purgeStale) au démarrage¶
| Champ | Valeur |
|---|---|
| Type | Risque sécu/conformité |
| Référence | Plan §7 / CC seal-secure-storage / Learnings PD-283, PD-262 |
| Description | Le plan repose uniquement sur useEffect cleanup (unmount de SealDetailScreen, C14) et sur la purge à la déconnexion/suppression de compte pour supprimer les artefacts sensibles en SecureStore. Un crash app (OOM, kill signal, force-quit iOS) bypass le cleanup React et les hooks. Les artefacts sensibles (tsa_token_ref, clés session SSE) restent en SecureStore jusqu'au prochain logout explicite. Les learnings PD-283 et PD-262 imposent explicitement un mécanisme purgeStale() au démarrage du flux (pas seulement en cleanup) pour garantir le zero-residuel après crash. Aucun composant ni code contract ne prévoit cette purge proactive. |
| Impact | Artefacts sensibles résiduels après crash app — violation potentielle de INV-284-10 et de la politique de purge §5.11. |
| Gravité | MAJEUR |
E-05 — Section « Contraintes techniques » absente du plan¶
| Champ | Valeur |
|---|---|
| Type | Contrainte technique non documentée |
| Référence | Plan (section absente) / Procédure Gate 5 axe 7 |
| Description | Le plan ne contient pas de section « Contraintes techniques » documentant : (a) Statut de PD-80 : dépendance principale, statut non déclaré (DONE / TODO / STUB). Le plan suppose que les endpoints POST /seals/urgent, GET /seals/{id}/status et le flux SSE existent, sans préciser s'ils sont implémentés ou stubbés. (b) Framework de test : ni Jest, ni Vitest, ni React Native Testing Library ne sont explicitement choisis. Le §12 mentionne des niveaux (Unit, Integration, Perf) sans framework. © Compatibilité ESM/CJS : l'implémentation SSE fetch-based custom peut dépendre de modules ESM-only (ReadableStream polyfill, etc.). Non documenté. (d) Variables CI : aucune variable d'environnement CI documentée pour les tests d'intégration avec mocks API. |
| Impact | Risque de blocage CI (framework non compatible, ESM runner manquant) et de dépendance PD-80 non traçable. |
| Gravité | MAJEUR |
E-06 — TC-NOM-13 (P95 ≤ 100ms) exclu du CI — CA-284-14 non vérifiable en non-régression¶
| Champ | Valeur |
|---|---|
| Type | Test irréalisable |
| Référence | TC-NOM-13 / Plan §12 / CA-284-14 |
| Description | Le plan §12 exclut TC-NOM-13 du CI : « nécessite un iPhone 12+ physique. Exécution manuelle hors CI. Ticket de suivi : à créer post-Gate 8. » Le critère d'acceptation CA-284-14 (« Perf rendu événement→UI respecte P95 ≤ 100ms ») n'a donc aucune vérification automatisée. Toute régression de performance est silencieuse. Le « ticket de suivi » est un report sans engagement contractuel. |
| Impact | CA-284-14 non vérifiable en non-régression automatisée. Dégradation perf invisible. |
| Gravité | MAJEUR |
E-07 — has_active_urgent_seal défaut false : fail-open sur hypothèse inter-story¶
| Champ | Valeur |
|---|---|
| Type | Hypothèse implicite |
| Référence | Plan §8 HT-06 / R-03 / Spec §5.6 / Gate 3 E-04 |
| Description | Le plan justifie le défaut false (fail-open) pour has_active_urgent_seal absent/invalide par l'idempotence de PD-80 sur POST /seals/urgent : « un second POST retourne le seal existant, pas de doublon ». Cette justification repose entièrement sur un comportement cross-story (PD-80) hors périmètre PD-284. L'idempotence de PD-80 n'est ni vérifiée ni contractualisée dans les documents d'entrée de PD-284. Gate 3 E-04 avait déjà signalé ce risque. Le plan le reconnaît (R-03) mais ne le mitige pas — il le déclare « acceptable ». |
| Impact | Double déclenchement de scellement urgent si l'hypothèse d'idempotence PD-80 est fausse. |
| Gravité | MAJEUR |
E-08 — Contradiction interne : Set<number> vs ring buffer pour cache FIFO¶
| Champ | Valeur |
|---|---|
| Type | Ambiguïté |
| Référence | Plan §4 (CA-284-07) vs Plan §9 point 3 / CC seal-event-processor |
| Description | Le mapping §4 pour CA-284-07 décrit le cache de déduplication comme « Cache FIFO Set<number> de taille N=100 ». Le §9 point 3 exige « un tableau circulaire (ring buffer) pour l'éviction FIFO » et interdit « Set avec delete aléatoire ». Le code contract seal-event-processor confirme « ring buffer, pas LRU ». Le plan propose deux structures de données mutuellement exclusives pour le même mécanisme. Un Set JavaScript n'a pas d'éviction FIFO native. |
| Impact | L'implémenteur reçoit deux directives contradictoires — choix arbitraire nécessaire. |
| Gravité | MINEUR |
E-09 — position_in_queue : champ contractuel reçu sans exploitation¶
| Champ | Valeur |
|---|---|
| Type | Couverture manquante |
| Référence | Spec §5.12 (QUEUED_PRIORITY) / Plan §1-§5 |
| Description | La spec §5.12 liste position_in_queue comme champ obligatoire additionnel pour l'état QUEUED_PRIORITY. Aucun composant du plan (C9 carte, C10 expert, C5 store) ne mentionne ce champ. La validation Zod (C4/C6) le recevra mais aucun affichage ni stockage n'est prévu. Gate 3 E-09 avait signalé cette ambiguïté. Le plan ne la résout pas. |
| Impact | Donnée contractuelle reçue et ignorée — l'utilisateur ne voit pas sa position dans la file d'attente. |
| Gravité | MINEUR |
E-10 — Flux lecture tsa_token_ref SecureStore → ExpertPanel non documenté¶
| Champ | Valeur |
|---|---|
| Type | Code Contract — Cohérence |
| Référence | CC expert-panel forbidden / CC seal-secure-storage |
| Description | Le code contract C10 (expert-panel) interdit « Stocker tsa_token_ref en clair dans le state (doit être en SecureStore via C12) ». Le code contract C12 (seal-secure-storage) confirme que tsa_token_ref est en SecureStore uniquement. Mais C10 doit afficher ce champ en mode expert à l'état TSA_SEALED. Le mécanisme de lecture transitoire (SecureStore → affichage sans passage par le state Zustand) n'est documenté ni dans le plan ni dans les contrats. Aucune interface de C12 ne propose un getter pour l'affichage. |
| Impact | L'implémenteur ne sait pas comment afficher un artefact sensible sans violer le contrat qui interdit de le mettre en state. |
| Gravité | MINEUR |
E-11 — tsa_timestamp non typé dans seal-types¶
| Champ | Valeur |
|---|---|
| Type | Code Contract — Complétude |
| Référence | Spec §5.12 (TSA_SEALED) / CC seal-types interfaces |
| Description | La spec §5.12 liste tsa_timestamp comme champ obligatoire additionnel pour l'état TSA_SEALED. Le code contract seal-types (C1) ne le liste pas dans ses interfaces. Il n'apparaît ni dans les types, ni dans les schémas de validation Zod. Un événement TSA_SEALED conforme à la spec mais contenant tsa_timestamp pourrait être rejeté ou accepté sans validation. |
| Impact | Champ contractuel non couvert par le typage ni la validation — lacune de complétude dans le modèle de types. |
| Gravité | MINEUR |
E-12 — degradation_flag inconnu : interprétation silencieuse non justifiée¶
| Champ | Valeur |
|---|---|
| Type | Ambiguïté |
| Référence | Spec §5.3 vs Spec §3 (définition erreur contrôlée) / Plan §6 |
| Description | La spec §5.3 dit qu'un degradation_flag inconnu est « traité comme none + trace telemetry ». Le plan §6 confirme : telemetry unknown_degradation_flag, pas de toast. Mais la définition d'erreur contrôlée (spec §3) inclut « toast non bloquant affiché 5 secondes ». Le plan fait le choix d'une trace silencieuse (pas de toast) pour un flag inconnu. Ce choix semble raisonnable mais n'est pas formellement justifié : un flag inconnu est-il une « erreur contrôlée » au sens §3, ou un cas normal traité de façon conservatrice ? Le plan ne tranche pas explicitement. |
| Impact | Ambiguïté mineure sur le comportement UX — risque d'écart en implémentation. |
| Gravité | MINEUR |
E-13 — Préférence mode_expert : tâche implicite hors contrat¶
| Champ | Valeur |
|---|---|
| Type | Tâches manquantes |
| Référence | Plan §9 (dette technique) / CC expert-panel |
| Description | Le plan §9 reconnaît que « La préférence mode_expert n'existe pas encore dans le store settings. À ajouter dans useAuthStore ou un nouveau useSettingsStore ». Mais aucun composant du plan (C1-C15), aucun code contract, aucun fichier autorisé ne couvre cette modification. C10 (ExpertPanel) dépend de cette préférence via son guard if (!modeExpert) return null. La tâche est reconnue mais non formalisée : pas de module, pas de contrat, pas de fichier. |
| Impact | Tâche implicite hors périmètre contractuel — risque d'oubli en implémentation step 6b. |
| Gravité | MINEUR |
3. Synthèse¶
Récapitulatif par gravité¶
| Gravité | Nombre | IDs |
|---|---|---|
| BLOQUANT | 0 | — |
| MAJEUR | 7 | E-01, E-02, E-03, E-04, E-05, E-06, E-07 |
| MINEUR | 6 | E-08, E-09, E-10, E-11, E-12, E-13 |
Récapitulatif par type¶
| Type d'écart | Nombre | IDs |
|---|---|---|
| Hypothèse implicite | 2 | E-01, E-07 |
| Ambiguïté | 3 | E-02, E-08, E-12 |
| Couverture manquante | 3 | E-03, E-09, E-11 |
| Risque sécu/conformité | 1 | E-04 |
| Contrainte technique non documentée | 1 | E-05 |
| Test irréalisable | 1 | E-06 |
| Code Contract — Cohérence | 1 | E-10 |
| Tâches manquantes | 1 | E-13 |
Points critiques¶
-
Impasse architecturale SSE (E-01) : La mitigation de HT-03 viole le code contract du même module. Si Expo SDK 54 ne supporte pas le streaming fetch, le plan est bloqué sans alternative contractuellement autorisée.
-
Mapping états→étapes visuelles (E-02) : 7 états backend → 5 étapes visuelles, sans table de correspondance. Risque d'incohérence entre la state machine (C2) et l'affichage (C9).
-
Sécurité post-crash (E-04) : Le pattern
purgeStale()issu de PD-283/PD-262 n'est pas appliqué. Les artefacts sensibles survivent aux crashs app. -
Performance non vérifiable (E-06) : CA-284-14 (P95 ≤ 100ms) sans vérification automatisée — toute régression est invisible.
-
Section contraintes techniques absente (E-05) : Ni le statut de PD-80, ni le framework de test, ni la compatibilité ESM/CJS ne sont documentés.
4. Verdict de la revue¶
- Statut : ⚠️ Accepté avec réserves
- Motif synthétique : Le plan est globalement conforme à la spec et couvre les 13 invariants et 17 critères d'acceptation. L'architecture en 15 composants est cohérente et les code contracts sont complets en périmètre. Cependant, 7 écarts MAJEUR nécessitent une correction avant implémentation : contradiction interne sur la stratégie SSE (E-01), mapping états→visuels absent (E-02), champ
failure_reasonnon exploité (E-03), absence de purge proactive post-crash (E-04), section contraintes techniques manquante (E-05), test perf non automatisé (E-06), et hypothèse fail-open inter-story non mitigée (E-07). Aucun écart n'est bloquant — tous sont résolvables par ajouts documentaires ou ajustements de contrats sans refonte de l'architecture.