PD-80 — Specification Review¶
Axe 1 : Ambiguïtés¶
A-01 Type : Ambiguïté Référence : §5.1 (note enum account_type) + §5.2 (quotas) Description : Le champ plan (freemium, premium, enterprise) est utilisé pour déterminer le quota applicable, mais il n'est pas défini dans le modèle de données contractuel §5.1. Ses valeurs valides, son format, sa validation et son comportement en cas de valeur invalide sont absents. De plus, premium apparaît à la fois dans account_type et dans plan — les combinaisons valides entre les deux champs ne sont pas spécifiées (un mineur peut-il avoir un plan enterprise ?). Impact : Une équipe tierce ne saurait pas quel champ interroger pour appliquer les quotas, ni comment valider plan à l'entrée. Gravité : Majeur
A-02 Type : Ambiguïté Référence : §5.4 — transitions retour Description : Les transitions retour (TSA_PENDING -> QUEUED_PRIORITY, TSA_SEALED -> TSA_PENDING) sont décrites comme des « requeue internes » distinctes des retries, déclenchées par une « décision technique explicite (ex : invalidation du résultat TSA détectée avant ancrage) ». Les conditions de déclenchement ne sont pas formalisées : qui décide ? sur quel critère ? automatiquement ou manuellement ? Cela contredit le principe d'INV-80-01 (« machine d'états explicitement définie, sans transition implicite »). Impact : Comportement non déterministe — implémentations divergentes possibles. Gravité : Majeur
A-03 Type : Ambiguïté Référence : §5.2 — sla_global_max (60 min) vs final_timeout (120 min) Description : Le SLA global est P95 < 60 min, et le timeout forçant FAILED_TIMEOUT est ≥120 min. La plage 60–120 min est décrite comme « SLO violation » (§5.2 Hors bornes) sans action contractualisée. Aucun observable, aucune alerte, aucune notification n'est spécifiée pour un scellement individuel dépassant 60 min mais inférieur à 120 min. Impact : Un scellement à 119 min ne déclenche aucune action visible, potentiel trou d'auditabilité. Gravité : Mineur (le P95 global reste mesuré, mais l'absence d'action unitaire mérite clarification)
A-04 Type : Ambiguïté Référence : §5.10 — critère de détection d'orphelin Description : « sans job BullMQ actif correspondant » — le mécanisme de correspondance entre un enregistrement DB et un job BullMQ n'est pas spécifié (par document_id ? par un job_id stocké en DB ? par clé composite ?). Impact : Faux positifs (rattrapage de jobs non orphelins) ou faux négatifs (orphelins non détectés). Gravité : Majeur
A-05 Type : Ambiguïté Référence : §5.6 — « Utilisateur éligible » Description : L'éligibilité au fast-track manuel est définie par « éligibilité plan + quota + rate-limit ». Quota et rate-limit sont formalisés, mais l'« éligibilité plan » ne l'est pas. Tout plan (y compris freemium) est-il éligible au déclenchement manuel ? Si oui, le terme « éligible » est redondant avec quota/rate-limit. Si non, les critères manquent. Impact : Ambiguïté d'implémentation — risque de rejet ou d'acceptation non contractualisé. Gravité : Mineur
Axe 2 : Contradictions¶
C-01 Type : Contradiction Référence : §5.4 (transitions retour) vs INV-80-06 / §5.4 point 1 (retries = même état) Description : INV-80-06 et §5.4 point 1 affirment « Chaque retry reste dans le même état ». Or §5.4 point 2 décrit des transitions retour (TSA_PENDING -> QUEUED_PRIORITY, TSA_SEALED -> TSA_PENDING) qualifiées de « distinctes des retries ». Le texte de §5.4 précise que ces transitions sont « déclenchées uniquement par une décision technique explicite » mais ne définit pas de critère formel. Le lecteur ne peut pas distinguer opérationnellement un retry (même état) d'une transition retour (changement d'état) sans critère formalisé. Impact : Deux implémentations pourraient traiter le même scénario différemment. Gravité : Majeur
C-02 Type : Contradiction Référence : §6 — code 422 Description : §6 liste 422 UNPROCESSABLE_ENTITY comme code d'erreur API, puis précise que « ces erreurs sont internes au pipeline et déclenchent un retry, pas un rejet API vers l'utilisateur ». Un code HTTP 422 est par définition une réponse API. Le mélange de codes d'erreur internes et API dans la même section crée une confusion sur l'interface contractuelle exposée. Impact : L'équipe d'implémentation pourrait exposer un 422 au client, ou un testeur pourrait chercher un 422 en surface API. Gravité : Mineur
Axe 3 : Règles non testables¶
NT-01 Type : Non testable Référence : §5.7 — atomicité async « Idempotent, retry-safe » Description : Les opérations async post-commit sont décrites comme « idempotent, retry-safe » mais le mécanisme d'idempotence n'est pas spécifié (clé d'idempotence, déduplication par document_id, job_id BullMQ, etc.). Sans observable, l'idempotence ne peut être vérifiée que par effet de bord (absence de duplication), ce qui est un test négatif non borné. Impact : TC-NOM-10 mentionne « sans duplication non contrôlée » — critère insuffisamment défini pour un verdict déterministe. Gravité : Majeur
Axe 4 : Incohérences Spec ↔ Tests¶
ST-01 Type : Incohérence Spec↔Tests Référence : §5.4 (transitions retour) vs matrice de couverture Description : Les transitions retour TSA_PENDING -> QUEUED_PRIORITY et TSA_SEALED -> TSA_PENDING sont spécifiées mais aucun test ne les couvre. Aucun TC ne simule une « invalidation du résultat TSA détectée avant ancrage » ni ne vérifie la traçabilité audit de ces transitions retour. Impact : Transitions spécifiées mais non vérifiées — risque de non-implémentation ou d'implémentation non conforme passant inaperçue. Gravité : Majeur
ST-02 Type : Incohérence Spec↔Tests Référence : §5.13 (synchronisation NTP) vs tests Description : La spec exige une vérification NTP au démarrage avec alerte CRITICAL si dérive >1s. Aucun test ne couvre ce comportement (ni détection, ni alerte CRITICAL, ni comportement du service si NTP non conforme). Impact : Exigence spec sans couverture test. Gravité : Majeur
ST-03 Type : Incohérence Spec↔Tests Référence : §5.10 — reconciliation_max_catchup_delay + alerte CRITICAL vs tests Description : La spec exige une alerte CRITICAL si le rattrapage dépasse 30 min. TC-NOM-11 vérifie le rattrapage sous 30 min mais aucun test ne couvre le cas où le seuil est dépassé ni l'émission de l'alerte CRITICAL. Impact : Condition de dégradation non testée. Gravité : Mineur
ST-04 Type : Incohérence Spec↔Tests Référence : §5.2 — retry_delays et webhook_retry_delays « config invalide rejetée au démarrage » vs TC-NOM-15 Description : §5.2 indique que les tableaux retry_delays et webhook_retry_delays invalides sont « rejetés au démarrage » (pas clampés). TC-NOM-15 teste uniquement le comportement clamp sur des scalaires. Aucun test ne vérifie le rejet au démarrage d'un tableau retry_delays invalide (ex : tableau vide, valeurs non croissantes, valeur hors bornes dans le tableau). Impact : Comportement de rejet de config non couvert. Gravité : Mineur
Axe 5 : Hypothèses dangereuses¶
HD-01 Type : Hypothèse dangereuse Référence : §5.10 — worker de réconciliation Description : Le worker recrée un job BullMQ pour un job considéré orphelin. Aucune protection contre le cas où le job original est encore en cours d'exécution (stale mais pas crashé — ex : GC pause longue, network partition temporaire). La détection repose sur last_activity_at qui peut être dépassé sans crash réel. Risque de double exécution simultanée (TSA double-timestamped, ancrage dupliqué). Impact : Double scellement, surcoût blockchain, preuves dupliquées — atteinte potentielle à l'intégrité probatoire. Gravité : Bloquant
HD-02 Type : Hypothèse dangereuse Référence : §5.7 — crash post-commit Description : En cas de crash post-commit, « état DB source de vérité, async rattrapé par réconciliation ». Mais si le crash survient après commit DB et avant publication BullMQ, le job est en état QUEUED_PRIORITY en DB mais sans job BullMQ. Le worker de réconciliation ne le détectera qu'après orphan_threshold (10 min). Ce délai est additionnel au SLA et non comptabilisé dans les SLA par étape (§5.3). Impact : Un scellement post-crash pourrait consommer 10 min supplémentaires non prévues dans le budget SLA. Gravité : Mineur (le SLA global de 60 min a de la marge, mais le cas n'est pas documenté)
Axe 6 : Risques sécurité / conformité¶
RS-01 Type : Risque sécu/conformité Référence : INV-80-09 — chiffrement at-rest des artefacts temporaires Description : L'invariant exige AES-256-GCM ou HSM envelope pour les artefacts temporaires, mais ne spécifie pas le cycle de vie des DEK (Data Encryption Keys) : génération, stockage, rotation, destruction après usage. Un DEK non détruit après scellement laisse un vecteur d'attaque persistant. Impact : Conformité crypto partielle — l'artefact est chiffré mais la clé de déchiffrement peut survivre indéfiniment. Gravité : Majeur
RS-02 Type : Risque sécu/conformité Référence : §6 — note disclosure + §5.2 quotas Description : La mitigation anti-disclosure (pas de nom de plan ni quota dans le corps de réponse) ne mentionne pas les headers HTTP. Des headers comme Retry-After (429) ou X-RateLimit-Remaining pourraient indirectement exposer le plan. La spec ne prend pas position (autoriser ou interdire ces headers). Impact : Canal de disclosure non couvert par la mitigation documentée. Gravité : Mineur
Synthèse¶
| Gravité | Nombre | IDs |
|---|---|---|
| Bloquant | 1 | HD-01 |
| Majeur | 7 | A-01, A-02, A-04, C-01, NT-01, ST-01, ST-02, RS-01 |
| Mineur | 5 | A-03, A-05, C-02, ST-03, ST-04, HD-02, RS-02 |
Point bloquant : HD-01 — l'absence de protection contre la double exécution par le worker de réconciliation est un risque d'intégrité probatoire. Un mécanisme de verrouillage distribué (lock, lease, ou vérification d'activité BullMQ avant recréation) doit être spécifié.