Aller au contenu

PD-56 — Génération contractuelle de preuve Merkle par eventId (v3)

1. Objectif

Contractualiser la capacité du backend à produire, pour un eventId donné, une preuve d’inclusion Merkle complète, déterministe et vérifiable off-chain, exploitable par le service ProofEnvelope sans accès API/BDD tiers.

Le résultat fonctionnel exposé est un objet MerkleProofResult avec : - status: 'available' et toutes les données de preuve si l’événement est prouvable. - status: 'pending' avec estimatedAvailableAt si l’événement n’est pas encore prouvable.

L’état interne CORRUPTED est persisté côté service mais n’est pas exposé comme valeur status; il est matérialisé par ERR-56-03 ou ERR-56-04 selon le cas (§6).

2. Périmètre / Hors périmètre

Inclus

  • Résolution eventId -> eventHash(leafHash) -> merkle leaf -> merkle tree -> proof.
  • Production de MerkleProofResult au format custom ProbatioVault.
  • Auto-vérification systématique de la preuve avant retour.
  • Statut pending avec ETA UTC.
  • Transition persistée vers CORRUPTED en cas d’incohérence cryptographique (computedRoot != merkleRoot) ou structurelle.
  • Consommation interne par le service ProofEnvelope.
  • Vérifiabilité off-chain avec SHA-256.

Exclu

  • Exposition d’un endpoint REST.
  • Construction d’arbre Merkle (PD-54).
  • Ancrage blockchain (PD-55).
  • Persistance Merkle structurelle (PD-237), hors lecture/écriture d’état de disponibilité.
  • Toute exigence non objectivable techniquement est hors périmètre.

3. Définitions

  • eventId : identifiant d’événement probatoire.
  • eventHash : hash canonique de l’événement, utilisé comme feuille Merkle.
  • merklePath : liste ordonnée des siblings du niveau feuille vers la racine.
  • MerkleProofResult : contrat de sortie de getMerkleProof(eventId).
  • pending : preuve non disponible à l’instant T, réessai attendu.
  • available : preuve disponible, auto-vérifiée, et arbre finalisé.
  • corrupted : état interne de cohérence invalide détecté (preuve stockée inutilisable).
  • première détection de corruption : premier appel qui provoque effectivement une transition persistée vers CORRUPTED.
  • même snapshot : même état transactionnel des données (lectures dans la même transaction, ou absence d’écritures concurrentes entre lectures).

4. Invariants (non négociables)

ID Règle Justification
INV-56-01-root-source-of-truth merkleRoot retourné DOIT être exactement la valeur persistée (aucun recalcul/substitution). Intégrité probatoire.
INV-56-02-determinisme Deux appels avec le même eventId et le même snapshot transactionnel DOIVENT produire le même MerkleProofResult. Reproductibilité audit.
INV-56-03-minimal-disclosure Le résultat n’expose que eventHash, merklePath, merkleRoot et métadonnées associées; aucune donnée métier brute, aucun payload d’événement. Confidentialité.
INV-56-04-algo-explicit hashAlgorithm='SHA-256' et hashAlgorithmVersion='1.0' DOIVENT être présents quand status='available'. Vérification indépendante.
INV-56-05-auto-verification Avant retour available, le service DOIT vérifier computeRoot(eventHash, merklePath) == merkleRoot. Détection corruption.
INV-56-06-transitions La machine d’état interne PENDING/AVAILABLE/CORRUPTED DOIT respecter les transitions contractuelles (§5.4). Robustesse comportementale.
INV-56-07-format-single-source Tous formats et règles de validation de données sont définis uniquement en §5.1 et référencés ailleurs. Évite ambiguïtés de format.
INV-56-08-no-secret-cleartext Aucun secret cryptographique en clair ne DOIT être persisté par ce flux; ce flux manipule uniquement des hashes et métadonnées publiques. Sécurité crypto.
INV-56-09-security-alert-on-first-corruption-detection La première détection de corruption menant à une transition vers CORRUPTED (ERR-56-03 structurel ou ERR-56-04) DOIT émettre un événement d’audit SECURITY_ALERT avec severity=CRITICAL; les appels ultérieurs sur état déjà CORRUPTED ne DOIVENT PAS réémettre d’alerte. Détection fiable sans flood.

