PD-280 — Retour d'experience (REX)
1. Resume executif
| Metrique | Valeur |
| Objectif initial | Alignement canonique de l'etat PENDING pour la verification de preuve |
| Resultat obtenu | Conforme — endpoint lecture seule, FSM 4 etats, SLA lazy, intercepteur coherence |
| Verdict final | GO (Gate 8 v1 : 9.312/10) |
| Tests contractuels | 25/30 TC implementes et passants (5 absents = CI/formel/documentaire hors scope backend) |
2. Metriques de convergence
2.1 Temps et iterations
| Etape | Duree estimee | Duree reelle | Iterations | Ecart |
| 0 - Besoin | 30 min | 30 min | 1 | 0% |
| 1 - Specification | 2h | 3 min | 1 | -98% |
| 2 - Tests | 1h | 2 min | 1 | -97% |
| 3 - Gate spec | 1h | 3h42 min | 3 | +270% |
| 4 - Plan | 1h | 9 min | 1 | -85% |
| 5 - Gate plan | 1h | 41 min | 3 | -32% |
| 6 - Implementation | 4h | 30 min | 1 | -88% |
| 7 - Acceptabilite | 2h | 14 min | 1 | -88% |
| 8 - Gate acceptabilite | 1h | 11 min | 1 | -82% |
| 9 - REX | 30 min | ~30 min | 1 | 0% |
| TOTAL | ~14h | ~6.1h | 14 | -56% |
Note : Gate 3 inclut une pause utilisateur de ~3h entre v2 (12:06) et v3 (15:16). Temps actif estime : ~42 min. Le temps reel total actif est ~3h hors pause.
2.2 Scores de convergence par gate
| Gate | Score v1 | Score v2 | Score final | Delta v1->final | Iterations |
| Gate 3 | 4.688/10 | 8.25/10 | 9.25/10 | +4.562 | 3 |
| Gate 5 | 5.5/10 | 7.562/10 | 9.0/10 | +3.5 | 3 |
| Gate 8 | 9.312/10 | — | 9.312/10 | 0 | 1 |
2.3 Ecarts par categorie
| Categorie d'ecart | Gate 3 | Gate 5 | Gate 8 | Total |
| ECT (completude/testabilite) | 4 | 1 | 1 | 6 |
| DIV (divergence spec/impl) | 5 | 0 | 0 | 5 |
| AMB (ambiguite) | 4 | 3 | 0 | 7 |
| SEC (securite) | 1 | 0 | 0 | 1 |
| PERF (performance) | 0 | 0 | 0 | 0 |
| TOTAL ecarts | 14 | 4 | 1 | 19 |
3. Points fluides
- Gate 8 GO en v1 (9.312/10) : score le plus eleve de l'historique legal-compliance backend. L'architecture read-only + intercepteur de coherence a produit un dossier propre.
- Implementation rapide (~30 min) : la decomposition en 8 composants orthogonaux (C1-C8) a permis une implementation sequentielle sans backtracking.
- Couverture tests elevee (95.03%) : les 49 tests unitaires couvrent exhaustivement les invariants. Le pattern mapper + intercepteur facilite le test isole.
- Faux positifs LLM correctement identifies : la confrontation step 7 a reclasse 4 faux positifs (guards transversaux, RLS, CHECK constraints, tests CI/formel).
- Convergence Gate 3 v2->v3 rapide : delta +1.0 avec corrections ciblees (verificationRequestId, mode lazy, idempotence concurrente).
4. Points difficiles
- Gate 3 v1 NON_CONFORME (4.688/10) : score le plus bas de l'historique mesure pour une Gate 3. Les 4 criteres etaient sous 6.0. Cause : la spec v1 ChatGPT manquait de formalisme sur les frontiere interne/API, l'identifiant de verification, et les regles de concurrence.
- Gate 5 v1 NON_CONFORME (5.5/10) : le plan v1 manquait de detail sur la faisabilite (lecture seule vs mutation DB pour SLA lazy) et la couverture des invariants. Le tension entre "reclassification lazy" (impliquant une mutation) et "endpoint lecture seule" (INV-280-09) a necessite 3 iterations pour etre resolue par le pattern "projection a la lecture".
- Ambiguite
reclassifie dans la spec : le verbe "reclassifie" dans le contexte SLA a ete interprete comme une mutation DB, alors que la spec + INV-280-09 imposent un endpoint lecture seule. Resolution : semantique de "projection a la lecture" documentee dans le plan §2.2. - Ecart MAJEUR E-01 residuel : l'intercepteur ne valide pas explicitement
verificationStatus in {PENDING, DONE}. Accepte en Gate 8 car defense-in-depth (le mapper ne produit que ces 2 valeurs), mais dette technique a corriger.
5. Hypotheses revelees tardivement
- HT-03 (DB accepte deja 'PENDING' comme string) : decouverte a l'etape 6 — le champ
chain_blockchain dans IntegrityCheckAttempt avait deja default: 'PENDING' en DB, confirmant que PostgreSQL accepte la string sans ALTER TYPE formel. A valider en environnement DEV. - Tension lecture seule vs persistance UUID : decouverte a l'etape 5 (v2) — le
verificationRequestId doit etre stable entre PENDING et DONE mais l'endpoint est lecture seule. Resolution : UUID genere a la creation du job (processus externe), lu par l'endpoint GET. - Projection vs mutation pour SLA lazy : decouverte a l'etape 5 (v1->v2) — la spec dit "reclassifie" mais l'endpoint est lecture seule. Le plan a clarifie : projection a la lecture (pas de mutation en base).
6. Invariants complexes
- INV-280-02 (status-coherence) : biconditionnelle PENDING ssi au moins un null. Necessite un mapper derive + un intercepteur de verification en sortie. — TC-NOM-01, TC-NOM-02, TC-ERR-03
- INV-280-06 (job-transitions) : DONE terminal avec idempotence sur rappel. La resolution de l'ambiguite "meme verification" par l'introduction du
verificationRequestId a coute 2 iterations de Gate 3. — TC-INV-06 - INV-280-09 (concurrent-idempotence) : endpoint lecture seule sans lock applicatif. Impose que la resolution des maillons soit realisee par des processus externes. — TC-NOM-10
7. Dette technique
- E-01 : validation explicite verificationStatus dans intercepteur — impact: moyen. ~5 lignes + 1 test. Non bloquant mais defense-in-depth incomplete.
- E-02 : requestId manquant dans logs intercepteur — impact: faible. Correlation forensique incomplete, proofId seul present.
- E-03 : fallback null silencieux dans mapLinkValue — impact: faible. Masquage potentiel de corruption, intercepteur couvre en defense-in-depth.
- E-04 : guardFinalization partiel — impact: faible. Ne detecte que
CheckResult.PENDING explicitement, pas les strings corrompues. - E-05 : migration DB sans ALTER TYPE — impact: faible. DB accepte deja 'PENDING' comme string (HT-03), mais delta contractuel a documenter.
- E-06 : DTO pendingReason type string au lieu d'enum — impact: faible. Validation runtime assure par intercepteur.
8. Risques residuels
| Risque | Type | Probabilite | Impact | Mitigation |
| Maillon PENDING indefini sans worker SLA | ops | moyen | moyen | Mode lazy couvre les appels API ; worker a planifier (STUB PD-???) |
| HT-03 non valide en DEV | tech | faible | moyen | Tester ALTER TYPE ADD VALUE sur environnement DEV avant deploiement |
Clients legacy ignorant null dans linkResults | metier | faible | moyen | Documentation API + politique versionnement a definir |
| E-01 (verificationStatus non valide) | tech | faible | faible | Ajouter check explicite dans l'intercepteur (dette mineure) |
8bis. Matrice de delegation inter-PD
| Story | Direction | Statut | Nature de la dependance | Probleme rencontre |
| PD-251 | <- depend de | DONE | Enum CheckResult partage, patterns verification integrite | RAS — enum etendu sans casse |
| PD-281 | -> bloque | TODO | Zlint anchor enum — detection PENDING_FINALITY | A surveiller si PD-281 modifie validateurs d'ancrage |
| PD-??? | -> bloque | TODO | Worker SLA background (reevaluation active) | Story non creee, mode lazy suffisant pour l'instant |
8ter. Bugs de tests
Aucun bug de test rencontre. Les 49 tests ont passe au premier cycle d'implementation.
8quater. Corrections post-Gate 8
Aucune correction post-Gate 8 necessaire. Gate 8 GO en v1.
9. Patterns recurrents detectes
9.1 Patterns confirmes (deja vus dans d'autres stories)
- Machine a etats avec transitions interdites : FSM 4 etats avec transitions monotones (PENDING -> {OK,KO,INDETERMINATE}). Pattern stabilise, 9e occurrence. — aussi dans PD-82, PD-250, PD-264, PD-251, PD-277, PD-276, PD-275, PD-279
- Guard de securite fail-closed : intercepteur de coherence rejette 500 au lieu d'envoyer une reponse incoherente. 9e occurrence. — aussi dans PD-238, PD-240, PD-250, PD-251, PD-277, PD-276, PD-275, PD-279
- Stubs inter-PD documentes avec story destination : 2 STUBs (PD-281, PD-??? Worker SLA). Pattern accepte en Gate 8. 9e occurrence.
- Format non contractualise en spec v1 : frontiere interne/API, verificationRequestId, regles de concurrence absents en v1 -> Gate 3 NON_CONFORME. 10e occurrence.
- Faux positifs LLM en reviews : guards transversaux, RLS, CHECK constraints signales comme CRITIQUE/MAJEUR par ChatGPT mais hors perimetre PD-280. 7e occurrence.
- Sonar Phase 1.5 indisponible : QG ERROR cross-project, 0 issues dans probatiovault-backend. 6e occurrence.
9.2 Nouveaux patterns identifies
- Projection a la lecture vs mutation pour logique lazy : la reevaluation SLA est une projection (pas de mutation DB) pour respecter la lecture seule de l'endpoint. Pattern a generaliser pour tout endpoint GET qui doit "evaluer" un etat derive. — a surveiller dans les prochaines stories.
- Intercepteur de coherence DTO en sortie :
VerificationContractInterceptor verifie les invariants de coherence APRES construction de la reponse, AVANT envoi au client. Pattern NestJS sous-utilise mais puissant pour defense-in-depth contractuelle. — a surveiller. - Double NON_CONFORME Gate 3+5 v1 sur story complexe : premiere occurrence de double NON_CONFORME en v1 pour les deux premieres gates. Indicateur de complexite conceptuelle elevee (frontiere interne/API + lecture seule + idempotence concurrente).
10. Ameliorations du workflow
10.1 Ameliorations des prompts/templates
| Fichier | Amelioration suggeree | Priorite |
templates/prompts/1 Specification.md | Exiger une section "Mapping interne/API" explicite quand l'API expose une transformation non triviale (ex: PENDING interne -> null API) | haute |
templates/prompts/1 Specification.md | Exiger un identifiant technique UUID serveur pour toute ressource stateful (evite ambiguite "meme verification") | moyenne |
templates/prompts/4 Plan d'implementation.md | Clarifier la semantique lecture seule vs mutation quand la spec utilise des verbes ambigus ("reclassifie", "met a jour") | haute |
templates/prompts/7a Review Code.md | Injecter la liste des intercepteurs/guards transversaux pour reduire les faux positifs sur les checks de securite hors perimetre | moyenne |
10.2 Ameliorations des agents
| Agent | Amelioration suggeree | Justification |
config/agents step 1 | Pour stories avec frontiere interne/API, injecter les conventions de mapping (null = en cours, enum = terminal) | Eviterait ambiguite AMB-01 recurrente |
config/agents step 5 | Ajouter check explicite : si spec dit "reclassifie/modifie" et plan dit "lecture seule", forcer la resolution avant v2 | Eviterait double NON_CONFORME Gate 3+5 |
10.3 Ameliorations du processus
- Resoudre la tension lecture/ecriture en spec (etape 1) : quand la spec utilise des verbes impliquant une mutation ("reclassifie", "met a jour") mais que le perimetre impose la lecture seule, la spec DOIT expliciter "projection a la lecture" des l'etape 1. Cela aurait evite 2 iterations de Gate 5.
- Pre-check Gate 3 sur la frontiere interne/API : ajouter une checklist "Si API expose une transformation non triviale, la spec documente-t-elle le mapping ?" avant de soumettre a Gate 3.
11. Enseignements cles
-
Projection vs mutation dans les endpoints lecture seule — quand la spec exige une "reevaluation" ou "reclassification" mais l'endpoint est GET (lecture seule), modeliser la logique comme une projection a la lecture. Documenter explicitement cette semantique dans le plan pour eviter les allers-retours Gate 5.
-
Intercepteur de coherence en sortie (defense-in-depth) — un intercepteur NestJS verifiant les invariants de coherence DTO APRES construction de la reponse et AVANT envoi au client est un pattern puissant pour les contrats d'API complexes. Cout : ~50 lignes de code + tests dedies. ROI : Gate 8 GO en v1.
-
Double NON_CONFORME v1 = indicateur de complexite conceptuelle — un double NON_CONFORME en Gate 3 v1 + Gate 5 v1 signale une story avec ambiguite conceptuelle elevee. Investir plus de temps a l'etape 0 pour clarifier les frontieres et semantiques avant la spec ChatGPT.
-
verificationRequestId comme desambiguisateur — l'introduction d'un identifiant technique UUID serveur elimine l'ambiguite "meme verification" et simplifie la modelisation de l'idempotence. Pattern a generaliser pour toute ressource stateful avec etats transitoires.
-
SLA lazy sans worker = dette planifiee — le mode lazy (projection a la lecture) est suffisant pour un MVP mais necessite un worker pour la couverture operationnelle complete. Documenter le STUB avec story destination des l'etape 4.
12. Metriques cumulatives (auto-calculees)
| Metrique | Cette story | Moyenne projet | Tendance |
| Temps total | 6.1h | 4.8h (7 dernieres) | ↑ |
| Iterations gates | 7 | 5.0 | ↑ |
| Ecarts totaux | 19 | 22.0 | ↓ |
| Score convergence moyen | 9.19/10 | 8.56/10 | ↑ |