Aller au contenu

PD-86 — Agent Developer : Module types-config

Metadata

  • 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é à :

  1. 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.
  2. 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.
  3. Vérifier la conformité contractuelle de chaque type par rapport à la spécification, aux invariants et aux interdits du code contract.

2. Conformité au 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

  1. 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).

  2. 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.

  3. 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).