Aller au contenu

PD-296 — Plan d'implémentation

Résolution des conditions RESERVE Gate 3 v1

Ce plan intègre les corrections des 3 écarts bloquants identifiés en Gate 3 v1 (verdict RESERVE 7.438/10) :

Écart Condition Résolution dans ce plan
Écart 1 mandatory_gates_formal=3 sans checkpoint Gate 3 Ajout de GATE3_SPEC_FORMAL (checkpoint pré-Gate 3)
Écart 2 CA-296-01 (step 0+1) vs INV-296-01 (5 checkpoints) Alignement sur 6 checkpoints (pas 5). L'exécution step 0 (/coherence) reste hors comptage formel — elle est un contrôle préliminaire. Le 6e checkpoint est GATE3_SPEC_FORMAL.
Écart 3 TC-INV-01..04 référencés mais non définis Scénarios GIVEN/WHEN/THEN détaillés dans §5

Les écarts majeurs (4-9, 12) sont traités dans les hypothèses (§8) et points de vigilance (§9).


1. Découpage en composants

# Composant Responsabilité Fichier(s) Type
C1 formal-check.sh Wrapper central : validation entrées, invocation /coherence ou /formal-verify, mapping sortie → formal_check_result_json (D-296-14), gestion timeout/fail-closed scripts/formal-check.sh Script shell (nouveau)
C2 formal-state.sh Gestion d'état des checkpoints : lecture/écriture dans .gov-local.json, FSM des checkpoints (PENDING→RUNNING→PASSED/FAILED_BLOCKING), guard de transition aval scripts/lib/formal-state.sh Librairie shell (nouvelle)
C3 formal-lock.sh Lock distribué (flock), idempotence (SHA-256 → fichier flat), rate-limiting (compteur par minute), réconciliation orphelins scripts/lib/formal-lock.sh Librairie shell (nouvelle)
C4 Skills modifiés Injection des appels formal-check.sh aux 6 points d'intégration + guards de blocage gov-step.md, gov-gate.md, gov-check-plan.md, gov-accept.md Skills Claude Code (modification)
C5 Article VIII + refs Ajout Article VIII dans CONSTITUTIONAL.md, mise à jour table CLAUDE.md, mise à jour vérification constitutionnelle obligatoire governance/CONSTITUTIONAL.md, CLAUDE.md Documentation constitutionnelle (modification)
C6 FSM + procédures Mise à jour data/fsm.yaml (événements formels), procedures.md (nouvelles procédures), workflow-rules.md (nouvelles règles) data/fsm.yaml, .claude/rules/procedures.md, .claude/rules/workflow-rules.md Configuration + documentation (modification)

2. Flux techniques

2.1 Flux nominal — Checkpoint formel

1. Le skill (gov-step, gov-gate, gov-check-plan, gov-accept) atteint un point d'intégration
2. Appel : ./scripts/formal-check.sh <story_id> <project_code> <checkpoint_id> <trigger_event> <artifact_path>
3. formal-check.sh :
   a. Valide les entrées (D-296-01..D-296-05, D-296-10) → si invalide : FAILED_BLOCKING immédiat
   b. Génère correlation_id (uuidgen) et idempotency_key (sha256 du payload)
   c. Acquiert le lock flock sur /tmp/formal-lock-<story_id>-<checkpoint_id>.lock (TTL via timeout)
   d. Vérifie idempotence (fichier .formal-idempotency/<key>) → si replay identique : retourne résultat caché
   e. Met l'état à RUNNING dans .gov-local.json via formal-state.sh
   f. Invoque l'outil formel avec timeout :
      - coherence_spec → /coherence check PD-XX (via unset CLAUDECODE && claude -p)
      - formal_contracts, formal_plan, formal_code → /formal-verify (via unset CLAUDECODE && claude -p)
      - formal_full → /formal-verify pipeline complet
   g. Mappe la sortie vers verdict GO|FAIL :
      - /coherence : "blocking": true + issues > 0 → FAIL, sinon GO
      - /formal-verify : exit code 0 → GO, exit code 1/2/3 → FAIL
      - Timeout (180s) → FAIL + failure_code=TIMEOUT
      - Outil absent → FAIL + failure_code=TOOL_UNAVAILABLE
   h. Construit formal_check_result_json (D-296-14) avec toutes les clés requises
   i. Met l'état à PASSED ou FAILED_BLOCKING via formal-state.sh
   j. Libère le lock, enregistre idempotence, écrit résultat en audit
   k. Retourne le JSON sur stdout (exit 0 si PASSED, exit 1 si FAILED_BLOCKING)
