Aller au contenu

PD-253 — Rapport de confrontation (Gate 8 — CLOSURE)

Ce rapport est produit par l'orchestrateur Claude avant la gate PMO 8. Il confronte les documents produits pour identifier convergences, divergences et zones d'ombre.

1. Sources confrontées

  • Specification : PD-253-specification.md (v2) — étape 1
  • Tests : PD-253-tests.md (v2) — étape 2
  • Plan : PD-253-plan.md (v1.0) — étape 4
  • Acceptability : PD-253-acceptability.md — étape 7

2. Convergences

  • C-01 — Machine à états (INV-253-13) : Les 8 états (REQUESTED, ASSEMBLING, READY_FOR_DOWNLOAD, DOWNLOADED, EXPIRED, FAILED, FAILED_TIMEOUT, CANCELLED), les transitions autorisées/interdites, et le caractère terminal de 5 états sont cohérents entre spec §5.4, tests TC-NOM-09/TC-NOM-13/TC-NOM-14, plan CC-253-04, et acceptabilité (corrections appliquées). FAILED_TIMEOUT distinct de FAILED dans tous les documents.

  • C-02 — 14 invariants : Les 14 invariants (INV-253-01 à INV-253-14) sont identiques dans la spec, couverts par la matrice de tests (§2), mappés aux tâches dans le plan (§8), et vérifiés dans l'acceptabilité (corrections E-01 à E-05, T-01 à T-03, S-01 à S-07).

  • C-03 — Dual manifest (INV-253-04) : Noms manifest-sha256.txt et manifest-sha3.txt alignés entre spec, tests TC-NOM-04, plan CC-253-09. Correction E-03 dans l'acceptabilité confirme le renommage effectif de manifest-sha3-256.txtmanifest-sha3.txt. Convergence confirmée après correction.

  • C-04 — Audit fail-closed (INV-253-10) : Pattern anti-catch-absorb contractualisé dans spec, testé (TC-ERR-07), formalisé dans plan CC-253-05 (pattern fail-closed explicite), et corrigé dans acceptabilité (E-01 : injection AuditLogService, T-02 : +2 tests audit). Convergence confirmée après correction.

  • C-05 — Quota 1 actif/user (INV-253-07) : 3 statuts actifs (REQUESTED, ASSEMBLING, READY_FOR_DOWNLOAD) — cohérent entre spec, tests TC-ERR-04, plan CC-253-04/CC-253-07 (COUNT WHERE status IN 3 statuts), et acceptabilité (correction T-01/S-01 ajoutant READY_FOR_DOWNLOAD à ACTIVE_BULK_EXPORT_STATUSES). Convergence confirmée après correction.

  • C-06 — Soft-deleted / destroyed (INV-253-09) : Inclusion soft-deleted avec marquage, exclusion détruits avec traçage destruction-log.json — cohérent entre spec, tests TC-NOM-08, plan CC-253-07/CC-253-10, et acceptabilité (correction E-02 : withDeleted: true). Convergence confirmée après correction.

  • C-07 — Pending anchor (INV-253-08) : Conservation du statut pending sans upgrade implicite — aligné entre spec §5.4/INV-253-08, tests TC-NOM-07/TC-NEG-07, plan CC-253-06/CC-253-08, acceptabilité sans déviation.

  • C-08 — Dual-hash et Merkle (INV-253-03) : plaintext_hash + ciphertext_hash SHA3-256, chaîne Merkle référence ciphertext_hash — aligné dans les 4 documents.

  • C-09 — Atomicité sync/async (INV-253-14) : DB ACID synchrone + BullMQ post-commit — cohérent entre spec §5.6, tests TC-NOM-10 (chaos test), plan CC-253-05.

  • C-10 — No-residuals (INV-253-12) : purgeStale() au démarrage + finally — aligné entre spec, tests TC-INV-12, plan CC-253-06/CC-253-11.

  • C-11 — Annulation : Flux DELETE /exports/{export_id} avec idempotence si package déjà produit — aligné entre spec §5.5 flux 4, tests TC-NOM-13/TC-NOM-14, plan CC-253-05.

  • C-12 — Sécurité inter-utilisateur : 403 FORBIDDEN_EXPORT_ACCESS uniforme sur GET/download/DELETE — cohérent entre spec §5.7, tests TC-SEC-01, plan CC-253-12.

  • C-13 — Résolution ECTs Gate 3 : Les 6 écarts techniques (ECT-01 à ECT-06) identifiés en Gate 3 (verdict step3-v2) sont tous adressés dans le plan §2 avec décisions techniques justifiées.

  • C-14 — BagIt RFC 8493 : Structure package, chemins relatifs sans .., séparateur /, encodage UTF-8 sans BOM — cohérent entre spec §5.5, tests TC-NOM-04, plan CC-253-08.

  • C-15 — Learnings appliqués : Le plan intègre PD-283 (purgeStale), PD-85 (anti-catch-absorb), PD-63 (randomUUID), PD-55 (BullMQ v5, pas de subquery index), PD-282 (ALTER TYPE ADD VALUE évité via VARCHAR+CHECK), PD-250 (stubs inter-PD). Cohérent avec les règles learnings de gouvernance.

