PD-279 — Rapport de confrontation (Étape 5)¶
Ce rapport est produit par l'orchestrateur Claude avant la gate PMO 5. Il confronte les documents produits pour identifier convergences, divergences et zones d'ombre.
1. Sources confrontées¶
- Spécification (étape ⅓, v2) :
PD-279-specification.md - Tests contractuels (étape 2) :
PD-279-tests.md - Plan d'implémentation (étape 4) :
PD-279-plan.md/PD-279-plan.md - Code contracts (étape 4) :
PD-279-code-contracts.yaml
2. Convergences¶
- Machine à états : Les 4 documents s'accordent sur les transitions
SEALED→RESTITUTEDetRESTITUTED→SEALED, et l'interdiction des transitionsRESTITUTED→DISPOSED,RESTITUTED→PENDING,RESTITUTED→EXPIRED,RESTITUTED→RESTITUTED. Convergence totale. - Gardes de restitution : Ownership,
legal_lock=false,geo_copy_count >= 2, état sourceSEALEDsont présents dans la spec (INV-279-02), les tests (TC-NOM-01, TC-ERR-03/05/06/07), le plan (§2.1) et les code contracts (modulerestitution-service). - Gardes de retour : Ownership + état
RESTITUTED, sans vérificationgeo_copy_count— convergent dans les 4 documents. - Atomicité transactionnelle : Spec (INV-279-09), plan (§2.1 étape 8, §5.8), tests (TC-INV-09A/B, TC-ERR-10), code contracts (
restitution-service) s'accordent sur l'atomicité ACID status + lifecycle_log. - SLA temporels : Spec (INV-279-05, §5.6), plan (§2.4), tests (TC-NOM-03) et code contracts (
restitution-sla-scheduler) convergent sur les 3 seuils (80%, 100%, OVERDUE) et l'absence de transition automatique. - Interdiction de destruction : Spec (INV-279-06, INV-279-10), plan (§2.3, §11), tests (TC-NOM-05), code contracts (
destruction-guard-extension) convergent sur le rejet HTTP 409 pour les documentsRESTITUTED. - Migration DDL réversible : Spec (INV-279-08), plan (C1, §9 V2), tests (TC-NOM-06), code contracts (
migration-ddl) convergent sur la réversibilité avec précondition. - Vérification TLA+ : Spec (CA-279-11), plan (C13), tests (TC-NOM-07), code contracts (
tla-plus-model) convergent. - Idempotence des endpoints : Spec (INV-279-11), plan (§2.1 étape 4, §2.2 étape 4), code contracts (
restitution-serviceINV-279-11) convergent sur le principe : état cible déjà atteint → 200 sans attestation.
3. Divergences¶
⚠️ Les conflits ne doivent JAMAIS être lissés. Chaque divergence est rendue visible.
- DIV-01 : Code HTTP pour
legal_lock=true— 409 (spec) vs 423 (plan) - Spec §5.3 (étape 7) :
legal_lock=false→ 409 Conflict (error_code: DOCUMENT_UNDER_LEGAL_LOCK) - Spec §6 (table des erreurs) : aucune entrée HTTP 423 ;
DOCUMENT_UNDER_LEGAL_LOCKest listé sous409 Conflict - Plan §2.1 (étape 5) :
legal_lock→ 423 DOCUMENT_UNDER_LEGAL_LOCK - Plan §6 (table des erreurs) : ligne explicite
423 | DOCUMENT_UNDER_LEGAL_LOCK - Plan §9 (V7) : affirme « La spec v2 utilise HTTP 423 » — affirmation contredite par le texte réel de la spec
- Tests (TC-ERR-07) : mentionnent 409 (alignés sur la spec)
- Code contracts (
restitution-service) : ne spécifient pas le code HTTP explicitement -
Impact : BLOQUANT — contrat API incohérent entre spec et plan. L'implémentation doit choisir un seul code. HTTP 423 (WebDAV) est sémantiquement plus précis pour un verrou juridique ; HTTP 409 est le choix de la spec. Les tests sont alignés spec.
-
DIV-02 : Numérotation des invariants — INV-279-11 redéfini dans le plan
- Spec §4 : INV-279-11 = idempotence (retour 200 sans attestation si état cible déjà atteint)
- Plan §3 (table mapping) : INV-279-11 = destruction-checkpoint-uniqueness (double vérification inclusion + exécution) — concept différent
- Plan §3 (table mapping) : INV-279-12 = expired-terminal (EXPIRED sans transition sortante) — invariant absent de la spec
- Code contracts (
restitution-service) : INV-279-11 = idempotence (aligné spec) - Code contracts (
state-machine-extension) : INV-279-12 référencé (non canonique) -
Impact : MAJEUR — le plan a une incohérence interne : sa table de mapping §3 contredit ses propres code contracts sur INV-279-11. La traçabilité invariant→mécanisme est rompue pour l'audit.
-
DIV-03 : CA-279-13 ajouté par le plan, absent de la spec
- Spec §7 : 12 critères d'acceptation (CA-279-01 à CA-279-12)
- Plan §4 : ajoute CA-279-13 (détection idempotence) hors canon
- Tests : ne référencent pas CA-279-13
-
Impact : MINEUR — extension du plan, mais écart de traçabilité par rapport au corpus canonique. Le concept est déjà couvert par INV-279-11.
-
DIV-04 : Ordre d'évaluation des gardes — idempotence vs état source
- Spec §5.3 : étape 5 = vérifier état
SEALED(→ 409 si non-SEALED), étape 6 = vérifier idempotence (si déjàRESTITUTED→ 200). Or un documentRESTITUTEDéchoue à l'étape 5 avant d'atteindre l'étape 6, rendant l'idempotence irréalisable dans cet ordre. - Plan §2.1 : étape 4 vérifie d'abord l'idempotence (si
RESTITUTED→ 200), puis si!= SEALED→ 409. Cet ordre rend l'idempotence fonctionnelle. - Tests (TC-NEG-02) : attendent un 409 sur un appel return idempotent (document déjà
SEALED), ce qui contredit INV-279-11 de la spec qui spécifie un 200 idempotent pour le retour aussi. -
Impact : BLOQUANT — la spec a une incohérence interne entre l'ordre des gardes §5.3 et l'invariant d'idempotence INV-279-11. Le plan corrige implicitement ce problème mais ne le documente pas comme écart.
-
DIV-05 : Tests TC-NEG-02 — rejeu retour attendu 409 vs spec 200 idempotent
- Spec INV-279-11 : « POST /documents/:id/return-from-restitution est idempotent : si le document est déjà SEALED, retourner HTTP 200 sans nouvelle attestation »
- Tests TC-NEG-02 : « Rejeu d'appel return-from-restitution après retour déjà effectué → Requête rejouée en 409 »
- Plan §2.2 (étape 4) : « Si déjà SEALED → 200 idempotent » (aligné spec)
-
Impact : BLOQUANT — le document de tests contredit directement l'invariant INV-279-11 de la spec sur le comportement idempotent du retour.
-
DIV-06 :
lifecycle_log(spec) vsintegrity_journal_entries(plan) - Spec §4, §5.3, §5.4 : utilise systématiquement le terme
lifecycle_log - Plan §2.1, §3, §5 : utilise
IntegrityJournalService.appendEntry()etintegrity_journal_entries(table existante PD-251) -
Impact : MAJEUR — le plan effectue une substitution sémantique non formalisée. Si
lifecycle_logde la spec ESTintegrity_journal_entriesdu backend, l'équivalence doit être déclarée contractuellement. Si ce sont deux artefacts distincts, le plan manque la création delifecycle_log. -
DIV-07 :
geo_copy_count— champ existant (spec) vs colonne à créer (plan) - Spec §5.1 : traite
geo_copy_countcomme un attribut existant du document, avec format et validation définis - Plan §8 (HT-279-02) : identifie que le champ n'existe pas dans l'entité
DocumentSecureet propose de l'ajouter en migration PD-279 avecDEFAULT 0 - Spec §2 (périmètre inclus) : ne mentionne pas l'ajout de
geo_copy_countcomme livrable - Spec §5.7 (migration DDL) : ne liste que l'extension enum +
restituted_at+restitution_deadlinecomme colonnes ajoutées -
Impact : MAJEUR — extension de périmètre technique non contractualisée. La migration PD-279 touche un concept (comptage copies géo) qui n'est pas dans le périmètre déclaré de la spec.
-
DIV-08 : Couverture tests INV-279-11 (idempotence)
- Spec §4 : INV-279-11 est un invariant non négociable
- Tests §2 (matrice) : INV-279-11 n'apparaît pas dans la matrice de couverture
- Tests §5 (table invariants) : INV-279-10 est le dernier invariant couvert
-
Impact : MAJEUR — l'invariant d'idempotence n'a pas de couverture de test formelle dans la matrice. TC-NEG-02 le couvre partiellement mais avec le mauvais code HTTP attendu (409 vs 200).
-
DIV-09 : Routes destruction — contrôle explicite vs filtre implicite
- Spec §5.5 : exige un rejet HTTP 409 explicite à l'inclusion batch (
POST /destruction/batches) - Plan §2.3 : pour l'inclusion, s'appuie sur
EligibilityService.selectEligible()qui filtrestatus=EXPIRED(excluant implicitementRESTITUTEDpar filtre SQL, pas par rejet explicite) - Plan §11 : mentionne
EligibilityService.selectEligible()comme « filtre déjà status=EXPIRED, exclut implicitement RESTITUTED » - Impact : MAJEUR — un filtre SQL implicite ne produit pas de HTTP 409 ni d'audit de refus. La spec exige un rejet explicite auditable. Le plan ne satisfait pas cette exigence pour la route d'inclusion.
4. Zones d'ombre¶
-
ZO-01 : Mécanisme de mise à jour de
geo_copy_count. Le plan ajoute la colonne avecDEFAULT 0et documente un STUB, mais aucun document ne précise quel mécanisme (trigger, job, événement) mettra à jour cette valeur. AvecDEFAULT 0, tous les documents existants sont bloqués pour la restitution — est-ce le comportement voulu ? La spec suppose le champ comme « déjà renseigné ». -
ZO-02 : Source exacte de
security_levelau moment de la transition. La spec exigesecurity_leveldans chaque attestation (INV-279-04). Le plan (HT-279-03) propose de le récupérer depuis@CurrentUser()ou le coffre-fort associé, mais sans spécifier lequel est normatif. Les tests (§9) marquent ce point comme « non testable » en citant Q-279-03, alors que la spec v2 indique ce point comme RÉSOLU. -
ZO-03 : Tests rédigés sur une version antérieure de la spec. Les tests §9 (règles non testables) référencent Q-279-02/03/04/05 comme ouverts, alors que la spec v2 les marque tous RÉSOLUS (§10.2). Le document de tests n'a pas été mis à jour après la Gate 3.
-
ZO-04 :
RESTITUTION_OVERDUEvs escalade 100% — même événement ou séquence ? La spec §5.6 mentionne à la fois « escalade à 100% » et « événement RESTITUTION_OVERDUE ». Le plan §2.4 les traite comme 3 événements séquentiels distincts (80%, 100%, OVERDUE). La spec ne clarifie pas si l'escalade 100% et OVERDUE sont le même moment ou deux moments distincts. -
ZO-05 :
DELETE /documents/:iddans les code contracts. La spec §5.5 et le plan §11 listent 3 routes destruction protégées, incluantDELETE /documents/:id. Les code contracts du moduledestruction-guard-extensionne mentionnent queeligibility.service.tsetdestruction-execution.service.ts— le fichier du controller soft-delete n'est pas listé dansfiles. -
ZO-06 : Framework de test. Le plan §12 ne spécifie pas le runner de test (Jest ou Vitest). Les code contracts du module
testslistent des fichiers.spec.ts(convention Jest), mais aucune déclaration normative.
5. Recommandation¶
- Rework nécessaire — divergences à résoudre avant de continuer
Divergences bloquantes à résoudre : 1. DIV-01 : Trancher 409 vs 423 pour legal_lock et aligner spec/plan/tests. 2. DIV-04 : Corriger l'ordre des gardes dans la spec §5.3 (idempotence avant vérification état source) ou documenter l'écart. 3. DIV-05 : Corriger TC-NEG-02 (409 → 200 pour idempotence retour) conformément à INV-279-11.
Divergences majeures à résoudre : 4. DIV-02 : Réaligner la table de mapping §3 du plan sur la numérotation canonique des invariants spec. 5. DIV-06 : Formaliser l'équivalence lifecycle_log = integrity_journal_entries. 6. DIV-07 : Contractualiser l'ajout de geo_copy_count dans le périmètre spec §2 et §5.7, ou le retirer du plan. 7. DIV-08 : Ajouter INV-279-11 dans la matrice de couverture tests avec les bons observables. 8. DIV-09 : Remplacer le filtre implicite par un rejet explicite 409 à l'inclusion batch.