PD-278 — Specification Review¶
Auditeur : Claude (mode factuel, température 0.1) Documents audités : PD-278-specification.md, PD-278-tests.md Date : 2026-03-01 Domaine : Cycle de vie documentaire OAIS / NF Z42-013 (hors crypto-proof)
Synthèse¶
| Gravité | Nombre |
|---|---|
| Bloquant | 2 |
| Majeur | 8 |
| Mineur | 4 |
| Total | 14 |
Écarts identifiés¶
CONTR-01¶
Type : Contradiction Référence : INV-278-02 (§4) vs §5.12 (Rétention et anti-contournement DIP) vs §5.3 (Préconditions F1) Description : INV-278-02 définit les gardes exhaustives de SEALED → DIP : copies >= MIN_COPIES, acteur authentifié, rôle ∈ {PA, SA, auditor}, RLS valide, limites de débit respectées. §5.3 reprend les mêmes préconditions. Mais §5.12 ajoute une garde supplémentaire : « Tant que retention_due=true, toute nouvelle tentative SEALED → DIP sur ce document est refusée 409. » Cette garde n'apparaît ni dans INV-278-02, ni dans les préconditions de §5.3. L'invariant contractuel est donc incomplet par rapport au corps de la spécification. Impact : Une implémentation fidèle aux seuls invariants (§4) n'intégrerait pas le blocage rétention, permettant le contournement de la rétention légale via maintien en DIP — violation NF Z42-013 / RGPD. Gravité : Bloquant
CONTR-02¶
Type : Contradiction Référence : TC-NEG-07 (§7 tests négatifs) vs §5.4 (Effets testables F2) Description : TC-NEG-07 teste l'« injection horodatage retour antérieur diffusion » avec résultat attendu Rejet 409 (E-409-TEMPORAL-ORDER). Or, §5.4 définit dissemination_returned_at comme un effet de la transition DIP → SEALED (timestamp serveur) — pas comme une entrée client. Si les timestamps sont générés côté serveur, un client ne peut pas « injecter » un horodatage antérieur. Le scénario de test suppose un modèle (timestamps client) que la spécification ne décrit pas. Impact : Test non implémentable en l'état si les timestamps sont serveur-générés. Si les timestamps sont partiellement client-fournis, la spécification doit le contractualiser explicitement. Gravité : Majeur
AMB-01¶
Type : Ambiguïté Référence : §5.1 (Modèle de données — dissemination_package_id) vs §5.3 (Effets F1) vs TC-ERR-02 Description : §5.1 définit dissemination_package_id comme un champ stocké avec des règles de nullabilité (NULL en mono, non-NULL en multi). §5.3 le liste comme un effet de la transition, suggérant une génération serveur. Mais TC-ERR-02 teste « Requête multi-documents avec dissemination_package_id invalide (non UUID) » — impliquant qu'il est fourni par le client dans la requête. La spécification ne définit pas qui génère cette valeur (client ou serveur). Impact : Selon le choix, les validations d'entrée, les tests et la surface d'attaque diffèrent significativement. Si client-fourni, risque de réutilisation malveillante de package IDs. Gravité : Majeur
AMB-02¶
Type : Ambiguïté Référence : §5.12 (Rétention et anti-contournement) + §5.11 (Contraintes inter-modules) — retention_due Description : Le signal retention_due=true est utilisé dans §5.12 comme condition bloquante et dans §5.11 comme « signal retention_due » cross-module. La spécification ne définit pas : (a) si retention_due est un champ stocké sur le document ou une propriété calculée à la volée, (b) quel module/service produit ce signal, © sur quels critères il passe à true (date d'échéance vs politique vs événement externe). Impact : Un implémenteur ne peut pas coder la garde §5.12 ni le flux INV-278-14 sans connaître la nature et la source de ce signal. Gravité : Majeur
AMB-03¶
Type : Ambiguïté Référence : §5.1 (Modèle de données) — champ copies Description : INV-278-02 exige copies >= MIN_COPIES comme garde de SEALED → DIP. §5.6 fixe MIN_COPIES = 2 par défaut. Mais la spécification ne définit jamais ce que constitue une « copie » : réplica de stockage objet, copie physique sur site distinct, copie logique dans le même cluster, ou instance de backup. Le terme n'est référencé dans aucune définition (§3). Impact : Garde contractuelle INV-278-02 non implémentable de manière déterministe sans définition du dénombrement des copies. Gravité : Majeur
AMB-04¶
Type : Ambiguïté Référence : INV-278-05 + CA-07 — Attestation de restitution Description : INV-278-05 exige « une attestation par requête de communication ». §3 définit l'attestation comme « preuve horodatée de communication d'un AIP vers DIP ». Mais aucune section ne spécifie : (a) le format/schéma de l'attestation (JSON ? document signé ? enregistrement DB ?), (b) les champs obligatoires au-delà de ceux inférables (document_ids, acteur, horodatage, motif), © le mécanisme de stockage (même base ? système dédié ?), (d) la durée de conservation. CA-07 vérifie « 1 attestation/requête, liée docs+acteur(+motif) » mais sans schéma contractuel, l'observable est subjectif. Impact : Deux implémentations conformes pourraient produire des attestations incompatibles. Non-interopérabilité et difficulté d'audit NF Z42-013 §4.6.4.2. Gravité : Majeur
AMB-05¶
Type : Ambiguïté Référence : §5.6 (Bornes numériques) — Rate limit Description : Le quota journalier SEALED → DIP est défini à 1000 req/jour par acteur. La spécification ne précise pas le mécanisme de réinitialisation : fenêtre glissante de 24h ou réinitialisation fixe (minuit UTC). Le comportement diffère significativement entre les deux approches en termes de pics autorisés. Impact : Comportement non déterministe aux limites du quota. Gravité : Mineur
AMB-06¶
Type : Ambiguïté Référence : §5.12 vs §6 (Cas d'erreur) — Code erreur rétention Description : §5.12 spécifie « refusée 409 » quand retention_due=true bloque SEALED → DIP. Mais §6 ne liste pas de code d'erreur spécifique pour ce cas. E-409-STATE désigne « transition incompatible avec l'état courant » — or SEALED → DIP est normalement valide. E-409-CONFLICT désigne un conflit de concurrence. Aucun code ne correspond à un blocage rétention. Impact : Ambiguïté pour le client API qui reçoit un 409 sans pouvoir distinguer un conflit de concurrence d'un blocage rétention. Gravité : Mineur
INC-01¶
Type : Incohérence Spec↔Tests Référence : §5 (Tests d'invariants) — TC-INV-01 à TC-INV-13 Description : La matrice de couverture (§2) et la table des invariants (§5) référencent 13 identifiants de tests dédiés (TC-INV-01 à TC-INV-13). Aucun de ces tests ne possède de scénario Given/When/Then défini dans le document de tests. Seuls les tests TC-NOM-XX, TC-ERR-XX, TC-NR-XX et TC-NEG-XX ont des scénarios explicites. Les TC-INV-XX existent uniquement comme entrées dans les tables de couverture, sans spécification exécutable. Impact : 13 tests contractuels non implémentables par une équipe tierce. La couverture des invariants repose sur des combinaisons implicites d'autres tests, sans traçabilité explicite. Gravité : Majeur
INC-02¶
Type : Incohérence Spec↔Tests Référence : §5.12 (Rétention et anti-contournement) — Garde retention_due sur SEALED → DIP Description : §5.12 contractualise : « Tant que retention_due=true, toute nouvelle tentative SEALED → DIP sur ce document est refusée 409. » Aucun scénario de test (TC-ERR-XX, TC-INV-XX, TC-NEG-XX) ne couvre explicitement ce cas. TC-INV-13 couvre « Clôture explicite retention_service » (DIP→SEALED) mais pas le blocage en entrée (SEALED→DIP quand retention_due=true). TC-ERR-06 couvre les transitions statiquement interdites, pas les gardes conditionnelles. Impact : Garde de conformité rétention/RGPD sans couverture de test. Risque de non-détection d'une régression sur cette protection. Gravité : Bloquant
HYP-01¶
Type : Hypothèse dangereuse Référence : §5.9 (Concurrence et isolation) — Verrouillage ordonné Description : §5.9 contractualise « verrouillage ordonné déterministe (tri document_id) pour éviter interblocages » en package multi-documents. Cette convention suppose que tous les modules accédant aux mêmes documents (retention_service, audit, export — listés §5.11) utilisent le même ordre de verrouillage. La spécification ne pose pas cette contrainte cross-module. Si retention_service verrouille dans un ordre différent (par ex. par date de rétention), un interblocage est possible. Impact : Risque de deadlock en production entre le flux DIP et le flux rétention. Gravité : Majeur
HYP-02¶
Type : Hypothèse dangereuse Référence : §5.10 (Horloge et ordre temporel) + INV-278-13 Description : INV-278-13 exige dissemination_returned_at >= disseminated_at. §5.10 spécifie « UTC synchronisée NTP (dérive max 100 ms) ». En architecture multi-instances (NestJS scalé horizontalement), si la transition SEALED → DIP est traitée par l'instance A et DIP → SEALED par l'instance B, un clock skew entre A et B (même ≤ 100 ms) peut produire returned_at < disseminated_at pour des transitions rapides. La spécification ne traite pas la coordination d'horloge inter-instances. Impact : Violation possible de INV-278-13 en conditions réelles, déclenchant un rejet E-409-TEMPORAL-ORDER sur une transition légitime. Gravité : Majeur
RISK-01¶
Type : Risque sécu/conformité Référence : INV-278-04 (Auditability) + §6 (Cas d'erreur) — Audit des transitions refusées Description : INV-278-04 contractualise « Chaque transition DIP persiste un enregistrement audit ». Le terme « transition » désigne classiquement un changement d'état réussi. Les cas d'erreur (§6) — en particulier E-401-AUTH, E-403-ROLE, E-403-RLS, E-429-RATE-LIMIT — ne sont pas couverts par cette exigence d'audit. Seul TC-ERR-13 mentionne « Alerte sécurité/audit rate-limit observable ». Les tentatives d'accès refusées (403) ne sont pas contractuellement auditées. Impact : Trou d'auditabilité sécurité : les tentatives d'exfiltration (SEALED→DIP par acteur non autorisé) ne laissent pas de trace contractuellement garantie. Non-conformité potentielle NF Z42-013 §10.1 sur les événements de sécurité. Gravité : Majeur
RISK-02¶
Type : Risque sécu/conformité Référence : §5.1 (motif_communication) — Immutabilité WORM Description : §5.1 contractualise « [motif_communication] reste immuable après création (WORM métadonnées probatoires) ». TC-NOM-06 vérifie que « motif_communication reste immuable après création ». Mais la spécification ne définit aucun mécanisme d'enforcement de cette immutabilité : pas de trigger DB, pas de contrainte applicative, pas de check d'intégrité. L'observable est déclaratif sans preuve d'enforcement. Impact : En l'absence de mécanisme contractualisé, l'immutabilité repose sur une convention d'implémentation. Un UPDATE direct en base (accidentel ou malveillant) altérerait une métadonnée probatoire sans détection garantie. Gravité : Mineur
AMB-07¶
Type : Ambiguïté Référence : §5.5 (SLA temporels) — Seuil SLOW_OPERATION Description : §5.5 définit SLOW_OPERATION comme un drapeau attaché quand « P95 dépasse cible ». Le tableau SLA liste une « Valeur par défaut » (2000 ms pour SEALED→DIP, 1500 ms pour DIP→SEALED) et un « Max » (5000 ms). La spécification ne clarifie pas si le seuil déclencheur de SLOW_OPERATION est la « Valeur par défaut » ou une valeur configurable distincte. Impact : Non-déterminisme du drapeau de performance ; TC-NOM-05 non implémentable sans ce seuil. Gravité : Mineur
Récapitulatif par axe¶
| Axe | Bloquant | Majeur | Mineur | Total |
|---|---|---|---|---|
| Contradiction | 1 | 1 | 0 | 2 |
| Ambiguïté | 0 | 4 | 3 | 7 |
| Incohérence Spec↔Tests | 1 | 1 | 0 | 2 |
| Hypothèse dangereuse | 0 | 2 | 0 | 2 |
| Risque sécu/conformité | 0 | 1 | 0 | 1 |
| Total | 2 | 9 | 3 | 14 |
Note : Le comptage final donne 9 majeurs (correction du tableau de synthèse initial qui indiquait 8 — AMB-04 avait été omis du décompte). Synthèse corrigée : 2 bloquants, 9 majeurs, 3 mineurs = 14 écarts.