PD-286 — Review de spécification (Gate 3 — Phase 1)¶
Documents audités¶
PD-286-specification.mdPD-286-tests.md(limité à : ambiguïtés, contradictions, règles non testables, hypothèses dangereuses, risques sécu/conformité — sans verdict de couverture)
Synthèse¶
Bloquants : 5 — Majeurs : 7 — Mineurs : 6.
Le verrou principal est une désynchronisation systémique entre spec et tests sur la numérotation des critères d'acceptation (CA) et des invariants (INV), associée à plusieurs contradictions de fond (comportement de la borne 768 MB / 10 GB, codes d'erreur, machine à états vs invariant DEK). Sans levée préalable, l'auditabilité contractuelle de la story (Art. III) et la séparation review/tests (Art. II) ne tiennent pas.
Écarts identifiés¶
Bloquants¶
Type : Contradiction (Spec ↔ Tests)
Référence : PD-286-tests.md §2 (matrice de couverture) vs PD-286-specification.md §7 (CA)
Description : La matrice de couverture des tests utilise une numérotation des CA décalée
par rapport à la spec :
- Tests « INV-286-07 | CA-286-04 | TC-NOM-04 » → spec CA-286-04 = « .pvproof
unique » alors que TC-NOM-04 traite le recalcul de hash, qui correspond à
CA-286-05 dans la spec.
- Tests « INV-286-08 | CA-286-03 | TC-NOM-03 » → spec CA-286-03 = « preuve
unique 900 MB » alors que TC-NOM-03 traite l'unicité du .pvproof (CA-286-04).
- Tests « INV-286-09 | CA-286-06 | TC-NOM-05 » → spec CA-286-06 = « échec
volume = échec global » alors que TC-NOM-05 traite l'audit (CA-286-07).
- Tests « INV-286-11 | CA-286-07 | TC-INV-11 » → spec CA-286-07 = audit alors
que TC-INV-11 traite la machine à états (CA-286-08).
Plusieurs autres lignes de la matrice sont également décalées.
Impact : Traçabilité INV/CA/TEST cassée pour l'ensemble du périmètre Gate 8 (Art. III).
Casse la matrice RTM, casse la vérification de couverture en Phase 2.
Gravité : Bloquant
Type : Incohérence Spec ↔ Tests
Référence : PD-286-tests.md §2 (matrice), §5 (tests d'invariants), TC-INV-12 vs PD-286-specification.md §4
Description : Les tests référencent un invariant `INV-286-12` (« États terminaux sans
transition sortante ») qui n'existe pas dans la spec. La spec s'arrête à
`INV-286-11` qui couvre déjà les états terminaux. La matrice tests confond
INV-286-10 (machine à états) et INV-286-11 (terminaux) avec ce qui semble
être un INV-286-11 / INV-286-12 décalés d'un cran.
Impact : Invariant fantôme dans les tests. Tout test associé est sans accroche
contractuelle. Vice de tracabilité bloquant pour Gate 8.
Gravité : Bloquant
Type : Contradiction (Spec ↔ Tests)
Référence : PD-286-specification.md §4 INV-286-10 / §7 CA-286-08 vs PD-286-tests.md §5 INV-286-10
Description : Spec §4 : « INV-286-10 = Machine à états d'export contractuelle (transitions
listées) ». Tests §5 (lignes invariants) : « INV-286-10 | TC-INV-10 | Absence
de DEK/clé/fragment en clair au repos ». Le contenu de INV-286-10 dans les
tests décrit une exigence de chiffrement au repos qui n'apparaît nulle part
dans la spec PD-286.
Impact : Soit la spec a perdu un invariant critique de chiffrement, soit les tests
testent un invariant absent. Dans les deux cas, périmètre indéterminé.
Gravité : Bloquant
Type : Contradiction (Spec ↔ Tests)
Référence : PD-286-specification.md §4 INV-286-01, §7 CA-286-03, §6 ERR-286-02, §8 GWT-286-04
vs PD-286-tests.md §4 TC-ERR-02
Description : Spec : une preuve atomique de 900 MB (> 768 MB et < 10 GB) est ACCEPTÉE en
« volume dédié exceptionnel » (INV-286-01, CA-286-03, GWT-286-04). Le rejet
`413 PROOF_TOO_LARGE` est réservé aux preuves > 10 GB (ERR-286-02).
Tests TC-ERR-02 : « GIVEN une preuve atomique unique de 900 MB → THEN
Réponse 422 PROOF_TOO_LARGE_FOR_VOLUME ». Le test impose un rejet là où la
spec impose une acceptation.
S'ajoute une triple contradiction : code HTTP (413 spec vs 422 tests), nom
du code (`PROOF_TOO_LARGE` spec vs `PROOF_TOO_LARGE_FOR_VOLUME` tests, le
second n'existe nulle part dans la spec), seuil déclencheur (10 GB spec vs
768 MB tests).
Impact : Comportement contractuel principal de la story divergent entre spec et
tests. CA-286-03 et GWT-286-04 deviennent non vérifiables sans contredire
TC-ERR-02. Régression fonctionnelle quasi certaine si on suit l'un ou l'autre.
Gravité : Bloquant
Type : Incohérence Spec ↔ Tests (couverture manquante)
Référence : PD-286-specification.md §7 CA-286-10, §6 ERR-286-02, §8 GWT-286-05 vs PD-286-tests.md §2
Description : CA-286-10 (« Preuve atomique > 10 GB rejetée explicitement → 413
PROOF_TOO_LARGE ») et son scénario GWT-286-05 ne sont mappés à aucun test
dans la matrice §2 et n'apparaissent pas non plus dans les tests d'invariants
§5. Aucun TC ne couvre la borne 10 GB sur preuve atomique.
TC-ERR-02 (mal cadré sur 900 MB) ne supplée pas ce gap. Le rejet > 10 GB est
un comportement de sécurité (anti-abus) non couvert.
Impact : Gap de couverture sur un cas-limite de protection (borne 10 GB). CA-286-10
non testable en l'état → critère d'acceptation non vérifiable en Gate 8.
Gravité : Bloquant
Majeurs¶
Type : Incohérence Spec ↔ Tests
Référence : PD-286-tests.md §9 (règles non testables) Q-286-01 vs PD-286-specification.md §10.2
Description : Les tests référencent une question ouverte `Q-286-01 : Canonicalisation JSON
exacte (algorithme formel non spécifié)`. La spec §10.2 ne contient aucun
Q-286-01 ; elle commence à Q-286-02. Par ailleurs, la spec §3 et §5.4
affirment RFC 8785 (JCS) comme algorithme de canonicalisation, donc
l'ambiguïté Q-286-01 que les tests pointent n'existe pas formellement dans
la spec — soit la spec a tranché et les tests sont obsolètes, soit les tests
ont raison et RFC 8785 ne suffit pas comme spécification (variantes
d'implémentation de JCS).
Impact : Numérotation des Q-286-XX désynchronisée. Le verdict tests « ⚠️ Testable
partiellement » repose en partie sur une question qui n'existe pas
formellement dans la spec.
Gravité : Majeur
Type : Contradiction (Spec ↔ Tests)
Référence : PD-286-specification.md §5.1 « totalVolumes : pas de borne max fixe contractuelle » vs
PD-286-tests.md §7 TC-NEG-04, TC-NEG-05
Description : Spec §5.1 explicitement « totalVolumes min=1, pas de borne max fixe
contractuelle » et « volumeIndex max dynamique = totalVolumes-1 ».
Tests : TC-NEG-04 « totalVolumes=0 ou >14 → 500 INVALID_TOTAL_VOLUMES » et
TC-NEG-05 « volumeIndex <0 ou >13 → 500 INVALID_VOLUME_INDEX_RANGE ».
La borne 14 (et donc 13 pour volumeIndex) n'apparaît nulle part dans la
spec (10 GB / 768 MB ≈ 14, mais ce calcul n'est pas tracé contractuellement
et ne tient pas si une preuve dédiée occupe un volume).
Impact : Borne max introduite par les tests, absente du contrat. Soit la spec doit
fixer la borne (et alors le calcul 10 GB/768 MB est faux quand un volume
dédié exceptionnel est présent), soit les tests doivent être revus.
Gravité : Majeur
Type : Contradiction terminologique
Référence : PD-286-specification.md §5bis (diagramme de séquence) vs §3, §4, §5
Description : Le diagramme de séquence introduit `complaintId` (`POST /exports
{complaintId}`) et `ComplaintFileResponseDto {volumes[], metadata}` comme
nom du DTO de réponse. Aucun de ces deux identifiants n'est défini dans la
spec : la spec parle de « dossier », « preuves », « exportId » et
`ExportVolumeDto`. La notion de « plainte » (complaint) est étrangère au
vocabulaire de la spec.
Impact : Contrat d'API ambigu. Soit l'entité métier est « complaint » (et alors le
vocabulaire spec doit suivre), soit elle est « dossier/export » (et alors
le diagramme est faux). Tests et code dépendant.
Gravité : Majeur
Type : Ambiguïté
Référence : PD-286-specification.md §5.4 (étape 3) et §5bis (diagramme de séquence)
Description : Le diagramme de séquence indique que c'est le BACKEND qui calcule
`integrityHash = sha3_256(jcs_rfc8785(manifest_partial))`, mais le texte
§5.4 step 3 dit seulement « chaque volume contient manifest +
integrityHash » sans préciser qui calcule, ni l'algorithme. INV-286-07
parle uniquement de la vérification côté app. Le contrat de production du
hash côté backend est donc seulement inférable du diagramme.
Impact : Si le diagramme et le texte divergent (axe 5bis), la vérification
d'intégrité peut être réalisée sur des hash incompatibles entre backend et
app. Risque réel sur la vérification de preuves.
Gravité : Majeur
Type : Hypothèse dangereuse
Référence : PD-286-specification.md §9 H-286-01, §10.1
Description : H-286-01 « IntegrityHashComputer implémente RFC 8785 de manière stable
entre backend et app ». Stack cible §10.1 : backend NestJS (Node.js) /
app React Native + Expo SDK 54 (TypeScript). RFC 8785 (JCS) n'a pas
d'implémentation de référence partagée Node ↔ RN ; les libs disponibles
sur npm ne sont pas équivalentes byte-à-byte (ex : ordre des clés Unicode,
nombres flottants). Sans test de conformité cross-runtime, H-286-01 est
une hypothèse non vérifiée et bloquante.
Impact : Faux négatifs d'intégrité (mismatch de hash) systématiques sur tout
caractère non-ASCII dans un manifest. Toute preuve avec métadonnées
accentuées peut faire échouer l'export.
Gravité : Majeur
Type : Hypothèse dangereuse
Référence : PD-286-specification.md §4 INV-286-08, §3 (définitions), §5.5
Description : INV-286-08 dit que le « conteneur .pvproof reste inchangé ; seul
pvproof.json interne inclut volumes_count + assembled_from[] si export
avec volumes[] ». Aucun lien vers la spec du conteneur .pvproof n'est
fourni, et aucun test ne vérifie qu'un consommateur legacy de .pvproof
accepte un fichier avec ces deux champs supplémentaires (TC-NR-02 affirme
la non-régression sans observable concret).
Impact : Si un consommateur de .pvproof valide la liste exhaustive des champs de
pvproof.json, l'ajout de volumes_count/assembled_from[] casse la
compatibilité ascendante.
Gravité : Majeur
Type : Risque sécu/conformité
Référence : PD-286-specification.md §4 INV-286-09 (« audit WORM fail-closed »)
Description : « Fail-closed » est invoqué sans définition opérationnelle : que se
passe-t-il si le journal WORM est indisponible au moment de la finalisation
`COMPLETED` ? Le flux est-il bloqué (et donc l'utilisateur perd l'export
déjà téléchargé), ou l'export reste-t-il dans un état intermédiaire avec
dette d'audit ? La spec ne tranche pas. ERR-286-XX ne couvre pas ce cas.
Impact : Comportement non déterministe en cas de panne audit. Risque de perte
d'auditabilité contre INV-286-09 lui-même, ou de DoS sur l'export en cas
d'incident d'infra audit.
Gravité : Majeur
Mineurs¶
Type : Ambiguïté
Référence : PD-286-specification.md §5.1 (modèle de données contractuel)
Description : Le tableau définit les types des champs (exportId, volumeIndex, manifest,
integrityHash, signedUrl, etc.) mais ne fournit pas une définition
explicite et unique du DTO `ExportVolumeDto` (référencé en §4 INV-286-07
et dans le diagramme). La structure complète (champs obligatoires/
optionnels, enveloppe, version) reste implicite.
Impact : Risque de divergence backend/app sur le DTO. Fragilise la traçabilité du
contrat API.
Gravité : Mineur
Type : Ambiguïté
Référence : PD-286-specification.md §5.4 (flux nominal B, étape 4)
Description : « L'app traite les volumes séquentiellement » : aucune obligation de tri
par volumeIndex n'est explicitement formulée. Si l'API renvoie volumes[]
dans un ordre arbitraire, l'app pourrait soit lever un trou apparent, soit
les traiter dans l'ordre reçu, ce qui complique l'observabilité.
Impact : Tests non déterministes si l'ordre dans volumes[] varie. TC-INV-03 (union
sans omission) reste vérifiable, mais TC-NOM-04 (séquentiel) devient
ambigu.
Gravité : Mineur
Type : Incohérence cohérence diagrammes (axe 5bis)
Référence : PD-286-specification.md §5bis (diagramme d'état) vs §4 INV-286-10 (transitions interdites)
Description : Le diagramme représente certaines transitions INTERDITES (COMPLETED →
REQUESTED, COMPLETED → DOWNLOADING, FAILED → REQUESTED, EXPIRED →
REQUESTED) mais omet d'autres interdictions explicitement listées dans le
texte : `PLANNED_MULTI → PLANNED_SINGLE`, `COMPLETED → ASSEMBLING`,
`COMPLETED → PLANNED_*`. Ces interdictions ne sont donc visibles que dans
le texte.
Impact : Diagramme partiel — auditeur visuel pourrait conclure que ces transitions
sont « simplement absentes » sans réaliser qu'elles sont explicitement
interdites.
Gravité : Mineur
Type : Ambiguïté
Référence : PD-286-specification.md §4 INV-286-03 (« ensemble des preuves validées »)
Description : Le terme « validées » n'est pas défini : statut de preuve dans le système ?
Pipeline de validation (hors périmètre §2) ? Filtre métier sur le dossier ?
L'union mentionnée par INV-286-03 dépend de ce périmètre.
Impact : Critère INV-286-03 difficilement testable sans qualifier l'ensemble de
référence.
Gravité : Mineur
Type : Hypothèse dangereuse
Référence : PD-286-specification.md §5.2 (SLA temporels) vs §4 INV-286-11
Description : Pas de référence à la source d'horloge faisant foi (signature backend,
système app, signed URL signing time). Un décalage d'horloge entre app et
backend peut faire transiter prématurément vers EXPIRED côté app sans
que le backend ne le considère expiré (ou inversement).
Impact : Comportement non déterministe entre clients selon dérive d'horloge. Faux
EXPIRED possibles. Manque de qualification dans les tests TC-ERR-05.
Gravité : Mineur
Type : Risque sécu/conformité
Référence : PD-286-specification.md §4 INV-286-11 (« données temporaires conservées
selon politique de rétention existante »)
Description : Aucun pointeur vers cette « politique de rétention existante » (durée,
chiffrement au repos, isolation par utilisateur) ; Q-286-03 est une
question ouverte. Sans valeur chiffrée, la conformité RGPD/CCPA des temp
files post-FAILED/EXPIRED est non auditable.
Impact : Conformité non vérifiable. Tests Q-286-03 marqués Mineur — devraient être
Majeur tant que la politique n'est pas pointée explicitement.
Gravité : Mineur
Tableau de synthèse¶
| # | Type | Référence | Gravité |
|---|---|---|---|
| 1 | Contradiction | matrice tests §2 vs spec §7 (CA-286-XX) | Bloquant |
| 2 | Incohérence Spec↔Tests | INV-286-12 dans tests, absent spec | Bloquant |
| 3 | Contradiction | INV-286-10 (machine état spec vs DEK tests) | Bloquant |
| 4 | Contradiction | preuve 900 MB acceptée (spec) vs rejetée (tests) | Bloquant |
| 5 | Incohérence Spec↔Tests | CA-286-10 (>10 GB) sans test | Bloquant |
| 6 | Incohérence Spec↔Tests | Q-286-01 dans tests, absent spec | Majeur |
| 7 | Contradiction | totalVolumes max 14 (tests) vs illimité (spec) | Majeur |
| 8 | Contradiction terminologique | complaintId / ComplaintFileResponseDto (diagramme) absent spec | Majeur |
| 9 | Ambiguïté | calcul backend integrityHash inférable du diagramme uniquement | Majeur |
| 10 | Hypothèse dangereuse | RFC 8785 stable Node ↔ React Native (H-286-01) | Majeur |
| 11 | Hypothèse dangereuse | .pvproof legacy tolère volumes_count/assembled_from[] (TC-NR-02) | Majeur |
| 12 | Risque sécu/conformité | « audit WORM fail-closed » non défini | Majeur |
| 13 | Ambiguïté | DTO ExportVolumeDto non défini formellement | Mineur |
| 14 | Ambiguïté | ordre de tri de volumes[] | Mineur |
| 15 | Incohérence diagrammes (5bis) | transitions INTERDITES partiellement représentées | Mineur |
| 16 | Ambiguïté | « preuves validées » (INV-286-03) | Mineur |
| 17 | Hypothèse dangereuse | source d'horloge TTL non spécifiée | Mineur |
| 18 | Risque sécu/conformité | politique rétention temp files non chiffrée (Q-286-03) | Mineur |
Verdict d'auditabilité (sans correction proposée)¶
La spécification PD-286 décrit un contrat fonctionnel cohérent en flux nominal et en états terminaux, mais comporte des contradictions structurelles avec ses propres tests (numérotation INV/CA, codes d'erreur, comportement borne 768 MB / 10 GB) qui rendent l'acceptation formelle de Gate ⅝ non démontrable en l'état. La levée des 5 bloquants est un préalable à toute soumission Gate 5.