Aller au contenu

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-loop a été ajoutée mais placée hors du branchement if, ce qui la fait s'exécuter aussi dans la branche else (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-cas fn==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 branche else (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 branche else ; 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 sur sn==0 => FAIL(ERR-294-09).
  • Impact : INV-294-06 non satisfaisable pour toute preuve dont le chemin contient au moins un nœud fn pair 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 matrice INV-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'ordonnancement merklePath v1 bottom-to-top). Le document de tests n'a pas suivi : il référence encore partout INV-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 de envelope-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 matrice CA-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. Chiffrement est 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 lever ERR-294-11" ; spec §5.4 "DOIT retourner 409 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 un ERR-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'"aucun ERR-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_version autorisée : absent, 1, 2 ; spec v2 §10.2 Q-294-01 (nouveau contenu : "Confirmation convention HTTP 409 pour ERR-294-11") ; tests §9 ligne 2 "Ambiguïté Q-294-01 (proof_version -> 1 inféré vs sortie imposée proof_version=2) | Bloquant"
  • Description : La spec v2 a résolu l'ambiguïté v1 en acceptant proof_version=1 en 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-11 THEN "Transition refusée explicitement / Aucun downgrade de format exposé" ; spec §6 ERR-294-11 ; spec §7 CA-294-13 "retourne ERR-294-11"
  • Description : Le THEN de TC-ERR-11 ne référence pas le code ERR-294-11 ni 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-09 impose "artefact temporaire persistant est chiffré au repos (AES-256-GCM ou enveloppe HSM)" et TC-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 max 2147483647 ; §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-1 au lieu de uint64) mais ne résout pas la contradiction avec INV-294-06-rfc-verify-applicable qui revendique l'applicabilité RFC 9162 §2.1.3.2.
  • Impact : Interopérabilité RFC 9162 partielle. Une preuve RFC native avec tree_size >= 2^31 est 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-12 empirique et ST-294-16 (campagne H-294-02). Le document de tests n'a pas suivi : CA-294-12 est squatté par un test chiffrement (cf. E-03), aucun TC dans §3/§4 ne matérialise ST-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érifier hsm_signature avant 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.1 LH(m) = HASH(0x00 || m)
  • Description : La spec définit NODE_HASH avec le préfixe inner-node 0x01 (conforme RFC) mais ne définit pas la primitive de leaf-hash LEAF_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éfixer 0x00 pour être conforme RFC. Aucun invariant / CA / test ne vérifie cette propriété du hash stocké.
  • Impact : Si event_hash amont est produit par SHA3-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=true sont 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-10 existe, mais aucun invariant / CA ne le référence dans la matrice de couverture §2.
  • Impact : Non-régression du code 404 non 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_READY sans passage par LEGACY_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-294 et 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 explicitement absent, 1, 2 en entrée → résolution E-02 / E-09 v1.
  • Ordonnancement merklePath v1 : 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 / else et expose la conditionnelle LSB(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)