3. Divergences

⚠️ Les conflits ne doivent JAMAIS être lissés. Chaque divergence est rendue visible.

  • DIV-01 : INV-253-11 (chiffrement artefacts temporaires) — invariant non satisfait, reporté
  • Spec : INV-253-11 stipule « Tout artefact cryptographique temporaire [...] est chiffré au repos ; aucun secret en clair persistant. »
  • Plan (H-253-10) : Hypothèse que les fichiers temp /tmp/bulk-export-{exportId}/ ne contiennent « aucun secret cryptographique » (Zero-Knowledge : content.enc déjà chiffré + hashes non-réversibles). S'appuie sur le chiffrement disque hôte.
  • Tests (TC-INV-11) : Vérifie qu'aucun secret n'est stocké en clair.
  • Acceptabilité (E-04) : Identifié MAJEUR → reporté PD-253b.
  • Impact : L'invariant INV-253-11 est formellement non satisfait au niveau applicatif. La mitigation (chiffrement disque hôte) est une hypothèse infrastructure non vérifiée par le code.

  • DIV-02 : Code HTTP 504 — spec/tests vs plan

  • Spec §6 : liste 504 EXPORT_TIMEOUT comme code d'erreur.
  • Plan §ZA-02 : supprime le code 504 de la couche HTTP synchrone. Un client interrogeant GET sur un export FAILED_TIMEOUT reçoit 200 OK avec { status: "FAILED_TIMEOUT" }.
  • Tests TC-ERR-09 : attend « Code 504 EXPORT_TIMEOUT ».
  • Impact : Incohérence triple entre spec (504), tests (504) et implémentation (200). TC-ERR-09 teste un comportement qui n'existe pas dans l'implémentation.

  • DIV-03 : Test TC-NOM-15 — absent du document de tests

  • Plan ECT-01 : « TC-NOM-15 (à ajouter en Gate 5) — Given export READY_FOR_DOWNLOAD, When POST /confirm-download, Then état DOWNLOADED, audit émis ».
  • Tests : TC-NOM-15 absent du document contractuel de tests.
  • Acceptabilité : Le endpoint est fonctionnel, testé dans les 126 tests bulk-export mais sans test contractuel nommé TC-NOM-15.
  • Impact : Lacune de couverture test formelle pour le mécanisme confirm-download.

  • DIV-04 : ExportExpiryScheduler — bypass FSM vs plan

  • Plan CC-253-11 : Prescrit que le scheduler appelle expireExport() via ExportStateMachineService (passage par la FSM).
  • Acceptabilité E-05/S-05 : « ExportExpiryScheduler bypass la FSM (set status direct) » — MAJEUR reclassé mineur, reporté PD-253b.
  • Impact : Violation de INV-253-13 (transitions explicites via FSM). Le scheduler fait un UPDATE direct sans passer par ExportStateMachineService. Risque de régression si un nouvel état est ajouté.

  • DIV-05 : create() — absence de transaction DB

  • Plan CC-253-05 : Prescrit un pattern queryRunner transactionnel (quota + audit + INSERT atomiques).
  • Acceptabilité S-06 : « create() sans transaction — export orphelin si queue.add() échoue » — MINEUR reporté PD-253b.
  • Impact : Violation de INV-253-14 (atomicité sync/async). Sans transaction, un crash entre INSERT et queue.add() laisse un export REQUESTED orphelin sans job BullMQ.

  • DIV-06 : confirmDownload — non idempotent

  • Plan CC-253-05/ECT-01 : « Idempotent — si déjà DOWNLOADED, retourne 200 sans re-audit ».
  • Acceptabilité S-07 : « confirmDownload non idempotent (ECT-01) » — MINEUR reporté PD-253b.
  • Impact : L'implémentation ne respecte pas le contrat de code CC-253-05.

  • DIV-07 : Préfixe URL API — /exports vs /bulk-exports

  • Spec §5.5 : DELETE /exports/{export_id} (préfixe /exports).
  • Plan CC-253-12 : DELETE /bulk-exports/:id (préfixe /bulk-exports).
  • Impact : Incohérence de nommage. Le plan justifie /bulk-exports pour éviter le conflit avec PD-85 (/exports). La spec n'a pas été mise à jour. Impact faible — le plan est postérieur et la décision est justifiée.

