PD-294 — Spécification : Revue (Gate 3, v2)¶
- Rôle : auditeur technique indépendant
- Portée : PD-294-specification.md (contractuelle, v2) + PD-294-tests.md (audit limité)
- Sans amélioration, sans reformulation, sans implémentation
1. Synthèse¶
| Gravité | Nombre |
|---|---|
| Bloquant | 3 |
| Majeur | 10 |
| Mineur | 9 |
État global : la spec v2 a résolu plusieurs écarts Bloquants de la v1 (entrée proof_version=1, ordonnancement merklePath, longueur inclusion_path vs tree_size, code ERR-294-11 normé, ambiguïté INV-294-10). Mais :
- l'algorithme §5.8 reste divergent du RFC 9162 §2.1.3.2 : la
inner while-loopa été ajoutée mais placée hors du branchementif, ce qui la fait s'exécuter aussi dans la brancheelse(régression sémantique inédite) ; - le document de tests n'a pas été resynchronisé avec la spec v2 : il référence encore
INV-294-10-envelope-encryption,CA-294-12 = chiffrement,ERR-294-11 non normé,Q-294-01 = proof_version inféré. Ces désynchronisations contredisent directement les correctifs spec v2.
Deux hypothèses critiques demeurent non testées en pratique (hash_algorithm amont, tree_size > 2^31-1).
2. Écarts détaillés¶
E-01 — Inner while-loop §5.8 mal placée (régression d'un écart v1 partiellement corrigé)¶
- Type : Contradiction (spec ↔ norme revendiquée) + Incohérence Spec↔Tests
- Référence : spec §5.8 étape 4c ; INV-294-06-rfc-verify-applicable ; CA-294-09 "avec inner while-loop" ; TC-NOM-06 ; TC-ERR-09
- Description : RFC 9162 §2.1.3.2 impose que la
inner while-loop(si LSB(fn) n'est pas set, right-shift fn et sn jusqu'à LSB(fn)=1 ou fn=0) soit imbriquée dans la branche(LSB(fn)==1) OU (fn==sn), sous-casfn==sn AND LSB(fn)==0. La spec v2 a ajouté la boucle mais au même niveau d'indentation que les étapes 4b et 4d (sibling step), ce qui la fait s'exécuter inconditionnellement après le hash. Conséquence : dans la brancheelse(LSB(fn)==0 AND fn != sn), la spec v2 effectue un shift multi-niveau là où RFC 9162 ne prescrit qu'un shift unique. Exemple minimal reproductible :leaf_index=4, tree_size=8; première itération brancheelse; RFC :fn=2, sn=3; spec v2 : while décale àfn=1, sn=1, puis step d décale àfn=0, sn=0; la seconde itération échoue sursn==0 => FAIL(ERR-294-09). - Impact : INV-294-06 non satisfaisable pour toute preuve dont le chemin contient au moins un nœud
fnpair strict (fn != sn). Rejets massifs de preuves valides dès que l'arbre n'est pas dégénéré à droite. TC-NOM-06 (vecteur figé non qualifié) et TC-ERR-09 (vecteur altéré) ne contraignent pas ce cas. La rédaction CA-294-09 "avec inner while-loop" donne une fausse garantie d'alignement RFC. - Gravité : Bloquant
E-02 — Désynchronisation INV-294-10 entre spec v2 et tests¶
- Type : Contradiction (spec ↔ tests) + Incohérence Spec↔Tests
- Référence : spec §4
INV-294-10-v1-path-order; tests §2 matriceINV-294-10-envelope-encryption | CA-294-12 | TC-NOM-09; tests §5 ligne INV-294-10 ; TC-NOM-09 ; TC-NEG-05 - Description : La spec v2 a renommé l'invariant INV-294-10 en
v1-path-order(règle d'ordonnancementmerklePathv1 bottom-to-top). Le document de tests n'a pas suivi : il référence encore partoutINV-294-10-envelope-encryption(chiffrement enveloppe). Les deux règles n'ont aucun lien sémantique. La matrice §2 et le §5 "Tests d'invariants" testent donc un invariant qui n'existe plus dans la spec v2. - Impact : Couverture formelle de INV-294-10
v1-path-order: zéro dans le document de tests. Couverture deenvelope-encryption: fantomatique (règle supprimée). Gate 3 matériellement non satisfaisable en l'état (aucun TC associé à l'invariant réel de la spec v2). - Gravité : Bloquant
E-03 — Désynchronisation CA-294-12 entre spec v2 et tests¶
- Type : Contradiction (spec ↔ tests)
- Référence : spec §7
CA-294-12 = "Vérification empirique H-294-02 : SHA3-256 valide ; SHA-256 ne reproduit pas la racine"; spec §8 ST-294-16 ; tests §2 matriceCA-294-12 | TC-NOM-09 | Chiffrement au repos - Description : Le critère d'acceptation CA-294-12 est réassigné entre spec v2 et tests. Spec : validation H-294-02 sur échantillon DB. Tests : chiffrement au repos d'artefacts temporaires. Deux critères totalement distincts partagent le même identifiant.
- Impact : Traçabilité exigence → test rompue. H-294-02 n'a aucun TC de couverture dans le document de tests.
Chiffrementest couvert par un TC-NOM-09 qui pointe vers un invariant inexistant (cf. E-02). - Gravité : Bloquant
E-04 — Tests §9 "ERR-294-11 non normalisé" contredit spec v2 §6¶
- Type : Contradiction (spec ↔ tests)
- Référence : spec §6
ERR-294-11(HTTP 409) ; spec §4 INV-294-08 "DOIT leverERR-294-11" ; spec §5.4 "DOIT retourner409 ERR-294-11" ; spec §7 CA-294-13 ; tests §9 ligne 1 "Code d'erreur exact pour transitions interdites de §5.4 (TC-ERR-11) | La spécification interdit la transition mais ne normalise pas explicitement unERR-294-*dédié | Majeur" - Description : La spec v2 a explicitement normalisé
ERR-294-11(HTTP 409) pour les transitions interdites §5.4. Le §9 des tests classe toujours ce point en "règle non testable" au motif qu'"aucunERR-294-*dédié n'est normalisé", ce qui est factuellement faux. - Impact : Verdict QA "testable partiellement" basé sur une prémisse obsolète. Régression documentaire.
- Gravité : Majeur
E-05 — Tests §9 "Q-294-01 = proof_version=1 inféré" contredit spec v2¶
- Type : Contradiction (spec ↔ tests)
- Référence : spec v2 §5.1 entrée
proof_versionautorisée :absent, 1, 2; spec v2 §10.2 Q-294-01 (nouveau contenu : "Confirmation convention HTTP409pourERR-294-11") ; tests §9 ligne 2 "Ambiguïté Q-294-01 (proof_version -> 1 inférévs sortie imposéeproof_version=2) | Bloquant" - Description : La spec v2 a résolu l'ambiguïté v1 en acceptant
proof_version=1en entrée (§5.1 + §5.4). Q-294-01 a été redéfini (HTTP 409). Tests §9 conserve l'ancienne formulation et la classe "Bloquant". - Impact : Tests indûment classés bloquants. Contradictoire avec la résolution de l'écart v1 E-02/E-09.
- Gravité : Majeur
E-06 — TC-ERR-11 sans code d'erreur attendu¶
- Type : Incohérence Spec↔Tests
- Référence : tests §4
TC-ERR-11THEN "Transition refusée explicitement / Aucun downgrade de format exposé" ; spec §6ERR-294-11; spec §7 CA-294-13 "retourneERR-294-11" - Description : Le THEN de
TC-ERR-11ne référence pas le codeERR-294-11ni le HTTP 409 prescrits par spec v2 §6 et CA-294-13. Observable sous-spécifiée (n'importe quel refus générique validerait le test). - Impact : CA-294-13 non testable a priori via
TC-ERR-11. Risque d'implémentation hétérogène (exception générique vs code contractuel). - Gravité : Majeur
E-07 — TC-NOM-09 et TC-NEG-05 hors périmètre déclaré¶
- Type : Contradiction (spec ↔ tests) + Règle non testable
- Référence : spec §2 "Exclu : Chiffrement d'artefacts cryptographiques temporaires : hors périmètre PD-294" ; tests §3 TC-NOM-09 ; tests §7 TC-NEG-05 ; tests §9 ligne 3 "Exhaustivité absolue de INV-294-10 ... non testable universellement"
- Description :
TC-NOM-09impose "artefact temporaire persistant est chiffré au repos (AES-256-GCM ou enveloppe HSM)" etTC-NEG-05"recherche de secrets temporaires en clair". Ces exigences reposent sur un invariant supprimé par spec v2 (cf. E-02) et portent sur un sujet explicitement exclu du périmètre PD-294 (§2). - Impact : Deux tests inexécutables (aucune surface de chiffrement implémentée par PD-294). Dépendance infra non couverte par la spec. Les deux tests feraient systématiquement FAIL ou seraient ignorés, polluant la campagne QA.
- Gravité : Majeur
E-08 — tree_size int32 vs uint64 RFC 9162 (persistant v1)¶
- Type : Contradiction (spec ↔ norme revendiquée)
- Référence : spec §5.1
tree_size"entier signé 32-bit" ; spec §5.2 max2147483647; §9 H-294-03 ; INV-294-06 - Description : Écart E-04 du review v1 non corrigé en v2. La justification §5.2 reconnaît la divergence (borne contractuelle
<= 2^31-1au lieu deuint64) mais ne résout pas la contradiction avecINV-294-06-rfc-verify-applicablequi revendique l'applicabilité RFC 9162 §2.1.3.2. - Impact : Interopérabilité RFC 9162 partielle. Une preuve RFC native avec
tree_size >= 2^31est rejetée (ERR-294-03) alors qu'elle est conforme RFC. Couvert par H-294-03 sans test associé. - Gravité : Majeur
E-09 — H-294-02 (hash_algorithm amont SHA3-256) : couverture tests inexistante¶
- Type : Hypothèse dangereuse + Risque sécu/conformité
- Référence : spec §9 H-294-02 ; spec §7 CA-294-12 (renommé en vérification empirique) ; spec §8 ST-294-16 ; tests §2 matrice (aucun TC ne couvre CA-294-12
vérification empirique) ; tests §5 (aucun test d'invariant H-294-02) - Description : La spec v2 a introduit
CA-294-12empirique etST-294-16(campagne H-294-02). Le document de tests n'a pas suivi :CA-294-12est squatté par un test chiffrement (cf. E-03), aucun TC dans §3/§4 ne matérialiseST-294-16. L'hypothèse reste donc non testée en pratique. - Impact : Si l'amont produit en réalité du SHA-256, §5.5 labelise abusivement
hash_algorithm='sha3-256', les vérifications RFC §5.8 échouent silencieusement, et la valeur probatoire des preuves legacy est détruite. Risque eIDAS / RGPD. - Gravité : Majeur
E-10 — Absence de vérification hsm_signature / tsa_token avant normalisation (persistant v1)¶
- Type : Risque sécurité / conformité
- Référence : spec §2 Hors périmètre ; §5.5 / §5.7 normalisation ; INV-294-06
- Description : Écart E-10 du review v1 non corrigé en v2. Le normalizer applique les renommages et le forçage
hash_algorithm='sha3-256'sans prérequis d'intégrité sur la preuve source. La spec ne prescrit pas "vérifierhsm_signatureavant normalisation" comme invariant. - Impact : Un attaquant fournissant une structure v1 forgée voit sa preuve re-labelisée v2
sha3-256. Angle d'attaque pour forgerie sous label de confiance. - Gravité : Majeur
E-11 — Validateur ERR-294-08 non localisé (persistant v1)¶
- Type : Règle non testable
- Référence : spec §5.1 ligne
treeId; INV-294-07 ; spec §6 ERR-294-08 ; TC-ERR-08 - Description : Écart E-11 du review v1 non corrigé. Le point d'insertion du validateur (middleware NestJS, décorateur JSON Schema, post-sérialisation, CI) reste non spécifié.
- Impact : Risque d'implémentation laxe (validateur CI-only, pas runtime prod). Invariant défensif INV-294-07 non garanti en exécution.
- Gravité : Majeur
E-12 — Convention leaf-hash RFC 9162 non spécifiée¶
- Type : Hypothèse dangereuse + Ambiguïté
- Référence : spec §5.8 primitive
NODE_HASH(left, right) = HASH(0x01 || left || right); §5.8 étape 3 note "Convention PD-294: event_hash est le leaf-hash stocké; r = hexToBytes(event_hash)" ; RFC 9162 §2.1.1LH(m) = HASH(0x00 || m) - Description : La spec définit
NODE_HASHavec le préfixe inner-node0x01(conforme RFC) mais ne définit pas la primitive de leaf-hashLEAF_HASH(m) = SHA3-256(0x00 || m)imposée par RFC 9162 §2.1.1. La note "event_hash est le leaf-hash stocké" externalise l'hypothèse sans la contractualiser : l'amont doit déjà préfixer0x00pour être conforme RFC. Aucun invariant / CA / test ne vérifie cette propriété du hash stocké. - Impact : Si
event_hashamont est produit parSHA3-256(data)sans préfixe, la racine calculée par §5.8 diverge de la racine d'une vérification RFC 9162 native. Orthogonal à E-09 (label). - Gravité : Majeur
E-13 — §5.8 étape 3 : ambiguïté r = hash(event_hash) vs note correctrice¶
- Type : Ambiguïté (contradiction interne)
- Référence : spec §5.8 étape 3 "r = hash(event_hash)" + note "Convention PD-294 : r = hexToBytes(event_hash)"
- Description : L'énoncé principal prescrit un hachage, la note pragmatique impose un simple décodage hex. Deux implémentations conformes à la lettre produiraient des racines différentes pour la même entrée. La note se présente comme dérogation sans fermer explicitement la première option.
- Impact : Divergence d'implémentation certaine entre lectures de la spec. Tous les TC
valid=truesont ambigus sur cette base. - Gravité : Majeur
E-14 — ST-294-17 et CA-294-14 sans TC équivalent dans tests¶
- Type : Incohérence Spec↔Tests
- Référence : spec §7 CA-294-14 "merklePath v1 bottom-to-top sans inversion" ; spec §8 ST-294-17 ; tests §2 matrice (pas d'entrée CA-294-14 / INV-294-10-v1-path-order) ; tests §3/§4 (pas de TC-* associé)
- Description : La spec v2 a ajouté CA-294-14 et ST-294-17 pour couvrir INV-294-10-v1-path-order (correction de l'écart v1 E-07). Le document de tests n'a pas créé de TC équivalent, et la matrice §2 n'a pas été mise à jour (elle référence encore l'ancien INV-294-10).
- Impact : Correction de E-07 v1 annulée au niveau tests. Pas de couverture formelle de l'invariant bottom-to-top dans la campagne QA.
- Gravité : Majeur
E-15 — ERR-294-10 non mappé dans la matrice §2 tests (persistant v1)¶
- Type : Incohérence Spec↔Tests
- Référence : spec §6 ERR-294-10 ; tests §2 matrice (absent) ; TC-ERR-10
- Description : Écart E-08 du review v1 non corrigé.
TC-ERR-10existe, mais aucun invariant / CA ne le référence dans la matrice de couverture §2. - Impact : Non-régression du code
404non protégée. Angle mort de traçabilité. - Gravité : Majeur
E-16 — Single-write : terminologie toujours non désambiguïsée (persistant v1)¶
- Type : Ambiguïté terminologique (pattern REX PD-250)
- Référence : spec §3 "Dual-read / single-write" ; INV-294-03 ; §5.7 "sans écrire en base"
- Description : Écart E-12 du review v1 non corrigé. "Single-write" peut s'interpréter comme "une seule écriture DB" ou comme "un seul format de sortie".
- Impact : Lecture divergente possible entre rédacteur, implémenteur et reviewer. Pattern REX PD-250 §10.1 (clarity oscillante).
- Gravité : Mineur
E-17 — Émission / exposition : terminologie toujours non unifiée (persistant v1)¶
- Type : Ambiguïté terminologique
- Référence : INV-294-01 "preuve émise" ; INV-294-07 "merkle_proof v2 exposé" ; §5.6 "retourne
merkle_proof" ; CA-294-01 ; CA-294-05 - Description : Écart E-16 du review v1 non corrigé. Les surfaces "émise", "exposée", "retournée" ne sont pas définies comme synonymes. Pour une spec contractuelle, API publique / export batch / log d'audit devraient être distinguées.
- Impact : Un invariant "émise" peut être interprété comme couvrant uniquement l'API publique, laissant un export probatoire non contraint.
- Gravité : Mineur
E-18 — INV-294-04 temporellement non borné (persistant v1)¶
- Type : Règle non testable (partiellement)
- Référence : INV-294-04-no-retrowrite ; CA-294-11 ; TC-NR-01 ; TC-NOM-02
- Description : Écart E-17 du review v1 non corrigé. La non-réécriture est vérifiée uniquement sur un instantané (diff avant/après une lecture). Pas de sonde continue.
- Impact : Vérification en continu non prescrite. Invariant faiblement tenable au-delà du test ponctuel.
- Gravité : Mineur
E-19 — Anti-énumération 404 vs 400 (persistant v1)¶
- Type : Risque sécurité / conformité
- Référence : spec §6 ERR-294-10 (404) vs ERR-294-06/04/05 (400)
- Description : Écart E-19 du review v1 non corrigé. Pattern REX PD-85 (learnings universels : anti-énumération 404) : un client peut distinguer "preuve absente" de "identifiant mal formé" par le code HTTP.
- Impact : Fuite d'information de présence de preuves (énumération ID légitimes).
- Gravité : Mineur
E-20 — Placeholder {{LEARNINGS}} non renseigné (persistant v1)¶
- Type : Hypothèse dangereuse (processus)
- Référence : spec §10.2 Q-294-03 ; en-tête prompt
{{LEARNINGS}} - Description : Écart E-20 du review v1 non corrigé. Bloc learnings historiques non injecté. Anti-patterns connus (catch-absorb, validation format ≠ fonctionnelle, crypto roundtrip) non croisés systématiquement.
- Impact : Omission d'invariant déjà capturé par REX précédents. E-09 (label), E-10 (signature), E-11 (validateur) relèvent déjà de patterns PD-282/PD-283.
- Gravité : Mineur
E-21 — INV-294-09 reste une règle documentaire (persistant v1)¶
- Type : Règle non testable (runtime)
- Référence : INV-294-09-format-single-source ; TC-NOM-08
- Description : Écart E-21 du review v1 non corrigé. INV-294-09 contraint la rédaction de la spec, pas l'exécution du système. Classé comme invariant technique NON négociable.
- Impact : Pollue la matrice d'invariants runtime. Gate 8 peut exiger une preuve d'exécution inapplicable.
- Gravité : Mineur
E-22 — Diagramme d'état : transitions initiales toujours non listées en §5.4 (persistant v1)¶
- Type : Incohérence diagramme ↔ texte (axe 5bis)
- Référence : spec §5bis diagramme
[*] --> LEGACY_V1_DETECTED,[*] --> CANONICAL_V2_READY,[*] --> REJECTED_INVALID (ERR-294-01); spec §5.4 (table "transitions sortantes" ne couvre pas les entrées initiales) - Description : Écart E-14 du review v1 non corrigé. Le diagramme montre 3 transitions initiales depuis
[*]mais §5.4 ne formalise que la classification initiale (§5.4 tableau 1) sans les déclarer comme transitions. Asymétrie résiduelle. - Impact : Ambiguïté sur un enregistrement pouvant naître directement
CANONICAL_V2_READYsans passage parLEGACY_V1_DETECTED. - Gravité : Mineur
E-23 — Q-294-04 "référence épique textuelle non fournie"¶
- Type : Hypothèse dangereuse (traçabilité)
- Référence : spec §10.2 Q-294-04 "Référence épique textuelle métier non fournie dans le besoin (seul chemin technique disponible)"
- Description : La spec v2 reconnaît que la référence métier du besoin n'est pas fournie. La référence JIRA
PD-294et le chemin technique ne dispensent pas d'un rattachement métier (epic probatoire, valeur probatoire ciblée). - Impact : Métadonnées de traçabilité incomplètes. Risque documentation RTM non fermée côté métier.
- Gravité : Mineur
E-24 — Atomicité §5.10 : "aucune mutation persistée" ignore logs/audit potentiels¶
- Type : Hypothèse dangereuse (implicite)
- Référence : spec §5.10 "Crash pré-réponse / post-réponse : Aucune mutation persistée / Aucun rattrapage requis" ; tests §8 observabilité "journal d'audit : lecture, normalisation, rejet, transition"
- Description : §5.10 spec affirme qu'aucune mutation n'est persistée. §8 des tests exige pourtant un journal d'audit avec événements "lecture, normalisation, rejet, transition". Ces entrées sont par nature des mutations persistées sur la surface logs/audit. La spec ne prescrit pas quel mécanisme d'audit (journaliser avant réponse ? après ?), ni la conduite en cas de crash entre l'action et l'écriture audit.
- Impact : Zone grise entre "synchrone sans effet de bord" et exigence d'observabilité. Audit bloquant potentiel non tranché.
- Gravité : Mineur
3. Vérifications positives (non exhaustives)¶
Écarts corrigés par la v2 et jugés conformes en l'état (mentionnés à titre informatif, sans complément) :
- Cas entrée
proof_version=1: v2 §5.1 autorise explicitementabsent, 1, 2en entrée → résolution E-02 / E-09 v1. - Ordonnancement
merklePathv1 : v2 §5.1 + INV-294-10-v1-path-order + CA-294-14 + ST-294-17 contractualisent bottom-to-top → résolution E-07 v1 (côté spec ; cf. E-14 pour le volet tests). - Code d'erreur transitions interdites : v2 §6 normalise
ERR-294-11(HTTP 409), couvert par CA-294-13 → résolution E-06 v1 (côté spec ; cf. E-04 pour le volet tests). - Suppression INV-294-10 envelope-encryption hors périmètre : v2 réaffecte l'identifiant à
v1-path-order→ résolution E-05 v1 (côté spec ; cf. E-02 pour le volet tests). - Relation
inclusion_path.length=0 <=> tree_size=1: v2 §5.1 l'enforce explicitement → résolution E-18 v1. - Étape §5.8 #1 (
leaf_index >= tree_size => FAIL(ERR-294-02)) : code d'erreur normé désormais inline → résolution E-13 v1. - Diagramme de séquence : v2 ajoute
alt / elseet expose la conditionnelleLSB(fn)=1 OU fn==sn→ résolution E-15 v1. - H-294-02 partiellement adressée côté spec (ajout CA-294-12 empirique + ST-294-16), mais couverture tests non suivie (cf. E-09).
4. Recommandation QA¶
Verdict : Non conforme en l'état — 3 écarts Bloquants rendent la spec + tests non acceptables au titre contractuel avant résolution :
- E-01 : algorithme §5.8 reste divergent RFC 9162 §2.1.3.2 (inner while-loop mal placée, erreur sémantique inédite dans la branche
else). - E-02 : désynchronisation INV-294-10 entre spec v2 (
v1-path-order) et tests (envelope-encryption) — invariant testé fantomatique. - E-03 : désynchronisation CA-294-12 entre spec v2 (vérification empirique H-294-02) et tests (chiffrement au repos).
Les 10 écarts Majeurs doivent être tranchés avant Gate 5 (dont la resynchronisation intégrale du document de tests avec la spec v2 : E-04, E-05, E-06, E-07, E-14). Les 9 écarts Mineurs peuvent être adressés en parallèle ou documentés comme dette contractuelle.
Observation transverse : la majorité des écarts Bloquants et Majeurs v2 proviennent d'un document de tests resté en état v1 après correction de la spec. Une revue tests.md alignée sur spec v2 (invariants, CA, questions ouvertes) résorberait E-02, E-03, E-04, E-05, E-06, E-07, E-14 en un seul cycle.
Références¶
- PD-294-specification.md (v2, §1–§10)
- PD-294-tests.md (§1–§10)
- PD-294-review-step3.md (v1) — référence de suivi des écarts persistants
- RFC 9162 §2.1.1 (leaf-hash LH), §2.1.3, §2.1.3.2 (inclusion path verification), §4.12
- Learnings universels : REX PD-250 §10.1 (clarity oscillante), PD-85 (enumeration), PD-282/PD-283 (validation format ≠ fonctionnelle, crypto roundtrip)