Aller au contenu

PD-86 — Rapport de confrontation (Etape 5)

Ce rapport est produit par l'orchestrateur Claude avant la gate PMO 5 (AMBIGUITY). Il confronte la specification, les tests et le plan d'implementation + code contracts pour identifier convergences, divergences et zones d'ombre.

1. Sources confrontees

  • PD-86-specification.md (Etape 1 — v2.0.0, 2026-02-24)
  • PD-86-tests.md (Etape 2 — TC-86-01 a TC-86-34, SEC/PERF/ERR/UX)
  • PD-86-plan.md (Etape 4 — v1.0.0, 2026-02-24)
  • PD-86-code-contracts.yaml (Etape 4 — v1.0.0, 2026-02-24)
  • Contexte : verdict Gate 3 v2 = RESERVE (7.75/10), ecarts ECT-v2-01 a ECT-v2-11 identifies

2. Convergences

2.1 Architecture locale-only et zero-knowledge

Spec (INV-86-01, CA-86-04, S7), tests (TC-86-04, TC-86-18/19/20, SEC-86-01) et plan (C21 NetworkGuard, architecture offline-only, mapping INV-86-01) sont strictement alignes sur l'interdiction de toute transmission reseau de contenu, scores ou metadonnees d'analyse. Le code contract classification-engine renforce en interdisant tout import fetch/axios/XMLHttpRequest. Le plan va au-dela avec NetworkGuard actif en dev/test — approche conservatrice coherente.

2.2 Detection uniquement au viewer

Spec (INV-86-02), tests (TC-86-17) et plan (C22, hook useSensitiveDetection exclusivement dans MediaPreviewScreen) sont alignes. Aucune ambiguite.

2.3 Integrite probatoire

Spec (INV-86-03, CA-86-05), tests (TC-86-05) et plan (C14 BufferZeroizer, pipeline in-memory) convergent : le fichier source n'est jamais modifie, hash probatoire inchange. Le code contract classification-engine interdit toute ecriture sur le filesystem.

2.4 Whitelist des categories

Spec (INV-86-04 : VIOLENCE | NUDITE | SEXUEL | CHOQUANT), tests (TC-86-14), plan (C1 types.ts, C13 ThresholdEvaluator) et code contract types-config sont parfaitement alignes. Enforcement compile-time via union litterale TypeScript.

2.5 Gate de consentement (image, video, PDF)

Spec (INV-86-05, CA-86-01/02/03), tests (TC-86-01/02/03) et plan (C16 ViewerGate R3, C17 ViewerGateModal) convergent : modal obligatoire avant tout rendu si status=SUCCESS && isSensitive=true.

2.6 Politique prudente sur erreurs

Les 6 codes d'erreur (spec S9, INV-86-09), les 6 tests (TC-86-08/09/18/19/20 + ERR-86-01..06) et le plan (C16 ViewerGate R2, S6 DetectionService) sont alignes. Le plan documente explicitement les messages UI par code d'erreur — coherent avec la spec.

2.7 Cache local chiffre, sans derives visuels

Spec (INV-86-07, INV-86-08, CA-86-06), tests (TC-86-06, SEC-86-02/03) et plan (C10/C11, AES-256-GCM) convergent. Le code contract store-cache renforce avec interdiction explicite de tout stockage de pixels/frames/thumbnails/embeddings/OCR.

2.8 Idempotence et serialisation concurrente

Spec (INV-86-19, CA-86-17), tests (TC-86-31/32) et plan (C15 DetectionService, mutex par (documentId, modelVersion)) sont alignes. L'unicite de persistance et l'idempotence d'ecriture sont couvertes.

2.9 Regles mineur (confirmation, suppressWarning, seuils)

Spec (INV-86-06/16/17, CA-86-14/15), tests (TC-86-13/27/28/30) et plan (C16 R4, C18 MinorConfirmation, C13 clamp) convergent sur les trois axes mineur : confirmation additionnelle, suppressWarning ignore, seuils plafonnes aux defauts. Exception : voir DIV-01.

2.10 Sampling video et PDF

Spec (Q3/Q4/Q8), tests (TC-86-02/24/25/26, PERF-86-04/05) et plan (C7/C8/C12 SamplingStrategy) convergent : 12 frames video (uniforme + 2 premieres secondes, agregation max), 5 pages PDF max (premiere + derniere + 3 interieures uniformes), rendu memoire uniquement.

