Aller au contenu

PD-284 — Scénarios de tests contractuels (v3)

1. Références

  • Spécification : PD-284-specification.md (v3)
  • Epic : EPIC-XX (identifiant réel à confirmer, cf. Q-284-01)

2. Matrice de couverture

ID Invariant ID Critère ID Test Couverture Commentaire
INV-284-01 CA-284-02 TC-NOM-01 Oui Bouton urgent visible pour account_type != minor + quota affiché
INV-284-02 CA-284-01 TC-NOM-02 Oui Compte minor : aucun bouton urgent affiché
INV-284-03 CA-284-03 TC-NOM-03 Oui Bouton disabled quand quota=0 (tooltip "Quota épuisé")
INV-284-03 CA-284-04 TC-NOM-15 Oui Bouton disabled quand has_active_urgent_seal=true
INV-284-04 CA-284-03 TC-NOM-03 Oui Tooltip "Quota épuisé ce mois" quand quota=0
INV-284-04 CA-284-04 TC-NOM-15 Oui Tooltip "Scellement urgent déjà en cours" quand urgent actif
INV-284-05 CA-284-11 TC-NOM-10 Oui Badge dégradation reflète flags serveur uniquement
INV-284-06 CA-284-05 TC-NOM-05 Oui Transitions autorisées selon §5.7
INV-284-06 CA-284-05 TC-ERR-04 Oui État inconnu / transition interdite → erreur contrôlée
INV-284-07 CA-284-05 TC-NOM-05 Oui Table des sorties par état appliquée strictement
INV-284-08 CA-284-08 TC-NOM-06 Oui SEALED terminal + notification succès
INV-284-08 CA-284-09 TC-NOM-07 Oui FAILED_TIMEOUT terminal + notification échec
INV-284-08 CA-284-05 TC-ERR-06 Oui Toute transition sortante depuis terminal interdite
INV-284-09 CA-284-06 TC-NOM-14 Oui Perte réseau → badge Hors ligne immédiat
INV-284-09 CA-284-06 TC-NOM-08 Oui Échec SSE sans perte réseau → bascule polling silencieuse (pas de badge)
INV-284-10 N/A TC-INV-09 Oui Artefacts sensibles (tsa_token_ref, tokens) protégés iOS Keychain/SecureStore
INV-284-11 N/A TC-INV-11 Oui Artefacts publics (hash, merkle, tx) non classés sensibles
INV-284-12 CA-284-08 TC-NOM-06 Oui Deep-link succès vers seal_id
INV-284-12 CA-284-09 TC-NOM-07 Oui Deep-link échec vers seal_id
INV-284-13 N/A TC-INV-10 Partielle Vérification périmètre backend via traçage réseau
N/A CA-284-05 TC-NOM-04 Oui Après POST, GET /seals/{id}/status AVANT ouverture SSE
N/A CA-284-07 TC-NOM-16 Oui Déduplication client par event_id (cache N=100)
N/A CA-284-08 TC-NOM-17 Oui Tri par sequence_number + resync si gap
N/A CA-284-10 TC-NOM-13 Oui Latence rendu événement→UI P95 ≤ 100 ms
N/A CA-284-11 TC-NOM-11 Oui Panneau expert absent si mode_expert=false
N/A CA-284-12 TC-NOM-12 Oui Champs expert progressifs selon état et payload §5.12
N/A §5.12 TC-NOM-18 Oui Payload SSE contractualisé par état (champs requis)

3. Scénarios de test – Flux nominaux

TEST-ID: TC-NOM-01
Référence spec: INV-284-01, CA-284-02

GIVEN
  - Utilisateur authentifié account_type=standard
  - document_id valide
  - Donnée serveur: urgent_quota_remaining=2
WHEN
  - L'utilisateur ouvre l'écran détail document
THEN
  - Le bouton "Scellement urgent" est visible
  - Le bouton est actif
  - Le quota restant affiché vaut "2" (strictement cohérent payload)
AND
  - Aucun message d'inéligibilité n'est affiché
