Aller au contenu

PD-299 — Retour d'expérience (REX)

1. Résumé exécutif

Métrique Valeur
Objectif initial Consolider PD-298 côté app (A1-A8 : 45 tests sharing, guard owner, auth réelle, telemetry allowlist, fallback maskIp, blocage offline, fix useProofShares, preuve A8) et durcir le workflow gouvernance (B1-B6 : 6c.bis, cap Gate 8 zéro test, injection companion, règle telemetry learnings, bloc 6a données résolues, detect-plan-extensions).
Résultat obtenu Partiel. Partie A (app) livrée avec 45/45 tests Jest et coverage 92%. Partie B (gov) scripts créés (6/6) mais câblage dans les skills /gov-* absent. 3 artefacts annoncés au plan non produits (check-6a-block.py, parse-plan-sections.py, legal-validation.yaml).
Verdict final RESERVE (Gate 8 v1 : 7.875/10)
Tests contractuels 45/45 Jest passés côté app (200 assertions, coverage 92,12%). Tests shell/Python gov non matérialisés (TC-NOM-09/11/13/16/18 et TC-ERR-08/09/11/12/14/15 non rejoués).

2. Métriques de convergence

2.1 Temps et itérations

Étape Durée estimée Durée réelle Itérations Écart
0 - Besoin 30 min 7 min 1 −77%
1 - Spécification 2h 12 min 1 −90%
2 - Tests 1h 6 min 1 −90%
3 - Gate spec 1h 2h42 2 +170%
4 - Plan 1h 15 min 1 −75%
5 - Gate plan 1h 15 min 1 −75%
6 - Implémentation 4h 1h40 1 (10 agents, 2 waves) −58%
7 - Acceptabilité 2h 15 min 1 −87%
8 - Gate acceptabilité 1h 15 min 1 −75%
9 - REX 30 min ~30 min 1 0%
TOTAL ~14h ~6h 11 −57%

2.2 Scores de convergence par gate

Gate Score v1 Score final Delta Itérations
Gate 3 6.875/10 (NON_CONFORME) 7.75/10 (RESERVE v2) +0.875 2
Gate 5 7.375/10 (RESERVE) 7.375/10 0 1
Gate 8 7.875/10 (RESERVE) 7.875/10 0 1

2.3 Écarts par catégorie

Catégorie d'écart Gate 3 (v1+v2) Gate 5 Gate 8 Total
ECT (complétude/testabilité) 11 2 2 15
DIV (divergence spec/impl) 8 8 4 20
AMB (ambiguïté) 8 2 1 11
SEC (sécurité) 3 1 1 5
PERF (performance) 0 0 0 0
TOTAL écarts 30 13 8 51

3. Points fluides

  • Bloc « Données résolues » en décomposition 6a : dès le step 6a, les 8 ambiguïtés critiques (glob récursif, échelle projet, regex Bearer, cap exact 6.0, source companion, ratification PO, allowlist metadata, fallback maskIp) ont été tranchées et tracées avec leur source (plan DEC-01 à DEC-10). Pattern PD-298 capitalisé et appliqué.
  • Matérialisation 45 tests Jest + coverage 92% : l'agent sharing-tests a produit la suite complète en une passe. Statements 92,12 %, branches 81,81 %, functions 89,34 %, lines 93,88 % — bien au-dessus du seuil INV-299-02 (80%).
  • Cache-first 10 agents en 1h40 : deux waves (gov + app) orchestrées séquentiellement. Les 6 modules gov produits en wave 1 (scripts Python/Shell), les 4 modules app en wave 2, sans dépendance croisée bloquante. Rendement stable malgré 55 fichiers créés.
  • Convergence toutes gates ≤ 2 itérations : seule la Gate 3 a nécessité une v2 (6.875 → 7.75), les Gate 5 et Gate 8 sont passées en RESERVE v1 sans correction.

