Aller au contenu

CONFRONTATION Gate 8 (CLOSURE) — PD-254

1. Sources confrontées

Document Version Date
PD-254-specification.md Validée Gate 3 RESERVE v2 + Gate 5 RESERVE v1 2026-03-13
PD-254-tests.md 45 TC (44 PASS, 1 ABSENT, 1 PARTIEL) 2026-03-13
PD-254-acceptability.md Verdict initial REFUSÉ (2 BLOQUANTS) 2026-03-13
PD-254-review-step8-v1.md Revue post-correction 2026-03-13

2. Convergences

C-01 — Résolution des 2 écarts BLOQUANTS (E-01, E-02)

  • E-01 (3 erreurs TypeScript) : confirmé résolu par npx tsc --noEmit exit 0. Les 3 fichiers corrigés sont identifiés avec preuves factuelles.
  • E-02 (ManifestIntegrityCheck absent du VerificationEngine) : confirmé résolu. ManifestService.revalidate() appelé par MigrationCampaignService.runPostcheck() à la ligne 282, rapport peuplé ligne 314. Choix architectural documenté (orchestrateur vs engine) — légitime et conforme à INV-254-12.
  • Alignement spec : INV-254-12 (§5.7 étape 2) exige revalidation hash + signature au début du postcheck. L'implémentation satisfait cette exigence.

C-02 — Résolution écart MAJEUR E-03 (ESLint)

  • 0 erreur ESLint dans le module migration post-correction. Les 2 erreurs sécurité (detect-object-injection, detect-unsafe-regex) et les 10 erreurs qualité sont corrigées.
  • Les 5 warnings résiduels sont hors périmètre PD-254. Conforme.

C-03 — Couverture fonctionnelle solide

  • 44/45 tests contractuels PASS (acceptabilité initiale). TC-INV-07 (rollback manuel) ABSENT — hors scope automatisé, conforme à la spec §5.4.
  • TC-ERR-07 (timeout BullMQ) PARTIEL — couvert par config, non E2E. Acceptable pour une story protocolaire.
  • La matrice de couverture (tests §2) couvre les 11 invariants, les 12 cas d'erreur, les 8 flux nominaux, les 11 tests négatifs et les 5 tests de non-régression.

C-04 — Machine d'états conforme

  • TC-INV-10A/10B : matrice exhaustive des transitions, états terminaux fermés. Aligné avec spec §5.2.
  • Codes d'erreur métier (§3, §5.2) distincts des états formels — vérifié par TC-CODES-METIER-01.

C-05 — Document protocole présent

  • TC-NOM-01 PASS : document Markdown avec les 3 types de migration (support, provider, région). Conforme CA-01.

3. Divergences

D-01 — RÉGRESSION : test READABILITY_RATE (224/225) — MAJEUR

  • Fait : validation.spec.ts:137 — regex ^[01](\.\d{1,4})?$ accepte 1.0001 à 1.9999.
  • Spec : §5.1 définit readability_sample_pass_rate dans 0.0000..1.0000 avec regex ^(0(\.\d{1,4})?|1(\.0{1,4})?)$.
  • Écart : le code utilise une regex simplifiée qui ne contraint pas la partie après 1. à 0000. La regex de la spec est stricte et correcte. Le code diverge de la spec.
  • Impact : une valeur 1.5000 serait acceptée comme pass_rate valide, ce qui violerait le domaine contractuel. L'attestation pourrait contenir un readability_pass_rate sémantiquement invalide.
  • Verdict : MAJEUR. La condition de levée « 225/225 PASS après corrections » n'est pas satisfaite.

D-02 — E-04 : chemins code-contracts non vérifiés — MAJEUR

  • Fait : les fichiers sont à src/modules/migration/ (confirmé par arborescence). Le PD-254-code-contracts.yaml référence src/migration/.
  • Spec : §5.13 ne prescrit pas l'arborescence, mais les code-contracts sont un artefact de traçabilité (Art. III CONSTITUTIONAL).
  • Impact : écart de traçabilité. Les contracts ne pointent pas vers le code réel. Un audit trouverait une incohérence.
  • Verdict : MAJEUR pour la traçabilité, non bloquant fonctionnellement.

D-03 — E-05 : JSON.stringify vs RFC 8785 JCS — MINEUR

  • Fait : attestation.service.ts:84 utilise JSON.stringify, manifest.service.ts:95 utilise canonicalize() (RFC 8785).
  • Spec : §5.6 étape 2 prescrit "JSON canonique, clés triées" pour le manifest. §5.8 ne prescrit pas explicitement la méthode de sérialisation de l'attestation.
  • Impact : divergence de convention. Pas de violation fonctionnelle (sign et verify utilisent la même sérialisation). Risque théorique si un vérificateur tiers attend JCS pour l'attestation.
  • INV-254-09 (reproductibilité) : JSON.stringify est déterministe en Node.js pour un même objet, mais pas garanti cross-runtime. Risque faible mais réel pour la reproductibilité inter-environnement.
  • Verdict : MINEUR. Recommandation d'alignement sur JCS pour cohérence.