TEST-ID: TC-NOM-02
Référence spec: INV-284-02, CA-284-01

GIVEN
  - Utilisateur authentifié account_type=minor
  - document_id valide
WHEN
  - L'utilisateur ouvre l'écran détail document
THEN
  - Aucune occurrence du bouton "Scellement urgent" n'est rendue
AND
  - Aucune action UI ne permet de déclencher un urgent explicite
TEST-ID: TC-NOM-03
Référence spec: INV-284-01, CA-284-03 (v2)

GIVEN
  - Utilisateur account_type=premium
  - urgent_quota_remaining=0
  - has_active_urgent_seal=false
  - document_id valide
WHEN
  - L'utilisateur ouvre l'écran détail document
THEN
  - Le bouton urgent est visible et disabled (jamais absent)
  - La raison explicite "quota épuisé" est affichée
AND
  - Aucune requête de déclenchement urgent n'est émise sur interaction
TEST-ID: TC-NOM-04
Référence spec: Flux A §5.1, CA-284-05, §5.12 (v3)

GIVEN
  - Bouton urgent visible et actif
  - Mock API POST urgent répond succès avec seal_id valide
  - Mock API GET /seals/{id}/status disponible
WHEN
  - L'utilisateur appuie sur "Scellement urgent"
THEN
  - Un feedback immédiat de chargement est visible
  - Le client appelle GET /seals/{id}/status avant toute ouverture SSE
  - La carte de progression du scellement s'affiche avec l'état retourné par GET
AND
  - L'abonnement SSE est initialisé uniquement après succès du GET status
TEST-ID: TC-NOM-05
Référence spec: INV-284-04, INV-284-05, CA-284-05, §5.7

GIVEN
  - Carte active pour seal_id S
  - Flux SSE fournit la séquence:
    RECEIVED -> QUEUED_PRIORITY -> TSA_PENDING -> TSA_SEALED -> ANCHOR_PENDING -> SEALED
WHEN
  - Chaque événement valide est reçu dans l'ordre
THEN
  - L'UI reflète exactement la séquence sans saut interdit
  - L'étape visuelle "Scellé" n'apparaît qu'à l'état SEALED
AND
  - Aucun retour arrière d'étape n'est affiché
TEST-ID: TC-NOM-06
Référence spec: INV-284-06, INV-284-08, CA-284-08, Flux E

GIVEN
  - Scellement en ANCHOR_PENDING pour seal_id S
  - Canal notification mobile disponible
WHEN
  - Événement terminal SEALED reçu
THEN
  - L'UI passe en état terminal succès
  - Une notification succès est émise
  - Le deep-link ouvre l'écran détail du scellement S
AND
  - Aucun polling/SSE supplémentaire n'est requis pour transition ultérieure
TEST-ID: TC-NOM-07
Référence spec: INV-284-06, INV-284-08, CA-284-09, Flux E

GIVEN
  - Scellement en cours pour seal_id S
  - Canal notification mobile disponible
WHEN
  - Événement terminal FAILED_TIMEOUT reçu
THEN
  - L'UI passe en état terminal échec
  - Le message de contact support est visible
  - Une notification échec est émise
  - Le deep-link ouvre l'écran détail du scellement S en terminal
AND
  - Aucune transition sortante n'est ensuite affichable
TEST-ID: TC-NOM-08
Référence spec: INV-284-07, CA-284-06, Flux B (v2)

GIVEN
  - Suivi actif via SSE pour seal_id S
  - Connectivité réseau disponible (pas de coupure réseau)
  - Paramètre sse_reconnect_base_delay=1s
WHEN
  - La connexion SSE échoue 3 fois consécutivement
THEN
  - Les tentatives de reconnexion respectent un backoff exponentiel: 1s, 2s, 4s
  - Le badge "Hors ligne" n'est pas affiché (pas de perte réseau)
  - Le client bascule silencieusement en polling périodique toutes les 5 secondes
AND
  - Le journal client trace explicitement la séquence SSE retry puis bascule SSE->polling
TEST-ID: TC-NOM-09
Référence spec: Flux B §5.2

