Aller au contenu

PD-277 — Rapport de confrontation (Étape 5)

Ce rapport est produit par l'orchestrateur Claude avant la Gate 5 PMO (AMBIGUITY). Il confronte les documents produits pour identifier convergences, divergences et zones d'ombre.

1. Sources confrontées

  • Doc A : PD-277-specification.md v2 (étape 1 — spécification canonique)
  • Doc B : PD-277-tests.md v2 (étape 2 — scénarios de tests contractuels)
  • Doc C : PD-277-plan.md v3 (étape 4 — plan d'implémentation)
  • Doc D : PD-277-code-contracts.yaml v2.0.0 (étape 4 — frontières de code)
  • Doc E : Review v3 (étape 5 — revue du plan par reviewer externe)

2. Convergences

  • CONV-01 — Objectif 24/24 checks bloquants : Les 5 documents s'accordent sur l'objectif de résultat : 24/24 checks bloquants à OK après exécution de run_audit.. Aucune ambiguïté sur cette cible. (Doc A §1, Doc B §TC-NOM-04, Doc C §F3, Doc D module tests, Doc E §3)

  • CONV-02 — 8 invariants alignés : Les invariants INV-277-01 à INV-277-08 sont identiques entre la spec (Doc A §5), les tests (Doc B §5 matrice), le plan (Doc C §3 mapping) et les code contracts (Doc D). Aucun invariant ajouté ou supprimé entre les documents.

  • CONV-03 — 9 critères d'acceptation couverts : Les CA-277-01 à CA-277-09 sont tracés dans la matrice de couverture des tests (Doc B §2), dans le mapping du plan (Doc C §4) et dans les code contracts (Doc D). Couverture 100% confirmée.

  • CONV-04 — Périmètre module legal-pre : Tous les documents convergent sur le fait que PD-277 est entièrement contenu dans le module legal-pre. Aucune modification de pre.service.ts, umbral.provider.ts ou d'autres modules. (Doc A §2, Doc C §10, Doc D forbidden clauses)

  • CONV-05 — Atomicité anti-rejeu via transaction SERIALIZABLE : La spec impose atomicité (Doc A §7), le plan implémente via transaction SERIALIZABLE (Doc C §C3), les tests vérifient la concurrence (Doc B §TC-NEG-02), les contracts interdisent le retry automatique (Doc D module pd277-rekey-manager-controls forbidden).

  • CONV-06 — Format nonce UUID v4 lowercase : Spec (Doc A §4), plan (Doc C §C3 regex), tests (Doc B §TC-ERR-02, TC-NEG-01) et contracts (Doc D) s'accordent sur le format strict UUID v4 lowercase ASCII 36 caractères.

  • CONV-07 — Immuabilité des certificats post-création : INV-277-05 est présent dans les 4 documents normatifs. Le test TC-ERR-08 et TC-NEG-04 couvrent le cas. (Doc A §6, Doc B §TC-ERR-08, Doc C §C5, Doc D module pd277-rekey-repository)

  • CONV-08 — Codes d'erreur déterministes : Les 5 codes d'erreur (ERR-NONCE-MISSING, ERR-NONCE-FORMAT, PRE_NONCE_REPLAY_DETECTED, PRE_CERTIFICATE_BINDING_FAILED, ERR-PERSISTENCE-CONTROL) sont identiques dans la spec (Doc A §10), le plan (Doc C §6), les tests (Doc B §4) et les contracts (Doc D module pd277-error-codes).

  • CONV-09 — Faits Prolog canoniques : Les 3 faits entity_column attendus sont identiques dans la spec (Doc A §8), les tests (Doc B §TC-NOM-03) et le plan (Doc C §C8).

  • CONV-10 — Aucun nouveau StatusEnum : INV-277-08 est unanime. Le plan confirme qu'aucun enum n'est modifié (Doc C §3), les tests vérifient par snapshot (Doc B §TC-INV-08), les contracts l'interdisent explicitement (Doc D module pd277-entity-extension forbidden).

  • CONV-11 — Migration up/down exigée : Spec (Doc A §9 stratégie migration), plan (Doc C §C1, F4), tests (Doc B §TC-NOM-05, TC-NR-03), contracts (Doc D module pd277-migration) — tous exigent une migration réversible.

  • CONV-12 — Périmètre nonce par LegalReKey : Doc A §H-277-03, Doc C §V4, Doc B §TC-NEG-03 convergent : le nonce est unique par LegalReKey, pas globalement. Le même UUID peut être utilisé sur 2 LegalReKey différents.

3. Divergences

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

  • DIV-01 : Génération du nonce — serveur uniquement vs client retry
  • Source A (Spec §4) : « Génération : crypto.randomUUID() côté serveur uniquement, jamais côté client. »
  • Source C (Plan §6 erreurs de sérialisation) : « Le client reçoit un HTTP 500 et peut retenter avec un nouveau nonce. »
  • Source E (Review §2 constat 1) : Identifie cette divergence comme MAJEUR.
  • Impact : Si le client génère le nonce pour le retry, la règle « serveur uniquement » de la spec est violée. Si seul le serveur génère, le plan doit décrire le mécanisme de régénération côté serveur. L'architecture du flux nonce (qui fournit, qui génère) est structurante pour l'API et les tests.

  • DIV-02 : Transport du nonce — « endpoint existant, aucune modif controller » vs nonce obligatoire

  • Source C (Plan §F2) : « LegalPreController (endpoint existant, aucune modification controller) »
  • Source C (Plan §C3) : reEncryptWithNonce(legalReKeyId, nonce, capsule, kfragIndex) — nonce est un paramètre obligatoire.
  • Source A (Spec §9 F2) : « Le système reçoit une demande reEncrypt contenant un nonce. » — sans préciser le mécanisme de transport (header, body, query param).
  • Source E (Review §2 constat 2) : Identifie cette divergence comme MAJEUR.
  • Impact : Si le nonce n'est pas déjà transporté dans l'API actuelle, soit le controller doit être modifié (contradiction avec le plan), soit le nonce doit être ajouté dans le DTO existant (modification implicite non tracée). Le chemin d'injection du nonce depuis l'appelant jusqu'à reEncryptWithNonce() n'est pas démontré.

  • DIV-03 : DEFAULT transitoire '' pour certificats — décision de plan vs spec

  • Source A (Spec §6 DDL) : owner_certificate_id VARCHAR(255) NOT NULL et recipient_certificate_id VARCHAR(255) NOT NULLsans DEFAULT.
  • Source C (Plan §C1) : DEFAULT '' comme « décision d'implémentation autonome ».
  • Source C (Plan §C1 justification) : Affirme « contractualisé §6.1 DDL » puis affirme « Non contradictoire avec la spec ».
  • Source E (Review §2 constat 3) : Identifie l'ambiguïté normative comme MAJEUR.
  • Impact : La spec ne prévoit pas de DEFAULT — c'est un ajout du plan. Le plan dit tantôt que c'est contractualisé dans la spec, tantôt que c'est une décision de plan. Cette ambiguïté normative peut déclencher un débat en Gate 8 sur la conformité du DDL à la spec. La justification technique (migration sur table non vide) est crédible mais la traçabilité normative est incohérente.

  • DIV-04 : Exhaustivité de la garde d'immuabilité certificats

  • Source A (Spec §6) : « Toute tentative de modification ultérieure est rejetée en fail-closed. »
  • Source C (Plan §C5) : « dans LegalReKeyRepository, toute méthode updateStatus() ne doit jamais toucher les champs certificats. Ajouter une vérification explicite dans le service si un DTO de mise à jour contient ces champs → rejet fail-closed. »
  • Source D (Contracts module pd277-rekey-repository) : « updateStatus() ne touche JAMAIS ownerCertificateId ni recipientCertificateId »
  • Source E (Review §2 constat 4) : Mécanisme partiel, ne couvre pas toutes les voies d'update (save/update direct).
  • Impact : Le plan et les contracts ne protègent que updateStatus() et une vérification DTO dans le service. Si un autre chemin de code utilise repository.save() ou repository.update() avec les champs certificats, l'immuabilité n'est pas garantie. INV-277-05 exige un rejet fail-closed pour « toute tentative », pas seulement via updateStatus().

  • DIV-05 : Artefact probatoire INV-277-06 absent du plan de livraison

  • Source A (Spec §11 CA-277-06) : « Preuves de configuration TDE/Vault transit conformes (contrôle de config). »
  • Source B (Tests §9) : « Contrôlé par audit de configuration » — reconnu comme non testable unitairement.
  • Source C (Plan §3 mapping INV-277-06) : « Pas de code nouveau. Validé par configuration PostgreSQL TDE / Vault transit. »
  • Source C (Plan §10 hors périmètre) : Ne mentionne pas la production de preuves de configuration dans les livrables.
  • Source E (Review §2 constat 5) : Risque de blocage en clôture conformité.
  • Impact : Le plan ne matérialise aucun artefact probatoire pour INV-277-06. Si la Gate 8 exige une preuve de conformité at-rest, l'absence d'artefact prévu peut bloquer la clôture. Le risque est MOYEN car il s'agit d'un contrôle infra, pas de code, mais il doit être planifié.

4. Zones d'ombre

  • ZO-01 — Validation des certificats dans le stub : Le plan (Doc C §C7) enrichit TspVerifierStub pour retourner des certificateId. Mais le plan (Doc C §C4) exige aussi « Valider que les certificats sont valides (non expirés, non révoqués, compatibles avec le mandat) ». Comment cette validation est-elle réalisée en contexte stub où il n'y a pas de PKI réelle ? Le plan mentionne « le stub retourne toujours des certificats valides sauf configuration de test explicite » — mais le mécanisme de configuration de test pour TC-ERR-06 et TC-NEG-05 (certificat expiré/révoqué) n'est pas décrit.

  • ZO-02 — Structure exacte de TspVerificationResult : Le plan (Doc C §C7) ajoute ownerCertificateId?: string et recipientCertificateId?: string comme champs optionnels. Mais l'hypothèse H-277-T02 reconnaît que « le TspVerificationResult actuel peut être étendu ». La structure actuelle de TspVerificationResult n'est citée nulle part — le plan suppose une extension possible sans la démontrer.

  • ZO-03 — Chemin d'appel de reEncryptWithNonce() depuis l'orchestrateur : Le plan (Doc C §F2) montre un flux Controller → OrchestratorService → reEncryptWithNonce(). Mais le plan indique aussi « aucune modification controller ». Qui appelle reEncryptWithNonce() au lieu de l'ancien reEncrypt() ? L'orchestrateur (LegalPreOrchestratorService) doit-il être modifié pour router vers la nouvelle méthode ? Cette modification n'est tracée dans aucun code contract.

  • ZO-04 — Interaction entre DEFAULT '' et contrôle fail-closed F2 étape 3b : Le plan (Doc C §F2 étape 3b) dit que les ReKeys hérités avec certificats vides (DEFAULT '') seront rejetés par reEncryptWithNonce(). Mais aucun test (Doc B) ne couvre explicitement ce scénario de ReKey pré-existant avec certificats vides soumis à reEncrypt. Le test TC-ERR-04 couvre « certificat owner introuvable » sur generateReKey, pas « certificat vide sur reEncrypt pour un ReKey legacy ».

  • ZO-05 — Référence au test TC-NEG-02 et mécanisme de concurrence réelle : Les contracts (Doc D module pd277-tests) exigent « test de concurrence réelle (pas séquentiel) avec Promise.all ». Les tests (Doc B §7 TC-NEG-02) décrivent « N requêtes simultanées même nonce ». Mais le niveau de test visé dans le plan (Doc C §5) est « Integration (concurrent) ». Aucun document ne précise si l'environnement de test supporte réellement des transactions SERIALIZABLE concurrentes (nécessite une base PostgreSQL réelle, pas un mock).

  • ZO-06 — Modification de LegalPreOrchestratorService : Aucun code contract ne couvre LegalPreOrchestratorService. Si ce service doit router vers reEncryptWithNonce() au lieu de l'appel existant, cette modification est hors des frontières de code définies. Le module pd277-rekey-manager-controls ne couvre que legal-rekey-manager.service.ts.

  • ZO-07 — Validation du nonce au niveau controller ou service : La spec (Doc A §9 F2 étape 2) dit « Le système valide le nonce ». Le plan place la validation dans LegalReKeyManagerService.reEncryptWithNonce() (Doc C §C3). Mais si le controller ne transporte pas le nonce, la validation ne peut pas avoir lieu au niveau service. Le point d'entrée de la validation dépend de DIV-02.

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 : 4 divergences MAJEUR (DIV-01, DIV-02, DIV-03, DIV-04) et 1 divergence MOYEN (DIV-05) identifiées. Les divergences DIV-01 et DIV-02 sont structurantes pour l'architecture du flux nonce. DIV-03 crée une ambiguïté normative qui peut bloquer en Gate 8. DIV-04 laisse une faille dans la garde d'immuabilité. Les zones d'ombre ZO-03 et ZO-06 révèlent un trou dans les frontières de code (orchestrateur non couvert).

Actions prioritaires avant Gate 5 GO : 1. Clarifier la source de génération du nonce (DIV-01) : amender le plan pour préciser que le nonce est fourni par l'appelant (DTO), et que crypto.randomUUID() côté serveur est une recommandation d'implémentation client, pas une contrainte de flux serveur. 2. Démontrer le chemin de transport du nonce (DIV-02, ZO-03, ZO-06) : tracer la modification de l'orchestrateur et/ou du DTO, et ajouter un code contract pour LegalPreOrchestratorService. 3. Résoudre l'ambiguïté normative DEFAULT '' (DIV-03) : soit amender la spec pour contractualiser le DEFAULT, soit adopter une migration en 2 phases (ADD COLUMN nullable → UPDATE → ALTER NOT NULL). 4. Renforcer la garde d'immuabilité (DIV-04) : ajouter un mécanisme explicite (subscriber TypeORM ou override de save()/update()) qui rejette toute modification des champs certificats, pas seulement via updateStatus(). 5. Planifier l'artefact probatoire INV-277-06 (DIV-05) : ajouter un livrable « preuves de configuration at-rest » dans le plan de clôture.