4. Points difficiles

  • Gate 3 v1 NON_CONFORME (6.875) : la spec v1 contenait 4 écarts BLOQUANTS dont 2 contradictions internes (INV-299-12 dit « forcé à 6.0 », diagramme §5bis écrit min(raw, 6.0) ; §3 fige *.test.ts, Q-299-03 laisse ouvert .test.tsx/.spec.ts) et 1 contradiction normative (INV-299-13 vs Q-299-02 déclarée ouverte). Rédaction v2 nécessaire pour lever ces BLOQUANTS.
  • Gate 5 en RESERVE sans v2 : 4 BLOQUANTS identifiés par le reviewer (contournabilité INV-299-14 par absence de front-matter, bypass Gate 5 si sections plan non canoniques, TC-NOM-09 et TC-ERR-11 non déterministes) n'ont pas été corrigés. Décision orchestrateur : accepter les réserves structurelles, documenter en §9.
  • Intégration workflow non câblée : les scripts gov-6cbis.sh, gate8-zero-test.py, detect-plan-extensions.py, validate-legal-approvals.py et l'enrichissement assemble-prompt.sh fonctionnent isolément, mais leur invocation depuis /gov-impl, /gov-gate, /gov-check-plan reste documentaire (à câbler dans .claude/commands/*.md). Les 5 INV B1/B2/B3/B6 restent structurellement contournables jusqu'au câblage.
  • 3 artefacts annoncés au plan absents : check-6a-block.py, parse-plan-sections.py, legal-validation.yaml listés en §1.2 / §4 du plan et non livrés. validate-legal-approvals.py échoue sur FileNotFoundError.
  • E-06 useProofShares(undefined) sentinelle : le wrapper useSafeProofShares filtre en amont mais appelle volontairement le hook avec undefined (no-op documenté). Comportement fonctionnellement équivalent à INV-299-08 mais la lettre de l'invariant (« NE DOIT JAMAIS être invoqué avec proof_id vide/undefined ») est violée.
  • E-07 fail-closed offline incomplet : protégé sur les writes (ShareCreate, ShareDetail), absent sur les reads (MySharesScreen, ShareEventsScreen via useShareList/useShareEvents).

5. Hypothèses révélées tardivement

  • H-T-07 (plan DEC-07) : source companion via front-matter YAML du besoin — découverte à l'étape 4. Le modèle spec ne canonise pas cette convention (Q-299-07 ouverte), le plan l'a tranchée unilatéralement. Conséquence : load-companion-source.py suppose un schéma non documenté dans data/specs-index/.
  • H-T-11 (plan §8) : API Atlassian accessible pour vérifier jira_comment_id — découverte à l'étape 6. Rend validate-legal-approvals.py dépendant d'une clé Vault et d'une latence réseau, ce qui viole l'hypothèse implicite de déterminisme local de Gate 8.
  • Q-299-05 ciblage écran ProofDetailScreen vs ProofScreen — découverte à l'étape 6c. Le guard OwnershipGuard écrit dans sharing/guards/ a été conçu pour ProofDetailScreen.tsx mais ce fichier n'a pas été modifié (pattern ACC-01 de PD-298 réitéré).
  • Transition NON_CONFORME → PENDING non atomique — découverte à l'étape 3 (revue spec E-HD-02 / E-HD-05). La spec traite les re-checks séquentiellement sans primitive d'atomicité, ce qui interdit un re-gate concurrent. Documenté §5.4 Comportement retour.

6. Invariants complexes

  • INV-299-12/13 (cap Gate 8 zéro test = 6.0 exact + NON_CONFORME forcé) — TC-NOM-11, TC-ERR-08, TC-NEG-09. 3 réécritures spec pour fermer la divergence min(raw, 6.0) vs forçage exact. L'agent gov-gate-zerotest implémente gate8-zero-test.py correctement, mais INV-299-13 (forcer NON_CONFORME même si moyenne ≥ 7) reste non câblé dans /gov-gate — pattern « scripts isolés, workflow non modifié ».
  • INV-299-14 (prompt companion enrichi) — TC-NOM-13, TC-ERR-11. Contournement structurel : si source_story_id est absent du front-matter, assemble-prompt.sh reste no-op. L'invariant est NON NÉGOCIABLE mais sa contournabilité par omission reste documentée (plan §9.1).
  • INV-299-17 (detect-plan-extensions + kind invalide) — TC-NOM-16, TC-ERR-10, TC-ERR-15. Le script detect-plan-extensions.py existe, mais son invocation depuis /gov-check-plan phase 4 n'est pas documentée dans .claude/commands/gov-check-plan.md. Identique à INV-299-10/11 et INV-299-12/13.
  • INV-299-18 (FSM Gate 8 fermée) — TC-NOM-19/20/21, TC-ERR-14, TC-NR-07/08. La table de transitions est documentée dans la spec §5.4 mais gate8-zero-test.py n'impose pas le rejet explicite des transitions non listées. Dépend du câblage workflow.

