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 resoluspresente 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+nextCheckAfterSecondsobligatoires si PENDING, interdits si DONE — aligne dans les 4 documents. - INV-280-04 (finalisation) : Aucun
PENDINGinterne /nullAPI siproof_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) :
DONEterminal pour unverificationRequestIddonne ; rappel idempotent retourne reponse identique (pas erreur) — aligne apres correction ECT-V2-01. - INV-280-07 (TLA+ bijection) :
RealStates = CheckResultsa 4 valeurs — aligne. Le plan precise quePV_Proof.tlan'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 -> nulldanslinkResults— aligne spec §5.7, plan C2, code contracts (forbidden: exposer"PENDING"en API). - Validation UUID v4 :
ParseUUIDPipereutilise — 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_contractsdu 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
INDETERMINATEpendant le traitement de cet appel » — ambiguite : mutation ou projection ? - Tests (§8 observabilite) : « preuve horodatee de
PENDING -> INDETERMINATEpendant un appel API de verification » — suggere un evenement trace avec effet durable. - Plan (§2.2) : « Projeter le maillon comme
INDETERMINATEdans la reponse courante (pas de mutation en base — l'etat DB restePENDING). La reclassification en base est du ressort du processus de resolution externe. » - Impact : Si le plan a raison (projection seule), un maillon
PENDINGexpire en base ne sera jamais mute enINDETERMINATEpar 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
INDETERMINATEimmediate (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) : «
verificationRequestIdest obligatoire sur toute reponse200» — cela inclut les reponsesPENDING. - Spec (INV-280-06) : « Pour un
verificationRequestIddonne :PENDING -> DONEautorise » — 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
verificationRequestIdest 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) : «
verificationRequestIdest 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
verificationRequestIdest 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_iden 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
verificationRequestIdest 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. |