2.11 Zeroization best-effort

Spec (INV-86-10, CA-86-13), tests (TC-86-16, SEC-86-04) et plan (C14 BufferZeroizer try/finally) convergent. Le plan documente la limitation runtime JS/GC comme dette technique — coherent avec le signalement ST-86-01 des tests.

2.12 Logs whitelist/blacklist

Spec (INV-86-12, S7), tests (TC-86-15, SEC-86-05) et plan (C19 DetectionLogger) convergent sur la whitelist exacte de champs autorisables. Le code contract security reproduit fidelement la whitelist spec.

2.13 Invalidation par modelVersion

Spec (INV-86-13, CA-86-12), tests (TC-86-12) et plan (C11 verdictCache.get() compare modelVersion) sont alignes.

2.14 Desactivation globale

Spec (INV-86-14/18, CA-86-10/19), tests (TC-86-10/29) et plan (C22 court-circuit, C16 R1) convergent. Le plan adresse explicitement ECT-v2-01 de Gate 3 : enabled=false = skip complet, y compris pour verdicts sensibles en cache.

2.15 Reevaluation seuils sans re-inference

Spec (INV-86-20, CA-86-16), tests (TC-86-30) et plan (C13 ThresholdEvaluator.reevaluate) convergent. Le chemin negatif (rawScores absents -> reclassification) est couvert dans le plan (S2.5 etape c) — adresse la zone d'ombre signalee en Gate 3.

2.16 Warm-up moteur

Spec (Q9, S8), tests (TC-86-22, PERF-86-02) et plan (C9 EngineWarmup) convergent : warm-up a l'ouverture du coffre, lazy fallback au premier document.

2.17 Checklist INV/CA complete

Le plan (S12) fournit un mapping complet 20/20 INV et 19/19 CA vers taches et tests. Aucune ligne vide. La matrice de tests (S1.1, S1.2) couvre 20/20 INV et 19/19 CA. Convergence confirmee.

2.18 Ecarts Gate 3 adresses

Le plan (S9 "Ecarts Gate 3 adresses") documente les 11 ecarts ECT-v2 identifies lors de la confrontation Gate 3 et indique pour chacun le mecanisme d'adressage. C'est un point de convergence notable entre le plan et les attentes formulees en Gate 3.

3. Divergences

