Aller au contenu

PD-284 — Agent Developer : seal-progress-card (C9)

1. Module implémenté

Fichier : src/components/seal/SealProgressCard.tsx

Responsabilité : Carte de progression 5 étapes, badges dégradation, badge hors-ligne, affichage position_in_queue en état QUEUED_PRIORITY, affichage failure_reason en état FAILED_TIMEOUT.

2. Invariants couverts

Invariant Mécanisme Fichier:ligne
INV-284-05 computeDegradationBadge() consomme degradationFlag brut du store — aucun Date.now(), timer, ni comparaison de durée SealProgressCard.tsx:computeDegradationBadge
INV-284-06 Affichage dérivé de currentState via STATE_TO_VISUAL_STEP (table importée de types/seal.ts, conforme PD-80) SealProgressCard.tsx:computeVisualSteps
INV-284-08 SEALED affiche message succès terminal, FAILED_TIMEOUT affiche overlay failure avec failureReason + message support SealProgressCard.tsx sections terminales
INV-284-09 Badge "Hors ligne" conditionné uniquement par prop isOffline (perte réseau réelle, pas échec SSE) SealProgressCard.tsx render conditionnel isOffline

3. Critères d'acceptation couverts

CA Mécanisme Observable
CA-284-06 computeVisualSteps() mappe currentState → étapes visuelles monotones via STATE_TO_VISUAL_STEP Étapes completed/active/pending sans retour arrière
CA-284-10 Badge "Hors ligne" uniquement si isOffline=true testID="seal-offline-badge" absent si SSE échoue mais réseau OK
CA-284-11 selectDegradationFlag consomme flag brut → computeDegradationBadge() → badge exact testID="seal-degradation-badge" avec label "En retard" ou "Critique"
CA-284-14 6 sélecteurs granulaires (un par champ), React.memo sur StepIndicator, useMemo sur dérivations Re-renders isolés par champ modifié

4. Tests contractuels mappés

Test ID Couvert Mécanisme
TC-NOM-05 Oui computeVisualSteps() avec séquence d'états ordonnés → étapes monotones
TC-NOM-06 Oui currentState === "SEALED" ou "FAILED_TIMEOUT" → sections terminales sans transition sortante
TC-NOM-07 Oui transportMode === "POLLING" + !isOffline → badge "Mode dégradé", pas "Hors ligne"
TC-NOM-08 Oui degradationFlag → badge UI strictement aligné (none/delayed/critical → aucun/"En retard"/"Critique")
TC-NOM-12 Non (C10) Mode expert délégué à ExpertPanel.tsx (C10)
TC-NOM-14 Oui isOffline=true → badge "Hors ligne" visible + dernier état conservé dans store
TC-ERR-02 Partiel L'état reste cohérent (pas de mutation directe — le store gère les rejets)

5. Décisions architecturales

5.1 isOffline comme prop vs hook interne

  • Décision : Prop isOffline: boolean fournie par le parent
  • Justification : Le hook useNetworkStatus() basé sur NetInfo n'existe pas encore dans le codebase. Créer un hook réseau à l'intérieur de C9 violerait la séparation des responsabilités (C9 = UI pure, pas détection réseau). Le parent (SealDetailScreen C14) injectera la valeur depuis un hook dédié.
  • Alternatives considérées : (1) Hook interne — rejeté car responsabilité hors périmètre C9. (2) Zustand store pour état réseau — rejeté car suringénierie (un simple prop suffit).
  • Trade-offs : Le composant ne peut pas fonctionner sans que le parent fournisse isOffline. Acceptable car C14 est le seul consommateur.

5.2 FAILED_TIMEOUT comme overlay vs 6e étape

  • Décision : FAILED_TIMEOUT n'est PAS une 6e étape — c'est un overlay rouge distinct sous les steps
  • Justification : Conforme au plan §2.1b : "FAILED_TIMEOUT n'est PAS une 6e étape mais un overlay rouge sur la dernière étape active au moment de l'échec."
  • Alternatives considérées : 6e étape dans la liste — rejeté car non conforme au plan et à la spec.
  • Trade-offs : La carte affiche les 5 étapes + un bloc erreur séparé. L'étape en cours au moment du failure n'est pas visuellement marquée comme "étape échouée" (on marque la 1ère étape comme failed par défaut car l'info de "dernière étape avant échec" n'est pas dans le store).

6. Hypothèses

  1. H-DEV-01 : Le parent (C14) fournit isOffline basé sur NetInfo. Si NetInfo n'est pas installé, le badge sera toujours absent (fail-safe).
  2. H-DEV-02 : Le store (useSealStore) est initialisé avant le rendu de la carte. Si currentState === null, la carte ne rend rien.
  3. H-DEV-03 : Les traductions i18n pour le namespace seal.progressCard.* seront ajoutées dans les fichiers de locale. Les defaultValue servent de fallback FR.

7. Fichiers modifiés

Fichier Action Justification
src/components/seal/SealProgressCard.tsx Créé Composant C9 — carte de progression

8. Dépendances

Composant Direction Nature
C1 (seal-types) Import Types, constantes, VISUAL_STEPS, STATE_TO_VISUAL_STEP
C5 (seal-store) Import Sélecteurs granulaires Zustand
C14 (seal-detail-screen) Consommateur Intègre C9 et fournit isOffline

9. Signalements

  • Hors périmètre C9 : Le hook useNetworkStatus() doit être créé (probable fichier src/hooks/useNetworkStatus.ts) et la dépendance @react-native-community/netinfo installée. C14 est responsable de l'injection.
  • Limitation FAILED_TIMEOUT : Le store ne conserve pas l'état précédant le FAILED_TIMEOUT. La carte marque la 1ère étape comme "failed" par défaut. Si un rendu plus précis est souhaité (marquer l'étape exacte d'échec), le store devrait exposer un champ lastNonTerminalState.