PD-282 — Retour d'experience (REX)
1. Resume executif
| Metrique | Valeur |
| Objectif initial | ProofEnvelope auto-verifiable : scellement HSM global (PROOF-14) + materiel validation eIDAS/OCSP embarque (PROOF-05b) |
| Resultat obtenu | Conforme apres corrections majeures (3 BLOQUANTS resolus entre Gate 8 v1 et v2) |
| Verdict final | GO (9.125/10 — Gate 8 v2) |
| Tests contractuels | 259/259 passes dans le module legal-pre (247 unitaires + 12 integration PD-282) |
| Complexite | medium (5h actif, 8 iterations de gate — plus eleve que la moyenne pour une story medium) |
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 | 1h 20 min | 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 | ~5h | 14 | -64% |
Note : le wall clock total est ~13h (incluant ~7h d'attente validation PO etape 0 et ~1h20 entre Gate 8 GO et lancement REX). Le temps actif est ~5h. Le pipeline post-merge a necessite 3 commits correctifs supplementaires (migration DDL — voir section 8quater).
2.2 Scores de convergence par gate
| Gate | Score v1 | Score v2 | Score final (v3) | Delta total | Iterations |
| Gate 3 | 6.56/10 (NON_CONFORME) | 7.25/10 (RESERVE) | 8.25/10 (RESERVE STOP) | +1.69 | 3 |
| Gate 5 | 6.69/10 (NON_CONFORME) | 7.50/10 (RESERVE) | 7.875/10 (RESERVE STOP) | +1.19 | 3 |
| Gate 8 | 7.19/10 (NON_CONFORME) | 9.125/10 (GO) | — | +1.94 | 2 |
Convergence moyenne finale : (8.25 + 7.875 + 9.125) / 3 = 8.42/10
Detail des scores par critere :
| Gate | Critere | v1 | Final |
| Gate 3 | completeness | 6.75 | 8.0 |
| Gate 3 | testability | 4.75 | 7.5 |
| Gate 3 | clarity | 6.75 | 8.5 |
| Gate 3 | traceability | 8.0 | 9.0 |
| Gate 5 | feasibility | 6.0 | 8.0 |
| Gate 5 | coverage | 5.5 | 7.5 |
| Gate 5 | risk_mitigation | 6.75 | 8.5 |
| Gate 5 | coherence | 8.5 | 7.5 |
| Gate 8 | conformity | 4.0 | 9.0 |
| Gate 8 | test_coverage | 8.75 | 8.75 |
| Gate 8 | security | 7.0 | 8.75 |
| Gate 8 | maintainability | 9.0 | 10.0 |
2.3 Ecarts par categorie
| Categorie d'ecart | Gate 3 | Gate 5 | Gate 8 | Total |
| ECT (completude/testabilite) | 2 | 2 | 2 | 6 |
| DIV (divergence spec/impl) | 1 | 1 | 2 | 4 |
| AMB (ambiguite) | 1 | 1 | 0 | 2 |
| SEC (securite) | 0 | 0 | 3 | 3 |
| PERF (performance) | 0 | 0 | 0 | 0 |
| TOTAL ecarts | 4 | 4 | 7 | 15 |
Les 3 ecarts BLOQUANTS de Gate 8 v1 etaient tous de categorie SEC (E-01 double-hash) ou DIV (E-02 structure JSONB, S-01 trust anchor bypass). Leur resolution complete a permis de passer a GO en une seule iteration supplementaire.
3. Points fluides
- La decomposition en 4 modules (entity, seal, verification, verifier) a fourni une structure claire et parallelisable. Chaque agent avait des frontieres de responsabilite nettes.
- Le pattern INSERT-only impose par le trigger PD-272 a ete correctement anticipe dans le plan (DA-02), evitant un refactoring majeur lors de l'implementation.
- La correction Gate 8 v1 → v2 a ete particulierement efficace (+1.94 en 1 iteration) grace a des ecarts bien identifies et actionnables par les reviews croisees ChatGPT.
- Les 259 tests contractuels ont ete ecrits et passaient des la v1 de Gate 8 — la couverture contractuelle etait solide malgre les ecarts crypto.
- La reutilisation des services existants (HashService, HsmSignatureService, JsonCanonicalizeService) a accelere l'implementation sans duplication.
- Le mecanisme de detection de secrets (INV-282-06) a ete implemente proprement via pattern matching sur une liste exhaustive de tokens interdits.
4. Points difficiles
- Double-hash crypto (E-01) : le pipeline sign/verify etait incompatible —
createVerify('SHA3-384') re-hash le buffer deja hashe, tandis que le HSM utilise CKM_ECDSA (raw sign). La resolution via crypto.verify(null, hash, key, sig) est non triviale et non documentee dans la plupart des guides Node.js/HSM. Cout estime : ~30 min de debug. - Structure JSONB imbriquee (E-02) : le wrapper
SealedProofEnvelope etait stocke dans la colonne envelope_seal au lieu de EnvelopeSeal directement. La confusion des niveaux d'abstraction (objet de transport vs objet persistable) est un bug silencieux — les tests mockaient la DB et ne detectaient pas le desalignement. - Bypass trust anchor (S-01) :
trustedRoots optionnel dans le verifier permettait la verification avec un certificat auto-signe. L'hypothese H-01 etait documentee dans la spec mais l'implementation ne l'enforc,ait pas. - Gates interleaving avec implementation : les Gates 3v3 et 5v3 ont ete relancees apres le debut de l'implementation (step 6), creant un flux non lineaire inhabituel. La correction de la spec pendant l'impl cree de la confusion sur la version de reference.
- Triple NON_CONFORME en v1 : les 3 gates ont demarre en dessous du seuil GO (6.56, 6.69, 7.19), necessitant 8 iterations totales — pattern caracteristique d'une story a complexite conceptuelle elevee.
- Pipeline post-merge migration : apres merge sur main, la migration PD-279/PD-278 a echoue (PostgreSQL erreur 55P04 —
ALTER TYPE ... ADD VALUE et clause WHERE dans la meme transaction). Resolution en 3 commits avec le pattern commitTransaction/startTransaction pour separer les phases DDL. Non lie a PD-282 mais impactant le pipeline CI.
5. Hypotheses revelees tardivement
- H-01 (trust-store verificateur) : l'hypothese etait documentee dans la spec (section 9) mais l'implementation ne la respectait pas (
trustedRoots optionnel) — decouverte a l'etape 7 lors de la review securite ChatGPT. - Interoperabilite SHA3-384 sign(HSM)/verify(Node.js) : la compatibilite du pattern pre-hash + raw sign n'etait pas prouvee avant l'implementation. Identifiee comme risque dans le plan (§8 risque 2) mais materialisee en ecart BLOQUANT.
- INV-282-03 perimetre trop large : la formulation couvrait potentiellement
envelopeSeal alors que INV-282-02 l'exclut explicitement — ambiguite clarifiee en Gate 5 v3. - CKM_ECDSA vs CKM_ECDSA_SHA3_384 : le HSM CloudHSM ne supporte que le raw sign (CKM_ECDSA). L'hypothese sur le mode de signature HSM n'etait pas explicite dans la spec et a conditionne toute la resolution du double-hash.
6. Invariants complexes
- INV-282-01/02/03 (integrite cryptographique) — TC-NOM-01/02. Le trio canonicalisation JCS + exclusion envelopeSeal + SHA3-384 + ECDSA P-384 forme une chaine ou chaque maillon doit etre byte-identical entre sign et verify. Le moindre desalignement (algorithme de hash, encodage DER/IEEE-P1363, niveau de canonicalisation) invalide toute la preuve.
- INV-282-04 (verification offline Mode A) — TC-NOM-04. La suffisance du verificationMaterial pour Mode A depend de la completude des chaines de certificats ET de la presence obligatoire de trusted roots — deux dimensions testees independamment. Mode A est satisfait. Mode B reste une dette technique.
- INV-282-07 (artefacts crypto temporaires) — TC-INV-07. Satisfait par conception (pipeline full-memory, cle privee dans HSM) mais non testable par assertions I/O classiques — preuve par audit statique du code. Acceptable.
- INV-282-09/10 (SEALED terminal) — relies au trigger PD-272. L'etat SEALED est terminal par construction DB (pas d'UPDATE possible). La machine a etats en memoire est coherente avec la persistance.
7. Dette technique
| Elementde dette | Impact | Priorite resolution |
ocsp-client.service.ts : couverture 9.83% | moyen | Story dediee OCSP reelle |
offline-verification.service.ts : couverture 43.43% | moyen | Story Mode B OCSP live |
| Mode B : verification OCSP live non constitutive (S-02) | moyen | Story dediee a creer |
Parsing OCSP heuristique au lieu de @peculiar/asn1-ocsp (S-04) | faible | Lors de l'integration OCSP reelle |
Assertions generiques (toBeDefined, toBeTruthy) dans certains tests (T-04) | faible | Refactoring tests opportuniste |
| 12 tests CI pre-existants en echec (destruction-audit: schema permissions, pd275-concurrency: missing table) | moyen | Stories dediees per module |
Note sur les echecs CI pre-existants : les 12 echecs CI identifie en post-merge sont independants de PD-282 et appartiennent a deux suites de tests pre-existantes (destruction-audit — permissions schema, pd275-concurrency — table manquante). Ils n'affectent pas les 259 tests du module legal-pre.
8. Risques residuels
| Risque | Type | Probabilite | Impact | Mitigation |
| OCSP responders intermittents en production | ops | moyen | moyen | Policy OCSP_UNAVAILABLE + monitoring 10% seuil alerte |
| Mode B non constitutif (OCSP live manquant) | tech | eleve | moyen | Story dediee pour implementer verification OCSP live constitutive |
| SSRF via AIA certificate extensions | sec | faible | eleve | Allowlist URLs OCSP recommandee (S-03, non corrige) |
| Interop SHA3-384 sur CloudHSM reel non prouvee en production | tech | faible | eleve | Test d'interoperabilite CI requis sur environnement avec HSM reel (DA-03) |
| Echecs CI pre-existants masquant des regressions futures | ops | moyen | moyen | Correction prioritaire des 12 echecs pre-existants dans leurs stories respectives |
8bis. Matrice de delegation inter-PD
| Story | Direction | Statut | Nature de la dependance | Probleme rencontre |
| PD-272 | depend de | DONE | Trigger immutabilite (UPDATE/DELETE refuses) | RAS — le trigger couvre automatiquement la nouvelle colonne envelope_seal |
| PD-81 | depend de | DONE | Token TSA dans ProofEnvelope | RAS — tsaCertificateChain verifie le token existant |
| PD-280 | depend de | DONE | Modele d'etats PENDING/INDETERMINATE | RAS — pas de contradiction avec SEALED terminal |
| PD-37 | depend de | DONE | JsonCanonicalizeService (RFC 8785) | RAS — service reutilise tel quel |
| PD-279/PD-278 | adjacent | DONE | Migration DDL partagee | Erreur 55P04 PostgreSQL post-merge (ADD VALUE enum + WHERE clause meme transaction). Resolu en 3 commits. |
| Mode B OCSP live | bloque | TODO | Verification en ligne constitutive | Story dediee a creer pour implementer les requetes OCSP/CRL publics constitutives |
8ter. Bugs de tests et corrections crypto
| Pattern incorrect | Pattern correct | Cause | Cout resolution |
createVerify('SHA3-384').update(hash).verify(key, sig) | crypto.verify(null, hash, key, sig) | createVerify ajoute son propre hash au buffer deja hashe (double-hash) | ~30 min |
Stocker SealedProofEnvelope {envelopeSeal, verificationMaterial} dans colonne | Stocker EnvelopeSeal directement | Confusion wrapper de transport vs objet persistable | ~20 min |
8quater. Corrections post-Gate 8
Corrections Gate 8 v1 → v2 (3 BLOQUANTS)
| Correction | Fichier(s) | Nature | Gravite originale |
| Alignement crypto sign/verify via crypto.verify(null) (E-01) | envelope-seal.service.ts, offline-verification.service.ts | Fix pipeline crypto (elimination double-hash) | BLOQUANT |
| Structure envelope_seal directe dans colonne JSONB (E-02) | legal-composite-proof.service.ts | Fix stockage JSONB (EnvelopeSeal direct, pas wrapper) | BLOQUANT |
| trustedRoots obligatoire dans verify() (S-01) | offline-verification.service.ts | Fix bypass securite trust anchor | BLOQUANT |
Corrections pipeline post-merge (migration DDL)
| Probleme | Cause | Resolution | Commits |
| PostgreSQL erreur 55P04 (migration PD-279/PD-278) | ALTER TYPE ADD VALUE et clause WHERE dans la meme transaction | Pattern commitTransaction/startTransaction pour separer phases DDL enum | 3 commits correctifs |
Reserves restantes apres Gate 8 v2 (MAJEUR — non bloquantes)
| ID | Description | Reference |
| DIV-04 | Policy OCSP degradee incoh. (E-03) : GENERATION_TIME_SNAPSHOT avec ocspResponses=[] | INV-282-05, ERR-05 |
| DIV-07 | Mode B verification OCSP live non constitutive (S-02) | INV-282-04, §Mode B |
| DIV-09 | SSRF via AIA certificate extensions (S-03) | Defense-in-depth |
| DIV-08 | Duplication verificationMaterial (E-05) | Maintenabilite |
9. Patterns recurrents detectes
9.1 Patterns confirmes (deja vus dans d'autres stories)
- Double NON_CONFORME Gate 3+5 v1 = complexite conceptuelle elevee — aussi dans PD-280, PD-278. Confirme (3eme occurrence, pattern stable). Prevision fiable : 3+ iterations de gate et corrections structurelles requises.
- Machine a etats explicite avec transitions interdites — SEALED terminal (INV-282-09/10). 11eme occurrence dans le projet.
- Guard de securite fail-closed obligatoire — S-01 trust anchor bypass = absence de fail-closed. 11eme occurrence.
- Format non contractualise dans spec v1 — testability 4.75 en Gate 3 v1 (regex/taille manquants pour envelopeSeal et verificationMaterial). 12eme occurrence.
- Atomicite multi-composant : ACID sync + INSERT-only — pattern PD-272 trigger. 8eme occurrence.
- Stubs inter-PD acceptes si documentes avec story destination — OCSP client stub, Mode B partiel. 11eme occurrence.
- Faux positifs LLM en reviews — reviews securite signalant des INV dependant de PD-272 externe. 9eme occurrence.
- Migration DDL + enum dans meme transaction = erreur PostgreSQL 55P04 — aussi dans PD-279/PD-278. 2eme occurrence. Pattern : separer toujours ALTER TYPE ADD VALUE dans une transaction distincte.
9.2 Nouveaux patterns identifies
- Double-hash crypto pipeline (pre-hash + HSM raw sign) —
createVerify('ALG') de Node.js ajoute toujours un hash sur les donnees passees. Incompatible avec un HSM qui fait du CKM_ECDSA (raw sign sur hash pre-calcule). Solution : crypto.verify(null, hash, key, sig) qui bypass le hachage interne. A documenter comme invariant pour toutes les futures stories HSM. - Structure JSONB imbriquee (wrapper vs objet direct) — confondre le wrapper de transport (
SealedProofEnvelope) avec l'objet a persister (EnvelopeSeal) cause un bug de lecture silencieux depuis la DB. Les tests avec mocks ne le detectent pas. - SSRF via AIA certificate extensions — les URLs de responders OCSP extraites des extensions AIA des certificats ne sont pas fiables. Tout appel HTTP vers ces URLs sans allowlist/denylist est un vecteur SSRF.
- Gate 8 delta massif apres corrections BLOQUANTES multiples — corriger 3 ecarts BLOQUANTS en une iteration fait passer le score de 7.19 a 9.125 (+1.94). Les ecarts BLOQUANTS bien identifies et actionnables permettent une convergence rapide.
- Spec corrigee pendant l'implementation = flux non lineaire — les Gates 3v3 et 5v3 ont ete relancees apres debut de step 6. Anti-pattern a eviter : terminer toutes les gates avant de demarrer l'implementation.
10. Ameliorations du workflow
10.1 Ameliorations des prompts/templates
| Fichier | Amelioration suggeree | Priorite |
templates/prompts/1 Specification.md | Exiger la documentation explicite du pipeline sign ET verify (avec algorithme de hash, encodage, API Node.js) pour toute story avec signature HSM | haute |
templates/prompts/7c Review Security.md | Verifier que le parametre trust-store (ou equivalent) est obligatoire dans tout service de verification de certificats — parametre optionnel = bypass possible | haute |
templates/prompts/7a Review Code.md | Detecter l'usage de createVerify(ALG).update(hash) quand le HSM fait du raw sign — pattern double-hash systematique | haute |
templates/prompts/4 Plan implementation.md | Pour les stories avec OCSP/CRL : contractualiser Mode A (offline) vs Mode B (online constitutif) avec les APIs concretes des la spec | moyenne |
templates/prompts/7c Review Security.md | Verifier les URLs cibles des requetes OCSP : origin depuis les extensions AIA du certificat => SSRF potentiel, allowlist requise | moyenne |
templates/prompts/6b Agent task.md | Pour les colonnes JSONB complexes : exiger un test de round-trip DB (INSERT + SELECT + assert structure) dans le contrat de l'agent-entity | moyenne |
10.2 Ameliorations des agents
| Agent | Amelioration suggeree | Justification |
config/agents step 6 (seal + verifier) | Ajouter un check d'interoperabilite sign/verify HSM comme prerequis avant merge : signer avec l'HSM mock, verifier avec crypto.verify(null), asserter valid=true | E-01 non detecte par les tests car mocks HSM ne valident pas la semantique de signature |
config/agents step 1 | Pour stories crypto-eIDAS : exiger la section "pipeline cryptographique" avec algorithme exact, encodage (DER/IEEE-P1363), API Node.js cible | Pipeline incomplet = BLOQUANT systematique en Gate 8 |
config/agents step 6 (entity) | Exiger un test round-trip DB pour chaque nouvelle colonne JSONB contenant des objets structures | Detecte le bug wrapper vs objet direct avant Gate 8 |
10.3 Ameliorations du processus
- Ne pas demarrer step 6 avant que Gates 3 et 5 soient terminales : le flux non lineaire (gates relancees pendant l'impl) cree de la confusion sur la version de reference de la spec et du rework. Le gain de temps illusoire est annule par les corrections.
- Pour stories crypto : test d'interoperabilite sign/verify en CI avec HSM reel : les mocks HSM ne detectent pas les incompatibilites crypto reelles (double-hash, dsaEncoding, CKM algorithm).
- Test round-trip DB pour toute colonne JSONB complexe : ajouter un test d'integration (INSERT + SELECT + asserter la structure attendue) avant soumission a Gate 8.
- Pattern commitTransaction/startTransaction pour migrations DDL avec enum : documenter ce pattern dans les templates de migration pour eviter les erreurs PostgreSQL 55P04. ALTER TYPE ADD VALUE doit toujours etre dans une transaction separee.
- Tracer les echecs CI pre-existants : maintenir un registre des tests CI en echec pre-existants par module pour ne pas les confondre avec des regressions introductes par la story en cours.
11. Enseignements cles
-
crypto.verify(null) pour raw ECDSA matching CKM_ECDSA — createVerify('SHA3-384').update(hash) applique SHA3-384 sur le buffer, produisant un double-hash quand le buffer est deja un hash SHA3-384. Pour un HSM qui signe en raw (CKM_ECDSA sans hachage interne), utiliser crypto.verify(null, hash, { key, dsaEncoding: 'ieee-p1363' }, signature) qui transmet le hash directement sans re-hashage. Ce pattern est distinct de createVerify et non-intuitif sans connaissance du fonctionnement interne de Node.js crypto.
-
Stocker l'objet direct, pas le wrapper — une colonne JSONB doit contenir exactement l'objet attendu a la lecture (EnvelopeSeal), pas un wrapper de transport (SealedProofEnvelope {envelopeSeal, verificationMaterial}). La confusion entre objet de transport et objet persistable est un bug silencieux : les tests avec mocks DB ne le detectent pas car ils retournent le mock directement, pas une deserialisation JSON.
-
trustedRoots optionnel = bypass silencieux — tout service de verification de certificats doit exiger un trust-store non vide et echouer explicitement si absent (raison: no_trusted_roots). Un parametre optionnel permet la verification avec des certificats auto-signes, annulant toute garantie d'ancrage de confiance.
-
Triple NON_CONFORME v1 = indicateur fiable de complexite elevee — quand les 3 gates demarrent en NON_CONFORME (aucun GO ni RESERVE en v1), prevoir 8+ iterations totales et des corrections structurelles (pas incrementales). Ce pattern est maintenant confirme sur 3 stories (PD-280, PD-278, PD-282).
-
Terminer les gates avant l'implementation — relancer des gates pendant l'implementation cree un flux non lineaire, du rework et de la confusion sur la version de reference de la spec. La tentation d'avancer en parallele nuit a la qualite globale du workflow.
-
ALTER TYPE ADD VALUE PostgreSQL dans sa propre transaction — combiner ALTER TYPE ... ADD VALUE (enum extension) avec des clauses WHERE utilisant la nouvelle valeur dans la meme transaction provoque l'erreur PostgreSQL 55P04. Le pattern correct : commitTransaction() apres le ALTER TYPE, puis startTransaction() pour les operations suivantes. Documenter dans les templates de migration TypeORM.
12. Metriques cumulatives (auto-calculees)
Calculs bases sur les 9 stories mesurees avec donnees completes (PD-251, PD-277, PD-276, PD-275, PD-281, PD-279, PD-280, PD-278, PD-282) :
| Metrique | Cette story (PD-282) | Moyenne du panel (9 stories) | Tendance |
| Temps total (actif) | 5.0h | 6.3h | inferieur a la moyenne |
| Iterations gates (G3+G5+G8) | 8 | 5.4 | superieur a la moyenne |
| Ecarts totaux detectes | 15 | 19.0 | inferieur a la moyenne |
| Score convergence Gate 3 | 8.25/10 | 8.44/10 | dans la norme |
| Score convergence Gate 5 | 7.88/10 | 8.37/10 | en dessous de la norme |
| Score convergence Gate 8 | 9.13/10 | 8.78/10 | superieur a la norme |
| Score convergence moyen | 8.42/10 | 8.53/10 | dans la norme |