4. Le skill lit le code de retour :
   - exit 0 → continue le workflow
   - exit 1 → affiche les détails, bloque la transition aval, propose correction

2.2 Flux de correction — FAILED_BLOCKING → PENDING → relance

1. Le skill affiche les détails d'échec (details[]) à l'utilisateur
2. L'utilisateur corrige l'artefact source (spec, plan, code...)
3. Le skill relance formal-check.sh avec le même checkpoint_id
4. formal-check.sh :
   a. Détecte état courant FAILED_BLOCKING → transition vers PENDING (autorisée)
   b. Génère nouveau correlation_id, nouvelle idempotency_key (payload différent)
   c. Exécute le contrôle formel normalement
   d. Si GO → PASSED, transition aval débloquée
   e. Si FAIL → FAILED_BLOCKING à nouveau, nouvelle boucle

2.3 Flux de ré-évaluation — PASSED → PENDING (résolution Écart 4)

1. Après une gate NON_CONFORME, l'artefact source est modifié (spec v2, code corrigé...)
2. Le skill appelle formal-check.sh avec flag --force-recheck
3. formal-check.sh :
   a. Détecte état courant PASSED + flag --force-recheck → transition vers PENDING
   b. Conserve l'historique du PASSED précédent dans details[]
   c. Exécute le contrôle formel sur l'artefact modifié
   d. Résultat : nouveau PASSED ou FAILED_BLOCKING
Note : Sans --force-recheck, PASSED reste terminal (protection contre les relances inutiles)

2bis. Diagramme de dépendances agents (step 6b)

graph LR
    subgraph Wave 1 — Parallélisable
        A1[C1: formal-check.sh]
        A2[C2: formal-state.sh]
        A3[C3: formal-lock.sh]
    end

    subgraph Wave 2 — Dépend de Wave 1
        A4[C5: Article VIII + CLAUDE.md]
        A5[C6: FSM + procédures]
    end

    subgraph Wave 3 — Dépend de Wave 1 + Wave 2
        A6[C4: Skills modifiés]
    end

    A1 --> A6
    A2 --> A6
    A3 --> A6
    A4 --> A6
    A5 --> A6

Wave 1 : Les 3 scripts/librairies (C1, C2, C3) sont indépendants — développables en parallèle. Wave 2 : Les modifications documentaires (C5, C6) dépendent de la connaissance des mécanismes Wave 1 pour les référencer correctement. Wave 3 : Les modifications de skills (C4) intègrent les appels aux scripts Wave 1 et référencent les articles/procédures Wave 2.


3. Mapping invariants → mécanismes

