PD-86-specification.md¶
1. Metadata¶
- Story ID : PD-86
- Epic : PD-185 — B2C-MINEURS
- Titre : Détection de contenu sensible (IA locale)
- Projet : ProbatioVault-app (iOS)
- Date : 2026-02-24
- Version : 2.0.0
2. Périmètre¶
2.1 Couvert¶
- Détection locale de sensibilité visuelle à la consultation (viewer) pour :
- Images
- Vidéos (échantillonnage de frames)
- PDF (rendu de pages échantillonnées contractuellement)
- Catégories détectées (whitelist contractuelle) :
VIOLENCENUDITESEXUELCHOQUANT- Affichage d'un écran intermédiaire de consentement avant rendu du contenu quand un risque sensible est détecté.
- Gestion d'une préférence locale "ne plus me prévenir pour ce document", avec garde-fous mineur et politique prudente.
- Cache local minimal des verdicts de classification, non ré-identifiant du contenu visuel.
- Réévaluation locale de
isSensitivelors d'un changement de seuils utilisateur à partir des scores bruts en cache (sans ré-inférence si scores disponibles).
2.2 Non couvert¶
- Aucune modération automatique (suppression, blocage, signalement).
- Aucune qualification légale/morale du contenu.
- Aucune analyse côté serveur / API externe.
- Aucune analyse à l'upload.
- Aucun contrôle parental externe au produit (parental gate côté parent).
- Aucune classification de texte (OCR/NLP).
- Aucune persistance serveur des verdicts.
2.3 Clarifications contractuelles (Q1–Q12)¶
- Q1 (modèle précis) : Décision d'implémentation. Exigence contractuelle : modèle hors ligne avec benchmark documenté (précision/latence/taille) avant mise en production.
- Q2 (ONNX vs CoreML) : Tranché. Référence de livraison iOS : moteur natif iOS hors ligne ; le pipeline de conversion éventuel est hors périmètre de cette spec.
- Q3 (agrégation vidéo) : Tranché. Agrégation contractuelle =
max(score_categorie)sur frames échantillonnées. - Q4 (nombre/stratégie frames) : Tranché. 12 frames par vidéo, stratégie uniforme + inclusion obligatoire des 2 premières secondes.
- Q5 (seuils) : Tranché. Seuil par catégorie (configurable utilisateur) avec valeurs par défaut prudentes :
VIOLENCE: 0.75NUDITE: 0.70SEXUEL: 0.70CHOQUANT: 0.75- Bornes contractuelles :
[0.50, 0.95]. - Garde-fou mineur : si
isMinor=true, les seuils effectifs sont plafonnés aux valeurs par défaut (aucune relaxation possible). - Q6 (cache chiffré) : Tranché. Cache local chiffré obligatoire.
- Q7 (timeout inférence) : Tranché. Timeout contractuel d'inférence fixé à
5000 ms; au-delà :TIMEOUTet comportement prudent obligatoire. - Q8 (thumbnails PDF) : Tranché. Rendu local en mémoire uniquement, sans persistance disque, avec stratégie d'échantillonnage déterministe :
maxPagesAnalyzed = 5- Si
totalPages <= 5: analyser toutes les pages. - Si
totalPages > 5: analyserpage 1,page N, et3pages intérieures uniformément réparties (quartiles), dédupliquées puis complétées par la page intérieure non sélectionnée la plus proche si nécessaire. - Q9 (warm-up) : Tranché. Warm-up déclenché à l'ouverture du coffre, puis lazy fallback au premier document si non prêt.
- Q10 (désactivation utilisateur) : Tranché. Désactivation globale autorisée (pas par catégorie dans PD-86). Les verdicts déjà en cache sont conservés mais non utilisés pour afficher un modal tant que
enabled=false. - Q11 (source
isMinor) : Tranché.isMinorprovient du profil utilisateur authentifié (flag serveur B2C-MINEURS non falsifiable localement). - Q12 (suppressWarning vs sécurité) : Tranché. Politique prudente et règles mineur priment toujours sur
suppressWarning.
3. Modèle de données¶
3.1 Entités locales¶
| Entité | Champs | Contraintes |
|---|---|---|
SensitiveDetectionSettings | enabled: Bool, thresholds: Map<Category, Float>, updatedAt: LocalTimestamp, thresholdsVersion: Int | threshold ∈ [0.50, 0.95] |
DocumentSensitiveVerdict | documentId: String, modelVersion: String, isSensitive: Bool, detectedCategories: Category[], rawScores: Map<Category, Float>, roundedScores: Map<Category, Float(2d)>, analyzedAt: LocalTimestamp, analysisStatus: Enum, thresholdsVersionAtDecision: Int | Unicité (documentId, modelVersion) |
DocumentSensitivePreference | documentId: String, suppressWarning: Bool, updatedAt: LocalTimestamp | Portée strictement locale |
ViewerGateDecision (événement en mémoire) | documentId, decision: SHOW_ANYWAY|KEEP_HIDDEN|CANCEL, requiresExplicitConfirmation: Bool | Non persistant, requiresExplicitConfirmation = isMinor && isSensitive |
3.2 Types¶
Category:VIOLENCE | NUDITE | SEXUEL | CHOQUANTanalysisStatus:SUCCESS | TIMEOUT | MODEL_UNAVAILABLE | UNSUPPORTED_FORMAT | CORRUPTED_INPUT | OUT_OF_MEMORY | INTERNAL_ERRORInMemoryHandle: handle opaque vers buffer mémoire déchiffré, non sérialisable, non loggable, taille maximale contractuelle64 MBpar artefact d'analyse ; si dépassement ->OUT_OF_MEMORY.- Décision
isSensitive: - calculée avant arrondi sur
rawScores, isSensitive = truesi au moins unrawScore[categorie] >= seuil_effectif[categorie],roundedScoresservent uniquement à la persistance et à l'observabilité locale.
3.3 Relations¶
SensitiveDetectionSettings(1) influence l'évaluation deDocumentSensitiveVerdict(N).DocumentSensitivePreference(0..1) pardocumentIdsurcharge l'affichage d'alerte pour ce document, sous réserve des règles de priorité sécurité/mineur.- Aucun lien serveur, aucune réplication cloud.
4. Règles métier¶
- INV-86-01 : Toute classification est locale au device ; transmission réseau de contenu en clair interdite.
- INV-86-02 : La détection n'est exécutée qu'au viewer ; jamais à l'import/upload.
- INV-86-03 : Le fichier original n'est jamais modifié ; hash et scellement probatoire restent inchangés.
- INV-86-04 : Seules les catégories whitelistées (
VIOLENCE,NUDITE,SEXUEL,CHOQUANT) peuvent produire un flag sensible. - INV-86-05 : Si
analysisStatus=SUCCESSetisSensitive=true, l'écran intermédiaire de consentement est obligatoire avant affichage. - INV-86-06 : Pour mineur, l'action "Afficher quand même" nécessite confirmation explicite additionnelle.
- INV-86-07 : Le cache ne stocke jamais de média dérivé (images, frames, thumbnails), embeddings, OCR, texte extrait.
- INV-86-08 : Le cache local des verdicts est chiffré.
- INV-86-09 : En cas de
TIMEOUT,MODEL_UNAVAILABLE,UNSUPPORTED_FORMAT,CORRUPTED_INPUT,OUT_OF_MEMORYouINTERNAL_ERROR, politique prudente : avertir avant affichage ; cette politique prime toujours sursuppressWarning. - INV-86-10 : Zeroization best-effort des buffers visuels en fin de traitement, y compris en cas d'échec/annulation, via parcours
try/finallysur toutes les allocations d'analyse. - INV-86-11 : Aucune écriture de fichier temporaire en clair durant le pipeline d'analyse.
- INV-86-12 : Les logs ne contiennent ni pixel data, ni miniatures, ni métadonnées reconstituables du contenu, selon politique de whitelist stricte.
- INV-86-13 : Le résultat de classification est invalidé si
modelVersionchange. - INV-86-14 : Le paramètre utilisateur
enabled=falsedésactive toute nouvelle classification, sans supprimer les preuves ni modifier les fichiers. - INV-86-15 : La préférence "ne plus me prévenir pour ce document" est réversible à tout moment par l'utilisateur.
- INV-86-16 : Si
isMinor=true,suppressWarningest ignoré ; les obligations de gate mineur restent appliquées. - INV-86-17 : Si
isMinor=true, les seuils effectifs ne peuvent pas être plus permissifs que les seuils par défaut (pas de relaxation). - INV-86-18 : Si
enabled=false, le viewer n'affiche aucun modal de détection (même si verdict sensible en cache) et rend directement le contenu. - INV-86-19 : Le module de détection est idempotent par
(documentId, modelVersion)et serialize les demandes concurrentes pour une même clé (mutex/PQueue mono-clé). - INV-86-20 : En cas de changement de seuils utilisateur,
isSensitiveest recalculé localement à partir derawScoresen cache sans ré-inférence ; sirawScoresindisponibles, reclassification requise.
4.1 Transitions d'état et transitions retour¶
| Domaine | Transition | Statut | Comportement retour |
|---|---|---|---|
| Détection globale | ENABLED -> DISABLED | Autorisée | Arrêt des nouvelles analyses ; modals désactivés ; aucun impact sur fichiers/probatoire |
| Détection globale | DISABLED -> ENABLED | Autorisée | Reprise immédiate des analyses au viewer |
| Préférence document | WARN -> SUPPRESSED | Autorisée | Plus d'écran intermédiaire pour ce document, sauf règles mineur/politique prudente |
| Préférence document | SUPPRESSED -> WARN | Autorisée | Avertissement réactivé immédiatement |
| Verdict analyse | UNANALYZED -> ANALYZED | Autorisée | Verdict cacheable |
| Verdict analyse | ANALYZED -> UNANALYZED (changement modèle) | Autorisée | Invalidation cache, reclassification requise |
| Décision sensible | DECIDED@thresholdsVx -> DECIDED@thresholdsVy (changement seuils) | Autorisée | Réévaluation isSensitive depuis rawScores sans ré-inférence |
| Affichage | HIDDEN -> SHOWN | Autorisée après consentement si gate actif | Affichage explicite contrôlé |
| Affichage | SHOWN -> HIDDEN | Autorisée | Retour immédiat au masquage |
4.2 SLA temporels¶
- Timeout d'inférence contractuel :
5000 ms(au-delà ->TIMEOUT). - Budget performance cible (non bloquant fonctionnel) défini en §8.
5. Interfaces¶
5.1 Contrat du module de détection locale¶
Entrées¶
documentId: StringdocumentType: IMAGE | VIDEO | PDFdecryptedContentHandle: InMemoryHandlesettingsSnapshot: SensitiveDetectionSettingscontext: { isMinor: Bool, isMinorSource: AUTH_PROFILE_SERVER_FLAG, profileVersion: String }executionKey: { documentId: String, modelVersion: String }(pour idempotence/serialization concurrente)
Sorties¶
SensitiveAnalysisResult:status: analysisStatusisSensitive: BooldetectedCategories: Category[]rawScores: Map<Category, Float>roundedScores: Map<Category, Float(2d)>modelVersion: StringdurationMs: IntsamplingMetadata:videoFramesAnalyzed: IntpdfPagesAnalyzed: IntpdfPageIndexes: Int[]
Erreurs contractuelles¶
MODEL_UNAVAILABLEUNSUPPORTED_FORMATCORRUPTED_INPUTTIMEOUTOUT_OF_MEMORYINTERNAL_ERROR
5.2 Contrat du gate viewer¶
Règles évaluées dans cet ordre (ordre contractuel de précédence) :
- Si
enabled=false-> pas de modal de détection, rendu direct. - Si
status in {TIMEOUT, MODEL_UNAVAILABLE, UNSUPPORTED_FORMAT, CORRUPTED_INPUT, OUT_OF_MEMORY, INTERNAL_ERROR}-> modal prudent obligatoire. - Si
status=SUCCESS && isSensitive=true-> modal obligatoire. - Si
isMinor=true->suppressWarningignoré. - Si
isMinor=falseetstatus=SUCCESS && isSensitive=trueetsuppressWarning=true-> modal omis pour ce document. - Si utilisateur choisit
KEEP_HIDDENouCANCEL-> aucun rendu du contenu.
Règle explicite : - requiresExplicitConfirmation = isMinor && isSensitive
6. Critères d'acceptation¶
- CA-86-01 : L'ouverture d'une image sensible détectée affiche un modal avant tout rendu du média.
- CA-86-02 : L'ouverture d'une vidéo sensible détectée (agrégation
max) affiche un modal avant tout rendu. - CA-86-03 : L'ouverture d'un PDF sensible détecté affiche un modal avant toute page.
- CA-86-04 : Le système ne transmet aucun contenu visuel ni score à un endpoint distant.
- CA-86-05 : Le hash probatoire du document reste identique avant/après classification.
- CA-86-06 : Le cache local contient uniquement les champs autorisés (
documentId,isSensitive, catégories,rawScores, scores arrondis,modelVersion,analyzedAt,analysisStatus,thresholdsVersionAtDecision). - CA-86-07 : Aucun fichier temporaire média n'est présent sur disque après classification réussie ou échouée.
- CA-86-08 : En cas de
TIMEOUT(>5000 ms), le modal "contenu potentiellement sensible/non analysé" est affiché. - CA-86-09 : En cas de modèle absent du bundle/runtime, le flux reste fonctionnel avec modal prudent.
- CA-86-10 : La désactivation globale utilisateur empêche toute nouvelle classification tant qu'elle reste active.
- CA-86-11 : La préférence "ne plus me prévenir" est appliquée par document et réversible, sous contraintes de précédence sécurité/mineur.
- CA-86-12 : À changement de
modelVersion, un document précédemment classifié est reclassifié à la prochaine consultation. - CA-86-13 : Les buffers visuels alloués par le pipeline d'analyse sont libérés/zeroized en best-effort via
try/finallysur succès, erreur, timeout et annulation. - CA-86-14 : Si
isMinor=true,suppressWarning=truene supprime pas le modal et la confirmation additionnelle reste obligatoire. - CA-86-15 : Si
isMinor=true, toute tentative de seuil au-dessus des valeurs par défaut est refusée ou clampée aux valeurs par défaut. - CA-86-16 : Un changement de seuils utilisateur réévalue
isSensitiveà partir derawScorescache sans ré-inférence. - CA-86-17 : Le module serialize les classifications concurrentes pour une même clé
(documentId, modelVersion)sans doublon persistant. - CA-86-18 : La stratégie d'échantillonnage PDF est déterministe (
max 5 pages, première + dernière + intérieures uniformes). - CA-86-19 : Si
enabled=false, un document déjà classé sensible est affiché sans modal de détection.
7. Sécurité¶
- Architecture zero-knowledge stricte : traitement local uniquement, aucun appel d'analyse externe.
isMinorest un attribut de profil authentifié côté serveur (B2C-MINEURS), non modifiable localement.- Zeroization best-effort obligatoire des buffers mémoire de rendu/analyse en fin de flux (succès, erreur, timeout, annulation) avec obligation de
try/finally. - Interdiction de persister des dérivés visuels (frames, thumbnails, previews non chiffrées).
- Interdiction de logs contenant données visuelles ou métadonnées reconstituables.
- Politique de logging (INV-86-12) :
- Whitelist autorisée :
eventName,documentId,analysisStatus,durationMs,modelVersion,detectedCategories,thresholdsVersion,errorCode. - Blacklist interdite : bytes média, chemins de fichiers temporaires, miniatures, dimensions exactes corrélables, EXIF, noms de fichiers source,
InMemoryHandledump. - Contrôle des mécanismes iOS pouvant générer des aperçus persistants non maîtrisés : App Switcher snapshots, Spotlight indexing, QuickLook previews.
- Le cache de verdict doit être chiffré localement et limité au minimum nécessaire.
8. Performance¶
- Budget d'analyse cible par ouverture :
<= 700 msau P95 sur iPhone 12 (A14, iOS 16.0+), hors décodage viewer incompressible. - Timeout fonctionnel distinct :
5000 ms(cf. §9), non confondu avec l'objectif performance. - Exécution en arrière-plan ; blocage UI prolongé interdit.
- Warm-up du moteur au contexte "ouverture du coffre" (fallback lazy au premier document).
- Downscaling agressif autorisé et attendu pour l'analyse.
- Vidéo : échantillonnage 12 frames max (uniforme + début), sans décodage intégral.
- PDF : échantillonnage déterministe
max 5 pages(première + dernière + 3 intérieures uniformes), rendu mémoire uniquement, zéro persistance disque.
8bis. Diagrammes Mermaid¶
8bis.1 Diagramme d'états — Cycle de vie du verdict de détection¶
Ce diagramme couvre les transitions d'état du verdict d'analyse et de la décision sensible (§4.1), incluant l'invalidation par changement de modèle (INV-86-13) et la réévaluation par changement de seuils (INV-86-20).
stateDiagram-v2
[*] --> UNANALYZED : Document ouvert au viewer
UNANALYZED --> ANALYZING : enabled=true (INV-86-02)
ANALYZING --> SUCCESS : Inférence < 5000ms
ANALYZING --> TIMEOUT : durationMs > 5000ms (INV-86-09)
ANALYZING --> MODEL_UNAVAILABLE : Modèle absent (INV-86-09)
ANALYZING --> CORRUPTED_INPUT : Fichier corrompu (INV-86-09)
ANALYZING --> UNSUPPORTED_FORMAT : Format non supporté (INV-86-09)
ANALYZING --> OUT_OF_MEMORY : Handle > 64MB (INV-86-09)
ANALYZING --> INTERNAL_ERROR : Erreur inattendue (INV-86-09)
SUCCESS --> SENSITIVE : isSensitive=true (rawScore >= seuil)
SUCCESS --> NOT_SENSITIVE : isSensitive=false
SENSITIVE --> RE_EVALUATED : Changement seuils (INV-86-20)
NOT_SENSITIVE --> RE_EVALUATED : Changement seuils (INV-86-20)
RE_EVALUATED --> SENSITIVE : rawScores recalculés → sensible
RE_EVALUATED --> NOT_SENSITIVE : rawScores recalculés → non sensible
SENSITIVE --> UNANALYZED : modelVersion change (INV-86-13)
NOT_SENSITIVE --> UNANALYZED : modelVersion change (INV-86-13)
state SENSITIVE {
[*] --> GATE_ACTIVE
GATE_ACTIVE --> SHOWN : Consentement utilisateur (INV-86-05)
GATE_ACTIVE --> HIDDEN : KEEP_HIDDEN ou CANCEL
SHOWN --> HIDDEN : Retour masquage
}
note right of TIMEOUT : Politique prudente :\nmodal obligatoire\n(prime sur suppressWarning)
note right of RE_EVALUATED : Sans ré-inférence :\nrecalcul depuis rawScores cache 8bis.2 Diagramme d'états — Préférences et gardes mineur¶
Ce diagramme couvre l'interaction entre la préférence document (suppressWarning), le flag mineur et la détection globale (INV-86-14, INV-86-16, INV-86-17, INV-86-18).
stateDiagram-v2
state "Detection Settings" as DS {
ENABLED --> DISABLED : Utilisateur désactive (INV-86-14)
DISABLED --> ENABLED : Utilisateur réactive
}
state "Document Preference" as DP {
WARN --> SUPPRESSED : suppressWarning=true (INV-86-15)
SUPPRESSED --> WARN : Utilisateur réactive alerte
}
state "Gate Viewer Decision" as GV {
state eval <<choice>>
[*] --> eval
eval --> NO_MODAL : enabled=false (INV-86-18)
eval --> MODAL_PRUDENT : status ∈ erreurs (INV-86-09)
eval --> MODAL_SENSIBLE : isSensitive=true (INV-86-05)
MODAL_SENSIBLE --> MODAL_SKIP : !isMinor && suppressWarning (§5.2 règle 5)
MODAL_SENSIBLE --> MODAL_CONFIRM : isMinor (INV-86-06, INV-86-16)
state "Décision utilisateur" as DU {
SHOW_ANYWAY
KEEP_HIDDEN
CANCEL
}
}
note right of MODAL_CONFIRM : isMinor=true :\nsuppressWarning ignoré\nseuils plafonnés (INV-86-17) 8bis.3 Diagramme de séquence — Flux nominal d'analyse au viewer¶
Ce diagramme détaille le flux complet depuis l'ouverture d'un document jusqu'à l'affichage, incluant le warm-up (Q9), le cache (INV-86-08), la sérialisation concurrente (INV-86-19), la zeroization (INV-86-10) et la gate viewer (§5.2).
sequenceDiagram
participant U as Utilisateur
participant V as Viewer
participant G as Gate Viewer (§5.2)
participant C as Cache Chiffré (INV-86-08)
participant D as Detection Module (§5.1)
participant M as Modèle IA Local (INV-86-01)
Note over V,M: Warm-up au démarrage du coffre (Q9)
V->>M: Warm-up modèle (lazy fallback si non prêt)
U->>V: Ouvre document (documentId, type)
V->>G: Évalue précédence (§5.2)
alt enabled=false (INV-86-18)
G-->>V: Pas de modal → rendu direct
V-->>U: Affiche contenu
else enabled=true
V->>C: Lookup (documentId, modelVersion)
alt Cache hit & modelVersion identique
C-->>V: Verdict existant
else Cache miss ou modelVersion différent (INV-86-13)
V->>D: Demande analyse (executionKey)
Note over D: Mutex mono-clé (INV-86-19)
D->>D: Déchiffre handle mémoire (InMemoryHandle ≤ 64MB)
alt Image
D->>M: Inférence image (downscaled)
else Vidéo
D->>D: Échantillonne 12 frames (uniforme + 2s début, Q4)
D->>M: Inférence par frame
D->>D: Agrégation max(score) par catégorie (Q3)
else PDF
D->>D: Échantillonne ≤5 pages déterministe (Q8)
D->>M: Inférence par page (rendu mémoire, INV-86-11)
D->>D: Agrégation max(score) par catégorie
end
M-->>D: rawScores par catégorie (INV-86-04)
alt durationMs > 5000ms
D-->>V: status=TIMEOUT (INV-86-09)
else Succès
D->>D: isSensitive = rawScore ≥ seuil_effectif (§3.2)
D->>D: roundedScores = arrondi 2d (persistance)
D->>C: Persiste verdict chiffré (INV-86-07, INV-86-08)
D-->>V: SensitiveAnalysisResult
end
D->>D: Zeroization buffers (try/finally, INV-86-10)
end
V->>G: Applique règles de précédence (§5.2)
alt status ∈ erreurs
G-->>V: Modal prudent obligatoire (INV-86-09)
else isSensitive=true
alt isMinor=true (INV-86-16)
G-->>V: Modal + confirmation explicite (INV-86-06)
else !isMinor && suppressWarning=true
G-->>V: Modal omis (§5.2 règle 5)
else !isMinor && suppressWarning=false
G-->>V: Modal standard (INV-86-05)
end
else isSensitive=false
G-->>V: Rendu direct
end
U->>V: Décision (SHOW_ANYWAY / KEEP_HIDDEN / CANCEL)
alt SHOW_ANYWAY
V-->>U: Affiche contenu
else KEEP_HIDDEN / CANCEL
V-->>U: Contenu non rendu
end
end 9. Gestion d'erreurs¶
| Cas d'erreur | Code | Comportement utilisateur | Persistance |
|---|---|---|---|
| Modèle absent/inaccessible | MODEL_UNAVAILABLE | Modal prudent, possibilité d'afficher quand même | Statut erreur horodaté |
| Image/PDF/vidéo corrompu(e) | CORRUPTED_INPUT | Message non culpabilisant + modal prudent | Statut erreur horodaté |
| Format non supporté | UNSUPPORTED_FORMAT | Message clair "format non pris en charge" + modal prudent ; pas de crash | Statut erreur horodaté |
Timeout inférence (durationMs > 5000) | TIMEOUT | Modal prudent "non analysé" | Statut erreur horodaté |
| Dépassement mémoire handle | OUT_OF_MEMORY | Dégradation contrôlée + modal prudent | Statut erreur horodaté |
| Erreur interne inattendue | INTERNAL_ERROR | Dégradation contrôlée, contenu masqué par défaut | Statut erreur horodaté |
Règles communes : - Aucune erreur ne doit provoquer de crash du viewer. - Aucune erreur ne doit déclencher d'envoi réseau de contenu. - Le mode dégradé conserve le contrôle utilisateur ("Afficher quand même" / "Garder masqué"). - La politique prudente prime sur suppressWarning.
10. Contraintes techniques¶
- Domaine : iOS (Swift/SwiftUI), traitement visuel local hors ligne.
- Modèle compatible exécution offline sur device, versionné, et identifiable (
modelVersion). - Taille du composant modèle compatible distribution mobile (contrainte bundle), avec validation perf sur devices cibles.
- Compatibilité minimale iOS : iOS 16.0.
- Mécanismes iOS à contrôler explicitement : App Switcher snapshot redaction, exclusion Spotlight, désactivation des previews QuickLook non maîtrisées.
- Concurrence : sérialisation mono-clé
(documentId, modelVersion)via mutex/PQueue ; écriture idempotente. - Stratégie DDL : Non applicable (aucune base serveur modifiée).
- Atomicité DB+queue : Non applicable (aucun flux serveur asynchrone).