PD-86 — Agent Developer : Module types-config
- Story : PD-86
- Module : types-config
- Agent : agent-developer
- Date : 2026-02-24
- Fichiers modifiés :
src/sensitive-detection/types.ts src/sensitive-detection/config.ts
1. Résumé des travaux
Les fichiers types.ts et config.ts existaient déjà avec une base solide. Le travail a consisté à :
- Renforcer l'immutabilité des interfaces de données critiques avec
readonly et Readonly<> pour empêcher toute mutation accidentelle des résultats d'analyse, verdicts, et settings. - Typer strictement
ERROR_MESSAGES avec un type ErrorMessageKey qui garantit la complétude des messages d'erreur tout en permettant l'indexation par AnalysisStatus via intersection de types. - Vérifier la conformité contractuelle de chaque type par rapport à la spécification, aux invariants et aux interdits du code contract.
Interfaces contractuelles — couverture
| Interface | Fichier | Statut |
Category | types.ts:12 | Conforme — union littérale stricte via as const |
AnalysisStatus | types.ts:27 | Conforme — 7 valeurs exactes |
SensitiveAnalysisResult | types.ts:117-126 | Conforme — tous champs readonly |
SensitiveDetectionSettings | types.ts:62-67 | Conforme — thresholds Readonly |
DocumentSensitiveVerdict | types.ts:73-83 | Conforme — tous champs readonly |
DocumentSensitivePreference | types.ts:89-93 | Conforme — documentId readonly, suppressWarning mutable (toggle) |
ViewerGateDecision | types.ts:101-105 | Conforme — événement en mémoire |
InMemoryHandle | types.ts:53-56 | Conforme — readonly buffer, non sérialisable par convention |
ClassifierInput | types.ts:132-135 | Conforme |
ClassifierOutput | types.ts:137-140 | Conforme — readonly scores |
Invariants vérifiés
| Invariant | Mécanisme de conformité |
| INV-86-04 | Category = (typeof CATEGORIES)[number] — union littérale stricte VIOLENCE \| NUDITE \| SEXUEL \| CHOQUANT, enforcement compile-time |
| Seuils [0.50, 0.95] | THRESHOLD_MIN = 0.5, THRESHOLD_MAX = 0.95 dans config.ts — validation au runtime par les consommateurs |
| InMemoryHandle opaque | Interface readonly sans méthode de sérialisation, commentaire explicite "non sérialisable, non loggable" |
| analysisStatus 7 valeurs | ANALYSIS_STATUSES array as const avec exactement 7 éléments, type dérivé automatiquement |
Interdits vérifiés
| Interdit | Vérification |
| Aucun type ne contient de données visuelles | Aucun champ pixels, embeddings, ocr, image, thumbnail dans aucune interface |
| Aucun type n'expose de chemins de fichiers temporaires | Aucun champ path, filePath, tempFile dans les types exportés |
| Interdiction d'ajouter des catégories hors whitelist | Category est dérivée de CATEGORIES as const — seule modification possible via le tableau source |
3. Décisions architecturales
Decision 1 : readonly profond sur les types de résultats
- decision : Ajout de
readonly sur toutes les propriétés des interfaces immutables (DocumentSensitiveVerdict, SensitiveAnalysisResult, SensitiveDetectionSettings, ClassifierOutput) - rationale : Les résultats d'analyse et verdicts ne doivent jamais être mutés après création ; le compile-time enforcement via
readonly prévient les bugs de mutation accidentelle - alternatives_considered : (1) Laisser les types mutables et compter sur la discipline du code, (2) Utiliser des classes avec getters only
- trade_offs : +Sécurité type-level, +Détection précoce des bugs de mutation ; -Impact mineur sur les consommateurs existants (1 erreur TS dans DetectionLogger.ts, triviale à corriger)
Decision 2 : Type intersection pour ERROR_MESSAGES
- decision :
ERROR_MESSAGES typé comme Readonly<Record<ErrorMessageKey, string>> & Readonly<Partial<Record<AnalysisStatus, string>>> avec type helper ErrorMessageKey - rationale : Garantit la complétude (tous les codes erreur ont un message) tout en permettant l'indexation par
AnalysisStatus (qui inclut SUCCESS) avec fallback ?? dans les consommateurs - alternatives_considered : (1)
Record<string, string> (trop permissif, pas de complétude), (2) as const satisfies (type trop étroit, casse l'indexation par AnalysisStatus) - trade_offs : +Complétude garantie à la compilation, +Compatible avec les consommateurs existants ; -Signature de type légèrement verbeuse
4. Types additionnels (hors contract, utilitaires)
Les types suivants ne sont pas listés dans le code contract mais sont nécessaires aux autres modules :
| Type | Justification |
DocumentType | Discriminant pour dispatch vers ImageAnalyzer/VideoAnalyzer/PdfAnalyzer |
GateAction | Union littérale pour les décisions utilisateur au gate |
SamplingMetadata | Sous-structure de SensitiveAnalysisResult (métadonnées d'échantillonnage) |
UserContext | Contexte utilisateur pour le gate (isMinor, source, profileVersion) |
GateResult | Discriminated union pour le résultat d'évaluation du gate |
ExecutionKey | Clé composite pour idempotence/sérialisation (documentId, modelVersion) |
DetectionInput | DTO d'entrée pour le DetectionService |
ErrorMessageKey | Type helper pour indexation typée de ERROR_MESSAGES |
ERROR_STATUSES | Constante runtime listant les 6 statuts d'erreur |
isErrorStatus() | Fonction helper pour discriminer SUCCESS vs erreurs |
5. Matrice de couverture tests
| Test-ID | Fichier de test | Ligne | Couverture |
| TC-86-14 | src/__tests__/sensitive-detection/types.test.ts | L25-32 | INV-86-04 — whitelist stricte des catégories |
| NON-CONTRACTUAL | src/__tests__/sensitive-detection/types.test.ts | L39-57 | AnalysisStatus (7 valeurs, 6 erreurs, isErrorStatus) |
| NON-CONTRACTUAL | src/__tests__/sensitive-detection/types.test.ts | L63-96 | Config constants (seuils, bornes, timeout, sampling, handle size) |
Résultat : 10/10 tests passent.
6. Impacts hors périmètre identifiés
Impact 1 : DetectionLogger.ts — readonly Category[]
- Fichier :
src/sensitive-detection/services/DetectionLogger.ts (lignes 17, 79) - Erreur :
readonly Category[] (de SensitiveAnalysisResult.detectedCategories) n'est pas assignable à Category[] mutable dans le paramètre de analysisCompleted() - Correction requise : Changer
detectedCategories?: Category[] en detectedCategories?: readonly Category[] dans DetectionLogEntry (L17) et analysisCompleted (L79) - Effort : Trivial (2 lignes)
Impact 2 : ViewerGateModal.test.tsx — erreur préexistante
- Fichier :
src/__tests__/sensitive-detection/ViewerGateModal.test.tsx (ligne 13) - Erreur :
"SENSITIVE" au lieu de "SENSITIVE_DETECTED" dans le type GateResult.reason - Note : Erreur préexistante, non introduite par ce module
7. Hypothèses documentées
-
InMemoryHandle opacité : En TypeScript, l'opacité ne peut être que conventionnelle (pas de sealed/opaque types natifs). Le commentaire "Non sérialisable, non loggable" et les propriétés readonly constituent le maximum d'enforcement possible. La protection effective repose sur DetectionLogger (whitelist) et BufferZeroizer (cleanup).
-
DocumentSensitivePreference.suppressWarning mutable : Contrairement aux autres interfaces, suppressWarning et updatedAt restent mutables car cette entité est un toggle réversible (INV-86-15) — le store doit pouvoir la modifier.
-
Import AnalysisStatus dans config.ts : Ajouté pour typer ErrorMessageKey. Crée une dépendance config.ts → types.ts qui est unidirectionnelle et conforme au plan d'architecture (C2 dépend de C1).