Invariant ID Exigence Mécanisme Composant Observable Risque
INV-296-01 Chaque story exécute exactement 6 checkpoints formels Mapping déterministe dans formal-check.sh : 6 checkpoint_id canoniques. Guard dans formal-state.sh : count_checkpoints_passed() vérifie 6/6 avant Done C1, C2 jq '.formal_checkpoints | length' .gov-local.json == 6 Oubli d'un point d'appel dans un skill
INV-296-02 STEP1_SPEC_COHERENCE obligatoire avant step 2 Appel formal-check.sh dans gov-step.md après sauvegarde spec. Guard dans formal-state.sh : check_formal_passed STEP1_SPEC_COHERENCE avant transition step 1→2 C1, C2, C4 Checkpoint PASSED dans .gov-local.json avant step 2 Spec sauvegardée mais checkpoint oublié
INV-296-03 STEP4_CONTRACTS_FORMAL obligatoire avant Gate 5 Appel formal-check.sh dans gov-step.md après sauvegarde plan+contracts. Guard dans formal-state.sh C1, C2, C4 Checkpoint PASSED avant Gate 5 Plan sauvé sans contracts
INV-296-04 GATE5_PLAN_FORMAL dans /gov-check-plan Phase 4 Nouvelle Phase 4 dans gov-check-plan.md appelant formal-check.sh C1, C4 Phase 4 visible dans traces avant verdict Gate 5 Phase 4 sautée si check-plan échoue avant
INV-296-05 STEP6_CODE_FORMAL obligatoire avant step 7 Appel formal-check.sh dans gov-step.md/gov-impl.md après step 6c C1, C2, C4 Checkpoint PASSED avant step 7 Timeout sur gros codebases
INV-296-06 GATE8_FINAL_FORMAL obligatoire avant Gate 8 Appel formal-check.sh dans gov-accept.md post-Phase 2 C1, C2, C4 Checkpoint PASSED avant soumission Gate 8 Durée cumulée > 180s sur pipeline complet
INV-296-07 FAIL → transition aval BLOQUÉE Guard check_formal_passed() dans formal-state.sh retourne exit 1 si état ≠ PASSED. Chaque skill vérifie avant progression C2, C4 Transition aval absente dans audit Guard contourné par appel direct
INV-296-08 Outil indisponible ou timeout → FAIL (fail-closed) formal-check.sh : which swipl, which claude → TOOL_UNAVAILABLE. timeout 180 → TIMEOUT. Défaut = FAIL C1 failure_code dans résultat JSON Outil présent mais qui hang
INV-296-09 Pas de Done Jira si FAIL ouvert Guard check_all_formal_passed() dans formal-state.sh appelé avant transition Done (31). Couvre aussi DONE_ANOMALY (2) et REJECTED (3) — résolution Écart 5 C2, C4 Transition refusée dans audit Transition Jira directe hors workflow
INV-296-10 Tous projets sans exception Aucune condition if project_code == ... dans formal-check.sh. Validation regex D-296-02 accepte les 8 codes C1 Mêmes checkpoints sur backend et site Projet non listé ajouté plus tard
INV-296-11 Article VIII dans CONSTITUTIONAL.md + ref CLAUDE.md Texte ajouté manuellement (C5). Vérifié par grep "Article VIII" governance/CONSTITUTIONAL.md C5 Article détectable par grep Oubli de mise à jour CLAUDE.md
INV-296-12 4 états uniquement : PENDING, RUNNING, PASSED, FAILED_BLOCKING Enum dans formal-state.sh : FORMAL_STATES=(PENDING RUNNING PASSED FAILED_BLOCKING). Toute valeur hors enum → rejet C2 set_checkpoint_state rejette états invalides Corruption manuelle du JSON
INV-296-13 Transitions hors §5.4 INTERDITES Matrice de transitions dans formal-state.sh : ALLOWED_TRANSITIONS associative array. Transitions non listées → rejet avec log C2 Tentative interdite → message d'erreur + exit 1 Appel direct jq sur le JSON
INV-296-14 Payload résultat conforme D-296-14 Validation JSON avec jq dans formal-check.sh : vérification des 12 clés requises + regex sur chaque valeur C1 Validation réussie sur chaque run Clé details vide vs absente
INV-296-15 Lock + idempotence + réconciliation + rate-limit formal-lock.sh : flock (lock), fichier SHA-256 (idempotence), cron-like scan (réconciliation), compteur /tmp/formal-rate-<story> (rate-limit) C3 Lock acquis/rejeté dans logs, replay idempotent flock non atomique sur NFS (non applicable ici — exécution locale)
INV-296-16 Données invalides → rejet + blocage Validation regex dans formal-check.sh pour chaque D-296-* avant toute exécution. Rejet immédiat avec FAILED_BLOCKING C1 Regex match/mismatch dans stderr Encoding UTF-8 non-ASCII dans story_id
INV-296-17 Aucun mode warning/informative/skip Pas de flag --warning-only, --skip, --dry-run dans formal-check.sh. Aucun if GOV_FORMAL_SKIP dans les skills C1, C4 Absence de ces modes dans le code Variable d'environnement non documentée
INV-296-18 Toutes les règles testables Matrice TC-* dans §5 couvre chaque invariant. TC-INV-04 vérifie la complétude Tous Matrice de couverture complète Évolution spec sans mise à jour tests

4. Mapping critères d'acceptation → mécanismes