7. Dette technique

  • Câblage workflow des 5 modules gouvernance (B1, B2, B3, B6, gov-legal) — impact : élevé. Scripts fonctionnels isolément mais non invocables depuis les skills. Nécessite modification des 4 fichiers .claude/commands/{gov-impl,gov-gate,gov-check-plan,assemble-prompt}.md. Story fille requise : PD-299-INTEG.
  • 3 artefacts annoncés au plan absents (check-6a-block.py, parse-plan-sections.py, legal-validation.yaml) — impact : moyen. Les invariants B5/B4/A8 restent vérifiables manuellement, mais aucun check automatique.
  • E-06 useProofShares sentinelle — impact : faible. Filtré par wrapper, comportement correct, mais lettre de l'invariant violée. Nécessite refactor pour supprimer l'appel sentinelle.
  • E-07 offline reads — impact : moyen. Les écrans de lecture ne bloquent pas hors-ligne. Risque d'affichage de données obsolètes sans message explicite. Fix : ajouter useNetworkGuard dans useShareList/useShareEvents.
  • Sonar local SKIP (Docker indisponible) — impact : faible. Validation reportée en pipeline post-merge. Pattern récurrent sur 14 stories consécutives.
  • Validation légale A8 non exécutée — impact : moyen. legal-validation.yaml absent, validate-legal-approvals.py non exécuté. Les textes ARB-7/ARB-8/RGPD-90J résolus en step 6a sans preuve PO+LEGAL traçable Jira.
  • Regex D-299-07 littérale vs implémentation stricte (DIV-01 confrontation Gate 5) — impact : faible. La spec admet N espaces ([ ]+), l'implémentation n'en admet qu'un. Choix documenté (plan §7.1) mais non ratifié en spec.

8. Risques résiduels

Risque Type Probabilité Impact Mitigation
Modules gov livrés mais non invoqués au prochain /gov tech élevée élevé PD-299-INTEG : câblage dans les 4 skills
Story companion déclarée sans source_story_id → injection no-op silencieuse tech moyenne moyen Rendre le front-matter obligatoire dans /gov-step-0
Sections plan non canoniques → bypass Gate 5 tech moyenne élevé detect-plan-extensions.py doit échouer dur si parsing vide
E-07 offline reads → affichage données obsolètes sans message métier moyenne moyen Story fille : étendre useNetworkGuard aux reads
A8 non vérifié automatiquement → auditabilité juridique fragile métier élevée élevé Produire legal-validation.yaml + câbler validate-legal-approvals.py en Gate 8
.gov-local.json modifiable localement sans contrôle d'intégrité ops faible moyen Signer les entrées ou persister en append-only
Scripts Python non linters/typés tech faible faible Ajouter ruff + mypy CI

8bis. Matrice de délégation inter-PD

Story Direction Statut Nature de la dépendance Problème rencontré
PD-298 ← dépend de DONE Source companion (INV/arbitrages), pattern 45 tests, guard owner ACC-01 (guard non câblé), ACC-02 (useProofShares undefined), ACC-03 (metadata PII-free) repris comme A2/A4/A7
PD-287 ← dépend de DONE Pattern « 0 test CI » (B2), extensions plan→spec (B6) Cap Gate 8 zéro test (INV-299-12) capitalise le learning de PD-287
PD-296 ← dépend de DONE Vérification formelle bloquante (Art. VIII) Non touché dans PD-299
PD-299-INTEG → bloque TODO Câblage des 5 modules gov dans /gov-impl, /gov-gate, /gov-check-plan, assemble-prompt.sh Sans ce câblage, INV-299-10/11/12/13/14/17 restent contournables
PD-299-LEGAL → bloque TODO Production legal-validation.yaml ARB-7/ARB-8/RGPD-90J + approbations PO+LEGAL Jira A8 non validé dans PD-299
PD-299-OFFLINE → bloque TODO Extension useNetworkGuard aux reads (MySharesScreen, ShareEventsScreen) E-07 non résolu
PD-299-REFACTOR → bloque TODO Supprimer l'appel sentinelle useProofShares(undefined) dans useSafeProofShares E-06 non résolu
PD-300+ companion → bloque TODO Toute story companion future qui ne déclare pas source_story_id en front-matter → injection no-op Rendre le front-matter obligatoire