GIVEN
  - Le client est en mode polling après failover SSE
WHEN
  - Le canal SSE redevient disponible et connexion réussie
THEN
  - Le client revient en mode SSE
  - Le polling est arrêté
AND
  - L'état affiché reste cohérent avec le dernier événement valide reçu
TEST-ID: TC-NOM-10
Référence spec: INV-284-05, CA-284-11, Flux C (v3)

GIVEN
  - Scellement en cours
  - Backend envoie successivement degradation_flag: none, delayed, critical (enum §5.3 v3)
WHEN
  - Les événements sont reçus
THEN
  - Badge absent pour none, "En retard" pour delayed, "Critique" pour critical
AND
  - Aucun badge n'est inféré à partir d'un calcul local de durée si flag absent
TEST-ID: TC-NOM-11
Référence spec: Flux D, CA-284-11

GIVEN
  - Préférence utilisateur mode_expert=false
WHEN
  - L'utilisateur consulte un scellement à n'importe quel état
THEN
  - Le panneau "Mode expert" est absent
AND
  - Aucun champ expert n'est rendu
TEST-ID: TC-NOM-12
Référence spec: Flux D, CA-284-12, §5.12 (v2)

GIVEN
  - Préférence utilisateur mode_expert=true
  - seal_id valide
WHEN
  - Les états progressent: RECEIVED -> TSA_SEALED -> ANCHOR_PENDING -> SEALED
THEN
  - hash_document apparaît dès réception valide
  - tsa_token_ref apparaît au plus tôt à TSA_SEALED
  - merkle_root apparaît quand backend le fournit
  - blockchain_tx_hash + proof package apparaissent uniquement à SEALED
AND
  - Les champs non disponibles restent masqués sans rupture de carte
TEST-ID: TC-NOM-13
Référence spec: Paramètre render_latency_after_valid_event, CA-284-10

GIVEN
  - Campagne de 500 événements SSE valides sur appareil de référence (iPhone 12+)
  - Horodatage t_event (réception) et t_render (UI stable) instrumenté
WHEN
  - La progression complète est rejouée
THEN
  - La distribution de latence respecte P95 <= 100 ms
AND
  - Tout résultat > 100 ms au P95 est classé non conforme contractuel
TEST-ID: TC-NOM-14
Référence spec: INV-284-07, Cas d'erreur "Coupure réseau" (v2)

GIVEN
  - Dernier état valide affiché = TSA_SEALED
  - Réseau indisponible
WHEN
  - La perte réseau est détectée
THEN
  - L'UI conserve TSA_SEALED
  - Le badge "Hors ligne" est affiché immédiatement
AND
  - La reprise automatique est tentée jusqu'au retour connectivité
TEST-ID: TC-NOM-15
Référence spec: CA-284-04 (v3), champ has_active_urgent_seal

GIVEN
  - Utilisateur éligible urgent
  - urgent_quota_remaining > 0
  - has_active_urgent_seal=true
WHEN
  - L'utilisateur ouvre l'écran détail document
THEN
  - Le bouton urgent est visible et disabled
  - La raison explicite "scellement urgent déjà en cours" est affichée
AND
  - Aucune requête POST urgent n'est émise sur interaction
TEST-ID: TC-NOM-16
Référence spec: §5.12 (v2), déduplication event_id

GIVEN
  - Cache de déduplication client configuré à N=100 event_id
  - État courant TSA_PENDING
WHEN
  - Le client reçoit plusieurs événements identiques avec le même event_id
THEN
  - Seul le premier événement est appliqué
  - Les doublons sont ignorés silencieusement sans effet visuel secondaire
AND
  - En mode debug uniquement, une trace telemetry de déduplication est émise (pas de toast, pas de telemetry en production)
TEST-ID: TC-NOM-17
Référence spec: §5.12 (v2), sequence_number + resync gap

GIVEN
  - Flux SSE pour seal_id S avec sequence_number croissants attendus
WHEN
  - Un gap est détecté (ex: réception 41 puis 43, manque 42)
