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
MerkleProofResultau format custom ProbatioVault. - Auto-vérification systématique de la preuve avant retour.
- Statut
pendingavec ETA UTC. - Transition persistée vers
CORRUPTEDen 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 degetMerkleProof(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 versCORRUPTED.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 consommerMerkleProofV2Service.toV2()pour emettre le format v2. Le format v1 reste lisible en entree (dual-read/single-write). Voirsrc/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¶
- F-01 — Preuve disponible (
available) - Entrée
eventIdvalide et résolue. - Résolution
eventId -> eventHash. - Résolution
eventHash -> leaf + tree. - Contrôles formats/bornes (§5.1/§5.2).
- Auto-vérification (
computedRoot == merkleRoot). - Vérification finalité :
finalized_at IS NOT NULL. -
Retour
status='available'avec champs obligatoires. -
F-02 — Preuve en attente (
pending) eventIdvalide et connu.- Événement présent mais arbre non finalisé ou preuve non encore exploitable.
- En cas de pending normal (
finalized_at IS NULLetwindow_end IS NOT NULL), retourstatus='pending'avecestimatedAvailableAtUTC. -
Ce cas correspond au code contractuel
ERR-56-02(décisionpendingnon fautive). -
F-03 — Vérification off-chain
- Tiers recalcule
computedRoot = fold(eventHash, merklePath)en SHA-256. - La reconstruction utilise le tri lexicographique des paires :
hashPair(sorted(a,b)), conformément à l’implémentationMerkleProofVerifier. -
Le résultat DOIT être strictement égal à
merkleRoot. -
F-04 — Détection mismatch cryptographique
- Condition :
computedRoot != merkleRoot(contrôleINV-56-05). - Le service DOIT :
- Persister la transition d’état vers
CORRUPTED(écriture DB). - Retourner
ERR-56-04. - Émettre
SECURITY_ALERTseverity=CRITICAL(première détection). -
Les appels suivants pour le même
eventIdretournentERR-56-03(état terminal), sans nouvelle transition et sans nouvelle alerte. -
F-05 — Pending sans ETA calculable
- Cas borné contractuellement : un batch candidat existe mais
finalized_at IS NULLETwindow_end IS NULL. - Dans ce cas, l’ETA ne peut pas être calculée : le service DOIT retourner
ERR-56-05(pas destatus='pending'sans ETA valide). -
Distinction explicite :
finalized_at IS NULLETwindow_end IS NOT NULLcorrespond au pending normal (ERR-56-02+ payload pending). -
F-06 — Corruption structurelle
- Si les données Merkle sont structurellement invalides (
merklePathabsent/null, élément invalide, bornes/format invalides, incohérence structurelle telle quemerklePath=[]avectreeSize>1), le service DOIT : - Persister la transition d’état vers
CORRUPTED(idem F-04). - Retourner
ERR-56-03. - Émettre
SECURITY_ALERTseverity=CRITICALlors de la première détection. - Cas explicitement valide :
treeSize=1avecmerklePath=[](longueur 0) ne constitue PAS une corruption. - Les appels suivants sur état déjà
CORRUPTEDretournentERR-56-03sans 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
eventIdconnu avec preuve persistée et arbre finalisé; WhengetMerkleProof(eventId)est appelé; Thenstatus='available'et tous les champs requis sont présents. - SCN-56-02 Pending batch finality : Given un
eventIdconnu avec preuve trouvée maisfinalized_at IS NULLetwindow_endcalculable; When appel du service; Thenstatus='pending'avecestimatedAvailableAtUTC. - SCN-56-03 Event inconnu : Given un
eventIdinexistant ou invalide; When appel du service; ThenERR-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 versCORRUPTED+ERR-56-03+SECURITY_ALERTcritique. - SCN-56-05 Root mismatch depuis
PENDING: GivencomputedRoot != merkleRoot; When appel du service; Then transition persistéePENDING->CORRUPTED+ERR-56-04. - SCN-56-06 Root mismatch depuis
AVAILABLE: Given état courantAVAILABLEet mismatch détecté; When appel du service; Then transition persistéeAVAILABLE->CORRUPTED+ERR-56-04. - SCN-56-07 Relecture état
CORRUPTED: Given état interneCORRUPTED; When appel du service; ThenERR-56-03sans transition sortante et sansSECURITY_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 avechashPair(sorted(a,b)); Then racine calculée identique àmerkleRoot. - SCN-56-10 Transition interdite : Given un état
AVAILABLE; When un retour versPENDINGest évalué; Then transition refusée contractuellement. - SCN-56-11 ETA non calculable : Given un batch candidat avec
finalized_at IS NULLetwindow_end IS NULL; When un caspendingest évalué; ThenERR-56-05. - SCN-56-12 Audit sécurité première détection : Given une première corruption détectée (
ERR-56-03structurel ouERR-56-04); When le service rejette la requête; Then émission d’unSECURITY_ALERT severity=CRITICAL. - SCN-56-13 Anti-flood alerte : Given un
eventIddéjà en étatCORRUPTED; When des appels répétés sont exécutés; Then pas de nouvelSECURITY_ALERT. - SCN-56-14 Cas limite arbre unitaire : Given
treeSize=1etmerklePath=[]; When appel du service avec données valides; Then pas de corruption structurelle (pas deERR-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)¶
- La source métier exacte de
eventHashpour tous les types d’événementseventIddoit être figée (table/champ canonique). - La règle définitive pour un
eventIdprésent dans un lotFAILEDmais absent de lot finalisé doit être tranchée. - La politique opérationnelle si
pendingdépasse durablement le SLA (>120 min) doit être confirmée. - 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.