5. Flux nominaux

5.1 Modèle de données contractuel (source unique de vérité)

Contrat de sortie exposé :

type MerkleProofResult =
  | {
      status: 'available';
      eventHash: string;
      merkleRoot: string;
      merklePath: string[];
      treeId: string;
      treeSize: number;
      leafIndex: number;
      hashAlgorithm: 'SHA-256';
      hashAlgorithmVersion: '1.0';
    }
  | {
      status: 'pending';
      estimatedAvailableAt: string; // RFC3339 UTC
    };

Règle explicite : CORRUPTED n’est pas une valeur de status; en sortie API/service, un état interne CORRUPTED est rendu via ERR-56-03 (ou ERR-56-04 lors de la détection initiale de mismatch).

Donnée Format / encodage Taille Jeu de caractères Case Regex / règle Si invalide
eventId UUID v4 texte 36 caractères ASCII [0-9a-fA-F-] insensitive en entrée ^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$ ERR-56-01
status (sortie) Enum texte 1 valeur ASCII lowercase sensitive ^(available|pending)$ ERR-56-03
eventHash hex SHA-256 64 caractères [a-f0-9] sensitive ^[a-f0-9]{64}$ ERR-56-03
merkleRoot hex SHA-256 64 caractères [a-f0-9] sensitive ^[a-f0-9]{64}$ ERR-56-03
merklePath[i] hex SHA-256 64 caractères/élément [a-f0-9] sensitive ^[a-f0-9]{64}$ ERR-56-03
merklePath tableau ordonné leaf->root 0..20 éléments JSON UTF-8 n/a longueur <= ceil(log2(treeSize)) ERR-56-03
treeId UUID v4 texte 36 caractères ASCII [0-9a-fA-F-] insensitive même regex UUID v4 ERR-56-03
treeSize entier 1..10000 chiffres ASCII n/a entier strict ERR-56-03
leafIndex entier 0..9999 chiffres ASCII n/a 0 <= leafIndex < treeSize ERR-56-03
hashAlgorithm littéral texte 7 caractères ASCII sensitive ^SHA-256$ ERR-56-03
hashAlgorithmVersion littéral texte 3 caractères ASCII sensitive ^1\.0$ ERR-56-03
estimatedAvailableAt RFC3339 UTC 20..35 caractères UTF-8 sensitive timestamp ISO8601 UTC valide (Z) ERR-56-05 si non calculable ou non conforme
proofAvailabilityState (interne) Enum persisté n/a n/a sensitive ^(PENDING|AVAILABLE|CORRUPTED)$ ERR-56-03

Terminologie : inclusion_proof est le nom de colonne en persistance (PD-237). Le nom contractuel en sortie et en logique PD-56 est merklePath.

Note PD-294 (migration v2) : Le format ci-dessus (v1) est remplace par le format v2 RFC 9162-inspired defini dans PD-294. Les champs v1 (merklePath, merkleRoot, leafIndex, hashAlgorithm: 'SHA-256') sont mappes vers v2 (inclusion_path, merkle_root, leaf_index, hash_algorithm: 'sha3-256', proof_version: 2). PD-56 doit consommer MerkleProofV2Service.toV2() pour emettre le format v2. Le format v1 reste lisible en entree (dual-read/single-write). Voir src/modules/merkle/v2/.

Règles explicites supplémentaires : - treeSize=1 implique merklePath=[] (longueur 0) : cas VALIDE. - merklePath=[] avec treeSize>1 : cas INVALIDE (ERR-56-03).

5.2 Bornes numériques contractualisées

