PD-32 — Confrontation Gate AMBIGUITY (Step 5) — v2¶
1. Contexte¶
- Story ID : PD-32
- Gate : AMBIGUITY (Review Plan d'implementation)
- Date : 2026-02-05
- Version : 2 (après corrections)
- Corrections par : Claude (orchestrateur)
2. Rappel des écarts v1¶
| ID | Gravité | Description |
|---|---|---|
| DIV-01 | BLOQUANT | Champ plan exposé dans GET |
| DIV-02 | BLOQUANT | Mécanisme test accès croisé non décrit |
| DIV-03 | MAJEUR | Mapping ERR-32-* non contractualisé |
| DIV-04 | MAJEUR | Seuil rate limiting non documenté |
| DIV-08 | MAJEUR | Invariant supplémentaire user-module |
| DIV-09 | MAJEUR | Code contract INV-32-08 incomplet |
| DIV-06 | MINEUR | Serialisation non contractualisée |
| DIV-07 | MINEUR | AppModule non contractualisé |
3. Vérification des corrections¶
DIV-01 : Champ plan exposé dans GET — ✅ CORRIGɶ
Avant : - §2.1 step 6.1 : SELECT name, email, plan, avatar_url, preferences - §2.1 step 8 : { name, email, plan, avatar_url, preferences }
Après : - §2.1 step 6.1 : SELECT name, email, avatar_url, preferences - §2.1 step 8 : { name, email, avatar_url, preferences } - §2.2 step 9 : { name, email, avatar_url, preferences }
Verdict : Conforme à CA-32-04 (pas de champ protégé en sortie)
DIV-02 : Mécanisme test accès croisé — ✅ CORRIGɶ
Avant : Aucune description du mécanisme de test
Après : Note ajoutée après §5 :
"Les tests TC-ERR-03/04 vérifient l'isolation RLS en créant deux utilisateurs U1 et U2 en base, puis en exécutant une requête avec le contexte RLS de U1 tout en vérifiant que les données de U2 ne sont jamais exposées ni modifiées. Le test contrôle l'état de U2 avant/après via SELECT direct."
Verdict : Mécanisme explicite et testable
DIV-03 : Mapping ERR-32-* — ✅ CORRIGɶ
Avant : "Si le filter global ne produit pas le format attendu, créer..."
Après (§6.3) : "Un ExceptionFilter (global ou dédié UserProfileExceptionFilter) DOIT mapper les exceptions vers le format contractuel {error: ERR-32-*, message}. La vérification de ce mapping fait partie des tests TC-INV-02."
Verdict : Formulation contractuelle affirmative
DIV-04 : Seuil rate limiting — ✅ CORRIGɶ
Avant : "RateLimitGuard | Rate limiting global"
Après (§1.3) : "RateLimitGuard | Rate limiting global (configuration globale existante : src/config/rate-limit.config.ts. Pour les tests TC-ERR-08, utiliser l'environnement de test avec seuil réduit configurable.)"
Verdict : Référence config et testabilité documentées
DIV-08 : Invariant supplémentaire user-module — ✅ CORRIGɶ
Avant : invariants: ["Le module DOIT exporter UserProfileService..."]
Après : invariants: []
Verdict : Invariant non-spec retiré
DIV-09 : Code contract INV-32-08 — ✅ CORRIGɶ
Avant : "GET DOIT retourner UserProfileResponseDto (name, email, avatar_url)"
Après : "GET DOIT retourner UserProfileResponseDto (name, email, avatar_url, preferences)"
Verdict : Aligné avec spec §5 F-32-01 step 4
DIV-06 : Serialisation — ✅ CORRIGɶ
Après (§9.3) : "Oublier de vérifier que ClassSerializerInterceptor est appliqué globalement"
Verdict : Piège documenté
DIV-07 : AppModule — ✅ CORRIGɶ
Après (code-contracts.yaml header) : "# Note technique: AppModule est exclu des code contracts (modification triviale d'import de module)."
Verdict : Exclusion explicite documentée
4. Écart identifié en review v2¶
DIV-10 : Incohérence terminologique §2.2 étape 3.1 — ✅ CORRIGɶ
Source : Review ChatGPT v2 Description : Le flux §2.2 indiquait "whitelist: true rejecte" alors que le mécanisme correct est forbidNonWhitelisted: true.
Correction appliquée : - Avant : 3.1 Si champ protégé présent (whitelist: true rejecte) - Après : 3.1 Si champ protégé présent (forbidNonWhitelisted: true rejecte)
Verdict : Aligné avec INV-32-06 et le mapping §3/§4.
5. Bilan v2¶
| Gravité | v1 | v2 |
|---|---|---|
| BLOQUANT | 2 | 0 |
| MAJEUR | 4 | 0 |
| MINEUR | 2 | 0 |
6. Verdict confrontation v2¶
Tous les écarts identifiés en v1 ont été corrigés. Le plan d'implémentation et les code contracts sont maintenant conformes à la spécification.
Statut : ✅ CONFORME