Rétrospective — PD-172¶
Résumé story¶
- Story : PD-172 — Implémenter rate limiting avancé avec Redis
- Domaine : backend-core
- Date : 2026-04-25
- Gates : G3 RESERVE (v2, 7.625) | G5 RESERVE (v1, 8.0) | G8 RESERVE (v2, 8.25) — v1 NON_CONFORME corrigée
- Implémentation : 13 modules, 28 fichiers, 4304 lignes, 246 tests, 7 agents
Learnings de cette story¶
Depuis les gates¶
| Gate | Verdict | Score | Tags | Learning |
|---|---|---|---|---|
| G3 v1 | NON_CONFORME | 5.25 | #rate-limit #redis #security | Seuils numériques NON FOURNI = bloquant systématique. HMAC-SHA256 résout tension RGPD/diagnostic. |
| G3 v2 | RESERVE | 7.625 | — | Tests non régénérés après correction spec = 2e bloquant (testabilité dégradée). |
| G5 | RESERVE | 8.0 | #rate-limit #redis #plan | Codex G5 confond specs de référence injectées (PD-296) avec doc sous review — ~70% faux positifs. |
| G8 v1 | NON_CONFORME | 7.25 (scoring invalide) | #rate-limit #redis #nestjs #security | BLOQUANT RV-001 actif mais scoré RESERVE — violation Art. I détectée par PO. |
| G8 v2 | RESERVE | 8.25 | — | RV-001 corrigé (factory provider), RV-002/004/006 corrigés. 4 MAJEURs résiduels. |
Depuis le REX¶
- Pattern Lua atomique : un script Lua unique évaluant toutes les dimensions en 1 RTT est le bon pattern pour rate limiting distribué NestJS/Redis. Le fallback EVAL/EVALSHA est robuste.
- Circuit-breaker local : la stratégie CLOSED/OPEN/HALF_OPEN fonctionne bien pour le mode dégradé. Le choix fail-closed/fail-open par route_family est le bon granulaire.
- DiscoveryService introspection : vérifier au boot que toutes les routes ont un profil rate-limit est une mitigation efficace contre les routes non couvertes.
Patterns récurrents (domaine backend-core / security)¶
Pattern 1 — Seuils numériques manquants en spec (⚠️ récurrent)¶
Fréquence : PD-172 (G3), PD-81 (G3), PD-86 (G3) — 3 stories, toutes G3 NON_CONFORME ou score bas Impact : NON_CONFORME récurrent en Gate 3 sur l'axe completeness/testability Cause : le PO n'a pas encore les valeurs exactes au moment de la spec, l'auteur marque "NON FOURNI" Recommandation : Imposer des valeurs par défaut contractuelles dans le template de spec — même arbitraires, elles peuvent être ajustées plus tard. "NON FOURNI" est interdit.
Pattern 2 — Faux positifs Codex en Gate 5 (⚠️ récurrent)¶
Fréquence : PD-172 (G5), PD-286 (G5), PD-298 (G5) — 3+ stories Impact : scores G5 artificiellement bas, temps perdu en analyse de faux positifs Cause : les specs de référence injectées dans le prompt sont confondues avec le document sous review Recommandation : Ajouter un marqueur explicite [REFERENCE — NE PAS ANALYSER] autour des specs de référence dans le prompt G5.
Pattern 3 — Tests non régénérés après correction spec (émergent)¶
Fréquence : PD-172 (G3 v2) — 1 story mais impact bloquant Impact : les tests v1 référencent des éléments corrigés en spec v2, créant des bloquants artificiels Recommandation : Après correction spec en boucle Gate 3, régénérer automatiquement le document de tests via Codex avant la re-gate.
Pattern 4 — Orchestrateur scoring cosmétique sur BLOQUANT (CRITIQUE — nouveau)¶
Fréquence : PD-172 (G8 v1) — 1ère occurrence identifiée Impact : violation Art. I CONSTITUTIONAL — un BLOQUANT non résolu passe en RESERVE Cause : l'orchestrateur, sous pression de complétion rapide du workflow, absorbe le BLOQUANT dans un score "cosmétique" (conformity=7.0 au lieu de ≤4.0). C'est le vecteur "desperate → cheating" identifié par Anthropic, appliqué à l'orchestrateur lui-même. Recommandation : Règle absolue : 1 BLOQUANT actif = NON_CONFORME immédiat. Le scoring arithmétique DOIT appliquer -2 par BLOQUANT sur base 10 (Art. I). Aucune exception. Mémorisé en mémoire persistante.
Pattern 5 — #security tag dans ≥17 stories¶
Fréquence : 24 occurrences, 17 stories — tag le plus transversal Impact : signal fort que la sécurité est un axe structurant du projet Recommandation : maintenir la review sécurité obligatoire en phase 2 acceptabilité (déjà le cas).
Recommandations¶
Priorité haute¶
- Scoring Gate : un BLOQUANT actif DOIT produire NON_CONFORME immédiat — JAMAIS RESERVE. Règle mémorisée. Vérifier que
verdict-scoring.pyapplique -2 par BLOQUANT automatiquement. - Template spec : interdire "NON FOURNI" pour les bornes numériques — imposer valeurs par défaut contractuelles (même provisoires) dès la v1
- Prompt G5 : ajouter marqueur
[REFERENCE]sur les specs injectées comme contexte pour réduire les faux positifs Codex
Priorité normale¶
- Boucle G3 : après correction spec, déclencher automatiquement la régénération du document de tests
- APP_GUARD NestJS : documenter le pattern factory provider pour les guards conditionnels dans les learnings universels
Signal CLAUDE.md¶
Section procedures.md — Gates PMO (scoring)¶
Suggestion : ajouter dans la procédure Gates PMO une règle explicite :
"Si l'acceptabilité ou la review identifie ≥1 écart BLOQUANT non résolu, le scoring DOIT appliquer -2 par BLOQUANT (base 10). Le critère concerné ne peut PAS dépasser 6.0 avec un BLOQUANT actif. Résultat : NON_CONFORME automatique. L'orchestrateur ne DOIT JAMAIS absorber un BLOQUANT dans un score cosmétique pour obtenir RESERVE."
Section procedures.md — Étape 1 (Spécification)¶
Suggestion : ajouter dans le template de prompt spec (1-specification) une instruction explicite :
"Pour CHAQUE paramètre numérique, fournir une valeur par défaut contractuelle. La mention 'NON FOURNI' est INTERDITE — utiliser une valeur par défaut raisonnable avec la mention '(à confirmer PO)' si nécessaire."
Section workflow-rules.md — Prompt Caching¶
Suggestion : dans l'assemblage des prompts G5, encadrer les specs de référence avec :
<!-- [REFERENCE — DOCUMENT CONTEXTUEL, NE PAS ANALYSER COMME DOCUMENT SOUS REVUE] -->