Paramètre Défaut Min Max Unité Contexte de référence Percentile Hors bornes
treeSize valeur persistée leaf_count 1 10000 feuilles backend + PostgreSQL (vault_merkle) n/a ERR-56-03
leafIndex valeur persistée leaf_index 0 9999 index backend + PostgreSQL n/a ERR-56-03
merklePath.length ceil(log2(treeSize)) 0 20 éléments vérification offline SHA-256 n/a ERR-56-03
Taille sérialisée de preuve (available) budget 10 0 10 KB payload JSON MerkleProofResult P95 non-conforme CA-56-04
Latence de génération 10 0 10 ms service backend + DB locale réseau P95 non-conforme CA-56-05

5.3 SLA temporels

SLA Défaut Min Max Configurabilité Comportement à expiration
Délai cible de disponibilité d’une preuve en pending ETA = window_end du batch candidat 0 min 120 min hérité configuration batch PD-55 Si ETA dépassée et preuve absente: rester pending, recalculer ETA sur fenêtre suivante, aucune promotion implicite vers available
Cadence de fenêtre batch de référence pour ETA 10 min 8 min 12 min oui (config module d’ancrage) Suivi d’écart en observabilité interne; le contrat de sortie reste estimatedAvailableAt en UTC

5.4 Machine à états et transitions retour

Entité contractuelle interne : ProofAvailabilityState (PENDING, AVAILABLE, CORRUPTED).

État courant Transitions sortantes autorisées Transitions interdites Conditions contractuelles
PENDING PENDING->PENDING, PENDING->AVAILABLE, PENDING->CORRUPTED toute autre PENDING->AVAILABLE uniquement si preuve trouvée + auto-vérification OK + finalized_at IS NOT NULL
AVAILABLE AVAILABLE->AVAILABLE, AVAILABLE->CORRUPTED AVAILABLE->PENDING Retour arrière interdit (append-only probatoire)
CORRUPTED (terminal) aucune CORRUPTED->* Aucune transition sortante, résolution manuelle uniquement

Comportement d’appel sur état terminal : - Si l’état courant est CORRUPTED, getMerkleProof(eventId) DOIT retourner ERR-56-03 sans transition d’état et sans SECURITY_ALERT.

Checklist machine à états : - Chaque état liste ses transitions autorisées/interdites. - CORRUPTED est terminal strict. - AVAILABLE->PENDING est explicitement interdit. - Couverture par INV-56-06-transitions.

5.5 Flux F-01/F-02/F-03/F-04/F-05/F-06

  1. F-01 — Preuve disponible (available)
  2. Entrée eventId valide et résolue.
  3. Résolution eventId -> eventHash.
  4. Résolution eventHash -> leaf + tree.
  5. Contrôles formats/bornes (§5.1/§5.2).
  6. Auto-vérification (computedRoot == merkleRoot).
  7. Vérification finalité : finalized_at IS NOT NULL.
  8. Retour status='available' avec champs obligatoires.

  9. F-02 — Preuve en attente (pending)

  10. eventId valide et connu.
  11. Événement présent mais arbre non finalisé ou preuve non encore exploitable.
  12. En cas de pending normal (finalized_at IS NULL et window_end IS NOT NULL), retour status='pending' avec estimatedAvailableAt UTC.
  13. Ce cas correspond au code contractuel ERR-56-02 (décision pending non fautive).

  14. F-03 — Vérification off-chain

  15. Tiers recalcule computedRoot = fold(eventHash, merklePath) en SHA-256.
  16. La reconstruction utilise le tri lexicographique des paires : hashPair(sorted(a,b)), conformément à l’implémentation MerkleProofVerifier.
  17. Le résultat DOIT être strictement égal à merkleRoot.

  18. F-04 — Détection mismatch cryptographique

  19. Condition : computedRoot != merkleRoot (contrôle INV-56-05).
  20. Le service DOIT :
  21. Persister la transition d’état vers CORRUPTED (écriture DB).
  22. Retourner ERR-56-04.
  23. Émettre SECURITY_ALERT severity=CRITICAL (première détection).
  24. Les appels suivants pour le même eventId retournent ERR-56-03 (état terminal), sans nouvelle transition et sans nouvelle alerte.

  25. F-05 — Pending sans ETA calculable

  26. Cas borné contractuellement : un batch candidat existe mais finalized_at IS NULL ET window_end IS NULL.
  27. Dans ce cas, l’ETA ne peut pas être calculée : le service DOIT retourner ERR-56-05 (pas de status='pending' sans ETA valide).
  28. Distinction explicite : finalized_at IS NULL ET window_end IS NOT NULL correspond au pending normal (ERR-56-02 + payload pending).

  29. F-06 — Corruption structurelle

  30. Si les données Merkle sont structurellement invalides (merklePath absent/null, élément invalide, bornes/format invalides, incohérence structurelle telle que merklePath=[] avec treeSize>1), le service DOIT :
  31. Persister la transition d’état vers CORRUPTED (idem F-04).
  32. Retourner ERR-56-03.
  33. Émettre SECURITY_ALERT severity=CRITICAL lors de la première détection.
  34. Cas explicitement valide : treeSize=1 avec merklePath=[] (longueur 0) ne constitue PAS une corruption.
  35. Les appels suivants sur état déjà CORRUPTED retournent ERR-56-03 sans transition et sans nouvelle alerte.