THEN
  - Le client déclenche une resynchronisation via GET /seals/{id}/status
  - L'UI n'applique pas d'état incohérent pendant la fenêtre de resync
AND
  - Après resync, l'ordre des états est rétabli selon sequence_number
TEST-ID: TC-NOM-18
Référence spec: §5.12 (v2), payload SSE contractualisé par état

GIVEN
  - Jeux d'événements SSE valides pour chaque état contractuel
WHEN
  - Chaque événement est injecté
THEN
  - Les champs requis par état sont présents et exploitables
  - Les champs progressifs n'apparaissent qu'aux états autorisés
AND
  - Tout payload conforme est rendu sans erreur contrôlée

4. Scénarios de test – Cas d’erreur

TEST-ID: TC-ERR-01
Référence spec: Cas d'erreur "POST urgent rejeté (4xx/5xx)"

GIVEN
  - Bouton urgent actif
  - API POST urgent répond 4xx métier
WHEN
  - L'utilisateur déclenche urgent
THEN
  - Message d'échec explicite affiché
  - Aucune carte de progression active n'est ouverte
  - Aucun abonnement SSE n'est démarré
AND
  - L'état document initial reste inchangé
TEST-ID: TC-ERR-02
Référence spec: Cas d'erreur "POST urgent rejeté (4xx/5xx)"

GIVEN
  - Bouton urgent actif
  - API POST urgent répond 5xx
WHEN
  - L'utilisateur déclenche urgent
THEN
  - Message d'échec technique affiché
  - Aucune progression active n'est affichée
AND
  - Aucun effet secondaire de scellement n'est visualisé
TEST-ID: TC-ERR-03
Référence spec: Cas d'erreur "Événement SSE invalide (format)", "erreur contrôlée" (v2)

GIVEN
  - Carte active sur seal_id S
WHEN
  - Un événement SSE mal formé est reçu (champ obligatoire manquant/invalide)
THEN
  - L'événement est ignoré
  - Un toast non bloquant est affiché pendant 5 secondes
  - Un log telemetry d'erreur contrôlée est émis
AND
  - L'UI conserve le dernier état valide sans interruption
TEST-ID: TC-ERR-04
Référence spec: INV-284-04, Cas d'erreur "état inconnu", "erreur contrôlée" (v2)

GIVEN
  - Dernier état valide = QUEUED_PRIORITY
WHEN
  - Un événement SSE propose transition interdite vers RECEIVED ou état non listé
THEN
  - Transition refusée côté affichage
  - Un toast non bloquant est affiché pendant 5 secondes
  - Un log telemetry d'anomalie de transition est émis
AND
  - Continuité de suivi maintenue sur dernier état valide
TEST-ID: TC-ERR-05
Référence spec: Cas d'erreur "seal_id incohérent"

GIVEN
  - Carte active sur seal_id S1
WHEN
  - Un événement SSE reçu porte seal_id S2 != S1
THEN
  - Événement ignoré
  - Aucune mutation d'état de la carte S1
AND
  - Journal client trace l'incohérence de corrélation
TEST-ID: TC-ERR-06
Référence spec: INV-284-06

GIVEN
  - État courant SEALED (puis scénario répété avec FAILED_TIMEOUT)
WHEN
  - Un événement ultérieur tente une transition sortante quelconque
THEN
  - L'état affiché reste terminal inchangé
  - L'événement est rejeté/ignoré comme invalide
AND
  - Un log telemetry d'anomalie contrôlée est produit
TEST-ID: TC-ERR-07
Référence spec: Cas d'erreur "Donnée expert invalide"

GIVEN
  - mode_expert=true
  - État compatible avec affichage d'artefact expert
WHEN
  - hash_document / merkle_root / blockchain_tx_hash ne respectent pas leur format contractuel
THEN
  - Le(s) champ(s) invalide(s) est/sont masqué(s)
  - Un toast non bloquant est affiché pendant 5 secondes
  - Un log telemetry de validation de payload est émis
AND
  - La carte de progression reste fonctionnelle
