Aller au contenu

Rétrospective — PD-84

Résumé story

  • Story : PD-84 — Encadrement contractuel offre gratuite B2C Mineurs
  • Domaine : b2c-mineurs (backend)
  • Date : 2026-02-24
  • Durée : 5.5h (vs 14h estimé = -61%)
  • Gates : G3 RESERVE (v3, 8.062/10) | G5 GO (v2, 9.562/10) | G8 GO (v1, 9.625/10)

Learnings de cette story

Depuis les gates

Gate Verdict Score Tags Learning
G3 v1 NON_CONFORME 6.625 #b2c, #freemium, #quotas Transitions de plan (downgrade) et modes dégradés dépendances doivent être spécifiés dès v1
G3 v2 RESERVE 8.188 #b2c, #freemium, #quotas Convergence STOP après escalade PO — 5 réserves résolues par décision produit
G5 v1 RESERVE 8.188 #plan, #stub, #gate5 Stubs 501 pour dépendances hors périmètre (PD-85) acceptables si explicitement documentés
G5 v2 GO 9.562 #plan, #gate5, #code-contracts Delta +1.374 en 1 itération — corrections chirurgicales (SLA, QuotaGuard, triple verrou)
G8 v1 GO 9.625 #freemium, #nestjs, #security pg_advisory_xact_lock + defense-in-depth (guard+RLS) = zéro écart sécurité

Depuis le REX

ID Tags Learning
L-84-01 #sonar, #cpd Extraire les duplications AVANT Gate 8 — un fichier extrait post-merge génère de nouvelles violations Sonar
L-84-02 #sonar, #hash codePointAt() + Math.trunc() obligatoires pour tout code de hashing (S7758 + S7767)
L-84-03 #nestjs, #di Checklist DI avant merge — vérifier chaque guard externe dans les imports du module
L-84-04 #postgresql, #quota Pattern pg_advisory_xact_lock + hashToInt réutilisable pour tout quota atomique sous concurrence
L-84-05 #security, #nestjs @UseGuards niveau classe (pas méthode) pour protection automatique de tout nouvel endpoint
L-84-06 #sonar, #pipeline new_violations = 0 s'applique à tout code nouveau, même extrait d'un fichier existant

Depuis les corrections post-merge (3 fixes pipeline)

Fix Cause Impact
CPD hashToInt Duplication entre 2 services Sonar QG FAILED → extraction utils/hash.util.ts
Sonar S7758+S7767 charCodeAt et \| 0 dans nouveau fichier Sonar new_violations = 0codePointAt + Math.trunc
DI NestJS OidcAuthModule manquant dans imports Deploy crash → ajout import. Tests unitaires ne détectent pas DI

Patterns récurrents (domaine b2c-mineurs + backend récent)

Pattern 1 — Sonar comme gardien structurel (4 stories : PD-107, PD-55, PD-63, PD-84)

Fréquence : #sonar dans 4 stories distinctes sur les 15 dernières.

Observations : - PD-107 : jest.doMock pattern pour singletons (Sonar flagge globals) - PD-55 : deprecated API BullMQ détectée uniquement par Sonar, pas ESLint - PD-63 : crypto.randomUUID() obligatoire (Math.random() = security hotspot) - PD-84 : codePointAt + Math.trunc + CPD duplication

Impact : 3 corrections post-merge sur PD-84 directement liées à Sonar. PD-55 avait aussi des corrections post-merge Sonar.

Recommandation : ALERTÉ FORTE — Le scan Sonar local (Phase 1.5 acceptabilité) est BLOQUANT depuis PD-55/PD-107, mais PD-84 prouve que l'extraction de code post-Gate 8 peut créer de nouvelles violations invisibles au scan initial.

Pattern 2 — Code contracts YAML accélèrent la convergence (9 stories)

Fréquence : #code-contracts dans 9 stories (PD-107, PD-19, PD-243, PD-245, PD-31, PD-32, PD-53, PD-81, PD-84).

Observations : - PD-84 : Gate 5 delta +1.374 en 1 correction, puis Gate 8 GO en 1 itération - PD-245 : Gate 8 GO en 1 itération avec code contracts bien définis - PD-81 : Code contracts ont structuré 19 tâches sur 7 modules

Impact : Les stories AVEC code contracts ont un Gate 8 moyen de 1.2 itérations vs 1.8 sans.

Pattern 3 — Specs ChatGPT et transitions d'état (3+ stories)

Fréquence : #spec-incomplete dans 3 stories (PD-19, PD-238, PD-32) + PD-84 (transitions manquantes).

Observations : - PD-84 Gate 3 : 3 itérations + escalade PO par manque de transitions retour (downgrade) - PD-19 Gate 3 : 2 itérations par critères d'acceptation non mesurables - PD-238 Gate 3 : 2 itérations par JWT/enum/error codes manquants

Impact : Chaque itération Gate 3 coûte ~1h. PD-84 a coûté 3 itérations + escalade = 4h.

Correction appliquée : Template spec v1.2.0 avec section "Transitions inverses" obligatoire (REX PD-84 §10.1).

Pattern 4 — NestJS DI invisible aux tests unitaires (3 stories : PD-30, PD-84, BATCH-RETRO)

Fréquence : #nestjs + #di dans 3 contextes distincts.

Observations : - PD-84 : OidcAuthModule manquant → crash deploy, invisible en tests - PD-30 : overrideGuard(Class) > overrideGuard(token) pour DI NestJS - BATCH-RETRO : Pattern transaction + advisory lock nécessite DI correcte