5bis. Diagrammes (applicables)

Diagramme d’état (stateDiagram-v2)

stateDiagram-v2
    [*] --> PENDING : event connu, preuve indisponible
    PENDING --> PENDING : relecture avant disponibilité
    PENDING --> AVAILABLE : preuve trouvée + auto-vérification OK + finalized_at IS NOT NULL
    PENDING --> CORRUPTED : preuve incohérente (mismatch) ou structure invalide

    AVAILABLE --> AVAILABLE : appel idempotent
    AVAILABLE --> CORRUPTED : incohérence détectée à la relecture

    note right of AVAILABLE
      AVAILABLE -> PENDING
      Transition interdite
    end note

    CORRUPTED : état terminal
    CORRUPTED : getMerkleProof => ERR-56-03
    CORRUPTED : aucune transition sortante
    CORRUPTED : pas de SECURITY_ALERT sur relectures

Diagramme de séquence (sequenceDiagram)

sequenceDiagram
    participant PES as ProofEnvelopeService
    participant MPS as MerkleProofService (PD-56)
    participant ES as Event Source
    participant MS as Merkle Storage
    participant ABS as Anchor Batch State
    participant MPV as MerkleProofVerifier
    participant AUD as Audit Bus

    PES->>MPS: getMerkleProof(eventId)
    MPS->>ES: lookup(eventId)

    alt eventId invalide ou inexistant
        ES-->>MPS: not found
        MPS-->>PES: ERR-56-01
    else event trouvé
        ES-->>MPS: eventHash
        MPS->>MS: read proofAvailabilityState + leaf/tree by eventHash

        alt proofAvailabilityState = CORRUPTED
            MPS-->>PES: ERR-56-03
        else leaf introuvable
            MPS->>ABS: read next batch metadata
            alt finalized_at IS NULL and window_end IS NULL
                MPS-->>PES: ERR-56-05
            else window_end calculable
                ABS-->>MPS: estimatedAvailableAt (UTC)
                MPS-->>PES: {status:"pending", estimatedAvailableAt}
            end
        else leaf trouvé
            MS-->>MPS: {treeId, merkleRoot, merklePath, leafIndex, treeSize, finalized_at}

            alt structure Merkle invalide
                MPS->>MS: persist state transition -> CORRUPTED
                MPS->>AUD: SECURITY_ALERT(severity=CRITICAL, code=ERR-56-03)
                MPS-->>PES: ERR-56-03
            else structure valide
                MPS->>MPV: computeRoot = fold(hashPair(sorted(a,b))) over merklePath
                MPV-->>MPS: computedRoot

                alt computedRoot != merkleRoot
                    MPS->>MS: persist state transition -> CORRUPTED
                    MPS->>AUD: SECURITY_ALERT(severity=CRITICAL, code=ERR-56-04)
                    MPS-->>PES: ERR-56-04
                else computedRoot == merkleRoot
                    alt finalized_at IS NULL
                        MPS->>ABS: read next batch metadata
                        alt window_end IS NULL
                            MPS-->>PES: ERR-56-05
                        else window_end calculable
                            ABS-->>MPS: estimatedAvailableAt (UTC)
                            MPS-->>PES: {status:"pending", estimatedAvailableAt}
                        end
                    else finalized_at IS NOT NULL
                        MPS-->>PES: {status:"available", eventHash, merkleRoot, merklePath, treeId, treeSize, leafIndex, hashAlgorithm, hashAlgorithmVersion}
                    end
                end
            end
        end
    end