TEST-ID: TC-ERR-08
Référence spec: Flux E, Cas d'erreur "Push impossible : fallback email"

GIVEN
  - Terminal atteint (SEALED ou FAILED_TIMEOUT)
  - Envoi push indisponible simulé
WHEN
  - La clôture est traitée
THEN
  - L'absence de push est constatée côté client
  - Le signal de fallback email backend est observable (événement/trace contractuelle)
AND
  - L'utilisateur peut toujours accéder au détail via l'application
TEST-ID: TC-ERR-09
Référence spec: §5.12 (v2), resync gap sequence_number

GIVEN
  - Flux SSE actif avec sequence_number attendu=120
WHEN
  - Le client reçoit sequence_number=124 (gap multiple)
THEN
  - Le client ne rejoue pas localement des transitions spéculatives
  - Le client déclenche immédiatement un GET /seals/{id}/status de resync
AND
  - L'état UI est recalé sur la réponse de resync

5. Tests d’invariants (non négociables)

Invariant Test(s) dédiés Observable Commentaire
INV-284-01 TC-NOM-01 Bouton visible pour account_type != minor Visibilité déterministe
INV-284-02 TC-NOM-02 Absence stricte du bouton pour minor Non ambigu
INV-284-03 TC-NOM-03, TC-NOM-15 Bouton disabled quand quota=0 ou urgent actif Conditions d’activation v2
INV-284-04 TC-NOM-03, TC-NOM-15 Tooltips contractuels exacts Texte déterministe
INV-284-05 TC-NOM-10 Badge aligné flag backend, pas de calcul local Source de vérité serveur
INV-284-06 TC-NOM-05, TC-ERR-04 Transitions autorisées/interdites + erreur contrôlée Conformité machine d’états
INV-284-07 TC-NOM-05 Sorties autorisées/interdites vérifiées par état Exigence explicite
INV-284-08 TC-NOM-06, TC-NOM-07, TC-ERR-06 États terminaux sans transition sortante Fermeture stricte
INV-284-09 TC-NOM-14, TC-NOM-08 Badge Hors ligne (perte réseau) vs bascule silencieuse (échec SSE) Distinction v2
INV-284-10 TC-INV-09 Artefacts sensibles en stockage sécurisé (Keychain/SecureStore) Sécurité client v2
INV-284-11 TC-INV-11 Hash/merkle/tx non classés sensibles Clarification NT-01
INV-284-12 TC-NOM-06, TC-NOM-07 Deep-link ouvrable sur bon seal_id Traçabilité utilisateur
INV-284-13 TC-INV-10 Pas de nouvelle contrainte inter-modules backend Couverture partielle (périmètre client)
TEST-ID: TC-INV-09
Référence spec: INV-284-09 (v2)

GIVEN
  - Parcours complet jusqu'à SEALED avec mode_expert=true
WHEN
  - Inspection du stockage durable client (clé/valeur, fichiers, caches applicatifs)
THEN
  - Aucun tsa_token_ref en clair hors stockage sécurisé
  - Aucun token auth/session en clair hors stockage sécurisé
  - Les hashes (hash_document, blockchain_tx_hash) peuvent être persistés car non sensibles
AND
  - Toute persistance sensible constatée utilise iOS Keychain / SecureStore
TEST-ID: TC-INV-10
Référence spec: INV-284-10, §5.10

GIVEN
  - Suite de tests couvrant tous flux UI nominaux et erreurs
WHEN
  - Traçage réseau applicatif complet est collecté
THEN
  - Aucun nouvel appel inter-module backend hors contrats existants PD-80/PD-284 n'est observé
AND
  - Aucune exigence backend additionnelle n'est déduite depuis le client

6. Tests de non-régression

