Aller au contenu

PD-80 — Specification Review

Auditeur : ChatGPT (Gate 3 — CONFORMITY_CHECK) Documents audités : PD-80-specification.md (v3), PD-80-tests.md (v3) Date : 2026-03-12


Constats

C-01 — Ambiguïté : relation entre les trois rate-limits

Type : Ambiguïté
Référence : §5.2 (rate_limit_urgent=1/h, rate_limit_minor_hour=2/h, rate_limit_enterprise_hour=10/h)
Description : La spec définit trois rate-limits distincts sans préciser leur relation :
  - rate_limit_urgent (1 req/h/user) — semble être le rate-limit par défaut
  - rate_limit_minor_hour (2 req/h/compte)
  - rate_limit_enterprise_hour (10 req/h/user)
  Quel rate-limit s'applique à un compte premium ? rate_limit_urgent (1/h) ?
  Pour un mineur, rate_limit_urgent (1/h) et rate_limit_minor_hour (2/h) coexistent-ils ?
  Le "par user" vs "par compte" ajoute à la confusion (un compte mineur peut avoir un tuteur).
Impact : L'implémentation peut appliquer un rate-limit différent de celui attendu, ou appliquer
  les deux simultanément de manière non déterministe.
Gravité : Bloquant

C-02 — Ambiguïté : quota applicable aux comptes mineurs

Type : Ambiguïté
Référence : §5.1 (note enum account_type), §5.2 (quotas par plan), INV-80-02
Description : Les quotas mensuels sont définis par plan (freemium=3, premium=10, enterprise=1000).
  Le champ account_type distingue minor|standard|premium|enterprise. Le champ plan distingue
  freemium|premium|enterprise. Quel plan a un compte mineur (account_type=minor) ?
  La spec ne définit pas le mapping account_type=minor → plan. Si minor a plan=freemium,
  le quota est 3/mois. Si minor a un plan dédié, le quota est indéfini.
  INV-80-02 dit que le fast-track est automatique pour les mineurs, mais INV-80-07 impose
  les quotas "avant admission en queue prioritaire". Un mineur freemium à 3/3 est-il rejeté 403 ?
Impact : Un mineur pourrait se voir refuser un scellement urgent alors que la protection des mineurs
  est l'objectif premier de la story. Ou inversement, un quota non défini pourrait permettre un
  abus illimité.
Gravité : Bloquant

C-03 — Ambiguïté : définition de "job BullMQ actif" pour la réconciliation

