PD-282 — Retour d'experience (REX)
1. Resume executif
| Metrique | Valeur |
| Objectif initial | ProofEnvelope auto-verifiable : scellement HSM global + materiel eIDAS/OCSP embarque |
| Resultat obtenu | Conforme apres corrections v2 (3 ecarts BLOQUANTS crypto resolus) |
| Verdict final | GO (Gate 8 v2 — 9.125/10) |
| Tests contractuels | 259/259 passes (247 unitaires legal-pre + 12 integration PD-282) |
2. Metriques de convergence
2.1 Temps et iterations
| Etape | Duree estimee | Duree reelle | Iterations | Ecart |
| 0 - Besoin | 30 min | 15 min | 1 | -50% |
| 1 - Specification | 2h | 4 min | 1 | -97% |
| 2 - Tests | 1h | 3 min | 1 | -95% |
| 3 - Gate spec | 1h | 55 min | 3 | -8% |
| 4 - Plan | 1h | 25 min | 1 | -58% |
| 5 - Gate plan | 1h | 25 min | 3 | -58% |
| 6 - Implementation | 4h | 1h20 | 1 | -67% |
| 7 - Acceptabilite | 2h | 14 min | 1 | -88% |
| 8 - Gate acceptabilite | 1h | 31 min | 2 | -48% |
| 9 - REX | 30 min | 30 min | 1 | 0% |
| TOTAL | ~14h | 5.0h | 15 | -64% |
2.2 Scores de convergence par gate
| Gate | Score v1 | Score final | Delta | Iterations |
| Gate 3 | 6.56/10 | 8.25/10 | +1.69 | 3 |
| Gate 5 | 6.69/10 | 7.88/10 | +1.19 | 3 |
| Gate 8 | 7.19/10 | 9.13/10 | +1.94 | 2 |
Delta total cumulatif : +4.82 (4eme plus eleve de l'historique).
2.3 Ecarts par categorie
| Categorie d'ecart | Gate 3 | Gate 5 | Gate 8 | Total |
| ECT (completude/testabilite) | 3 | 1 | 2 | 6 |
| DIV (divergence spec/impl) | 1 | 1 | 2 | 4 |
| AMB (ambiguite) | 1 | 1 | 0 | 2 |
| SEC (securite) | - | - | 3 | 3 |
| PERF (performance) | - | - | 0 | 0 |
| TOTAL ecarts | 5 | 3 | 7 | 15 |
3. Points fluides
Ce qui a bien fonctionne :
- Reutilisation de services existants : HashService, HsmSignatureService, JsonCanonicalizeService, le trigger PD-272 — l'implementation a pu s'appuyer sur des modules stables et testes, reduisant le temps de dev de 4h estimees a 1h20
- Spec ambitieuse des l'etape 0 : le besoin couvraitd'emblee les deux axes (scellement + materiel eIDAS), evitant les iterations de cadrage
- Pipeline de scellement atomique : la decision DA-02 (pas de colonne seal_status, INSERT atomique en SEALED) a simplifie la machine d'etats et elimine une classe entiere de bugs de concurrence
- Migration DDL minimale : un seul
ALTER TABLE ADD COLUMN JSONB NULL couvre la retro-compatibilite sans backfill, le trigger PD-272 protege automatiquement la nouvelle colonne
4. Points difficiles
Obstacles rencontres (sans justification) :
- Triple NON_CONFORME en v1 : les 3 gates ont donne NON_CONFORME en premiere iteration — premier cas de l'historique. 8 iterations de gate au total
- Double-hash crypto invisible : l'incompatibilite pre-hash SHA3-384 +
createVerify('SHA3-384') ne se manifeste pas dans les tests unitaires mocks (les mocks retournent une signature valide sans verifier le mecanisme reel) - Structure JSONB imbriquee : la confusion wrapper de transport (
SealedProofEnvelope) vs objet persiste (EnvelopeSeal) passe les tests unitaires mais cause un bug de lecture silencieux en integration - Gate 8 v1 NON_CONFORME : conformity = 4.0/10 — la plus basse note en Gate 8 de l'historique. 3 ecarts BLOQUANTS identifies simultanement par la review croisee ChatGPT
5. Hypotheses revelees tardivement
Hypotheses non explicites decouvertes en cours de workflow :
- H-01 trust-store — l'hypothese "la racine de confiance est disponible cote verificateur" etait documentee dans la spec mais l'implementation a rendu
trustedRoots optionnel, annulant la garantie. Decouvert en etape 7 (review securite) - Interop sign/verify HSM — l'hypothese que
createVerify('SHA3-384') est compatible avec un pre-hash + raw sign n'etait pas verifiee. Decouverte en etape 7 (review code) - Mode B constitutif vs optionnel — la spec declare Mode B comme inclus, mais l'implementation n'a implemente que la verification de validite temporelle (pas OCSP live). La correction a ete documentee mais pas completement implementee dans PD-282 (backlog)
- INV-282-03 perimetre trop large — l'invariant "toute modification d'un octet" couvrait
envelopeSeal (exclu par INV-282-02), creant une contradiction. Decouvert en Gate 5 v2
6. Invariants complexes
Invariants difficiles a implementer ou sensibles aux regressions :
- INV-282-01 (envelopeSeal valide) — TC-NOM-01 : le double-hash (E-01) rendait la verification invalide meme sur une enveloppe intacte. Correction :
crypto.verify(null, data, key, signature) au lieu de createVerify - INV-282-04 (Mode A offline) — TC-NOM-04 : necessite de prouver l'absence d'appel reseau. Mock
HttpService + assertion expect(...).not.toHaveBeenCalled(). Le Mode B (online) reste partiellement implemente - INV-282-07 (artefacts crypto temporaires) — TC-INV-07 : satisfait par conception (full-memory pipeline). Preuve par audit statique du code, pas par assertions I/O executables
- INV-282-08/09/10 (immutabilite et etat terminal) — dependance au trigger PD-272 : si le trigger est modifie, les garantees PD-282 tombent. Regression transverse
7. Dette technique
Compromis acceptes et non bloquants :
- Mode B OCSP live non implemente — impact: moyen. Le service
verifyOnlineOcsp() verifie uniquement la validite temporelle du certificat, pas la non-revocation via OCSP/CRL. Story dediee a creer - Coverage OCSP client faible (9.83%) — impact: moyen. Le service OcspClientService utilise un parsing heuristique ASN.1 au lieu de
@peculiar/asn1-ocsp. A remplacer lors de l'integration OCSP reelle - Coverage offline-verification faible (43.43%) — impact: moyen. Les chemins Mode B et verification de chaine ne sont pas couverts. Lie directement a la dette Mode B
- TC-NOM-09 absent — impact: faible. Test nominal Mode B non ecrit car le service sous-jacent n'est pas implemente
- TC-NR-02 absent — impact: faible. Non-regression PD-280 (etats) non verifiee dans la suite PD-282
8. Risques residuels
| Risque | Type | Probabilite | Impact | Mitigation |
| Interop SHA3-384 sign/verify avec CloudHSM reel (pas mock) | tech | faible | haut | Test d'interop CI prevu. Le pattern SHA3-256 + raw sign est deja valide sur LegalAuditTrailService |
| Modification trigger PD-272 casse immutabilite PD-282 | tech | faible | haut | TC-NR-01 dans la suite PD-282, mais depend de la non-regression transverse |
| Mode B incomplet utilise en production | ops | moyen | moyen | Mode B retourne valid=false si verification en ligne echoue. Story dediee en backlog |
| SSRF via AIA OCSP sans allowlist | sec | faible | moyen | Risque mineur tant que les certificats sont de sources fiables. Allowlist a implementer |
| ocspResponses=[] avec GENERATION_TIME_SNAPSHOT | metier | moyen | moyen | Corrige dans les corrections v2 (force OCSP_UNAVAILABLE si empty) |
8bis. Matrice de delegation inter-PD
| Story | Direction | Statut | Nature de la dependance | Probleme rencontre |
| PD-272 | <- depend de | DONE | Trigger immutabilite couvre automatiquement envelope_seal | RAS |
| PD-81 | <- depend de | DONE | Token TSA dans ProofEnvelope, tsaCertificateChain le verifie | RAS |
| PD-280 | <- depend de | DONE | Modele d'etats PENDING/INDETERMINATE compatible SEALED terminal | RAS |
| PD-37 | <- depend de | DONE | JsonCanonicalizeService (JCS RFC 8785) reutilise directement | RAS |
| Mode B OCSP | -> bloque | BACKLOG | Verification OCSP live constitutive en Mode B | S-02 non implemente dans PD-282 |
8ter. Bugs de tests
| Pattern incorrect | Pattern correct | Cause | Cout |
createVerify('SHA3-384').update(hash).verify() | crypto.verify(null, hash, key, sig) | createVerify re-hash le buffer deja hashe | 30 min (E-01 debug + correction) |
expect(result).toBeDefined() | expect(result.envelopeSeal.algorithm).toBe('ECDSA-P384-SHA3-384') | Assertion generique ne prouve pas le contrat | 10 min (T-04) |
8quater. Corrections post-Gate 8
| Correction | Fichier | Nature | Pipeline |
crypto.verify(null) au lieu de createVerify | envelope-seal.service.ts, offline-verification.service.ts | Fix double-hash crypto | Gate 8 v2 |
Stockage EnvelopeSeal direct (pas wrapper) | legal-composite-proof.service.ts | Fix structure JSONB | Gate 8 v2 |
trustedRoots obligatoire | offline-verification.service.ts | Fix bypass trust anchor | Gate 8 v2 |
Force OCSP_UNAVAILABLE si ocspResponses=[] | verification-material-assembler.service.ts | Fix policy incoherente | Gate 8 v2 |
9. Patterns recurrents detectes
9.1 Patterns confirmes (deja vus dans d'autres stories)
- Double NON_CONFORME Gate 3+5 v1 = complexite conceptuelle elevee — PD-280, PD-278, PD-282. PD-282 etend le pattern au triple NON_CONFORME (Gate 8 aussi en v1). Indicateur fiable : prevoir 8+ iterations totales
- Guard de securite fail-closed obligatoire —
trustedRoots optionnel = bypass total. Confirme depuis PD-238 (11 occurrences) - Machine a etats explicite avec transitions interdites — SEALED terminal sans transition sortante. Confirme depuis PD-82 (11 occurrences)
- Atomicite multi-composant : ACID sync + INSERT-only — INSERT atomique en SEALED, pas de sequence INSERT+UPDATE. Confirme depuis PD-55 (8 occurrences)
- Format non contractualise dans spec v1 — testability 4.75 en Gate 3 v1 car formats regex incomplets. Confirme depuis PD-32 (12 occurrences)
- Faux positifs LLM en reviews — certaines reserves portent sur des gardes applicatives presentes mais non visibles par le reviewer. Confirme depuis PD-251 (9 occurrences)
- Stubs inter-PD acceptes si documentes — Mode B OCSP partiellement implemente, documente comme backlog avec story destination. Confirme depuis PD-63 (11 occurrences)
9.2 Nouveaux patterns identifies
- Double-hash crypto pipeline — pre-hash SHA3-384 +
createVerify('SHA3-384') qui re-hash. Specifique aux pipelines HSM raw sign. A surveiller dans toute future story avec signature HSM - Structure JSONB imbriquee — confusion wrapper de transport vs objet persiste dans colonne. Erreur silencieuse si les tests ne reconstruisent pas l'objet depuis la DB
- SSRF via AIA certificate extensions — les URLs d'OCSP responders extraites des certificats X.509 peuvent pointer vers des services internes. A surveiller pour tout service OCSP/CRL
10. Ameliorations du workflow
10.1 Ameliorations des prompts/templates
| Fichier | Amelioration suggeree | Priorite |
templates/prompts/1 Specification.md | Exiger un test d'interoperabilite sign/verify explicite pour toute story avec signature HSM | haute |
templates/prompts/7c Review Security.md | Verifier que trustedRoots (ou equivalent) est obligatoire dans tout service de verification de certificats | haute |
templates/prompts/7a Review Code.md | Verifier l'absence de createVerify() quand le HSM fait du raw sign — detecter le double-hash | haute |
templates/prompts/7c Review Security.md | Verifier les URLs de requetes OCSP contre une allowlist (prevention SSRF via AIA) | moyenne |
10.2 Ameliorations des agents
| Agent | Amelioration suggeree | Justification |
| agent-seal (step 6b) | Injecter le pattern crypto.verify(null) vs createVerify() dans le system prompt pour stories HSM | Evite le double-hash systematiquement |
| agent-verifier (step 6b) | Exiger trustedRoots non-optionnel dans les interfaces de verification | Securite par defaut |
10.3 Ameliorations du processus
- Pre-flight crypto interop : pour les stories avec signature HSM, ajouter un test d'interoperabilite sign/verify comme prerequis de l'etape 7 (avant les reviews LLM) — aurait detecte E-01 plus tot
- Checklist structure JSONB : quand une colonne JSONB stocke un objet compose, verifier que le type persiste correspond au type lu (pas un wrapper de transport)
- Gate 8 v1 comme signal : un NON_CONFORME Gate 8 v1 avec conformity < 5.0 doit declencher une alerte — c'est un indicateur de bug fondamental (pas de polish)
11. Enseignements cles
- Le double-hash est un anti-pattern invisible —
createVerify() ajoute systematiquement son propre hash. Pour du raw sign HSM, utiliser crypto.verify(null, ...). Les tests mocks ne detectent pas ce probleme car le mock retourne une signature "valide" sans verifier la chaine crypto reelle - Les parametres de securite optionnels sont des failles —
trustedRoots optionnel transforme un service de verification en caoutchouc-tamponnage. Tout parametre de confiance doit etre obligatoire ou echouer explicitement si absent - Le triple NON_CONFORME en v1 est un signal de complexite maximale — confirme le pattern PD-280/PD-278. La resolution passe par des corrections structurelles (pas incrementales). Prevoir 8+ iterations totales
- La confusion wrapper/objet persiste est silencieuse — stocker un wrapper de transport dans une colonne JSONB passe les tests unitaires mais casse la lecture en integration. Verifier le type exact persiste avec un test round-trip DB
- L'implementation rapide ne garantit pas la qualite — 1h20 d'implementation, mais 3 ecarts BLOQUANTS decouverts en etape 7. Les reviews croisees LLM restent essentielles pour les stories crypto
12. Metriques cumulatives (auto-calculees)
| Metrique | Cette story | Moyenne projet (9 stories) | Tendance |
| Temps total | 5.0h | 5.82h | ↓ |
| Iterations gates | 8 | 5.67 | ↑ |
| Ecarts totaux | 15 | 21.2 | ↓ |
| Score convergence moyen | 8.42/10 | 8.64/10 | ↓ |
PD-282 est plus rapide que la moyenne (5.0h vs 5.82h) grace a la reutilisation de services existants, mais consomme plus d'iterations de gate (8 vs 5.67) en raison de la complexite crypto. Le score convergence moyen est legerement inferieur (8.42 vs 8.64) a cause de Gate 5 plafonee a 7.875 (convergence STOP). Les ecarts sont en baisse (15 vs 21.2) — benefice de la capitalisation REX sur le domaine legal-compliance.