Critère ID Mécanisme(s) Composant Observable Risque
CA-296-01 /coherence check invoqué au step 0 (existant, hors comptage) ET step 1 (STEP1_SPEC_COHERENCE via formal-check.sh) C1, C4 Deux exécutions dans session-log avec correlation_id distincts Confusion step 0 / step 1 dans le comptage
CA-296-02 4 checkpoints formal_* : STEP4_CONTRACTS_FORMAL, GATE5_PLAN_FORMAL, STEP6_CODE_FORMAL, GATE8_FINAL_FORMAL + GATE3_SPEC_FORMAL (nouveau) C1, C2, C4 5 checkpoints formal_* + 1 coherence = 6 dans .gov-local.json Oubli d'un point d'appel
CA-296-03 Guard check_formal_passed() avant chaque transition aval. Exit 1 = blocage C2, C4 Transition absente tant que FAILED_BLOCKING Appel direct sans guard
CA-296-04 formal-check.sh : which <tool> + timeout 180 → FAIL + TOOL_UNAVAILABLE/TIMEOUT C1 failure_code dans résultat JSON Tool présent mais qui retourne erreur inattendue
CA-296-05 Article VIII rédigé dans governance/CONSTITUTIONAL.md C5 grep -c "Article VIII" governance/CONSTITUTIONAL.md ≥ 1 Texte incorrect ou incomplet
CA-296-06 Table constitutionnelle dans CLAUDE.md mise à jour avec ligne Article VIII C5 grep "VIII" CLAUDE.md Oubli de mise à jour
CA-296-07 Aucun filtre projet dans formal-check.sh. Regex D-296-02 accepte 8 codes C1 Même comportement sur backend, app, site, infra Test exhaustif des 8 projets non réaliste → échantillonnage
CA-296-08 Guard check_all_formal_passed() avant Done (31), DONE_ANOMALY (2), REJECTED (3) C2, C4 Transition refusée si FAIL ouvert Transition Jira hors workflow
CA-296-09 formal-lock.sh : flock (lock), SHA-256 fichier (idempotence) C3 Double déclenchement → CONCURRENT_RUN ou replay identique Race condition sur flock
CA-296-10 timeout 180 dans formal-check.sh (configurable via GOV_FORMAL_TIMEOUT_SEC) C1 Dépassement → FAILED_BLOCKING + TIMEOUT Timeout trop court sur machines lentes
CA-296-11 Validation JSON jq dans formal-check.sh vérifie schéma D-296-14 C1 Validation réussie/échouée sur chaque run Champ optionnel vs obligatoire
CA-296-12 Phase 4 dans gov-check-plan.md : appel formal-check.sh GATE5_PLAN_FORMAL C4 Phase visible dans traces avant verdict Gate 5 Phase sautée si phases 0-3 échouent

5. Mapping tests (TC-*) → mécanismes + observables

5.1 Flux nominaux

Test ID Référence spec Mécanisme(s) Point(s) d'observation Niveau de test visé
TC-NOM-01 INV-296-02, CA-296-01 formal-check.sh STEP1_SPEC_COHERENCE + guard dans formal-state.sh État PENDING→RUNNING→PASSED dans .gov-local.json + résultat JSON archivé Integration
TC-NOM-02 INV-296-03, CA-296-02 formal-check.sh STEP4_CONTRACTS_FORMAL + guard Checkpoint PASSED + éligibilité Gate 5 Integration
TC-NOM-03 INV-296-04, CA-296-12 Phase 4 gov-check-plan.mdformal-check.sh GATE5_PLAN_FORMAL Phase formelle visible dans traces avant verdict Integration
TC-NOM-04 INV-296-05, CA-296-02 formal-check.sh STEP6_CODE_FORMAL + guard Transition step 6→7 autorisée Integration
TC-NOM-05 INV-296-06, CA-296-02 formal-check.sh GATE8_FINAL_FORMAL dans gov-accept.md Soumission Gate 8 autorisée Integration
TC-NOM-06 CA-296-01 /coherence au step 0 (existant) + formal-check.sh STEP1_SPEC_COHERENCE au step 1 Deux correlation_id distincts dans session-log Integration
TC-NOM-07 INV-296-01, INV-296-10 Aucun filtre projet dans formal-check.sh + validation regex D-296-02 6 checkpoints identiques sur chaque project_code testé E2E (échantillonnage)
TC-NOM-08 INV-296-11, CA-296-05, CA-296-06 Contenu CONSTITUTIONAL.md + CLAUDE.md vérifié par grep Article VIII détectable + référence dans table Unit (grep)
TC-NOM-09 INV-296-14, CA-296-11 Validation JSON jq dans formal-check.sh 12 clés requises + regex conformes Unit
TC-NOM-10 INV-296-15, CA-296-09 Fichier idempotence .formal-idempotency/<key> Même résultat, pas de double exécution Integration
TC-NOM-11 INV-296-13 Transition FAILED_BLOCKING→PENDING dans formal-state.sh + relance Historique conservé + verrous actifs jusqu'à PASSED Integration
TC-NOM-12 INV-296-15 formal-lock.sh : scan orphelins + clearing cycles Orphelin → FAILED_BLOCKING, levée après N cycles PASSED Integration