8ter. Bugs de tests

Pattern incorrect Pattern correct Cause Coût
Rejouer Jest depuis sandbox Codex Rejouer Jest depuis shell host .jest-cache EPERM dans sandbox ~10 min d'investigation

Aucun autre bug de test rencontré.

8quater. Corrections post-Gate 8

Aucune correction post-Gate 8 nécessaire à ce jour (Gate 8 RESERVE v1 sans v2). Les corrections listées en §7 (dette technique) feront l'objet de stories filles dédiées.

9. Patterns récurrents détectés

9.1 Patterns confirmés (déjà vus dans d'autres stories)

  • Scripts livrés mais workflow non câblé — aussi dans PD-298 (guard ShareCta écrit mais non monté dans ProofDetailScreen), PD-287 (0 test CI malgré plan C14 exigeant 80% coverage). 3e occurrence sur le domaine sharing/workflow. Signal structurel : la livraison d'artefacts isolés n'est pas suffisante, il faut une vérification de câblage.
  • Toutes gates RESERVE v1 sans v2 — aussi dans PD-298 (3/3 RESERVE v1 sans correction), PD-287 (double NON_CONFORME remonté en RESERVE). Signal : le workflow converge vite sur RESERVE structurel plutôt que d'itérer vers GO. Décision orchestrateur systématique.
  • Sonar Phase 1.5 SKIP — 15e occurrence consécutive (PD-276...PD-299). Dérogation de fait, Docker indisponible en local.
  • Faux positifs LLM en reviews — PD-299 Gate 8 review Codex rapporte 10/18 INV en échec dont 5 sont des questions d'intégration workflow (non des écarts réels). 23e occurrence. Pattern : les reviewers LLM ne distinguent pas « script livré isolément » vs « câblage dans skill ».
  • Machine à états explicite avec transitions interdites — 24e occurrence (FSM Gate 8 fermée §5.4). Pattern standard stabilisé.
  • Extensions plan→spec non ratifiées — aussi dans PD-287 (6 extensions), PD-298 (4 extensions). 3e occurrence. Signal fort : le reviewer plan doit détecter systématiquement ces extensions.
  • Guard cross-module avec jointure inter-schéma — aussi dans PD-251, PD-279, PD-298. 4e occurrence. Pattern « composant écrit mais pas monté dans le consommateur ».

9.2 Nouveaux patterns identifiés

  • Méta-récursion : PD-299 consolide PD-298, mais reproduit les patterns de PD-298 — PD-299 produit les scripts B1/B2/B3/B6 qui devraient détecter les patterns de PD-298/PD-287, mais ces scripts eux-mêmes ne sont pas câblés dans le workflow. La consolidation reste théorique tant que l'intégration n'est pas faite. À surveiller : besoin d'une story « PD-299-INTEG » dédiée au câblage pour valider la boucle.
  • Front-matter YAML comme convention non canonique — la décision plan DEC-07 (source_story_id dans le besoin) introduit une convention non documentée dans data/specs-index/. À canoniser dans le template besoin.
  • Cap Gate 8 déterministe vs scoring arithmétique — première introduction d'un cap forcé (6.0 exact) priorisé sur la moyenne arithmétique. Pattern à surveiller pour d'autres critères critiques (ex : security si CVSS ≥ 9.0).
  • Story companion sans source = injection no-op silencieuse — contournement par omission de métadonnée. Nouveau pattern à surveiller : rendre la déclaration source_story_id obligatoire ou émettre un warning explicite.

10. Améliorations du workflow

10.1 Améliorations des prompts/templates

Fichier Amélioration suggérée Priorité
templates/prompts/0 Expression de besoin.md Exiger explicitement un bloc front-matter YAML au début du besoin avec champ source_story_id (optionnel mais standardisé) haute
templates/prompts/4 Plan d'implémentation.md Exiger en §1 un mapping livrable → skill consommateur : pour chaque script livré, préciser dans quelle commande /gov-* il sera invoqué haute
templates/prompts/5 Plan Review.md Ajouter item « Câblage des nouveaux livrables dans les skills existants : oui/non/reporté » haute
templates/prompts/7a Review Code.md Distinguer « script livré isolément » vs « câblage dans skill » — ne pas noter NON_CONFORME une intégration documentaire absente si le script est fonctionnel moyenne
templates/prompts/8 Revue Acceptabilite.md Ajouter check systématique : tous les artefacts annoncés au plan sont présents sur disque (liste exhaustive) haute
templates/prompts/6c-synthese.md 6c.bis avec grep des points cross-module (reprise PD-298, tracé dans PD-299 mais non appliqué à lui-même) haute

10.2 Améliorations des agents

Agent Amélioration suggérée Justification
config/agents/agent-developer Ajouter check pré-commit : tous les fichiers annoncés dans le prompt agent sont créés E-08 (3 fichiers absents)
config/agents/agent-qa Exiger rejeu des tests shell/Python gov (pas seulement Jest app) TC-NOM-09/11/13/16/18 non rejoués
Reviewer LLM Gate 8 Injecter la différence « script livré » vs « câblé dans workflow » dans le system prompt 5 INV B1-B6 notés NON_CONFORME à tort en Gate 8 v1

10.3 Améliorations du processus

  • Séparer « livraison d'un script gouvernance » et « câblage dans skill » : produire deux stories distinctes, avec la seconde bloquée tant que la première n'a pas un verdict Gate 8 GO/RESERVE et tant que le câblage n'est pas mergé. Pratique systématique proposée : chaque nouvelle primitive gov doit produire en même temps sa modification documentaire dans .claude/commands/*.md.
  • Canoniser la convention source_story_id dans front-matter : soit la rendre obligatoire dans le template besoin (invalidant la story si absente pour une story companion), soit documenter clairement le no-op comme comportement par défaut dans les skills.
  • Automatiser la vérification des artefacts annoncés : /gov-check-docs doit comparer la liste des fichiers annoncés au plan vs les fichiers effectivement produits, en plus de la checklist 12 documents pré-clôture.
  • Rendre le reviewer Gate 8 conscient de la distinction workflow/code : injection d'un système de labels (#code, #workflow, #docs) dans les prompts pour adapter la grille.

11. Enseignements clés

  1. Scripts isolés ≠ workflow câblé — toute nouvelle primitive de gouvernance doit être livrée avec sa modification documentaire dans les skills .claude/commands/*.md. Sans câblage, les invariants restent contournables par omission.
  2. Front-matter canonique obligatoire pour story companion — une convention non documentée (comme source_story_id) entraîne une contournabilité silencieuse. Rendre explicite dans le template besoin ou dans l'injection unifiée PD-295.
  3. Cap déterministe > scoring arithmétique pour critères critiques — PD-299 introduit test_coverage = 6.0 exact forcé si test_file_count = 0. Pattern généralisable à d'autres critères (ex : security = 0 si CVSS ≥ 9.0). À évaluer en gate 8.
  4. Méta-récursion workflow : une story de consolidation doit appliquer ses propres règles à elle-même — PD-299 produit gov-6cbis.sh pour détecter les livraisons cross-module manquantes, mais n'a pas appliqué ce contrôle à sa propre livraison (guard OwnershipGuard pas monté dans ProofDetailScreen). Symétrie à exiger.
  5. Artefacts annoncés au plan = contrat de livraison — comparer systématiquement la liste du plan §1 aux fichiers produits, avec blocage Gate 8 si gap > 0. Pattern sans coût supplémentaire d'audit.

12. Métriques cumulatives (auto-calculées)

Section alimentée automatiquement par l'orchestrateur à partir de governance-metrics.yaml

Métrique Cette story Moyenne projet Tendance
Temps total 6.0h 6.31h
Itérations gates 4 5.3
Écarts totaux 51 ~17
Score convergence moyen 7.67/10 8.41/10

Interprétation : PD-299 poursuit la tendance PD-287/PD-298 (sharing/consolidation) : convergence rapide (4 itérations au lieu de 5.3) et RESERVE acceptée plutôt qu'itération vers GO. Les écarts remontent (51 vs moyenne ~17) parce que PD-299 cumule 3 périmètres (app, gov, backend partiel) et un niveau de contractualisation maximal (22 données D-299-01/22, 18 invariants, 15 erreurs). Le score moyen descend car toutes les gates passent en RESERVE v1 sans v2.