5.6 Stratégie de migration DDL

PD-56 DOIT ajouter une colonne proof_availability_state (VARCHAR + CHECK constraint, pas ENUM PostgreSQL natif — REX PD-282) sur vault_merkle.merkle_leaves : - Valeurs autorisées : PENDING, AVAILABLE, CORRUPTED - Défaut : PENDING - Index sur cette colonne pour les requêtes par état - La migration DOIT utiliser commitTransaction() AVANT toute clause WHERE utilisant la nouvelle valeur (REX PD-282, PD-279)

Note : PD-237 ne fournit pas cette colonne — vérification factuelle confirmée sur le codebase.

5.7 Atomicité multi-composant

Le flux est majoritairement lecture, avec une écriture contractuelle conditionnelle lors de la première détection de corruption (ERR-56-03 structurel ou ERR-56-04 mismatch).

Règles : - La transition vers CORRUPTED DOIT être persistée avant de retourner l’erreur. - L’appel qui effectue cette transition DOIT aussi porter l’émission de SECURITY_ALERT (INV-56-09). - Les mécanismes d’implémentation de l’observabilité (transport, outbox, retry, bus) sont hors scope PD-56. - En état déjà CORRUPTED, aucun nouvel update d’état n’est effectué et aucune nouvelle alerte n’est émise.

5.8 Mécanismes de protection distribuée

Mécanisme Applicabilité Contrat
Lock distribué Non requis Une transition conditionnelle atomique (row-level lock ou update optimiste) suffit
Idempotence Applicable Clé fonctionnelle eventId; après corruption persistée, appels répétés retournent ERR-56-03 sans nouvel alert
Réconciliation Hors scope PD-56 Le mécanisme de transport/rejeu d’observabilité n’est pas contractualisé par PD-56
Rate-limiting Non applicable Pas d’endpoint REST dans cette story
Clearing conditionnel Non applicable Aucune auto-résolution de CORRUPTED

5.9 Contraintes inter-modules

Élément Contrat PD-56
Routes d’un autre module à protéger Aucune (pas de guard cross-route)
Mécanisme inter-module Appel interne ProofEnvelopeService -> getMerkleProof(eventId)
Données d’autres schémas/modules Résolution événement probatoire + états batch + persistance Merkle
Résolution FK cross-module eventId -> événement probatoire; eventHash -> merkle_leaves; treeId -> merkle_trees
Scope d’enregistrement Scope service interne backend
Exceptions d’accès Non applicable (pas de nouvelle route, pas de nouveau rôle)
Audit sécurité SECURITY_ALERT severity=CRITICAL uniquement à la première détection menant à CORRUPTED (ERR-56-03 structurel ou ERR-56-04)

6. Codes de retour contractuels