5.2 Cas d'erreur

Test ID Référence spec Mécanisme(s) Point(s) d'observation Niveau de test visé
TC-ERR-01 D-296-01, INV-296-16 Validation regex ^PD-[0-9]{1,4}$ dans formal-check.sh Rejet immédiat, exit 1, pas de RUNNING Unit
TC-ERR-02 D-296-03, INV-296-16 Validation regex checkpoint_id dans formal-check.sh Rejet + FAILED_BLOCKING, audit Unit
TC-ERR-03 D-296-14, INV-296-14 Validation jq des clés obligatoires dans résultat Rejet + INTERNAL_ERROR Unit
TC-ERR-04 INV-296-07, CA-296-03 Guard check_formal_passed retourne exit 1 Step 2 refusé, contradictions dans details[] Integration
TC-ERR-05 INV-296-07 Guard check_formal_passed pour STEP4 ou GATE5 Gate 5 refusée Integration
TC-ERR-06 INV-296-07 Guard check_formal_passed pour STEP6 Step 7 interdit Integration
TC-ERR-07 INV-296-07 Guard check_formal_passed pour GATE8 Gate 8 refusée Integration
TC-ERR-08 INV-296-08, CA-296-04 which <tool> échoue dans formal-check.sh FAIL + TOOL_UNAVAILABLE Unit
TC-ERR-09 INV-296-08, CA-296-10 timeout 180 expire dans formal-check.sh RUNNING→FAILED_BLOCKING + TIMEOUT Integration
TC-ERR-10 INV-296-15 flock --nonblock échoue dans formal-lock.sh FAIL + CONCURRENT_RUN Unit
TC-ERR-11 INV-296-15 Fichier idempotence existant + payload différent Rejet de la relance Unit
TC-ERR-12 INV-296-17 Tentative --skip ou variable GOV_FORMAL_SKIP Rejet (flag non reconnu) Unit
TC-ERR-13 INV-296-09, CA-296-08 Guard check_all_formal_passed avant Done/DONE_ANOMALY Transition refusée Integration

5.3 Tests d'invariants (TC-INV-01..04 — résolution Écart 3)

TEST-ID: TC-INV-01
Référence spec: INV-296-12

GIVEN
  - Le composant formal-state.sh est chargé
  - Un checkpoint existe dans .gov-local.json avec un état valide (PENDING)
WHEN
  - Une tentative de set_checkpoint_state est faite avec un état invalide ("DONE", "SKIPPED", "WARNING", "N/A")
THEN
  - La fonction retourne exit 1 avec message "Invalid state: <state>. Allowed: PENDING, RUNNING, PASSED, FAILED_BLOCKING"
  - L'état dans .gov-local.json reste inchangé (PENDING)
AND
  - Seuls les 4 états PENDING, RUNNING, PASSED, FAILED_BLOCKING sont acceptés par set_checkpoint_state
  - Le test vérifie les 4 états valides (acceptés) ET au moins 5 états invalides (rejetés)
TEST-ID: TC-INV-02
Référence spec: INV-296-13

GIVEN
  - formal-state.sh est chargé avec la matrice de transitions ALLOWED_TRANSITIONS
  - Un checkpoint est dans l'état RUNNING
WHEN
  - Une transition RUNNING → PENDING est tentée (transition interdite §5.4)
THEN
  - La fonction retourne exit 1 avec message "Forbidden transition: RUNNING -> PENDING"
  - L'état reste RUNNING
AND
  - Le test vérifie exhaustivement les 12 transitions (4 autorisées, 8 interdites) de la matrice §5.4
  - Chaque transition interdite est rejetée avec message explicite
  - Chaque transition autorisée est acceptée
TEST-ID: TC-INV-03
Référence spec: INV-296-17

GIVEN
  - formal-check.sh est disponible sur le PATH
  - Un checkpoint valide est prêt à être déclenché
WHEN
  - L'appel est fait avec des flags de contournement :
    a) --skip
    b) --warning-only
    c) --dry-run
    d) --informative
    e) Variable d'environnement GOV_FORMAL_SKIP=1
THEN
  - Chaque tentative retourne exit 1 avec message "Unknown flag" ou "GOV_FORMAL_SKIP is not supported"
  - Aucun contrôle formel n'est exécuté
  - Aucun changement d'état ne se produit