Impact : Erreur DI = crash en déploiement (pas en CI local). Coût : 1 pipeline supplémentaire + 30min diagnostic.

Pattern 5 — Defense-in-depth comme garantie sécurité (4 stories)

Fréquence : PD-79 (guard+middleware), PD-84 (guard+RLS), PD-177 (interceptor+KMS), PD-44 (sanitization+KMS).

Observations : - PD-84 : Score sécurité 10/10 grâce à double couche guard/RLS - PD-79 : Double validation taille intentionnelle (defense-in-depth) - PD-177 : SecretLeakInterceptor + S2-KMS defense-in-depth

Impact : Stories avec defense-in-depth explicite = 0 écart SEC dans les gates.

Pattern 6 — Faux positifs LLM en reviews (5+ stories)

Fréquence : PD-81, PD-55, PD-63, PD-79, PD-31, PD-84 — faux positifs récurrents en Phase 1 review ChatGPT.

Observations : - PD-84 Gate 5 : 2 BLQ reclassés MINEUR (conflit tests↔spec vs plan↔spec) - PD-81 Gate 8 : 5 faux positifs sur code déjà corrigé - PD-31 Gate 3 : ⅚ écarts annulés après vérification exhaustive

Impact : Phase 2 (confrontation Claude) reclasse en moyenne 50-60% des écarts ChatGPT.

Correction existante : Injection stubs/corrections dans prompts 7a/7b/7c (CLAUDE.md).

Métriques comparatives (domaine b2c-mineurs)

Métrique PD-79 PD-84 Delta
Durée 8h 5.5h -31%
Gate 3 iter 1 3 (+escalade) +2 (transitions inverses)
Gate 5 iter 1 2 +1
Gate 8 iter 1 1 =
Gate 8 score 7.88 9.625 +1.745
Tests 48 133 +177%
Coverage 94.5% 92.5% -2pp
SEC écarts 0 0 =
Post-merge fixes 0 3 +3 (Sonar + DI)

Analyse : PD-84 est plus complexe que PD-79 (133 tests vs 48, 5 contrôleurs vs 1) mais les 3 itérations Gate 3 sont dues aux transitions inverses non spécifiées — maintenant corrigé dans le template spec v1.2.0. Les 3 post-merge fixes sont un angle mort structurel (scan Sonar + DI NestJS).

Recommandations

Priorité haute (pattern Sonar + DI = 7+ stories cumulées)

  • Checklist DI NestJS pré-merge : Pour chaque @UseGuards(XxxGuard) externe, vérifier que le module fournissant le guard est dans les imports. Les tests unitaires ne détectent pas ces erreurs. → Cible : template de plan (étape 4) ou checklist pré-merge (étape 6c).
  • Re-scan Sonar après extraction CPD : Si une correction post-Gate 8 crée un nouveau fichier (extraction de duplication), relancer le scan Sonar local sur ce fichier avant push. Règle new_violations = 0 s'applique à tout code nouveau. → Cible : procédure post-merge dans /gov-impl.

Priorité normale

  • Capitaliser pg_advisory_xact_lock + hashToInt comme pattern réutilisable pour toute story de quota atomique (INV candidat pour les futures stories b2c-mineurs et backend-core).
  • Triple verrou pour endpoints stub (env + header + NODE_ENV) : documenter comme pattern de référence dans CLAUDE.md pour toute story introduisant des endpoints dev/test.
  • Enrichir le template spec avec "modes dégradés dépendances" : au-delà des transitions inverses (déjà ajouté v1.2.0), PD-84 a révélé que les specs omettent systématiquement le comportement quand une dépendance (PD-31 audit, PD-85 export) est indisponible.

Signal CLAUDE.md

Section "Règles apprises" — Nouvelle règle suggérée

DI NestJS — Guards externes :

### DI NestJS — Vérification imports guards externes (2026-02-24)

**Issu du REX PD-84** : `@UseGuards(XxxGuard)` avec un guard d'un autre module NÉCESSITE l'import du module fournisseur.

Les tests unitaires mockent les guards → le graphe DI NestJS n'est jamais instancié → erreur invisible en CI locale.

**Checklist pré-merge** : Pour chaque `@UseGuards()` dans le module :
1. Le guard est-il fourni par le module courant ? → OK
2. Le guard est-il externe ? → Vérifier que `imports: [XxxModule]` est présent

```typescript
// CORRECT
@Module({
  imports: [OidcAuthModule], // <-- fournit OidcJwtAuthGuard
  controllers: [MyController],
})

// BUG (crash deploy, invisible en tests)
@Module({
  controllers: [MyController], // OidcAuthModule manquant
})
### Section "Étape 7 — Acceptabilité" — Enrichissement suggéré

Ajouter après "Scan Sonar local BLOQUANT" :
Re-scan après extraction CPD (issu du REX PD-84) : Si une correction Sonar crée un NOUVEAU fichier (extraction de duplication), relancer Sonar sur ce fichier car new_violations = 0 s'applique à tout code nouveau, même extrait d'un fichier existant. ```

Bilan

Indicateur Valeur
Patterns identifiés 6
Alertes haute priorité 2 (DI NestJS, re-scan Sonar)
Alertes normales 3
Stories domaine analysées 2 (PD-79, PD-84)
Stories global analysées 39
Tags dans ≥ 5 stories 11 (#backend, #crypto, #auth, #security, #code-contracts, #testing, #infra, #site, #zero-knowledge, #app, #nestjs)
Axe fragile identifié Gate 3 testability (PD-84: 7.25, PD-19: 6.5 v1)