D-04 — E-06 : localeCompare pour tri GRH — MINEUR

  • Fait : global-root-hash.check.ts:18 utilise a.localeCompare(b).
  • Spec : §3 prescrit "lexicographique sur la chaîne hex lowercase (comparaison caractère par caractère, code ASCII croissant)".
  • Impact : localeCompare dépend de la locale de l'environnement. Pour hex lowercase ASCII pur, le résultat est correct dans les locales courantes. Mais INV-254-09 (reproductibilité) exige un résultat déterministe cross-environnement.
  • Verdict : MINEUR. a < b (comparaison JavaScript par défaut) ou .localeCompare(b, 'en', {sensitivity: 'base'}) serait plus rigoureux.

D-05 — E-07 : WormGuard no-op — MINEUR

  • Fait : canActivate() retourne toujours true. Le WormRetentionChecker est défini mais non injecté.
  • Spec : INV-254-06 exige "aucune suppression/altération d'objet verrouillé WORM". L'événement WORM_VIOLATION_BLOCKED est émis correctement via emitViolation().
  • Impact : le guard NestJS ne remplit pas son rôle de garde d'accès HTTP. La protection est assurée au niveau service (MigrationCampaignService), ce qui est fonctionnellement suffisant mais architecturalement incomplet.
  • TC-INV-06 et TC-ERR-09 : PASS — l'événement est bien émis. Le test vérifie l'émission, pas le mécanisme de blocage HTTP.
  • Verdict : MINEUR. Le guard est un squelette. La protection est effective via le service.

D-06 — E-08 : MigrationModule non enregistré dans AppModule — MINEUR

  • Fait : grep MigrationModule src/app.module.ts — aucun résultat.
  • Spec : hors périmètre explicite (la spec couvre le protocole, pas le bootstrapping NestJS).
  • Impact : le module ne serait pas chargé par NestJS. Attendu (TODO #10 décomposition).
  • Verdict : MINEUR. Documenté comme TODO. Non bloquant pour Gate 8 si tracé.

4. Zones d'ombre

Z-01 — Coverage non mesuré

  • L'acceptabilité note "N/A — Non mesuré (pas de --coverage sur run isolé)". Aucune donnée de couverture de code.
  • Impact : impossible de vérifier si les 225 tests couvrent effectivement les chemins critiques (branches catch, edge cases regex, etc.).

Z-02 — TC-ERR-07 (timeout BullMQ) — PARTIEL

  • "Couvert par config timeout, non testé end-to-end". La spec §5.3 définit verification_timeout avec des bornes. Le comportement en cas de dépassement n'est pas vérifié en conditions réelles.
  • Risque : une campagne pourrait rester bloquée en POSTCHECK_RUNNING si le timeout n'est pas correctement propagé.

Z-03 — Clearing conditionnel (TC-CLR-01) PASS mais E-07 WormGuard no-op

  • Le clearing fonctionne au niveau service, mais le guard qui devrait bloquer les requêtes HTTP est inactif. Si un endpoint expose une action WORM sans passer par le service, la protection est absente.

Z-04 — Regex attestation vs code

  • La spec §5.14 définit readability_pass_rate avec regex ^(0(\.\d{1,4})?|1(\.0{1,4})?)$. Le test validation.spec.ts:137 utilise une regex différente. Pas de preuve que le code de production utilise la regex de la spec.

Z-05 — Points Q-03/Q-04/Q-06 non figés

  • Les tests §10 les identifient comme "règles non testables". Le verdict QA est "testable partiellement". Ces points impactent la reproductibilité contractuelle mais sont hors périmètre d'implémentation PD-254.

5. Recommandation

Scoring

Axe Note Justification
Couverture fonctionnelle 8.5 44/45 TC PASS, 1 ABSENT (manuel), machine d'états complète
Conformité invariants 8.0 11/11 invariants couverts, INV-254-09 fragilisé par D-03/D-04
Qualité code 7.0 BLOQUANTS résolus, mais 1 régression test, regex divergente
Traçabilité 7.0 E-04 non vérifié, code-contracts potentiellement désalignés
Sécurité 8.5 ESLint sécurité résolu, WORM fonctionnel via service, guard squelette
Complétude 7.5 Module non enregistré, WormGuard no-op, coverage non mesuré

Moyenne : 7.75/10

Verdict

  • Procéder — convergence confirmée
  • Rework nécessaire — 2 réserves MAJEUR à lever
  • Escalade

Actions correctives requises (avant verdict GO)

Priorité Action Réf
P1 Corriger regex READABILITY_RATE pour rejeter 1.0001..1.9999 — aligner sur la regex spec ^(0(\.\d{1,4})?\|1(\.0{1,4})?)$ D-01, R-01
P1 Mettre à jour PD-254-code-contracts.yaml : chemins src/migration/src/modules/migration/ D-02, R-02

Réserves MINEUR (non bloquantes Gate 8, à tracer comme dette)

ID Action Réf
R-03 Aligner attestation sur RFC 8785 JCS D-03
R-04 Remplacer localeCompare par comparaison byte-order stricte D-04
R-05 Injecter WormRetentionChecker dans le guard ou documenter le choix architectural D-05
R-06 Enregistrer MigrationModule dans AppModule ou créer ticket dédié D-06

Condition de passage GO

  1. Regex READABILITY_RATE corrigée → 225/225 tests PASS
  2. PD-254-code-contracts.yaml mis à jour avec chemins corrects
  3. npx tsc --noEmit exit 0 (maintenu)
  4. npm run lint 0 erreur module migration (maintenu)