Code Nature Condition Réponse attendue
ERR-56-01 Erreur eventId invalide ou événement inexistant Rejet explicite, aucune preuve retournée
ERR-56-02 Décision métier (non-fautive) Événement dans batch non finalisé / preuve non encore finalisée avec ETA calculable (window_end IS NOT NULL) Retour status='pending' avec estimatedAvailableAt UTC
ERR-56-03 Erreur de corruption Donnée Merkle corrompue structurellement (format/bornes/incohérence) ou état interne déjà CORRUPTED Si première détection structurelle: transition persistée vers CORRUPTED + rejet + SECURITY_ALERT critique. Si état déjà CORRUPTED: rejet explicite, aucune transition, aucune alerte
ERR-56-04 Erreur de corruption cryptographique computedRoot != merkleRoot à l’auto-vérification Transition persistée vers CORRUPTED, puis rejet explicite + SECURITY_ALERT critique
ERR-56-05 Erreur de disponibilité Cas pending sans ETA calculable: batch candidat avec finalized_at IS NULL ET window_end IS NULL Rejet explicite (pas de pending sans ETA UTC valide)

7. Critères d’acceptation (testables)

ID Critère Observable
CA-56-01 getMerkleProof(eventId) retourne available pour un événement inclus dans un arbre finalisé Payload complet conforme §5.1
CA-56-02 fold(eventHash, merklePath) reconstruit exactement merkleRoot Vérification offline SHA-256
CA-56-03 Un script externe JS/Python vérifie la preuve sans API/BDD Exécution script tiers réussie
CA-56-04 Taille de preuve sérialisée < 10 KB Mesure payload JSON
CA-56-05 Génération P95 <= 10 ms Mesure perf sur environnement de référence
CA-56-06 En cas non finalisé avec ETA calculable, retour pending avec estimatedAvailableAt UTC Payload pending conforme
CA-56-07 L’auto-vérification est exécutée avant chaque retour available Trace/test d’appel vérificateur
CA-56-08 La machine d’état respecte §5.4 (incluant interdictions) Tests de transitions
CA-56-09 Toute donnée hors format §5.1 déclenche le code contractuel attendu; le cas treeSize=1 avec merklePath=[] est accepté Tests négatifs/limites format-borne
CA-56-10 PENDING->AVAILABLE uniquement si finalized_at IS NOT NULL Tests finality gate
CA-56-11 En mismatch (computedRoot != merkleRoot), transition persistée vers CORRUPTED puis ERR-56-04 Trace DB + réponse
CA-56-12 Après état CORRUPTED, appels suivants renvoient ERR-56-03 sans transition Trace d’état inchangé
CA-56-13 Si ETA non calculable (finalized_at IS NULL et window_end IS NULL), retour ERR-56-05 Réponse d’erreur dédiée
CA-56-14 Toute première détection de corruption menant à CORRUPTED émet SECURITY_ALERT severity=CRITICAL Journal d’audit/capture événement
CA-56-15 Les appels répétés sur état déjà CORRUPTED n’émettent aucun SECURITY_ALERT supplémentaire Compteur/trace anti-flood

