PD-294 — Scénarios de tests contractuels
1. Références
- Spécification : PD-294-specification.md
- Epic :
ProbatioVault-backend/docs/epics/probatoire/PD-294-merkle-rfc9162
2. Matrice de couverture
| ID Invariant | ID Critère | ID Test | Couverture | Commentaire |
| INV-294-01-format-v2 | CA-294-01 | TC-NOM-01 | Oui | Sortie strictement limitée aux 7 champs v2. |
| INV-294-01-format-v2 | CA-294-06 | TC-ERR-04 | Oui | Validation stricte de inclusion_path. |
| INV-294-01-format-v2 | CA-294-07 | TC-NOM-04 | Oui | Bornes min/max numériques acceptées. |
| INV-294-01-format-v2 | CA-294-08 | TC-NOM-05 | Oui | Longueur inclusion_path 0 et 31 acceptée. |
| INV-294-02-hash-algorithm | CA-294-02 | TC-NOM-02 | Oui | Forçage hash_algorithm='sha3-256' en normalisation v1->v2. |
| INV-294-02-hash-algorithm | CA-294-06 | TC-ERR-07 | Oui | Toute autre valeur est rejetée. |
| INV-294-03-dual-read-single-write | CA-294-03 | TC-NOM-02 | Oui | Lecture v1/v2, émission v2 uniquement. |
| INV-294-03-dual-read-single-write | CA-294-01 | TC-NR-02 | Oui | Non-régression du contrat de sortie v2. |
| INV-294-04-no-retrowrite | CA-294-11 | TC-NR-01 | Oui | Aucune réécriture des preuves v1 persistées. |
| INV-294-04-no-retrowrite | CA-294-03 | TC-NOM-02 | Oui | Normalisation en mémoire, sans mutation persistée. |
| INV-294-05-discriminant | CA-294-04 | TC-NOM-03 | Oui | absent=>v1, 2=>v2. |
| INV-294-05-discriminant | CA-294-04 | TC-ERR-01 | Oui | Toute autre valeur rejetée (ERR-294-01). |
| INV-294-05-discriminant | CA-294-07 | TC-ERR-02 | Oui | leaf_index et relation avec tree_size contrôlés. |
| INV-294-05-discriminant | CA-294-06 | TC-ERR-03 | Oui | tree_size>=1 strict. |
| INV-294-06-rfc-verify-applicable | CA-294-09 | TC-NOM-06 | Oui | Vecteur positif RFC adapté SHA3-256 valide. |
| INV-294-06-rfc-verify-applicable | CA-294-10 | TC-ERR-09 | Oui | Preuve altérée invalide (ERR-294-09). |
| INV-294-06-rfc-verify-applicable | CA-294-12 | TC-NOM-10 | Oui | Vérification empirique H-294-02 (SHA3-256 conforme, SHA-256 non conforme). |
| INV-294-07-no-treeid-exposed | CA-294-05 | TC-ERR-08 | Oui | Détection fuite treeId/hashAlgorithmVersion. |
| INV-294-08-format-state-transitions | CA-294-03 | TC-NOM-07 | Oui | Transitions autorisées et idempotence vérifiées. |
| INV-294-08-format-state-transitions | CA-294-13 | TC-ERR-11 | Oui | Transitions interdites refusées avec ERR-294-11 HTTP 409. |
| INV-294-09-format-single-source | CA-294-06 | TC-NOM-08 | Oui (documentaire) | Contrôle documentaire “single source” §5.1. |
| INV-294-10-v1-path-order | CA-294-14 | TC-NOM-09 | Oui | merklePath v1 est conservé bottom-to-top sans inversion. |
| INV-294-10-v1-path-order | CA-294-14 | TC-NEG-05 | Oui | merklePath inversé (top-to-bottom) échoue (ERR-294-09). |
| INV-294-01-format-v2 | CA-294-06 | TC-ERR-05 | Oui | merkle_root invalide rejeté. |
| INV-294-01-format-v2 | CA-294-06 | TC-ERR-06 | Oui | event_hash invalide rejeté. |
| INV-294-01-format-v2 | CA-294-08 | TC-ERR-04 | Oui | inclusion_path.length=32 rejetée. |
3. Scénarios de test – Flux nominaux
TEST-ID: TC-NOM-01
Référence spec: INV-294-01, INV-294-07, CA-294-01, CA-294-05
GIVEN
- Fixture v2 valide versionnée (horloge figée UTC, données immuables)
- `merkle_proof` contient uniquement les 7 champs v2
WHEN
- Lecture API de la preuve
THEN
- HTTP 200
- Le payload retourné contient exactement: `proof_version`, `leaf_index`, `tree_size`, `inclusion_path`, `merkle_root`, `hash_algorithm`, `event_hash`
AND
- Aucun champ `treeId` ni `hashAlgorithmVersion` n'est exposé
- Aucune écriture DB n'est observée pendant la lecture
TEST-ID: TC-NOM-02
Référence spec: INV-294-02, INV-294-03, INV-294-04, CA-294-02, CA-294-03, CA-294-11
GIVEN
- Une preuve legacy v1 persistée (sans `proof_version`)
- Snapshot DB avant lecture (checksum ligne + `updated_at`)
WHEN
- Lecture API de cette preuve
THEN
- HTTP 200
- Réponse en v2 avec `proof_version=2`, renommages conformes §5.5, `hash_algorithm='sha3-256'`
AND
- Snapshot DB après lecture identique (pas d'UPDATE/INSERT/DELETE sur la preuve v1)
TEST-ID: TC-NOM-03
Référence spec: INV-294-05, CA-294-04
GIVEN
- Fixture A: preuve sans `proof_version`
- Fixture B: preuve avec `proof_version=2`
WHEN
- Lecture API des deux fixtures
THEN
- A est traitée legacy puis restituée en v2
- B est reconnue v2 et restituée inchangée
AND
- Le comportement est strictement déterministe et répétable
TEST-ID: TC-NOM-04
Référence spec: §5.2, CA-294-07
GIVEN
- Fixture LIM-MIN: `tree_size=1`, `leaf_index=0`
- Fixture LIM-MAX: `tree_size=2147483647`, `leaf_index=2147483646`
WHEN
- Validation/lecture API des deux preuves
THEN
- Les deux cas sont acceptés
- Aucun overflow, cast implicite, ni coercition de type
AND
- Les valeurs renvoyées restent inchangées
TEST-ID: TC-NOM-05
Référence spec: §5.2, CA-294-08
GIVEN
- Fixture PATH-0 avec `inclusion_path.length=0`
- Fixture PATH-31 avec `inclusion_path.length=31`, tous éléments `^[a-f0-9]{64}$`
WHEN
- Validation/lecture API
THEN
- Les deux preuves sont acceptées
- L'ordre des éléments de `inclusion_path` est conservé
AND
- Les longueurs retournées sont exactement 0 et 31
TEST-ID: TC-NOM-06
Référence spec: INV-294-06, §5.8, CA-294-09
GIVEN
- Vecteur de test figé `VEC-RFC9162-SHA3-256-01` (event_hash, leaf_index, tree_size, inclusion_path, merkle_root)
WHEN
- Exécution de la vérification RFC 9162 §2.1.3.2 adaptée SHA3-256
THEN
- Résultat `valid=true`
- `r` final est égal à `merkle_root`
AND
- Aucun code d'erreur n'est produit
TEST-ID: TC-NOM-07
Référence spec: INV-294-08, §5.4, CA-294-03
GIVEN
- Une preuve v1 valide et une preuve v2 valide
- Journalisation des transitions de classification activée
WHEN
- Relecture séquentielle: v1, v1, v2, v2
THEN
- Transitions observées uniquement parmi les autorisées:
`LEGACY_V1_DETECTED -> CANONICAL_V2_READY`,
`LEGACY_V1_DETECTED -> LEGACY_V1_DETECTED`,
`CANONICAL_V2_READY -> CANONICAL_V2_READY`
AND
- Aucune transition interdite n'est observée
TEST-ID: TC-NOM-08
Référence spec: INV-294-09
GIVEN
- Corpus documentaire contractuel PD-294 gelé (même révision)
WHEN
- Exécution d'un contrôle documentaire de cohérence
THEN
- Les définitions de format sont présentes uniquement en §5.1
- Les autres sections référencent §5.1 sans redéfinition contradictoire
AND
- Rapport de contrôle archivé comme preuve
TEST-ID: TC-NOM-09
Référence spec: INV-294-10-v1-path-order, §5.1, §5.5, CA-294-14
GIVEN
- Une preuve legacy v1 valide avec `merklePath` ordonné bottom-to-top
- Vecteur témoin pour lequel la racine attendue est connue
WHEN
- Normalisation v1 -> v2 puis vérification cryptographique
THEN
- `inclusion_path` reprend `merklePath` sans inversion
- Résultat de vérification `valid=true`
AND
- Aucun remaniement d'ordre n'est observé dans le payload normalisé
TEST-ID: TC-NOM-10
Référence spec: H-294-02, CA-294-12
GIVEN
- Échantillon DB réel versionné (jeu de preuves représentatif)
- Outil de recalcul paramétrable (`sha3-256` et `sha-256`)
WHEN
- Recalcul de la racine depuis `event_hash` + `inclusion_path` pour chaque preuve, en double mode
THEN
- En mode `sha3-256`, la racine recalculée égale `merkle_root` sur l’échantillon
- En mode `sha-256`, la racine recalculée ne reproduit pas `merkle_root`
AND
- Rapport comparatif archivé (preuve par preuve, hash algo, résultat)
4. Scénarios de test – Cas d’erreur
TEST-ID: TC-ERR-01
Référence spec: ERR-294-01, INV-294-05, CA-294-04
GIVEN
- Preuve avec `proof_version=3`
WHEN
- Lecture API
THEN
- HTTP 400 avec `ERR-294-01`
- Rejet déterministe
AND
- Aucune mutation persistée
TEST-ID: TC-ERR-02
Référence spec: ERR-294-02, §5.1, §5.2, CA-294-06, CA-294-07
GIVEN
- Cas A: `leaf_index=-1`
- Cas B: `leaf_index=tree_size`
WHEN
- Validation/lecture API
THEN
- HTTP 422 avec `ERR-294-02` pour les deux cas
AND
- Aucune écriture DB
TEST-ID: TC-ERR-03
Référence spec: ERR-294-03, §5.1, §5.2, CA-294-06, CA-294-07
GIVEN
- Preuve avec `tree_size=0`
WHEN
- Validation/lecture API
THEN
- HTTP 422 avec `ERR-294-03`
AND
- Aucune exécution de vérification crypto
TEST-ID: TC-ERR-04
Référence spec: ERR-294-04, §5.1, §5.2, CA-294-06, CA-294-08
GIVEN
- Jeu de cas invalide déterministe:
1) `inclusion_path` non tableau
2) `inclusion_path.length=32`
3) élément non `^[a-f0-9]{64}$`
WHEN
- Validation/lecture API
THEN
- HTTP 400 avec `ERR-294-04` pour chaque cas
AND
- Aucun calcul RFC n'est lancé
TEST-ID: TC-ERR-05
Référence spec: ERR-294-05, §5.1, CA-294-06
GIVEN
- `merkle_root` invalide (longueur != 64 ou caractère hors `[a-f0-9]`)
WHEN
- Validation/lecture API
THEN
- HTTP 400 avec `ERR-294-05`
AND
- Pas d'effet secondaire persisté
TEST-ID: TC-ERR-06
Référence spec: ERR-294-06, §5.1, CA-294-06
GIVEN
- `event_hash` invalide (longueur != 64 ou caractère hors `[a-f0-9]`)
WHEN
- Validation/lecture API
THEN
- HTTP 400 avec `ERR-294-06`
AND
- Pas d'effet secondaire persisté
TEST-ID: TC-ERR-07
Référence spec: ERR-294-07, INV-294-02, CA-294-02, CA-294-06
GIVEN
- Preuve avec `hash_algorithm='SHA-256'` (ou toute autre valeur)
WHEN
- Validation/lecture API
THEN
- HTTP 422 avec `ERR-294-07`
AND
- La preuve n'est pas émise
TEST-ID: TC-ERR-08
Référence spec: ERR-294-08, INV-294-07, CA-294-05
GIVEN
- Réponse API contenant `treeId` ou `hashAlgorithmVersion` dans `merkle_proof`
WHEN
- Exécution du validateur de contrat
THEN
- Non-conformité détectée avec `ERR-294-08` (HTTP 500 contractuel)
AND
- Le test échoue tant que la fuite n'est pas corrigée
TEST-ID: TC-ERR-09
Référence spec: ERR-294-09, INV-294-06, CA-294-10
GIVEN
- Vecteur valide puis version altérée (1 bit modifié dans `inclusion_path` ou longueur menant à `sn != 0`)
WHEN
- Exécution de la vérification RFC adaptée SHA3-256
THEN
- HTTP 422 avec `ERR-294-09` / `valid=false`
AND
- Aucune mutation persistée
TEST-ID: TC-ERR-10
Référence spec: ERR-294-10
GIVEN
- Identifiant de preuve inexistant
WHEN
- Lecture API
THEN
- HTTP 404 avec `ERR-294-10`
AND
- Aucune mutation persistée
TEST-ID: TC-ERR-11
Référence spec: ERR-294-11, INV-294-08, §5.4, CA-294-13
GIVEN
- Cas A: preuve classée `CANONICAL_V2_READY`
- Cas B: preuve classée `REJECTED_INVALID`
WHEN
- Tentative de transition interdite (`CANONICAL_V2_READY -> LEGACY_V1_DETECTED` ou `REJECTED_INVALID -> *`)
THEN
- HTTP 409 avec `ERR-294-11`
- Transition refusée explicitement et aucun downgrade de format exposé
AND
- État courant inchangé et journal de refus présent
5. Tests d’invariants (non négociables)
| Invariant | Test(s) dédiés | Observable | Commentaire |
| INV-294-01-format-v2 | TC-NOM-01, TC-NR-02 | Clés JSON exactes + schéma v2 PASS | Contrat de sortie univoque. |
| INV-294-02-hash-algorithm | TC-NOM-02, TC-ERR-07 | hash_algorithm toujours sha3-256 | Rejet strict des autres valeurs. |
| INV-294-03-dual-read-single-write | TC-NOM-02, TC-NOM-03 | v1 et v2 lisibles, sortie exclusivement v2 | Dual-read/single-write vérifié. |
| INV-294-04-no-retrowrite | TC-NOM-02, TC-NR-01 | Checksum/updated_at legacy inchangés | Aucune réécriture rétroactive. |
| INV-294-05-discriminant | TC-NOM-03, TC-ERR-01 | Routage déterministe selon proof_version | Valeurs non supportées rejetées. |
| INV-294-06-rfc-verify-applicable | TC-NOM-06, TC-ERR-09, TC-NOM-10 | valid=true sur vecteur positif, ERR-294-09 sur altération, comparatif SHA3/SHA-256 conforme | Applicabilité RFC adaptée SHA3-256 validée. |
| INV-294-07-no-treeid-exposed | TC-NOM-01, TC-ERR-08 | Absence de champs internes en sortie | Protection du contrat exposé. |
| INV-294-08-format-state-transitions | TC-NOM-07, TC-ERR-11 | Traces de transitions autorisées/interdites + refus ERR-294-11 HTTP 409 | Machine d’états respectée. |
| INV-294-09-format-single-source | TC-NOM-08 | Rapport documentaire de cohérence | Test de gouvernance documentaire. |
| INV-294-10-v1-path-order | TC-NOM-09, TC-NEG-05 | Ordre bottom-to-top conservé sans inversion ; ordre inversé rejeté | Contrat d’ordonnancement v1 explicite. |
6. Tests de non-régression
| Test ID | Objet | Observable | Commentaire |
| TC-NR-01 | Non-réécriture des preuves v1 existantes | Diff DB avant/après lecture (0 update sur lignes v1) | Couvre CA-294-11. |
| TC-NR-02 | Stabilité du contrat de sortie v2 | Snapshot JSON de réponse strictement identique (7 champs) | Évite dérive de schéma. |
| TC-NR-03 | Non-régression hors périmètre ProofEnvelope | tsa_token, hsm_signature, blockchain_anchor, event_metadata inchangés | Respect du hors périmètre. |
| TC-NR-04 | Absence de migration DDL induite | Schéma DB identique avant/après PD-294 | Conforme §5.9. |
7. Tests négatifs et adversariaux
| Test ID | Entrée invalide / abus | Résultat attendu | Observable |
| TC-NEG-01 | Hash en uppercase/mixte ([A-F]) | Rejet format (ERR-294-04/05/06 selon champ) | HTTP + code erreur exact. |
| TC-NEG-02 | inclusion_path contenant null, objet, nombre | Rejet ERR-294-04 | HTTP 400, aucune mutation DB. |
| TC-NEG-03 | Rejeu massif concurrent de lectures v1 (N appels) | Réponses v2 identiques, 0 écriture persistée | Diff DB + hash des payloads. |
| TC-NEG-04 | Tentative de downgrade forcé v2->v1 | Transition interdite refusée (ERR-294-11) | Trace de refus + absence de payload legacy. |
| TC-NEG-05 | Preuve v1 correcte mais merklePath inversé (top-to-bottom) | Échec vérification ERR-294-09 après normalisation | Résultat valid=false déterministe + HTTP 422. |
| TC-NEG-06 | Altération bit-à-bit de merkle_root après normalisation | Échec vérification ERR-294-09 | Résultat valid=false déterministe. |
8. Observabilité requise pour les tests
- État système : snapshot DB avant/après (
checksum, updated_at, compte d’updates), traces de classification d’état. - Réponse API : code HTTP,
error_code, payload JSON complet, ordre stable des champs vérifiés côté validateur. - Journal d’audit : lecture, normalisation, rejet de validation, transition de classification, tentative interdite.
- Événement signé / horodaté : résultat de vérification RFC (valid/invalid) horodaté UTC corrélable à l’ID de preuve.
- Export probatoire : fixtures versionnées, résultats bruts de tests, diffs DB, extraits journaux et rapport comparatif archivés.
9. Règles non testables
| Règle | Raison | Impact |
| Représentativité exhaustive de l’échantillon H-294-02 | Impossible de couvrir l’intégralité des arbres historiques en une seule campagne contractuelle | Majeur |
| Namespace d’erreurs final Q-294-02 | ERR-294-* doit être confirmé avec conventions backend effectives | Majeur |
10. Verdict QA
- ✅ Testable (avec réserves non bloquantes listées)
Note d’exécution : environnement en lecture seule, contenu généré mais non écrit sur disque dans ce run.