Test ID Objet Observable Commentaire
TC-NR-01 Régression visibilité bouton selon account_type/quota Bouton présent et disabled quand quota=0 Préserve INV-284-01/02
TC-NR-02 Régression machine d’états monotone Aucun retour arrière ni saut interdit en replay Préserve INV-284-04/05
TC-NR-03 Régression failover SSE Backoff 1s/2s/4s puis polling 5s, arrêt polling au retour SSE Préserve INV-284-07
TC-NR-04 Régression statut initial post-POST GET status systématique avant SSE Préserve Flux A v2
TC-NR-05 Régression notifications terminales Notifications succès/échec + deep-link correct Préserve INV-284-08
TC-NR-06 Régression mode expert progressif Ordre d’apparition des artefacts inchangé Préserve CA-284-12
TC-NR-07 Régression performance rendu P95 événement→UI <= 100 ms Préserve CA-284-10
TC-NR-08 Régression déduplication/event ordering Cache event_id N=100 + resync sur gap sequence Préserve §5.12
TC-NR-09 Régression sécurité stockage Aucun artefact sensible en clair non protégé Préserve INV-284-09

7. Tests négatifs et adversariaux

Test ID Entrée invalide / abus Résultat attendu Observable
TC-NEG-01 seal_id non UUID dans événement SSE Événement ignoré + erreur contrôlée (toast 5s + telemetry) Aucun changement d’état UI
TC-NEG-02 document_id invalide lors déclenchement urgent Rejet requête (4xx) + message échec Pas de carte progression
TC-NEG-03 Injection d’état backend inconnu (state=FOO) Erreur contrôlée non bloquante Dernier état valide conservé
TC-NEG-04 Transition inverse forcée (TSA_SEALED -> TSA_PENDING) Rejet de transition + telemetry Historique sans rollback
TC-NEG-05 hash_document non conforme regex Champ expert masqué non bloquant Carte intacte + toast 5s
TC-NEG-06 blockchain_tx_hash sans préfixe 0x Lien explorateur masqué Pas de crash UI
TC-NEG-07 Tempête de doublons même event_id (>100) Idempotence + éviction FIFO conforme cache N=100 Étape stable, logs dédup cohérents
TC-NEG-08 Réception désordonnée sequence_number Tri correct si possible, resync si gap Suivi cohérent sans état impossible
TC-NEG-09 Échec SSE sans perte réseau Bascule silencieuse en polling, pas de badge hors ligne UX non bloquante
TC-NEG-10 Tentative interaction urgente avec has_active_urgent_seal=true Action refusée/désactivée avec raison Aucun POST additionnel

8. Observabilité requise pour les tests

  • État système : état UI courant, étape visuelle, badge dégradation, badge Hors ligne, mode transport actif (SSE/polling).
  • Réponse API : payloads POST urgent, GET /seals/{id}/status, codes HTTP, messages métier, corrélation document_id/seal_id.
  • Journal d’audit client : transitions, erreurs contrôlées, bascules SSE/polling, retries backoff (délais exacts), validation de deep-link.
  • Telemetry obligatoire : émission d’événement sur erreur contrôlée, déduplication event_id, détection gap sequence_number, resync déclenché.
  • Mesure performance : horodatage réception (t_event) et rendu stable (t_render) pour P95.
  • Export probatoire : capture notifications reçues, preuve d’ouverture deep-link, dump traçage réseau, rapport inspection stockage local sécurisé.

9. Règles non testables

Règle Raison Impact
Validation formelle exhaustive tsa_token_ref Résolu v3 : format ASCII + regex ^[A-Za-z0-9:_-]{1,256}$ formalisés Majeur → testable
Politique iOS hors foreground (locale vs push distante) Décision produit non fixée (Q-284-06) Majeur
Vérification quota max par plan Valeurs non fournies (Q-284-08) Mineur
Référence Epic finalisée dans l’artefact Identifiant non fourni (Q-284-01) Mineur

10. Verdict QA

  • ✅ Testable quasi complètement (avec réserves résiduelles listées)

Motif : les corrections v2 rendent testables les points auparavant ambigus (bouton urgent déterministe, transport SSE/reconnexion, erreur contrôlée, payload SSE contractualisé, déduplication event_id, sequence_number, statut initial via GET avant SSE, classification hors-ligne). Les réserves restantes portent principalement sur des décisions produit et quelques formalismes de format non pleinement normés.