AND
  - Le code source de formal-check.sh ne contient aucune branche conditionnelle sur ces flags/variables
  - grep -c "warning.only\|skip\|dry.run\|informative" scripts/formal-check.sh == 0 (hors commentaires)
TEST-ID: TC-INV-04
Référence spec: INV-296-18

GIVEN
  - La matrice de couverture tests §2 (TC-* → INV-* → CA-*)
  - Les 18 invariants INV-296-01..18
  - Les 12 critères d'acceptation CA-296-01..12
WHEN
  - Un audit de couverture est exécuté (script ou vérification manuelle)
THEN
  - Chaque INV-296-* est couvert par au moins 1 test TC-*
  - Chaque CA-296-* est couvert par au moins 1 test TC-*
  - Les tests TC-INV-01..04 (ce document) sont définis avec GIVEN/WHEN/THEN
AND
  - Les réserves de testabilité du document tests §9 sont documentées :
    - GATE3_SPEC_FORMAL (nouveau checkpoint) : testable via TC-NOM ajouté
    - Configurabilité SLA : testable via variable d'environnement GOV_FORMAL_TIMEOUT_SEC
    - TC-NOM-07 exhaustif (8 projets) : test par échantillonnage (≥2 projets)
  - L'audit est reproductible (script ou checklist vérifiable)

5.4 Tests négatifs et non-régression

Test ID Référence spec Mécanisme(s) Point(s) d'observation Niveau de test visé
TC-NEG-01..12 D-296-*, INV-296-16 Validation regex dans formal-check.sh Rejet + FAILED_BLOCKING pour chaque entrée invalide Unit
TC-NR-01..05 F-296-*, §5.4 Replay déterministe, scope guard, historique, no-retry, terminalité Comportement identique sur replays Integration

6. Gestion des erreurs

Code erreur Cause Traitement dans formal-check.sh Observable
INPUT_INVALID Entrée non conforme D-296-01..15 Rejet immédiat, exit 1, pas de RUNNING stderr + résultat JSON
TOOL_UNAVAILABLE which swipl/claude/alloy échoue FAIL immédiat, failure_code=TOOL_UNAVAILABLE résultat JSON + stderr
TIMEOUT timeout $GOV_FORMAL_TIMEOUT_SEC expire Kill process, failure_code=TIMEOUT résultat JSON + stderr
CONCURRENT_RUN flock --nonblock échoue FAIL immédiat, failure_code=CONCURRENT_RUN résultat JSON
INTERNAL_ERROR Sortie outil non parseable, erreur jq, état incohérent FAIL, failure_code=INTERNAL_ERROR résultat JSON + stderr
CONTRADICTION_DETECTED /coherence détecte contradiction(s) FAIL, contradictions dans details[] résultat JSON
MODEL_VIOLATION /formal-verify détecte violation de modèle FAIL, violations dans details[] résultat JSON
NONE Succès (GO) PASSED, failure_code=NONE résultat JSON

Mapping erreur → flux de reprise

failure_code Reprise possible Action utilisateur
CONTRADICTION_DETECTED Oui Corriger l'artefact, relancer le checkpoint
MODEL_VIOLATION Oui Corriger l'artefact, relancer le checkpoint
TOOL_UNAVAILABLE Oui (après install) Installer l'outil manquant, relancer
TIMEOUT Oui Augmenter GOV_FORMAL_TIMEOUT_SEC ou optimiser l'artefact
CONCURRENT_RUN Oui (attendre) Attendre la fin du run concurrent
INPUT_INVALID Oui Corriger les paramètres d'appel
INTERNAL_ERROR Selon le cas Investiguer stderr, corriger ou ESCALADE

7. Impacts sécurité

Risque Mitigation Observable
Contournement via DONE (with anomaly) (Écart 5) Guard check_all_formal_passed couvre Done (31), DONE_ANOMALY (2) ET REJECTED (3) Transition refusée pour les 3
Contournement via mode « force » gate (Écart 12) Article VIII interdit explicitement tout override/force pour les échecs formels. Le guard dans formal-state.sh ne vérifie pas de flag force — il est binaire (PASSED ou bloqué) Aucune branche « force » dans le code
Injection dans artifact_path Validation regex D-296-10 : chemin POSIX absolu sous ProbatioVault-*. Résolution via GOV_WORKSPACE_ROOT (résolution Écart 6 — voir §8 H-PLAN-02) Path hors racine → rejet
Lock stale (crash pendant RUNNING) Réconciliation : scan fichiers .formal-state-* > orphan_threshold_sec → FAILED_BLOCKING Orphelin converti dans logs
Audit trail manipulation Résultats formels écrits en append-only dans .gov-local.json (clé formal_audit[]). Pas de suppression possible via l'API formal-state.sh Historique complet dans le JSON

