Aller au contenu

PD-284 — Specification Review (Gate 3 v2)

Auditeur : Claude (mode factuel) Date : 2026-03-13 Documents analysés : PD-284-specification.md (v3), PD-284-tests.md (v3) Portée : Ecarts résiduels post-corrections v2/v3. Les ecarts corrigés en v2 et v3 ne sont PAS répétés.


Ecarts identifiés

E-01 — Matrice de couverture : références CA croisées incorrectes

Type : Incohérence Spec↔Tests Référence : Tests §2 (matrice de couverture) vs Spec §7 (critères d'acceptation) Description : Trois lignes de la matrice de couverture référencent des CA dont le contenu ne correspond pas à la définition dans la spec §7 :

Ligne matrice CA référencé Contenu matrice CA correct (spec §7)
INV-284-08 → CA-284-08 → TC-NOM-06 CA-284-08 = "Ordonnancement SSE par sequence_number" "SEALED terminal + notification succès" CA-284-12
INV-284-08 → CA-284-09 → TC-NOM-07 CA-284-09 = "Après 3 échecs SSE, fallback polling" "FAILED_TIMEOUT terminal + notification échec" CA-284-13
INV-284-09 → CA-284-06 → TC-NOM-14 CA-284-06 = "Carte suit états autorisés" "Perte réseau → badge Hors ligne" CA-284-10
INV-284-09 → CA-284-06 → TC-NOM-08 CA-284-06 = "Carte suit états autorisés" "Échec SSE → polling silencieux" CA-284-10

La traçabilité INV → CA → TC est rompue pour 3 invariants (INV-284-08, INV-284-09). Un auditeur externe ne peut pas vérifier la couverture sans reconstruire manuellement les liens.

Impact : Audit de couverture non fiable ; risque de faux sentiment de couverture. Gravité : Majeur


E-02 — TC-INV-09 : référence invariant incorrecte

Type : Incohérence Spec↔Tests Référence : Tests §5, TC-INV-09 header "Référence spec: INV-284-09 (v2)" Description : TC-INV-09 dit référencer INV-284-09 (badge Hors ligne) mais teste en réalité le stockage sécurisé des artefacts sensibles, qui correspond à INV-284-10 (aucun artefact sensible en clair). La matrice de couverture (§2) mappe correctement INV-284-10 → TC-INV-09, mais le header du scénario lui-même pointe vers le mauvais invariant.

Impact : Confusion lors d'un audit de traçabilité ; le test est fonctionnellement correct mais mal référencé. Gravité : Mineur


E-03 — Échec GET /seals/{id}/status post-POST non couvert

Type : Ambiguïté Référence : Spec §5.1 (Flux A, étape 5), §6 (Cas d'erreur) Description : Le Flux A impose un GET /seals/{id}/status obligatoire entre le POST réussi et l'ouverture SSE (étape 5). La section §6 couvre l'échec du POST (4xx/5xx) mais ne couvre pas l'échec du GET status.

Questions non résolues : - Le client doit-il réessayer le GET ? Avec quel backoff ? - Peut-il ouvrir SSE directement si le GET échoue (dégradé) ? - Doit-il afficher une erreur et abandonner la carte de progression ?

Aucun test (TC-ERR-*) ne couvre ce cas.

Impact : Comportement indéfini dans un scénario réaliste (GET échoue alors que le POST a réussi — le scellement est lancé côté backend mais l'UI est bloquée). Gravité : Majeur


E-04 — Défaut non sûr pour has_active_urgent_seal invalide

Type : Hypothèse dangereuse Référence : Spec §5.6, colonne "Si invalide" pour has_active_urgent_seal Description : Si has_active_urgent_seal est invalide (ni true ni false), la spec impose un défaut à false + telemetry. Ce défaut rend le bouton urgent activable alors que l'état réel est inconnu.

Un défaut sûr (fail-closed) serait true (bouton disabled), empêchant un double déclenchement si le serveur envoie des données corrompues.

Impact : Risque de double scellement urgent si le champ est corrompu ou absent. Le backend PD-80 possède probablement sa propre protection (idempotence), mais la spec PD-284 ne peut pas s'y appuyer sans hypothèse explicite. Gravité : Majeur


E-05 — Contradiction INV-284-01 vs règle format account_type invalide

Type : Contradiction Référence : Spec §4 INV-284-01, §5.6 colonne "Si invalide" pour account_type Description : - INV-284-01 : "Le bouton urgent est visible pour tout utilisateur account_type != minor" - §5.6 : si account_type invalide (hors enum) → "traiter comme non éligible"

Un account_type invalide est != minor, donc INV-284-01 exige que le bouton soit visible. Mais "non éligible" peut être interprété comme "bouton absent" (comportement minor) ou "bouton disabled".

La spec ne définit pas ce que signifie "non éligible" en termes d'affichage : absent (comme minor, violant INV-284-01) ou visible-disabled (cohérent avec INV-284-01 mais sans tooltip contractuel défini dans INV-284-04).

Impact : Comportement ambigu pour un cas limite qui pourrait survenir en cas de bug backend ou d'évolution de l'enum. Gravité : Mineur


E-06 — TC-INV-11 : absence de scénario GIVEN/WHEN/THEN

Type : Non testable Référence : Tests §2 (matrice), §5 (invariants) Description : TC-INV-11 est référencé dans la matrice de couverture et la table §5 pour couvrir INV-284-11 (artefacts publics non sensibles). Cependant, contrairement à TC-INV-09 et TC-INV-10, il n'a aucun scénario GIVEN/WHEN/THEN défini. Le test est mentionné mais pas spécifié.

Impact : INV-284-11 n'a pas de scénario de test exécutable. La couverture affichée est nominale. Gravité : Mineur


E-07 — Affichage du quota : comportement spécifié en scénario §8 mais absent des CAs

Type : Incohérence Spec↔Tests Référence : Spec §8 scénario 1 ("le quota est affiché"), Tests TC-NOM-01 ("Le quota restant affiché vaut '2'") Description : Le scénario §8.1 et TC-NOM-01 exigent que le quota restant soit affiché à l'utilisateur. Mais aucun CA ni invariant ne contractualise l'affichage de la valeur du quota. CA-284-02 dit seulement "Bouton présent même si non activable", et INV-284-03 ne parle que des conditions enabled/disabled.

Un test vérifie un comportement que la spec ne contractualise pas formellement.

Impact : Incertitude sur le caractère contractuel de l'affichage du quota. Si c'est requis, un CA dédié manque. Sinon, le test TC-NOM-01 exige un observable non spécifié. Gravité : Mineur


E-08 — degradation_flag inconnu : ambiguïté "erreur contrôlée" vs trace simple

Type : Ambiguïté Référence : Spec §5.3, §3 (définition "erreur contrôlée") Description : §5.3 stipule qu'une valeur degradation_flag non listée est "traitée comme none + trace telemetry". La définition d'erreur contrôlée (§3) inclut un "toast non bloquant affiché 5 secondes". La spec ne précise pas si un flag inconnu déclenche un toast (erreur contrôlée au sens §3) ou une simple trace telemetry silencieuse.

Le comportement est différent : un toast à chaque flag inconnu est intrusif ; une trace silencieuse est invisible pour l'utilisateur.

Impact : Ambiguïté d'implémentation sur le comportement UX face à un flag de dégradation inconnu. Gravité : Mineur


E-09 — position_in_queue : champ reçu sans comportement d'affichage spécifié

Type : Ambiguïté Référence : Spec §5.12 (payload SSE état QUEUED_PRIORITY) Description : L'état QUEUED_PRIORITY inclut un champ obligatoire position_in_queue dans le payload SSE. Ni la carte de progression (§5.2), ni le mode expert (§5.4), ni aucun CA ne spécifient comment cette donnée est affichée à l'utilisateur, ni si elle doit l'être.

Le champ est reçu et contractualisé côté transport mais son exploitation UX est indéfinie.

Impact : Un développeur ne sait pas s'il faut afficher la position, la logger, ou l'ignorer. Gravité : Mineur


E-10 — Re-tentative SSE depuis polling : absence de backoff ou plafond

Type : Hypothèse dangereuse Référence : Spec §5.2 point 8 Description : En mode polling, "à chaque cycle de polling (toutes les polling_interval_after_sse_failover secondes), le client tente en parallèle une connexion SSE". Avec le défaut 5s, cela produit une tentative SSE toutes les 5 secondes, indéfiniment, en plus du polling.

Aucun backoff ni plafond n'est défini pour ces re-tentatives SSE depuis le mode polling. Sur mobile, cela peut impacter la batterie et le réseau si le serveur SSE est durablement indisponible.

Impact : Consommation ressources mobile potentiellement excessive en cas d'indisponibilité SSE prolongée. Gravité : Mineur


E-11 — Attribut Keychain iCloud-proof : non testé

Type : Incohérence Spec↔Tests Référence : Spec §5.11 (kSecAttrAccessibleWhenUnlockedThisDeviceOnly), Tests TC-INV-09 Description : La spec exige explicitement l'attribut kSecAttrAccessibleWhenUnlockedThisDeviceOnly pour empêcher la restauration iCloud Keychain des artefacts sensibles. TC-INV-09 vérifie "Aucun tsa_token_ref en clair hors stockage sécurisé" mais ne vérifie pas l'attribut d'accessibilité spécifique.

Un artefact dans le Keychain avec kSecAttrAccessibleWhenUnlocked (sans ThisDeviceOnly) passerait TC-INV-09 mais violerait la règle de purge §5.11.

Impact : La protection contre la restauration iCloud n'est pas vérifiable par le test actuel. Gravité : Mineur


Synthèse

Gravité Nombre IDs
Bloquant 0
Majeur 3 E-01, E-03, E-04
Mineur 8 E-02, E-05, E-06, E-07, E-08, E-09, E-10, E-11

Ecarts majeurs à résoudre avant Gate 3 GO : 1. E-01 : Corriger les 4 références CA dans la matrice de couverture (traçabilité rompue). 2. E-03 : Ajouter le cas d'erreur "GET status échoue post-POST" dans §6 et un TC-ERR associé. 3. E-04 : Justifier le défaut false pour has_active_urgent_seal invalide ou changer en true (fail-closed).