4. Zones d'ombre

  • ZO-01 : Périmètre exact signé par export.sig (PC-253-01). Spec, tests et plan mentionnent « signature du digest SHA3-256 du package final » comme option provisoire. Confirmation sécurité/crypto non obtenue. TC-NOM-06 en couverture « Partielle ». Tests §9 : point marqué « Majeur » dans les règles non testables.

  • ZO-02 : Multipart upload pour packages > 5GB. Plan H-253-11 : S3Service.uploadFile() est un stub nécessitant extension pour multipart (packages > 5GB, jusqu'à 100GB). Acceptabilité silencieuse sur ce point. Question : l'upload multipart est-il implémenté ? Si non, les exports > 5GB échouent avec EntityTooLarge.

  • ZO-03 : Performance P95 (CA-253-12). Tests : couverture « Partielle ». Tests §9 : « Bloquant » sans environnement instrumenté (H-253-04). Acceptabilité : aucun résultat de test de performance mentionné. Le critère CA-253-12 n'est pas vérifié.

  • ZO-04 : BulkExportProcessor — 0% couverture unitaire (T-03). 610 lignes de code critique sans tests unitaires, exclu par conception (nécessite env S3/HSM). Les tests d'intégration (TC-NOM-01, TC-NOM-10, TC-INV-11, TC-INV-12) sont listés mais leur exécutabilité effective en CI n'est pas confirmée par l'acceptabilité.

  • ZO-05 : Validation scopeParams (S-03). Plan CC-253-03 spécifie des sous-validations (@IsUUID(), @IsISO8601(), @ArrayMinSize(1)). Acceptabilité S-03 : seul @IsObject() est implémenté. Les sous-DTOs ne sont pas validés côté controller.

  • ZO-06 : ParseUUIDPipe sur @Param('id') (S-04). Absent selon l'acceptabilité. Un id non-UUID traverse le controller jusqu'au repository sans rejet 400.

  • ZO-07 : Canal de notification hors polling (PC-253-03). Contrat minimal = polling GET. Plan ajoute un stub // STUB: PC-253-03. Aucun scénario de notification dans les tests. Mécanisme entièrement non spécifié et non implémenté.

  • ZO-08 : Purge S3 post-DOWNLOADED. Plan ECT-05 : rétention indépendante du téléchargement. Plan correction E-02 : DOWNLOADED reste terminal, seul READY_FOR_DOWNLOAD transite vers EXPIRED. Question : que se passe-t-il physiquement pour l'objet S3 d'un export DOWNLOADED quand le TTL expire ? L'objet est-il purgé par le scheduler ? Si oui, le scheduler doit aussi scanner les DOWNLOADED avec expires_at dépassé — mais DOWNLOADED est terminal donc pas de transition d'état.

5. Recommandation

  • Procéder — convergence confirmée, aucun conflit bloquant
  • Rework nécessaire — divergences à résoudre avant de continuer
  • Escalade — décision humaine requise sur un point structurant

Justification :

Les convergences sont solides sur la majorité des invariants (C-01 à C-15). Les corrections BLOQUANT (E-01 audit fail-closed, E-03 nom manifest) et MAJEUR critiques (E-02 soft-deleted, T-01/S-01 quota, S-02 audit) sont appliquées et vérifiées.

Les divergences se classent en :

  1. Invariant non satisfait : DIV-01 (INV-253-11 chiffrement temp → reporté PD-253b). Le PMO doit statuer si un invariant explicitement non satisfait est acceptable en RESERVE.

  2. Contrats de code non respectés (3 items) : DIV-04 (scheduler bypass FSM), DIV-05 (create sans transaction), DIV-06 (confirmDownload non idempotent) — tous reportés PD-253b. Le volume d'écarts reportés (6 items PD-253b total) mérite évaluation PMO.

  3. Incohérence spec/tests/plan : DIV-02 (code 504 vs 200) — le test TC-ERR-09 attend un code HTTP qui n'est jamais émis.

  4. Lacunes documentaires : DIV-03 (TC-NOM-15 absent), DIV-07 (préfixe URL non mis à jour dans la spec).

Les zones d'ombre ZO-02 (multipart > 5GB) et ZO-03 (P95 non vérifié) sont des limitations opérationnelles à documenter. ZO-04 (processor 0% couverture) est un risque technique accepté par conception.