8. Hypothèses techniques

ID Hypothèse Impact si faux
H-PLAN-01 Les sorties /coherence (JSON {blocking, issues}) et /formal-verify (exit code 0/½/3) sont mappables sans ambiguïté vers verdict=GO\|FAIL via les règles de §2.1 étape g. Le mapping STOP → FAIL est explicite dans le code. Adaptateur à réécrire si le format de sortie change.
H-PLAN-02 artifact_path utilise une variable GOV_WORKSPACE_ROOT (défaut /Users/loic/Developpement/ProbatioVault) au lieu d'un chemin hardcodé. La regex D-296-10 est construite dynamiquement : ^${GOV_WORKSPACE_ROOT}/ProbatioVault-[a-z-]+/.+$. Résout Écart 6. Si la variable n'est pas définie, fallback sur le chemin par défaut (comportement actuel).
H-PLAN-03 Le lock distribué utilise flock (POSIX, atomique sur filesystem local). Suffisant pour le contexte d'exécution (même machine, sessions cmux concurrentes). Résout Écart 11. Si exécution sur machines différentes → nécessiterait Redis/SQLite. Non applicable pour PD-296.
H-PLAN-04 L'idempotency_key est un SHA-256 du payload canonique : sha256("${story_id}|${project_code}|${checkpoint_id}|${trigger_event}|$(sha256sum ${artifact_path})"). Résout Écart 8. Si l'artefact est modifié entre deux appels → clé différente → nouveau run (comportement attendu).
H-PLAN-05 L'état « dégradé » (clearing conditionnel) est défini comme : un checkpoint ayant été FAILED_BLOCKING au moins une fois dans la session courante. Le scope est par story_id + checkpoint_id. Le compteur clearing_success_cycles est stocké dans .gov-local.json. Résout Écart 7. Si le scope est trop fin (par checkpoint), risque de clearing prématuré.
H-PLAN-06 La transition PASSED → PENDING est autorisée uniquement via le flag --force-recheck dans formal-check.sh. Sans ce flag, PASSED est terminal. Résout Écart 4. Si un skill oublie le flag après correction → le checkpoint obsolète n'est pas relancé. Les skills doivent être modifiés pour passer --force-recheck systématiquement lors des boucles de correction gate.
H-PLAN-07 Les formats d'entrée des outils formels (/coherence, /formal-verify) ne sont pas contractualisés par PD-296 (hors périmètre — Écart 9). PD-296 contractualise uniquement le format de sortie (D-296-14). L'interface d'entrée est celle documentée dans les skills existants. Si les skills formels changent leur interface → formal-check.sh à adapter.
H-PLAN-08 Le checkpoint GATE3_SPEC_FORMAL (nouveau, résolution Écart 1) invoque /formal-verify avec scope formal_spec pour vérifier l'alignement spec↔tests↔invariants avant Gate 3. Distinct de STEP1_SPEC_COHERENCE qui ne vérifie que la cohérence inter-EB. Si le périmètre de vérification Gate 3 n'est pas défini → vérification redondante avec STEP1.
H-PLAN-09 Le rate-limit (Écart 14) produit un rejet simple (pas de FAILED_BLOCKING) : le checkpoint reste dans son état actuel, la requête est refusée avec message. Ceci évite qu'un pic de requêtes bloque artificiellement le workflow. Si FAILED_BLOCKING est attendu → modifier le comportement.

9. Points de vigilance (risques, dette, pièges)

9.1 Risques d'implémentation

Risque Probabilité Impact Mitigation
Timeout 180s insuffisant sur formal_full (GATE8) Moyenne FAILED_BLOCKING systématique Variable GOV_FORMAL_TIMEOUT_SEC configurable. Documenter dans CLAUDE.md.
Race condition sur .gov-local.json (deux agents écrivent simultanément) Faible État incohérent formal-state.sh utilise flock sur le fichier JSON avant chaque écriture.
Oubli d'appel --force-recheck dans un skill après correction Moyenne Checkpoint PASSED obsolète non relancé Convention documentée : toute boucle de correction gate DOIT appeler formal-check avec --force-recheck pour les checkpoints concernés.
claude -p échoue silencieusement (subprocess) Faible TOOL_UNAVAILABLE non détecté Vérifier exit code ET taille stdout > 0.