8. Scénarios de test (Given / When / Then)

  • SCN-56-01 Nominal available : Given un eventId connu avec preuve persistée et arbre finalisé; When getMerkleProof(eventId) est appelé; Then status='available' et tous les champs requis sont présents.
  • SCN-56-02 Pending batch finality : Given un eventId connu avec preuve trouvée mais finalized_at IS NULL et window_end calculable; When appel du service; Then status='pending' avec estimatedAvailableAt UTC.
  • SCN-56-03 Event inconnu : Given un eventId inexistant ou invalide; When appel du service; Then ERR-56-01.
  • SCN-56-04 Corruption structurelle (première détection) : Given une entrée leaf structurellement invalide; When appel du service depuis un état non CORRUPTED; Then transition persistée vers CORRUPTED + ERR-56-03 + SECURITY_ALERT critique.
  • SCN-56-05 Root mismatch depuis PENDING : Given computedRoot != merkleRoot; When appel du service; Then transition persistée PENDING->CORRUPTED + ERR-56-04.
  • SCN-56-06 Root mismatch depuis AVAILABLE : Given état courant AVAILABLE et mismatch détecté; When appel du service; Then transition persistée AVAILABLE->CORRUPTED + ERR-56-04.
  • SCN-56-07 Relecture état CORRUPTED : Given état interne CORRUPTED; When appel du service; Then ERR-56-03 sans transition sortante et sans SECURITY_ALERT.
  • SCN-56-08 Déterminisme : Given un même snapshot transactionnel; When deux appels avec le même eventId; Then réponses strictement identiques.
  • SCN-56-09 Vérification off-chain : Given une réponse available; When un script SHA-256 externe recalcule la racine avec hashPair(sorted(a,b)); Then racine calculée identique à merkleRoot.
  • SCN-56-10 Transition interdite : Given un état AVAILABLE; When un retour vers PENDING est évalué; Then transition refusée contractuellement.
  • SCN-56-11 ETA non calculable : Given un batch candidat avec finalized_at IS NULL et window_end IS NULL; When un cas pending est évalué; Then ERR-56-05.
  • SCN-56-12 Audit sécurité première détection : Given une première corruption détectée (ERR-56-03 structurel ou ERR-56-04); When le service rejette la requête; Then émission d’un SECURITY_ALERT severity=CRITICAL.
  • SCN-56-13 Anti-flood alerte : Given un eventId déjà en état CORRUPTED; When des appels répétés sont exécutés; Then pas de nouvel SECURITY_ALERT.
  • SCN-56-14 Cas limite arbre unitaire : Given treeSize=1 et merklePath=[]; When appel du service avec données valides; Then pas de corruption structurelle (pas de ERR-56-03).

9. Hypothèses explicites

ID Hypothèse Impact si faux
H-56-01 La source canonique permet de résoudre eventId -> eventHash de manière déterministe. Impossible de relier l’événement à une feuille Merkle.
H-56-02 Les métadonnées de fenêtre (window_end) sont disponibles pour calculer une ETA UTC quand le cas est pending normal. Retour ERR-56-05 au lieu de pending.
H-56-03 Le référentiel hash Merkle est strictement SHA-256 version 1.0. Incompatibilité de vérification offline.
H-56-04 La borne de capacité arbre reste <= 10000 feuilles (contrat amont). Les bornes §5.2 doivent être re-contractualisées.
H-56-05 L’appelant PD-56 est un service interne backend (pas d’exposition HTTP). Nécessite contractualiser auth/rate-limit API hors périmètre actuel.
H-56-06 proofAvailabilityState est initialisé et maintenu par le flux amont PD-237 avant invocation PD-56. Comportement initial indéterminé, risque de faux ERR-56-03 ou transitions invalides.

10. Points à clarifier

10.1 Contraintes techniques (obligatoires)

  • Projet cible : ProbatioVault-backend.
  • Stack contractuelle : TypeScript + NestJS + TypeORM + PostgreSQL.
  • Runtime contractuel : Node.js >= 20.
  • Module concerné : backend interne, service applicatif sans endpoint REST.
  • Le document ne mentionne aucune stack hors projet (Swift/SwiftUI, Spring Boot, etc.).

10.2 Questions ouvertes (données manquantes)

  1. La source métier exacte de eventHash pour tous les types d’événements eventId doit être figée (table/champ canonique).
  2. La règle définitive pour un eventId présent dans un lot FAILED mais absent de lot finalisé doit être tranchée.
  3. La politique opérationnelle si pending dépasse durablement le SLA (>120 min) doit être confirmée.
  4. L’environnement benchmark officiel pour CA-56-05 (P95 10 ms) doit être figé.

Références

  • Epic : PD-187 — BLOCKCHAIN.
  • JIRA : PD-56.
  • Repos concernés : ProbatioVault-backend.
  • Documents associés : PD-56-besoin, PD-54-specification, PD-55-specification, PD-237-specification.