Les conflits ne doivent JAMAIS etre lisses. Chaque divergence est rendue visible.

  • DIV-01 : Extension de la formule requiresExplicitConfirmation au-dela de la spec.
  • Source A (Spec S5.2, regle explicite) : requiresExplicitConfirmation = isMinor && isSensitive
  • Source B (Plan S3 INV-86-06, S6 regle transverse #7) : requiresExplicitConfirmation = isMinor && (isSensitive || isErrorStatus)
  • Constat : Le plan etend la formule pour couvrir aussi les modals prudents en cas d'erreur pour les mineurs. C'est un comportement additionnel non specifie.
  • Impact : Ecart contractuel — le plan introduit une protection supplementaire non tracee dans la spec. Si cette extension est souhaitee, la spec doit etre mise a jour pour acter ce comportement. Sinon, l'implementation ne doit pas l'inclure.

  • DIV-02 : Politique TTL 90 jours absente de la spec.

  • Source A (Spec) : Aucune mention de TTL ou de politique de purge du cache de verdicts. Le cache est decrit comme "local minimal" (INV-86-08) et chiffre, mais sans duree de vie.
  • Source B (Plan S7) : Introduit une politique TTL de 90 jours par defaut avec purge au deverrouillage du coffre, en reponse a ECT-v2-05 de Gate 3.
  • Constat : Le plan ajoute un mecanisme de lifecycle non specifie. La spec ne contredit pas cette politique mais ne la mandate pas non plus.
  • Impact : Si le TTL est contractuel, il doit apparaitre dans la spec comme invariant ou contrainte explicite. Sinon, c'est un detail d'implementation acceptable — mais non testable contractuellement.

  • DIV-03 : rawScores dans la blacklist logging du plan mais pas de la spec.

  • Source A (Spec S7, whitelist logging) : Liste des champs autorises inclut rawScores implicitement via CA-86-06 qui autorise rawScores dans le cache. La whitelist de logging ne mentionne pas explicitement rawScores dans les champs autorises, mais ne les interdit pas explicitement non plus.
  • Source B (Plan S7 Journalisation, blacklist) : Le plan ajoute explicitement rawScores a la blacklist des logs : "rawScores (scores bruts = data sensible potentielle)".
  • Source C (Code contract security) : La whitelist INV-86-12 reproduite dans le code contract n'inclut pas rawScores dans les champs autorises.
  • Constat : La spec autorise rawScores dans le cache (CA-86-06) mais sa whitelist de logging (INV-86-12) les omet silencieusement. Le plan prend la position conservatrice d'interdire leur logging. Pas de contradiction stricte, mais un durcissement non contractualise.
  • Impact : Mineur. Le durcissement est defense-in-depth. Si les rawScores s'averent necessaires au debugging, il faudrait mettre a jour la spec pour clarifier leur statut de loggabilite.

  • DIV-04 : Invariants supplementaires dans les code contracts non traces en spec.

  • Source A (Spec) : 20 invariants INV-86-01 a INV-86-20.
  • Source B (Code contracts) : Ajoutent des invariants hors spec, notamment :
    • classification-engine : "Le classifieur est stateless — aucune persistance interne"
    • store-cache : "Politique TTL: 90 jours par defaut, purge au deverrouillage du coffre"
    • sampling-strategy : "Aucune source d'aleatoire (Math.random, crypto.random) — determinisme strict"
    • media-analyzers : "Warm-up declenche a l'ouverture du coffre, lazy fallback au premier document"
  • Constat : Ces invariants sont coherents avec l'esprit de la spec mais ne sont pas traces dans le referentiel contractuel (INV-86-XX).
  • Impact : Moyen. L'ajout d'invariants non traces dilue la frontiere entre exigences contractuelles et decisions d'implementation. Les invariants supplementaires devraient etre distingues (ex: IMPL-86-XX) ou integres a la spec si contractuels.

  • DIV-05 : Niveau de test TC-86-05 — "Unit" dans le plan vs nature du test.

  • Source A (Tests TC-86-05) : "Verifier que l'analyse ne modifie jamais le fichier original" — necessite ouverture, analyse, puis verification hash.
  • Source B (Plan S5) : Classifie TC-86-05 comme "Unit".
  • Constat : Un test qui ouvre un document, execute une analyse complete puis verifie l'integrite hash est plus proche d'un test d'integration que d'un test unitaire.
  • Impact : Mineur — erreur de classification du niveau de test, pas de consequence fonctionnelle.

  • DIV-06 : Stub isMinor retourne false — incompatibilite avec TC-86-34.

  • Source A (Tests TC-86-34) : "Verifier que isMinor provient du profil authentifie serveur et ne peut pas etre override localement."
  • Source B (Plan Phase 0) : "isMinor stub retourne false par defaut. TODO(PD-84)."
  • Constat : TC-86-34 est non demonstrable tant que PD-84 n'est pas livre. Le plan documente le stub mais ne propose pas de mecanisme de verification partielle.
  • Impact : BLOQUANT pour la demonstration de conformite TC-86-34. Le plan doit preciser comment ce test sera gere : report explicite a post-PD-84, ou mock authentifie simulant le flag serveur.

  • DIV-07 : Spec iOS natif (Swift/SwiftUI) vs Plan React Native Expo.

  • Source A (Spec S10) : "Domaine : iOS (Swift/SwiftUI), traitement visuel local hors ligne."
  • Source B (Plan, Metadata + S1) : "Projet : ProbatioVault-app (iOS / React Native Expo)". Architecture en TypeScript/React Native avec native modules pour ONNX, PDF et video.
  • Constat : La spec mentionne explicitement "Swift/SwiftUI" comme stack technique. Le plan utilise React Native Expo avec des bridges natifs. Le reste du projet (ProbatioVault-app) est effectivement en React Native Expo — le plan est coherent avec la realite du projet, pas la spec.
  • Impact : MAJEUR — La spec doit etre corrigee pour referer "React Native Expo (avec bridges natifs Swift si necessaire)" au lieu de "Swift/SwiftUI". Cet ecart pourrait induire le reviewer de Gate 5 en erreur sur la stack attendue.

4. Zones d'ombre

  • ZO-01 : Absence de test pour la frontiere contractuelle InMemoryHandle 64 MB. Le plan (S6 OUT_OF_MEMORY, ECT-v2-10) documente le guard, mais aucun TC dedie ne verifie que le seuil 64 MB est respecte et que le comportement OUT_OF_MEMORY se declenche exactement a cette limite. Les tests couvrent OUT_OF_MEMORY (ERR-86-06) mais pas la valeur seuil.

  • ZO-02 : Benchmark modele ML absente du plan de test. La spec (Q1) exige un "benchmark documente (precision/latence/taille) avant mise en production". Le plan (H-01/H-03/H-09) documente cette exigence comme hypothese, mais aucun test ne verifie que le benchmark a ete effectue et documente. Le plan dit "benchmark obligatoire avant Gate 8" — sans protocole de verification.

  • ZO-03 : Algorithme PDF pour cas limites totalPages proches de 5. La spec (Q8) decrit la strategie de deduplication et "completion par la page interieure non selectionnee la plus proche si necessaire". Le plan (S2.3) reprend l'algorithme aux quartiles. Aucun test ne couvre specifiquement les cas totalPages = 5, totalPages = 6 (frontiere exacte), ou le mecanisme de completion en cas de collision de quartiles.

  • ZO-04 : Controles iOS anti-apercus persistants (App Switcher, Spotlight, QuickLook). Le plan (C20 iOSPrivacyGuard) et le code contract (security) documentent les mecanismes. SEC-86-07 les liste. Mais aucun TC detaille pas-a-pas ne decrit comment verifier l'overlay de redaction, l'exclusion Spotlight ou la desactivation QuickLook. Cette zone d'ombre etait deja signalee en Gate 3 (confrontation v2). Le plan (ECT-v2-04) dit "tests unitaires individuels" mais les tests ne les ajoutent pas.

  • ZO-05 : Comportement exact en cas de combinaison enabled=false + erreur persistee en cache. La spec (S5.2 R1) indique que enabled=false = pas de modal, rendu direct. Le plan l'adresse (ECT-v2-01). Mais aucun TC ne couvre explicitement le cas ou un verdict d'erreur (ex: TIMEOUT) est en cache ET enabled=false : le viewer rend-il directement sans modal ? La logique de precedence R1 > R2 l'implique mais n'est pas testee explicitement.

  • ZO-06 : Strategie de migration si le modele ML change entre versions de l'app (ex: v1.0 avec modele A, v2.0 avec modele B). La spec (INV-86-13, CA-86-12) couvre l'invalidation par modelVersion. Le plan gere le changement. Mais aucun document ne couvre le scenario de mise a jour de l'app ou tous les verdicts cache sont invalides simultanement — impact performance potentiel (re-classification en masse au premier usage post-update).

  • ZO-07 : Format exact de thresholdsVersion (entier incrementant) et de modelVersion (string). La spec definit thresholdsVersion: Int et modelVersion: String dans le modele de donnees. Le plan reprend. Mais aucun document ne precise le format de modelVersion (semver ? hash ? nom+version ?) ni comment thresholdsVersion est incremente (automatique au save ? gestion de conflit entre settings concurrent ?).

5. Recommandation

  • Proceder — convergence confirmee, aucun conflit bloquant
  • Rework necessaire — divergences a resoudre avant de continuer
  • Escalade — decision humaine requise sur un point structurant

Justification : Les convergences sont solides (17 points de convergence confirmes, mapping INV/CA complet 20/20 + 19/19). Cependant, 7 divergences sont identifiees dont : - 1 BLOQUANT (DIV-06 : TC-86-34 non demonstrable avec stub isMinor) - 1 MAJEUR (DIV-07 : spec dit Swift/SwiftUI, plan dit React Native Expo) - 1 MAJEUR (DIV-01 : extension non contractualisee de requiresExplicitConfirmation) - 4 MINEURS (DIV-02 TTL non specifie, DIV-03 rawScores blacklist, DIV-04 invariants supplementaires, DIV-05 niveau test)

Les zones d'ombre ZO-01 a ZO-07 ne sont pas bloquantes mais meritent clarification pour eviter des ecarts en Gate 8.