9.2 Dette technique acceptée

Dette Justification Ticket futur
Pas de base de données pour l'idempotence (fichiers flat) Suffisant pour exécution locale mono-machine. Refactoring si LOTR multi-machine.
Pas de dashboard temps réel des checkpoints formels Les traces dans .gov-local.json sont lisibles. Dashboard si volume > 10 stories/semaine.
TC-NOM-07 par échantillonnage (pas 8 projets exhaustifs) 8 workflows complets = ~16h. Échantillonner ≥2 projets (backend + un autre).

9.3 Pièges connus

  • unset CLAUDECODE : Tout appel claude -p dans formal-check.sh DOIT être préfixé par unset CLAUDECODE && (convention existante).
  • Encoding UTF-8 : Les details[] peuvent contenir des caractères non-ASCII (noms de variables français). Le JSON doit être UTF-8.
  • Correction multi-checkpoint : Si Gate 8 échoue → le code est corrigé → il faut relancer STEP6_CODE_FORMAL ET GATE8_FINAL_FORMAL (pas seulement le dernier). Les skills doivent gérer cette cascade.

10. Hors périmètre

Élément Raison
Création d'un nouveau modèle formel Explicitement exclu par la spec §2
Refonte de ProbatioVault-formal Explicitement exclu
Optimisation de performance des moteurs formels Explicitement exclu
Changement du job CI GitLab tla-verify Explicitement exclu
Contractualisation des formats d'entrée des outils formels (Écart 9) Hors périmètre — les skills existants documentent leur interface
Dashboard temps réel des checkpoints formels Dette acceptée (§9.2)
Statut Jira dédié aux échecs formels (Q-296-07) Réutilisation des statuts existants — le blocage est géré localement par les guards

Périmètre de test

Niveau de test In scope Hors scope (justification)
Unitaire Validation entrées (regex D-296-*), FSM transitions, états autorisés/interdits, parsing JSON, lock/idempotence
Intégration Flux complet checkpoint (PENDING→RUNNING→PASSED/FAILED_BLOCKING), guards de blocage, interaction skills↔formal-check.sh, correction+relance
E2E Workflow /gov complet sur 1 story avec les 6 checkpoints Workflow sur les 8 projets (échantillonnage ≥2 — justification : 16h de workflow exhaustif)

Tous les niveaux de test sont couverts. Exclusion partielle E2E justifiée par le coût d'exécution.


Mécanismes cross-module

Élément Détail
Commandes à protéger /gov-step (steps 1, 4, 6), /gov-check-plan (Phase 4), /gov-accept (post Phase 2), /gov-gate (G3, G5, G8)
Guard formel Fonction check_formal_passed() dans formal-state.sh, appelée avant chaque transition aval
Données cross-module story_id, checkpoint_id, état courant .gov-local.json, artefact(s) source
Résolution de liaison Mapping déterministe step/gate → checkpoint_id (6 mappings)
Scope d'enregistrement Local aux commandes listées — pas de guard global hors workflow /gov
Exceptions Aucune. Article VIII interdit tout bypass y compris mode « force » gate

Les 6 checkpoints formels (résolution Écarts 1 + 2)

# Checkpoint ID Déclencheur Scope Outil Bloque
1 STEP1_SPEC_COHERENCE SPEC_SAVED coherence_spec /coherence check Step 2
2 GATE3_SPEC_FORMAL GATE3_REVIEW_START formal_spec /formal-verify Verdict Gate 3
3 STEP4_CONTRACTS_FORMAL PLAN_AND_CONTRACTS_SAVED formal_contracts /formal-verify Gate 5
4 GATE5_PLAN_FORMAL CHECK_PLAN_PHASE4_START formal_plan /formal-verify Verdict Gate 5
5 STEP6_CODE_FORMAL STEP6C_DONE formal_code /formal-verify Step 7
6 GATE8_FINAL_FORMAL GOV_ACCEPT_PHASE2_DONE formal_full /formal-verify Gate 8

Bornes corrigées : mandatory_checkpoints_per_story = 6, mandatory_gates_formal = 3 (Gate 3, Gate 5, Gate 8 — tous couverts).