Type : Ambiguïté
Référence : §5.10 (critère de détection d'orphelin : "sans job BullMQ actif correspondant")
Description : BullMQ distingue plusieurs états de job : waiting, delayed, active, completed, failed.
  La spec ne définit pas quels états BullMQ comptent comme "actif" pour le critère d'orphelin.
  Un job en état "delayed" (retry planifié) a un job BullMQ présent mais pas en cours
  d'exécution. Le considérer comme "actif" empêcherait la réconciliation d'un job réellement
  bloqué. Le considérer comme "inactif" déclencherait une fausse réconciliation.
Impact : Faux positifs (double exécution) ou faux négatifs (orphelins non détectés).
Gravité : Majeur

C-04 — Ambiguïté : conditions de déclenchement des transitions retour

Type : Ambiguïté
Référence : §5.4 (TSA_PENDING → QUEUED_PRIORITY, TSA_SEALED → TSA_PENDING)
Description : Les transitions retour sont décrites comme "décision technique explicite" avec
  des exemples entre parenthèses ("invalidation du résultat TSA", "token TSA corrompu").
  Les conditions exactes de déclenchement ne sont pas listées exhaustivement. L'implémentation
  devra décider quels cas justifient un retour vs un retry dans le même état. La frontière
  entre "retry (même état)" et "requeue (transition retour)" n'est pas contractualisée.
Impact : Comportement divergent entre implémentations. Impossible de tester exhaustivement.
Gravité : Majeur

C-05 — Contradiction potentielle : cycle non borné via transitions retour

Type : Hypothèse dangereuse
Référence : §5.4 (transitions retour), INV-80-06 (retries)
Description : La machine d'états autorise le cycle :
  TSA_PENDING → QUEUED_PRIORITY → TSA_PENDING → QUEUED_PRIORITY → ...
  et : TSA_SEALED → TSA_PENDING → QUEUED_PRIORITY → TSA_PENDING → ...
  INV-80-06 borne les retries à 4 (5e échec → arrêt), mais §5.4 point 2 dit explicitement
  que "les transitions retour sont des requeue internes distincts des retries". Le compteur
  de retry est "préservé" (TC-NOM-16) mais pas incrémenté par la transition retour elle-même.
  Seul le final_timeout borne le cycle, mais aucune borne explicite sur le nombre de
  transitions retour n'est contractualisée. Si les transitions retour sont fréquentes,
  le job peut osciller indéfiniment jusqu'au timeout.
Impact : Risque d'oscillation sans progrès. Pas de distinction entre "retry productif" et
  "boucle stérile" avant le final_timeout.
Gravité : Majeur

C-06 — Incohérence Spec↔Tests : FAILED_TIMEOUT terminal non testé explicitement

Type : Incohérence Spec↔Tests
Référence : §5.4 (FAILED_TIMEOUT → * : INTERDITE), CA-14, TC-ERR-09, TC-INV-01
Description : CA-14 dit "États terminaux bloquent toute sortie" (pluriel). TC-ERR-09 ne teste
  que SEALED. TC-INV-01 est défini comme "TC-ERR-09 + TC-ERR-10", mais TC-ERR-10 teste
  les états non terminaux avec transitions non listées. Aucun test ne vérifie explicitement
  que FAILED_TIMEOUT rejette une transition sortante.
  La matrice §5 note INV-80-01 couvert par TC-INV-01, mais le cas FAILED_TIMEOUT n'y est pas.
Impact : Régression possible si l'implémentation oublie de bloquer les transitions depuis
  FAILED_TIMEOUT.
Gravité : Majeur

C-07 — Incohérence Spec↔Tests : destruction DEK sur transition terminale non testée

Type : Incohérence Spec↔Tests
Référence : §5.14 (destruction DEK post-scellement), TC-NOM-09/TC-INV-09
Description : §5.14 contractualise la suppression de la DEK wrappée "dans la même transaction
  que la transition terminale" (SEALED ou FAILED_TIMEOUT). TC-NOM-09 vérifie uniquement
  l'absence de secrets en clair en base (INV-80-09). Aucun test ne vérifie :
  (a) que la DEK wrappée est effectivement supprimée après SEALED,
  (b) que la DEK wrappée est supprimée après FAILED_TIMEOUT,
  (c) que la suppression est synchrone dans la transaction terminale.
Impact : DEK wrappées résiduelles en base après scellement, accumulation de matériel crypto
  inutile, risque de non-conformité rétention.
Gravité : Majeur

C-08 — Incohérence Spec↔Tests : scénario INSUFFICIENT_DATA sans test dédié

Type : Incohérence Spec↔Tests
Référence : §3 (P95, N<100 → INSUFFICIENT_DATA), §5.2 (p95_min_samples), TC-NOM-03
Description : La spec contractualise un comportement spécifique quand N < p95_min_samples :
  "P95 marqué INSUFFICIENT_DATA, aucune violation SLA émise". Ce comportement est mentionné
  dans une clause AND de TC-NOM-03 mais n'a pas de test dédié. TC-NOM-03 GIVEN exige N≥100.
  Le cas inverse (N<100) n'est jamais le scénario principal d'un test.
Impact : Le comportement INSUFFICIENT_DATA pourrait ne pas être implémenté ou mal implémenté
  sans régression visible.
Gravité : Mineur

C-09 — Hypothèse dangereuse : panne Redis corrélée queue + réconciliation

Type : Hypothèse dangereuse
Référence : §5.10 (lock Redis), §5.7 (queue BullMQ/Redis)
Description : Le worker de réconciliation utilise un lock distribué Redis pour éviter la double
  exécution. BullMQ utilise le même Redis pour la queue. En cas d'indisponibilité Redis,
  les deux mécanismes échouent simultanément : plus de queue ET plus de réconciliation.
  La spec ne mentionne pas cette dépendance corrélée ni le comportement attendu en cas
  de panne Redis totale.
Impact : Perte simultanée du mécanisme principal (queue) et du filet de sécurité (réconciliation).
  Les jobs en cours n'ont plus aucune garantie de progression.
Gravité : Majeur

C-10 — Hypothèse dangereuse : vérification NTP au démarrage uniquement

Type : Hypothèse dangereuse
Référence : §5.13 (synchronisation horloge)
Description : La vérification NTP ±1s est effectuée "au démarrage du service". Aucune vérification
  périodique en runtime n'est spécifiée. Une dérive d'horloge survenant après le démarrage
  (perte de synchronisation NTP, VM migration) n'est pas détectée.
  Les calculs de latence P95, les SLA par étape et les horodatages TSA dépendent de cette
  synchronisation.
Impact : Mesures SLA faussées et horodatages TSA potentiellement non fiables sans détection.
Gravité : Mineur

C-11 — Risque sécurité : cycle de vie du token TSA invalidé

Type : Risque sécu/conformité
Référence : §5.4 (transition retour TSA_SEALED → TSA_PENDING), TC-NOM-17
Description : TC-NOM-17 dit "l'horodatage TSA précédent est invalidé (nouveau TSA requis)".
  La spec ne définit pas comment l'ancien token TSA est traité :
  - Est-il supprimé de la base ?
  - Est-il marqué comme invalidé avec motif ?
  - Reste-t-il en base avec un statut ambigu ?
  Un token TSA RFC 3161 est un artefact probatoire horodaté. Son cycle de vie post-invalidation
  a des implications de conformité (traçabilité, non-répudiation, audit).
Impact : Token TSA orphelin en base pouvant être confondu avec un token valide lors d'un audit.
  Risque de non-conformité traçabilité.
Gravité : Majeur

C-12 — Risque sécurité : vecteur d'abus compte mineur non borné en volume mensuel

Type : Risque sécu/conformité
Référence : INV-80-02, §5.2 (rate_limit_minor_hour=2/h), C-02 (quota mineur indéfini)
Description : Un compte mineur avec fast-track automatique (INV-80-02) et rate-limit 2/h peut
  générer jusqu'à 48 scellements urgents/jour soit ~1440/mois. Si le quota mensuel n'est
  pas défini pour les mineurs (cf. C-02), aucune borne mensuelle ne s'applique.
  En cas de compromission du compte, l'attaquant bénéficie du fast-track automatique sans
  aucune action manuelle requise et sans plafond mensuel contractualisé.
  Le rate_limit_minor_hour + "alerte sécurité" atténue le risque horaire mais pas le volume
  cumulé mensuel.
Impact : Abus de ressources prioritaires (TSA, queue, blockchain) via un compte mineur compromis.
Gravité : Majeur

C-13 — Ambiguïté : comportement en cas d'échec total de notification

Type : Ambiguïté
Référence : INV-80-08, §5.11, §5.12
Description : INV-80-08 est "satisfait si au moins un canal de notification réussit". La spec
  ne définit pas le comportement si TOUS les canaux échouent :
  - Push échoue (ou pas de device → fallback email)
  - Email échoue
  - Webhook échoue (retries épuisés → webhook_delivery_failed journalisé)
  Dans ce cas, INV-80-08 est violé. Quelle est la conséquence ? Le scellement reste SEALED
  (état terminal, pas de rollback possible). L'utilisateur n'est jamais informé.
  Aucune escalade spécifique à l'échec total de notification n'est prévue.
Impact : Scellement réussi mais utilisateur jamais notifié. Violation d'INV-80-08 sans
  remédiation contractualisée.
Gravité : Mineur

C-14 — Non testable : alerte CRITICAL pour reconciliation_max_catchup_delay dépassé

Type : Non testable
Référence : §5.2 (reconciliation_max_catchup_delay : "alerte CRITICAL si dépassé")
Description : §5.2 définit que le dépassement de reconciliation_max_catchup_delay (30 min)
  déclenche une alerte CRITICAL. Aucun test (TC-NOM-11, TC-NOM-18) ne vérifie ce cas.
  TC-NOM-11 vérifie le rattrapage SOUS le délai (happy path). Le cas où le rattrapage
  dépasse 30 min n'est pas couvert.
Impact : L'alerte CRITICAL pourrait ne jamais être implémentée.
Gravité : Mineur

C-15 — Ambiguïté : éligibilité au fast-track manuel (§5.6)

Type : Ambiguïté
Référence : §1 ("utilisateurs autorisés"), §5.6, INV-80-03, TC-NOM-02
Description : §1 mentionne "utilisateurs autorisés (manuel)" mais ne liste pas les critères
  d'autorisation au-delà du quota/rate-limit. TC-NOM-02 GIVEN dit "Compte
  standard/premium/enterprise éligible" — un compte minor est-il éligible au fast-track
  manuel EN PLUS de l'automatique ? Si oui, le mineur peut cumuler auto + manuel.
  Si non, la restriction n'est pas contractualisée.
Impact : Comportement API ambigu pour les requêtes manuelles urgentes venant d'un compte mineur.
Gravité : Mineur

Synthèse

Gravité Nombre IDs
Bloquant 2 C-01, C-02
Majeur 8 C-03, C-04, C-05, C-06, C-07, C-09, C-11, C-12
Mineur 5 C-08, C-10, C-13, C-14, C-15
Total 15