Aller au contenu

PD-280 — Rapport de confrontation (Gate 5 — Review Plan)

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

1. Sources confrontees

Document Etape Version
PD-280-specification.md (v3 corrigee) Etape 1 v3
PD-280-tests.md (v3 corriges) Etape 2 v3
PD-280-plan.md (plan d'implementation) Etape 4 v1
PD-280-code-contracts.yaml Etape 4 v1

2. Convergences

2.1 Domaine metier et invariants

  • INV-280-01 (CheckResult domain) : Les 4 documents s'accordent sur exactement {OK, KO, INDETERMINATE, PENDING}. Le plan precise que l'enum est etendu sur place (pas de nouvel enum). Les code contracts interdisent explicitement une 5e valeur.
  • INV-280-02 (coherence status/linkResults) : Biconditionnelle PENDING ssi au moins un null / DONE ssi tous resolus presente dans la spec (§4), les tests (TC-NOM-01/02, TC-ERR-03), le plan (C2+C4) et les code contracts (proof-verification-service + proof-verification-guards).
  • INV-280-03 (champs conditionnels) : pendingReason + nextCheckAfterSeconds obligatoires si PENDING, interdits si DONE — aligne dans les 4 documents.
  • INV-280-04 (finalisation) : Aucun PENDING interne / null API si proof_finalized = TRUE — couvert par spec §4, test TC-NOM-06, plan C2, code contracts.
  • INV-280-05 (transitions maillon) : Monotonie PENDING -> {OK,KO,INDETERMINATE} ; retour interdit — aligne partout.
  • INV-280-06 (transitions job) : DONE terminal pour un verificationRequestId donne ; rappel idempotent retourne reponse identique (pas erreur) — aligne apres correction ECT-V2-01.
  • INV-280-07 (TLA+ bijection) : RealStates = CheckResults a 4 valeurs — aligne. Le plan precise que PV_Proof.tla n'est pas modifie (deja 4 etats).
  • INV-280-09 (idempotence concurrente) : Endpoint lecture seule, pas de lock applicatif — aligne dans les 4 documents.

2.2 Perimetre et exclusions

  • Exclusions identiques : Worker/cron SLA background, pattern async BullMQ, endpoint creation de preuve, logique de finalisation — exclus dans les 4 documents.
  • Epic parent : PD-217 — LEGAL & COMPLIANCE — aligne partout (correction DIV-05 de v2 appliquee).
  • Stubs inter-PD : Plan et code contracts mentionnent PD-281 (Zlint) et worker SLA future. Spec mentionne dependance PD-251 (gel/integrite). Coherent.

2.3 API et erreurs

  • Codes erreur : 400 INVALID_PROOF_ID, 404 PROOF_NOT_FOUND, 500 VERIFICATION_CONTRACT_BROKEN — alignes spec §6, tests §4/§7, plan §6.
  • Clamp nextCheckAfterSeconds : [1, 86400] en sortie — aligne spec §5.1, tests TC-NEG-05, plan C2, code contracts.
  • Mapping interne/API : CheckResult.PENDING -> null dans linkResults — aligne spec §5.7, plan C2, code contracts (forbidden: exposer "PENDING" en API).
  • Validation UUID v4 : ParseUUIDPipe reutilise — aligne plan C3, tests TC-ERR-01.

2.4 Architecture et fichiers

  • Fichiers impactes : Les 8 modules du plan (C1-C8) correspondent exactement aux 8 code_contracts du YAML. Les listes de fichiers sont identiques.
  • Separation service/intercepteur : Le plan introduit un VerificationContractInterceptor (pas middleware, pas APP_GUARD global) — aligne avec les code contracts qui interdisent l'enregistrement global.
  • Stack contractuelle : NestJS + TypeORM + PostgreSQL — aligne spec §10.1, plan §8.

3. Divergences

DIV-01 : Reclassification SLA lazy — mutation DB vs projection lecture seule

  • Spec (§5.2, ERR-280-05) : « maillon reclassifie INDETERMINATE » — le verbe « reclassifie » implique un changement d'etat persistant.
  • Spec (INV-280-09) : « L'endpoint de verification est en lecture seule ; la resolution des maillons est realisee par des processus externes. »
  • Tests (TC-NOM-05) : « Le maillon devient INDETERMINATE pendant le traitement de cet appel » — ambiguite : mutation ou projection ?
  • Tests (§8 observabilite) : « preuve horodatee de PENDING -> INDETERMINATE pendant un appel API de verification » — suggere un evenement trace avec effet durable.
  • Plan (§2.2) : « Projeter le maillon comme INDETERMINATE dans la reponse courante (pas de mutation en base — l'etat DB reste PENDING). La reclassification en base est du ressort du processus de resolution externe. »
  • Impact : Si le plan a raison (projection seule), un maillon PENDING expire en base ne sera jamais mute en INDETERMINATE par cet endpoint. Chaque appel refait le calcul de projection. Si la spec attend une mutation, le plan viole INV-280-09 (lecture seule) pour la satisfaire. Les deux interpretations sont defensables mais elles produisent des implementations radicalement differentes.

DIV-02 : Test TC-NOM-04 (INDETERMINATE durable) — absent du document de tests

  • Spec (SCN-280-04) : Scenario « blockchain inaccessible -> maillon = INDETERMINATE » present.
  • Plan (§5) : Reference TC-NOM-04 | SCN-280-04, CA-03 | Service : evaluation maillon blockchain inaccessible | Maillon interne = INDETERMINATE.
  • Tests : TC-NOM-04 n'existe pas dans le document de tests (§3 passe de TC-NOM-03 a TC-NOM-05). Absent de la matrice de couverture (§2).
  • Impact : Scenario spec non couvert par un test detaille. Le plan y fait reference comme s'il existait. Gap de couverture sur le cas INDETERMINATE immediate (distinct du SLA lazy).

DIV-03 : Nombre total de tests — decompte incoherent

  • Code contracts (proof-verification-tests) : « 28 scenarios TC-* ».
  • Tests (document) : Decompte effectif = 29 tests (9 nominaux + 5 erreurs + 2 invariants + 4 non-regression + 9 negatifs). TC-NOM-04 absent.
  • Plan (§5) : Decompte effectif = 30 tests (inclut TC-NOM-04 absent du doc tests).
  • Impact : Le chiffre « 28 » des code contracts ne correspond ni au document de tests (29) ni au plan (30). Risque de test manquant non detecte.

DIV-04 : Cycle de vie de verificationRequestId en phase PENDING

  • Spec (§5.1) : « verificationRequestId est obligatoire sur toute reponse 200 » — cela inclut les reponses PENDING.
  • Spec (INV-280-06) : « Pour un verificationRequestId donne : PENDING -> DONE autorise » — implique que le meme UUID persiste du premier appel PENDING jusqu'au DONE.
  • Plan (DDL-02) : « Quand le premier appel de verification produit un resultat DONE, le verificationRequestId est persiste. » — formulation qui suggere que le UUID n'est persiste qu'a l'atteinte de DONE.
  • Plan (INV-280-09 + lecture seule) : L'endpoint ne doit pas muter l'etat metier. Persister un UUID au premier appel est une mutation (meme si metadata).
  • Tests (TC-NOM-09) : « verificationRequestId est stable lors d'un rappel idempotent d'une verification deja DONE » — ne couvre pas la stabilite durant la phase PENDING.
  • Impact : Si le premier appel retourne PENDING, quel verificationRequestId est genere ? Est-il stable entre deux appels PENDING successifs ? Le plan ne repond pas. L'obligation spec « obligatoire sur toute reponse 200 » + « PENDING -> DONE pour un meme UUID » impose une persistance des le premier appel, y compris en PENDING, ce que le plan ne prevoit pas explicitement.

DIV-05 : Endpoint « lecture seule » vs persistance verificationRequestId

  • Spec (INV-280-09) : Endpoint lecture seule, « aucune mutation due a l'appel ».
  • Plan (DDL-02) : Prevoit de persister verification_request_id en base lors d'un appel (mutation d'ecriture).
  • Code contracts (proof-verification-service) : « Muter l'etat metier lors d'un appel de verification (endpoint lecture seule) » est interdit.
  • Impact : Tension architecturale non resolue. Si le UUID doit etre persistant et stable (INV-280-06 l'exige), il faut une ecriture en base. Mais l'endpoint est declare lecture seule. Option possible : le verificationRequestId est genere/assigne par un processus externe (ex: lors de la creation de la preuve) et simplement lu par l'endpoint. Le plan ne l'adresse pas.

4. Zones d'ombre

ZO-01 : Table cible pour les colonnes ajoutees (DDL-02, DDL-03)

Le plan mentionne « table de resultats de verification (ou table dediee proof_verification_cache) » sans trancher. Aucun document ne nomme la table exacte. Les code contracts referent a la migration mais pas a la table cible.

ZO-02 : HT-03 non resolu — enum PostgreSQL actuelle : 3 ou 4 valeurs ?

Le plan note que IntegrityCheckAttempt.chain_blockchain a deja default: 'PENDING' en DB, ce qui suggerait que PostgreSQL accepte deja PENDING. Mais DDL-01 prevoit ALTER TYPE ... ADD VALUE 'PENDING'. Si l'enum a deja 4 valeurs, la migration ADD VALUE echouera (valeur dupliquee). Aucun document ne leve cette ambiguite.

ZO-03 : Enregistrement module NestJS

Aucun document ne precise dans quel module NestJS le nouveau controller (ProofVerificationController), le service et l'intercepteur sont enregistres. Le plan mentionne un IntegrityModule implicitement mais ne donne pas le fichier *.module.ts a modifier. Les code contracts ne listent pas de fichier module.

ZO-04 : Observabilite de la reclassification SLA en mode lecture seule

Les tests (§8) exigent une « preuve horodatee de PENDING -> INDETERMINATE ». Si l'endpoint est lecture seule (projection, cf. DIV-01), cette preuve horodatee se reduit a un log applicatif non persistant. L'adequation entre l'exigence d'observabilite et le mode projection n'est pas explicitee.

ZO-05 : Taxonomie pendingReason — liste fermee ou extensible ?

La spec (§10.2) signale que la « taxonomie definitive (exhaustive ou extensible) » n'est pas fournie. Le code contracts interdit pendingReason hors enum TypeScript. Le plan et les tests ne resolvent pas ce point. Impact operationnel : si une 3e valeur est ajoutee ulterieurement, l'intercepteur rejettera en 500 (protection par design, mais necessitant un deploiement code).

ZO-06 : Politique de versionnement API

Declaree « non fournie » par la spec (§10.2) et « non testable » par les tests (§9). Le plan l'exclut (§10). Aucun document ne propose de mecanisme pour les consumers legacy qui ne supportent pas null dans linkResults.

ZO-07 : Down migration en production avec donnees PENDING

Declaree « non tranchee » par la spec (§10.2). Le plan (§9.2) propose un plan (cast varchar + recreation enum) avec un guard (verifier absence de lignes PENDING). Le cas ou des lignes PENDING existent effectivement en base n'a pas de procedure definie.

ZO-08 : Stabilite de verificationRequestId entre appels PENDING successifs

Le test TC-NOM-09 verifie la stabilite « lors d'un rappel d'une verification deja DONE ». Aucun test ne verifie la stabilite entre deux appels retournant PENDING (le meme proofId appele deux fois pendant que des maillons sont encore en cours). Pourtant INV-280-06 implique que le meme verificationRequestId doit persister de PENDING a DONE.

5. Recommandation

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

Divergences a resoudre avant Gate 5

Priorite Ref Action requise
BLOQUANT DIV-01 Trancher : la reclassification SLA lazy est-elle une mutation DB (spec litterale) ou une projection lecture seule (plan)? Aligner spec, tests et plan sur la meme semantique.
BLOQUANT DIV-04 + DIV-05 Clarifier le cycle de vie de verificationRequestId : (a) genere par l'endpoint (mutation, contredit INV-280-09) ou (b) assigne par un processus externe et lu par l'endpoint ? Couvrir le cas PENDING en test (ZO-08).
MAJEUR DIV-02 Ajouter TC-NOM-04 au document de tests (couverture SCN-280-04 : INDETERMINATE immediat).
MINEUR DIV-03 Aligner le decompte « 28 scenarios » des code contracts avec le nombre reel de tests.