Rétrospective — PD-253¶
Résumé story¶
- Story : PD-253 — Export bulk avec métadonnées et preuves (BagIt + NF Z42-013 §13.1)
- Domaine : legal-compliance
- Date : 2026-03-12
- Gates : G3 RESERVE→RESERVE (v2) | G5 GO (v1) | G8 RESERVE (v1)
- Score moyen : (8.625 + 8.625 + 8.438) / 3 = 8.563 / 10
- Durée totale : 3.7h (vs 6.49h moyenne projet — -43%)
- Post-clôture : DIV-01/INV-253-11 résolu le 2026-03-12 (disk encryption health-check — option C)
Learnings de cette story¶
Depuis les gates¶
| Gate | Verdict | Score | Tags | Note |
|---|---|---|---|---|
| G3 | RESERVE→RESERVE | 5.688 → 8.625 | #spec #testability #bulk-export | v1 NON_CONFORME : clarity 4.0, testability 5.75. Spec manquait confirmation download, schéma destruction-log, failure_reason |
| G5 | GO | 8.625 | #plan #code-contracts | Plan résolu les 5 ECT de Gate 3. 12 code-contracts, 0 ambiguïté résiduelle |
| G8 | RESERVE | 8.438 | #bulk-export #nfz42013 #bagit #audit-fail-closed | conformity 7.5 (< 8) : 3 BLOQUANT résolus + 6 items reportés PD-253b |
Depuis le REX¶
[BULK EXPORT NF Z42-013]Audit fail-closed + nom manifest BagIt = 2 pièges systématiques ZK crypto[BULK EXPORT]ACTIVE_STATUSES sous-ensemble : constantes dérivées de l'enum sont des vecteurs de régression silencieux[BAGIT NF Z42-013]Noms de fichiers contractuels copiés verbatim — les agents interprètent et "améliorent" les noms[GATE 3]v1 NON_CONFORME est normal pour les stories ≥ 10 invariants — +2.937 delta après corrections[ART. II DÉROGATION]Prompts > 30KB contraignent àclaude -pcomme reviewer principal — 3e story consécutive
Patterns récurrents (domaine legal-compliance + global)¶
Pattern 1 — AUDIT FAIL-CLOSED : Piège #1 des agents (18 stories)¶
| Métrique | Valeur |
|---|---|
| Stories concernées | 18 (PD-25, PD-26, PD-31, PD-37, PD-41, PD-60, PD-63, PD-85, PD-101, PD-177, PD-239, PD-244, PD-250, PD-253, PD-262, PD-265, PD-273, BATCH-RETRO) |
| Fréquence | 31 entrées dans learnings.jsonl |
| Impact | BLOQUANT dans PD-253, MAJEUR dans PD-85, PD-250, PD-262, PD-265 |
| Récurrence | 7e occurrence classée BLOQUANT ou MAJEUR |
Constat : Le learning existe depuis PD-25. La règle est dans CLAUDE.md ## Anti-catch-absorb. Malgré 5 stories l'ayant documenté comme pattern critique, l'agent agent-developer continue d'oublier l'injection de AuditLogService. Le problème n'est pas le learning — c'est l'absence de contrainte hard-coded dans le prompt agent.
⚠️ ALERTE FORTE : Ce pattern est le plus cher de tout le projet (corrections post-Gate 8 dans 7 stories).
Pattern 2 — MACHINE À ÉTATS : bypass scheduler / sous-ensemble d'états (4+ stories)¶
| Métrique | Valeur |
|---|---|
| Stories concernées | PD-253 (#quota ACTIVE_STATUSES), PD-265, PD-278, PD-280 (scheduler FSM bypass) |
| Impact | MINEUR dans PD-253, MAJEUR dans PD-265/PD-278 |
| Récurrence | 4e occurrence |
Constat double : 1. Bypass FSM scheduler : le scheduler/cron modifie status directement sans passer par ExportStateMachineService. Risque de transition invalide à chaque ajout d'état. 2. Sous-ensemble d'états : ACTIVE_STATUSES = [A, B] mais enum a [A, B, C]. Le quota/concurrence autorise des contournements via l'état oublié.
Pattern 3 — GATE 3 testability < 6 sur specs complexes (5+ stories)¶
| Métrique | Valeur |
|---|---|
| Stories concernées | PD-253 (5.75), PD-278, PD-276, PD-275, PD-85 |
| Impact | 1-2 itérations Gate 3 systématiques sur stories ≥ 10 INV |
| Score v1 moyen | ~6.0/10 sur l'axe testability |
Constat : Les specs avec ≥ 10 invariants et des machines à états produisent systématiquement Gate 3 v1 NON_CONFORME ou RESERVE faible sur testability. La correction v2 est toujours efficace (delta +2 à +3) mais représente 40-60min supplémentaires.
Pattern 4 — NOMS DE FICHIERS CONTRACTUELS (nouveau — PD-253 + PD-283)¶
| Métrique | Valeur |
|---|---|
| Stories concernées | PD-253 (manifest-sha3-256.txt → manifest-sha3.txt), PD-283 (suffixes collision) |
| Impact | BLOQUANT dans PD-253, MINEUR dans PD-283 |
| Récurrence | 2e occurrence — pattern émergent |
Constat : Les agents "normalisent" les noms de fichiers en les rendant plus descriptifs. Un nom de fichier BagIt/NF Z42-013 est un contrat normé — toute déviation casse l'interopérabilité. Les tests unitaires doivent vérifier les noms de fichiers produits par string-exact (pas par pattern regex).
Pattern 5 — ART. II DÉROGATION prompts > 30KB (3 stories consécutives)¶
| Métrique | Valeur |
|---|---|
| Stories concernées | PD-262, PD-283, PD-253 |
| Impact | Dérogation Art. II systématique — reviewer principal = claude -p (même LLM) |
| Fréquence | 3 stories consécutives |
Constat : La limite de 30KB OpenCode/ChatGPT en mode non-agentic est atteinte systématiquement sur les stories avec acceptability + plan (code review prompts > 50KB). La dérogation est documentée et stable mais elle réduit l'indépendance des reviews.
Recommandations¶
Priorité haute (pattern ≥ 5 stories ou BLOQUANT récurrent)¶
-
Contrainte hard-coded audit fail-closed dans prompt agent : Ajouter dans
templates/prompts/step6-agent.mdune section CONTRAINTES SYSTÉMATIQUES avec : (1) AuditLogService DOIT être injecté dans le constructeur si le module a des actions sur des entités auditées, (2) aucun catch ne doit absorber les erreurs d'audit (pattern anti-catch-absorb), (3) fail-closed = pas de try/catch autour de audit.log(). Priorité : immédiate (7e story concernée). -
Checklist ACTIVE_STATUSES dans
/gov-check-plan: Ajouter une vérification dans le script pre-Gate 5 : pour toute story avec machine à états + quota/concurrence, valider que la listeACTIVE_STATUSES(ou équivalent) couvre tous les états non-terminaux. Bloquer si la sommeACTIVE + TERMINAL ≠ TOTAL_ÉTATS.
Priorité normale¶
-
Test string-exact sur noms de fichiers contractuels : Ajouter dans
templates/prompts/step2-tests.mdun template de test pour les stories impliquant des formats normés (BagIt, TSA, WORM) : vérification parexpect(filename).toBe('manifest-sha3.txt')(string-exact, pas regex). -
Pre-check Gate 3 testability sur specs ≥ 10 INV : Intégrer dans le prompt ChatGPT étape 1 une section "Si la story contient ≥ 10 invariants ou une machine à états, ajouter obligatoirement : (a) tableau des transitions autorisées/interdites, (b) schéma JSON des structures de données principales, © mécanisme de confirmation de chaque flux asynchrone". Évite la Gate 3 v1 NON_CONFORME systématique.
-
Stratégie Art. II pour prompts > 30KB : Documenter dans CLAUDE.md que le reviewer principal est
claude -ppour tous les prompts > 30KB, avec appel distinct (system prompt différent) pour maintenir l'indépendance. La dérogation Art. II est automatiquement justifiée si documentée dans le verdict.
Signal CLAUDE.md¶
La mise à jour de CLAUDE.md reste à la discrétion du PO.
Section ## Anti-catch-absorb pour audit fail-closed — Renforcement suggéré¶
Section existante (CLAUDE.md) : couvre le pattern technique (ne pas catcher audit.log).
Renforcement suggéré : Ajouter après la règle existante :
**Contrainte agent (step 6b)** : L'injection de `AuditLogService` dans le constructeur est
OBLIGATOIRE pour tout service qui crée, modifie ou supprime des entités auditées. Cette
contrainte DOIT figurer dans le bloc CONTRAINTES SYSTÉMATIQUES du prompt agent (pas seulement
dans les learnings). 7 occurrences de BLOQUANT/MAJEUR sur cette même omission (PD-25 → PD-253).
Nouvelle règle suggérée — Constantes de sous-ensemble d'états¶
## Constantes de sous-ensemble d'états (ACTIVE_STATUSES, TERMINAL_STATUSES)
**Pattern** : Toute constante définissant un sous-ensemble des valeurs d'un enum d'états
(ex: `ACTIVE_BULK_EXPORT_STATUSES`, `CANCELLABLE_STATUSES`) est un vecteur de régression.
**Règle** : Pour chaque story avec machine à états + quota/concurrence :
1. La constante sous-ensemble DOIT avoir un test vérifiant sa taille exacte (`expect(arr).toHaveLength(N)`)
2. Tout ajout d'état à l'enum nécessite une revue de toutes les constantes dérivées
3. Documenter explicitement dans la spec : "États actifs = [A, B, C] — exhaustif"
Issu du REX PD-253 (quota bypass via READY_FOR_DOWNLOAD oublié dans ACTIVE_STATUSES).
Nouvelle règle suggérée — Noms de fichiers normés¶
## Noms de fichiers contractuels (BagIt, NF Z42-013, TSA)
**Pattern** : Les agents "normalisent" les noms de fichiers (ex: manifest-sha3.txt →
manifest-sha3-256.txt). Un nom de fichier défini par une norme est un contrat — toute
déviation casse l'interopérabilité.
**Règle** : Tout module produisant des fichiers à noms normés (BagIt manifests, TSA tokens,
WORM outputs) DOIT avoir un test contractuel vérifiant les noms par string-exact
(`expect(filename).toBe('manifest-sha3.txt')`), pas par pattern regex.
Issu du REX PD-253 (E-03 BLOQUANT) et PD-283 (suffixes collision).
Métriques de la story¶
| Métrique | Valeur |
|---|---|
| Stories analysées dans learnings.jsonl | 345 entrées |
| Domaine legal-compliance (stories récentes) | PD-250, PD-244, PD-252, PD-253 |
| Patterns identifiés | 5 |
| Alertes haute priorité | 1 (audit fail-closed — 18 stories) |
| Alertes normale | 4 |
| Signal CLAUDE.md | 3 sections concernées |