PD-297 — Boucle d’enrichissement formel contractuelle (capitalisation inter-stories)¶
1. Objectif¶
La User Story PD-297 DOIT fermer la boucle formelle du workflow /gov : à chaque story DONE, la base formelle DOIT être enrichie de manière traçable et idempotente (Prolog, TLA+, Alloy, Z), puis validée par non-régression. Les scopes contracts, code et full DOIVENT produire un verdict GO ou FAIL (jamais SKIP).
2. Périmètre / Hors périmètre¶
Inclus¶
- Enrichissement append-only des prédicats de story dans
ProbatioVault-formal. - Persistance des invariants dérivés des code-contracts dans les 4 formalismes (
prolog,tla,alloy,z). - Vérification de non-régression sur base formelle étendue.
- Verdict formel obligatoire
GO|FAILpourcontracts,code,full. - Intégration contractuelle au step 10 (
gov-retrospective). - Protection distribuée (lock, idempotence, réconciliation, rate-limit, clearing).
- Traçabilité story-source de tout artefact enrichi.
Exclu¶
- Modification du contenu normatif existant (hors append-only d’enrichissement).
- Enrichissement rétroactif des stories historiques déjà
DONE. - Changement de comportement fonctionnel hors PD-297 dans les autres steps.
- Toute règle non testable est hors périmètre.
3. Définitions¶
| Terme | Définition |
|---|---|
| Enrichissement formel | Ajout de faits/prédicats/invariants d’une story dans la base formelle, sans suppression ni mutation de l’existant. |
| Append-only | Écriture uniquement additive ; aucune ligne existante ne peut être modifiée/supprimée. |
| Non-régression formelle | Vérification que les nouveaux artefacts n’introduisent pas de contradiction avec la base existante. |
Scope contracts | Vérification formelle sur artefacts contractuels de la story. |
Scope code | Vérification formelle sur artefacts code de la story. |
Scope full | Vérification formelle globale (contracts + code + base enrichie). |
| Fail-closed | Toute erreur interne/timeout/outillage indisponible retourne FAIL. |
| État terminal | État sans sortie autorisée ; toute sortie doit être explicitement interdite. |
| Réconciliation | Détection et rattrapage des exécutions orphelines/partielles. |
| Transition retour | Transition explicite vers un état antérieur (autorisée ou interdite). |
4. Invariants (non négociables)¶
| ID | Règle | Justification |
|---|---|---|
| INV-297-01 | L’enrichissement est append-only : aucune suppression/modification d’un prédicat déjà persisté. | Prévention des régressions silencieuses. |
| INV-297-02 | Tout prédicat/invariant persisté DOIT porter une traçabilité story_id + trace_source (D-297-01, D-297-16). | Opposabilité et audit. |
| INV-297-03 | Le replay strictement identique (même idempotency_key, même payload) DOIT produire exactement le même résultat sans duplication. | Robustesse retry. |
| INV-297-04 | Toute erreur d’extraction/persistance place le run en ENRICHMENT_DEGRADED (pas DONE). | Dégradation contrôlée. |
| INV-297-05 | Toute erreur interne de vérification formelle retourne FAIL (fail-closed). | Art. VIII constitutionnel. |
| INV-297-06 | Les scopes contracts, code, full retournent uniquement GO ou FAIL (jamais SKIP). | Fermeture du trou PD-296. |
| INV-297-07 | Les 4 formalismes (prolog, tla, alloy, z) sont obligatoires à chaque enrichissement valide. | Couverture formelle complète. |
| INV-297-08 | Le check de non-régression est obligatoire après enrichissement avant clôture step 10. | Détection de contradictions. |
| INV-297-09 | États autorisés : PENDING, EXTRACTING, ENRICHED, ENRICHMENT_DEGRADED, VERIFICATION_PASSED, FAILED_BLOCKING, DONE. | FSM fermée et testable. |
| INV-297-10 | Toute transition non listée en §5.5 est interdite. | Zéro ambiguïté de transitions. |
| INV-297-11 | PENDING -> EXTRACTING est la seule entrée nominale du run d’enrichissement. | Démarrage déterministe. |
| INV-297-12 | EXTRACTING -> ENRICHED exige extraction + persistance réussies sur les 4 formalismes. | Intégrité du statut ENRICHED. |
| INV-297-13 | EXTRACTING -> ENRICHMENT_DEGRADED est obligatoire en cas de timeout/erreur d’extraction ou persistance. | Contrat de dégradation. |
| INV-297-14 | ENRICHED -> VERIFICATION_PASSED exige GO non-régression + GO scopes contracts,code,full. | Validation complète. |
| INV-297-15 | ENRICHED -> FAILED_BLOCKING est obligatoire si un check retourne FAIL, ERROR ou SKIP. | Bloquant non contournable. |
| INV-297-16 | ENRICHMENT_DEGRADED -> FAILED_BLOCKING est obligatoire (vérification bloquante). | Cohérence avec INV-297-04. |
| INV-297-17 | VERIFICATION_PASSED -> DONE est l’unique transition de clôture réussie. | Clôture contrôlée. |
| INV-297-18 | FAILED_BLOCKING -> PENDING est la seule transition retour autorisée, après correction explicite. | Boucle de correction maîtrisée. |
| INV-297-19 | DONE -> * : INTERDITE (état terminal, résolution manuelle uniquement). | Immutabilité de fin de run. |
| INV-297-20 | Les mécanismes distribués de §5.6 sont obligatoires en concurrence multi-runs. | Robustesse distribuée. |
| INV-297-21 | La clôture step 10 est interdite tant que l’état n’est pas DONE. | Alignement inter-modules. |
| INV-297-22 | Toute règle de cette spec est testable via §7/§8 ; sinon classée hors périmètre. | Contractualisation vérifiable. |
5. Flux nominaux¶
5.1 Modèle de données contractuel (source unique des formats)¶
| ID | Donnée | Format / encodage | Taille | Jeu de caractères | Case | Regex / contrainte | Si invalide |
|---|---|---|---|---|---|---|---|
| D-297-01 | story_id | String ASCII | 4..11 | [A-Z0-9-] | Sensitive | ^PD-[0-9]{1,4}$ | Rejet + FAILED_BLOCKING |
| D-297-02 | story_version | Entier décimal UTF-8 | 1..2 chars | [0-9] | n/a | ^[1-9][0-9]?$ | Rejet + FAILED_BLOCKING |
| D-297-03 | project_code | Enum string UTF-8 | 6..13 | [a-z-] | Sensitive | ^(ia-governance|formal)$ | Rejet + FAILED_BLOCKING |
| D-297-04 | domain_slug | String UTF-8 | 3..64 | [a-z0-9-] | Sensitive | ^[a-z0-9]+(?:-[a-z0-9]+)*$ | Rejet + FAILED_BLOCKING |
| D-297-05 | formal_scope | Enum ASCII | 4..9 | [a-z] | Sensitive | ^(contracts|code|full)$ | Rejet + FAILED_BLOCKING |
| D-297-06 | job_state | Enum ASCII | 7..21 | [A-Z_] | Sensitive | ^(PENDING|EXTRACTING|ENRICHED|ENRICHMENT_DEGRADED|VERIFICATION_PASSED|FAILED_BLOCKING|DONE)$ | Rejet + FAILED_BLOCKING |
| D-297-07 | verdict | Enum ASCII | 2..4 | [A-Z] | Sensitive | ^(GO|FAIL)$ | Rejet + FAILED_BLOCKING |
| D-297-08 | failure_code | Enum ASCII | 4..32 | [A-Z_] | Sensitive | ^(NONE|INPUT_INVALID|EXTRACTION_ERROR|PERSISTENCE_ERROR|NON_REGRESSION_CONTRADICTION|TOOL_UNAVAILABLE|TIMEOUT|CONCURRENT_RUN|IDEMPOTENCY_CONFLICT|INTERNAL_ERROR|SKIP_FORBIDDEN)$ | Rejet + FAILED_BLOCKING |
| D-297-09 | source_artifact_ref | Chemin POSIX absolu UTF-8 | 1..512 | UTF-8 printable | Sensitive | ^/.+$ | Rejet + FAILED_BLOCKING |
| D-297-10 | ontology_story_file_path | Chemin POSIX absolu UTF-8 | 1..512 | UTF-8 printable | Sensitive | ^.*/ProbatioVault-formal/coherence/ontology/stories/PD-[0-9]{1,4}\\.pl$ | Rejet + FAILED_BLOCKING |
| D-297-11 | predicate_atom | Ligne Prolog ASCII | 8..1024 chars | ASCII printable | Sensitive | ^[a-z_][a-z0-9_]*\\(.+\\)\\.$ | Rejet + FAILED_BLOCKING |
| D-297-12 | predicate_fingerprint | SHA-256 hex | 64 chars | [a-f0-9] | Sensitive | ^[a-f0-9]{64}$ | Rejet + FAILED_BLOCKING |
| D-297-13 | formalism | Enum ASCII | 1..6 | [a-z] | Sensitive | ^(prolog|tla|alloy|z)$ | Rejet + FAILED_BLOCKING |
| D-297-14 | formal_model_target_path | Chemin POSIX absolu UTF-8 | 1..512 | UTF-8 printable | Sensitive | ^.*/ProbatioVault-formal/normes/[a-z0-9-]+/formal/.+$ | Rejet + FAILED_BLOCKING |
| D-297-15 | invariant_id | String ASCII | 9..15 | [A-Z0-9-] | Sensitive | ^INV-[0-9]{1,4}-[0-9]{2}$ | Rejet + FAILED_BLOCKING |
| D-297-16 | trace_source | String ASCII | 12..128 | [A-Z0-9_:\\-\\.#/] | Sensitive | ^PD-[0-9]{1,4}:[a-z0-9_-]+:[0-9]{1,6}$ | Rejet + FAILED_BLOCKING |
| D-297-17 | idempotency_key | SHA-256 hex | 64 chars | [a-f0-9] | Sensitive | ^[a-f0-9]{64}$ | Rejet + FAILED_BLOCKING |
| D-297-18 | lock_key | String ASCII | 20..80 | [a-z0-9:_-] | Sensitive | ^formal_enrich:PD-[0-9]{1,4}:v[1-9][0-9]?$ | Rejet + FAILED_BLOCKING |
| D-297-19 | correlation_id | UUID v4 | 36 chars | [a-f0-9-] | Sensitive | ^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$ | Rejet + FAILED_BLOCKING |
| D-297-20 | timestamp_utc | RFC3339 UTC | 20..30 chars | ASCII | Sensitive | Horodatage parseable UTC (Z ou offset) | Rejet + FAILED_BLOCKING |
| D-297-21 | formal_result_json | Objet JSON UTF-8 | 200..20000 bytes | Clés ASCII, valeurs UTF-8 | Clés sensitive | Clés obligatoires: story_id, story_version, formal_scope, job_state, verdict, failure_code, idempotency_key, correlation_id, timestamp_utc, details | Rejet + FAILED_BLOCKING |
Référencement unique: toutes les sections suivantes réutilisent ces IDs (D-297-*) sans redéfinir les formats.
5.2 Bornes numériques contractuelles¶
| Paramètre | Défaut | Min | Max | Unité | Contexte de référence | Percentile | Hors bornes |
|---|---|---|---|---|---|---|---|
extraction_timeout_sec | 120 | 30 | 600 | secondes | Step 10 /gov-retrospective | P95 | Rejet config + FAILED_BLOCKING |
persistence_timeout_sec | 180 | 30 | 600 | secondes | Step 10 /gov-retrospective | P95 | Rejet config + FAILED_BLOCKING |
formal_scope_timeout_sec | 180 | 30 | 300 | secondes | Scopes contracts/code/full | P95 | Rejet config + FAILED_BLOCKING |
non_regression_timeout_sec | 180 | 30 | 600 | secondes | Check de cohérence post-enrichissement | P95 | Rejet config + FAILED_BLOCKING |
distributed_lock_ttl_sec | 600 | 60 | 1800 | secondes | Concurrence multi-runs | n/a | Rejet config + FAILED_BLOCKING |
idempotency_window_h | 24 | 1 | 168 | heures | Déduplication des relances | n/a | Rejet config + FAILED_BLOCKING |
reconciliation_interval_sec | 300 | 60 | 900 | secondes | Scan des runs orphelins | n/a | Rejet config + FAILED_BLOCKING |
orphan_threshold_sec | 900 | 180 | 3600 | secondes | Détection d’orphelin | n/a | Rejet config + FAILED_BLOCKING |
rate_limit_runs_per_min_per_story | 2 | 1 | 10 | runs/min/story | Protection de la base formelle | n/a | Rejet exécution (équivalent 429) |
clearing_success_cycles_required | 2 | 1 | 10 | cycles | Levée d’état dégradé | n/a | Rejet config + FAILED_BLOCKING |
max_formal_scopes_per_run | 3 | 3 | 3 | scopes | contracts,code,full | n/a | Rejet + FAILED_BLOCKING |
5.3 SLA temporels (transitions d’état)¶
| SLA | Défaut | Min | Max | Configurabilité | Comportement à expiration |
|---|---|---|---|---|---|
sla_extraction_window | 120s | 30s | 600s | Oui (extraction_timeout_sec) | EXTRACTING -> ENRICHMENT_DEGRADED |
sla_persistence_window | 180s | 30s | 600s | Oui (persistence_timeout_sec) | EXTRACTING -> ENRICHMENT_DEGRADED |
sla_non_regression_window | 180s | 30s | 600s | Oui (non_regression_timeout_sec) | ENRICHED -> FAILED_BLOCKING |
sla_contracts_scope_window | 180s | 30s | 300s | Oui (formal_scope_timeout_sec) | ENRICHED -> FAILED_BLOCKING |
sla_code_scope_window | 180s | 30s | 300s | Oui (formal_scope_timeout_sec) | ENRICHED -> FAILED_BLOCKING |
sla_full_scope_window | 180s | 30s | 300s | Oui (formal_scope_timeout_sec) | ENRICHED -> FAILED_BLOCKING |
sla_orphan_reconciliation_window | 900s | 180s | 3600s | Oui (orphan_threshold_sec) | Run orphelin forcé en FAILED_BLOCKING |
Aucune autre transition temporelle identifiée.
5.4 Flux nominaux contractuels¶
- F-297-01 — Déclenchement step 10
- Entrées minimales valides:
D-297-01àD-297-05,D-297-09,D-297-17àD-297-21. - Le lock distribué (
D-297-18) DOIT être acquis avant toute écriture. -
Transition:
PENDING -> EXTRACTING. -
F-297-02 — Extraction/persistance Prolog
- Transformation obligatoire:
spec_markdown + code_contracts -> predicate_atom[](D-297-11) + fingerprint (D-297-12). - Persistance append-only dans
D-297-10, avectrace_source(D-297-16) pour chaque entrée. -
En cas d’erreur/timeout extraction ou persistance:
EXTRACTING -> ENRICHMENT_DEGRADED. -
F-297-03 — Enrichissement TLA+/Alloy/Z
- Transformation obligatoire:
code_contracts -> invariant_id[](D-297-15) + ciblesD-297-14pourformalism(D-297-13). - Les 4 formalismes sont obligatoires pour un run validé.
-
Échec partiel sur un formalisme: état non validable (
ENRICHMENT_DEGRADEDpuisFAILED_BLOCKING). -
F-297-04 — Non-régression formelle
- Le check de cohérence DOIT s’exécuter sur la base étendue.
-
Contradiction détectée:
ENRICHED -> FAILED_BLOCKING,failure_code=NON_REGRESSION_CONTRADICTION. -
F-297-05 — Vérification scopes
contracts,code,full - Pour chaque scope (
D-297-05), verdict obligatoire (D-297-07) surD-297-21. SKIPest contractuellement interdit et traité commeFAIL(failure_code=SKIP_FORBIDDEN).- Tous scopes
GO+ non-régressionGO=>ENRICHED -> VERIFICATION_PASSED. -
Sinon =>
ENRICHED -> FAILED_BLOCKING. -
F-297-06 — Clôture step 10
- Seul
VERIFICATION_PASSED -> DONEautorise la clôture. - Tant que l’état n’est pas
DONE, la transition de clôture story est interdite.
5.5 Machine d’états (transitions retour explicites)¶
États: PENDING, EXTRACTING, ENRICHED, ENRICHMENT_DEGRADED, VERIFICATION_PASSED, FAILED_BLOCKING, DONE.
État PENDING¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
PENDING -> EXTRACTING | AUTORISÉE | Trigger step 10 valide + lock acquis | Démarrage run |
PENDING -> ENRICHED, ENRICHMENT_DEGRADED, VERIFICATION_PASSED, FAILED_BLOCKING, DONE | INTERDITE | Saut d’état | Rejet |
État EXTRACTING¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
EXTRACTING -> ENRICHED | AUTORISÉE | Extraction + persistance 4 formalismes réussies | Continue vérification |
EXTRACTING -> ENRICHMENT_DEGRADED | AUTORISÉE | Erreur/timeout extraction ou persistance | Dégradation contrôlée |
EXTRACTING -> PENDING, VERIFICATION_PASSED, FAILED_BLOCKING, DONE | INTERDITE | Transition hors contrat | Rejet |
État ENRICHED¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
ENRICHED -> VERIFICATION_PASSED | AUTORISÉE | Non-régression GO + scopes contracts/code/full = GO | Autorise clôture |
ENRICHED -> FAILED_BLOCKING | AUTORISÉE | Contradiction, timeout, erreur interne, ou verdict non-GO | Blocage |
ENRICHED -> PENDING, EXTRACTING, ENRICHMENT_DEGRADED, DONE | INTERDITE | Retour/saut non prévu | Rejet |
État ENRICHMENT_DEGRADED¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
ENRICHMENT_DEGRADED -> FAILED_BLOCKING | AUTORISÉE | Vérification bloquante fail-closed obligatoire | Blocage |
ENRICHMENT_DEGRADED -> PENDING, EXTRACTING, ENRICHED, VERIFICATION_PASSED, DONE | INTERDITE | Bypass de correction | Rejet |
État VERIFICATION_PASSED¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
VERIFICATION_PASSED -> DONE | AUTORISÉE | Clôture step 10 | Fin réussie |
VERIFICATION_PASSED -> PENDING, EXTRACTING, ENRICHED, ENRICHMENT_DEGRADED, FAILED_BLOCKING | INTERDITE | Retour/saut non prévu | Rejet |
État FAILED_BLOCKING¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
FAILED_BLOCKING -> PENDING | AUTORISÉE | Correction validée + relance explicite | Nouvelle tentative |
FAILED_BLOCKING -> EXTRACTING, ENRICHED, ENRICHMENT_DEGRADED, VERIFICATION_PASSED, DONE | INTERDITE | Contournement de la relance | Rejet |
État DONE (terminal)¶
| Transition sortante | Statut | Raison / condition | Comportement |
|---|---|---|---|
DONE -> * | INTERDITE | État terminal | état terminal, résolution manuelle uniquement |
Comportement de retour/downgrade: - ENRICHED -> FAILED_BLOCKING: les données déjà enrichies sont conservées (aucune suppression), clôture interdite. - FAILED_BLOCKING -> PENDING: historique conservé, quotas/rate-limit réappliqués immédiatement, verrouillages maintenus jusqu’à DONE. - Transition inverse directe non listée: interdite.
Checklist machine à états: - [x] Chaque état liste ses transitions sortantes (autorisées ou interdites). - [x] État terminal explicite: DONE -> * : INTERDITE (état terminal, résolution manuelle uniquement). - [x] Modèle couvert par invariants dédiés (INV-297-09 à INV-297-19).
5.6 Mécanismes de protection distribuée¶
| Mécanisme | Contrat |
|---|---|
| Lock distribué | Scope story_id + story_version (D-297-01, D-297-02), clé D-297-18, TTL=distributed_lock_ttl_sec; lock non acquis => FAIL, failure_code=CONCURRENT_RUN |
| Idempotence | Clé D-297-17; fenêtre=idempotency_window_h; même clé + même payload => même D-297-21; même clé + payload différent => FAIL, IDEMPOTENCY_CONFLICT |
| Réconciliation | Scan toutes reconciliation_interval_sec; run en EXTRACTING au-delà de orphan_threshold_sec => FAILED_BLOCKING |
| Rate-limiting | Granularité story_id; quota=rate_limit_runs_per_min_per_story; dépassement => rejet de run |
| Clearing conditionnel | Levée du statut dégradé uniquement après clearing_success_cycles_required cycles conformes consécutifs |
Checklist protection distribuée: - [x] Lock: scope + TTL + comportement lock non acquis. - [x] Idempotence: clé + durée de déduplication. - [x] Réconciliation: intervalle + seuil orphelin + rattrapage. - [x] Rate-limit: granularité + quota + comportement dépassement. - [x] Clearing: nombre de cycles + mécanisme de comptage.
5.7 Contraintes inter-modules¶
| Élément | Contrat |
|---|---|
| Routes/commandes d’autres modules à protéger | Step 10 gov-retrospective (clôture), vérifs formelles via formal-check scopes contracts/code/full, check de cohérence story suivante |
| Mécanisme de protection | Guard de clôture: transition step 10 interdite tant que job_state != DONE |
| Données nécessaires cross-module | story_id, story_version, artefacts source (spec, code-contracts, code), verdicts formal_result_json, état workflow |
| Résolution de liaison cross-module | Liaison déterministe story_id -> PD-XXX.pl + story_id -> artefacts docs/epics/... |
| Scope d’enregistrement du guard | Local aux commandes de workflow formel (pas de guard global hors périmètre PD-297) |
| Exceptions d’accès | Aucune exception de bypass sur FAILED_BLOCKING |
5.8 Clauses obligatoires “non applicables”¶
- Stratégie de migration DDL: non applicable (aucune colonne SQL modifiée).
- Atomicité multi-composant DB + queue/append-only: non applicable (pas de flux DB+queue dans PD-297).
- Invariant envelope encryption crypto: non applicable (domaine
formal/tooling, pascrypto/crypto-proof).
5bis. Diagrammes (obligatoire)¶
Diagramme d’état (stateDiagram-v2)¶
stateDiagram-v2
[*] --> PENDING
PENDING --> EXTRACTING: trigger_step10 + lock_ok
PENDING --> ENRICHED: INTERDITE
PENDING --> ENRICHMENT_DEGRADED: INTERDITE
PENDING --> VERIFICATION_PASSED: INTERDITE
PENDING --> FAILED_BLOCKING: INTERDITE
PENDING --> DONE: INTERDITE
EXTRACTING --> ENRICHED: extraction+persistance 4 formalismes OK
EXTRACTING --> ENRICHMENT_DEGRADED: timeout|error extraction/persistance
EXTRACTING --> PENDING: INTERDITE
EXTRACTING --> VERIFICATION_PASSED: INTERDITE
EXTRACTING --> FAILED_BLOCKING: INTERDITE
EXTRACTING --> DONE: INTERDITE
ENRICHED --> VERIFICATION_PASSED: non_regression=GO + contracts/code/full=GO
ENRICHED --> FAILED_BLOCKING: contradiction|timeout|error|SKIP_FORBIDDEN
ENRICHED --> PENDING: INTERDITE
ENRICHED --> EXTRACTING: INTERDITE
ENRICHED --> ENRICHMENT_DEGRADED: INTERDITE
ENRICHED --> DONE: INTERDITE
ENRICHMENT_DEGRADED --> FAILED_BLOCKING: fail_closed obligatoire
ENRICHMENT_DEGRADED --> PENDING: INTERDITE
ENRICHMENT_DEGRADED --> EXTRACTING: INTERDITE
ENRICHMENT_DEGRADED --> ENRICHED: INTERDITE
ENRICHMENT_DEGRADED --> VERIFICATION_PASSED: INTERDITE
ENRICHMENT_DEGRADED --> DONE: INTERDITE
FAILED_BLOCKING --> PENDING: correction + relance explicite
FAILED_BLOCKING --> EXTRACTING: INTERDITE
FAILED_BLOCKING --> ENRICHED: INTERDITE
FAILED_BLOCKING --> ENRICHMENT_DEGRADED: INTERDITE
FAILED_BLOCKING --> VERIFICATION_PASSED: INTERDITE
FAILED_BLOCKING --> DONE: INTERDITE
VERIFICATION_PASSED --> DONE: cloture_step10
VERIFICATION_PASSED --> PENDING: INTERDITE
VERIFICATION_PASSED --> EXTRACTING: INTERDITE
VERIFICATION_PASSED --> ENRICHED: INTERDITE
VERIFICATION_PASSED --> ENRICHMENT_DEGRADED: INTERDITE
VERIFICATION_PASSED --> FAILED_BLOCKING: INTERDITE
DONE --> PENDING: INTERDITE
DONE --> EXTRACTING: INTERDITE
DONE --> ENRICHED: INTERDITE
DONE --> ENRICHMENT_DEGRADED: INTERDITE
DONE --> VERIFICATION_PASSED: INTERDITE
DONE --> FAILED_BLOCKING: INTERDITE
DONE --> [*] Diagramme de séquence (sequenceDiagram)¶
sequenceDiagram
participant GR as gov-retrospective
participant EP as extract-eb-predicates
participant EI as extract-formal-invariants
participant OF as ProbatioVault-formal (ontology/models)
participant CO as coherence check
participant FV as formal-verify
participant FC as formal-check wrapper
GR->>EP: parse(spec_markdown + code_contracts_yaml)
EP-->>GR: predicate_atom[] + sha256(predicate_atom)
GR->>OF: append_only_write(PD-XXX.pl, predicate_atom[], trace_source)
GR->>OF: regenerate_ontology(domains+terms+synonyms) -> _ontology-facts.pl
GR->>EI: parse(code_contracts_yaml) -> invariants{prolog,tla,alloy,z}
EI-->>GR: invariants_by_formalism
GR->>OF: append_only_write(normes/{norme}/formal/*, invariants_by_formalism)
GR->>CO: verify(base_extended + new_predicates)
CO-->>GR: coherence_result_json{verdict, issues[]}
alt coherence verdict = FAIL
GR->>FC: formal_result_json{scope=full, verdict=FAIL}
FC-->>GR: FAIL
else coherence verdict = GO
GR->>FV: verify_contracts(contracts_yaml -> contract_predicates)
FV-->>GR: formal_result_json{scope=contracts, verdict}
GR->>FV: verify_code(code_manifest -> code_predicates)
FV-->>GR: formal_result_json{scope=code, verdict}
GR->>FV: verify_full(contract_predicates + code_predicates + ontology_facts)
FV-->>GR: formal_result_json{scope=full, verdict}
end
GR->>GR: aggregate verdicts -> job_state (VERIFICATION_PASSED|FAILED_BLOCKING) 6. Cas d’erreur¶
| ID | Cas | Réponse attendue |
|---|---|---|
| ERR-297-01 | story_id invalide (D-297-01) | Rejet immédiat, FAILED_BLOCKING, failure_code=INPUT_INVALID |
| ERR-297-02 | Lock non acquis (D-297-18) | FAIL, failure_code=CONCURRENT_RUN, aucun write |
| ERR-297-03 | Collision idempotence (même clé, payload différent) | FAIL, failure_code=IDEMPOTENCY_CONFLICT |
| ERR-297-04 | Échec extraction/persistance | EXTRACTING -> ENRICHMENT_DEGRADED puis FAILED_BLOCKING |
| ERR-297-05 | Tentative mutation/suppression d’un fait existant | FAIL, failure_code=PERSISTENCE_ERROR |
| ERR-297-06 | Contradiction non-régression détectée | FAIL, failure_code=NON_REGRESSION_CONTRADICTION |
| ERR-297-07 | formal-verify indisponible | FAIL, failure_code=TOOL_UNAVAILABLE |
| ERR-297-08 | Timeout SLA dépassé | FAIL, failure_code=TIMEOUT |
| ERR-297-09 | Scope retourne SKIP | FAIL, failure_code=SKIP_FORBIDDEN |
| ERR-297-10 | Transition non autorisée selon §5.5 | Rejet + maintien état courant |
| ERR-297-11 | DONE reçoit une transition sortante | Rejet explicite (état terminal) |
| ERR-297-12 | formal_result_json non conforme (D-297-21) | Rejet + FAILED_BLOCKING |
7. Critères d’acceptation (testables)¶
| ID | Critère | Observable |
|---|---|---|
| CA-297-01 | Une story DONE produit un fichier PD-XXX.pl dans ontology/stories | Présence du fichier cible (D-297-10) |
| CA-297-02 | Chaque prédicat persisté contient une traçabilité story-source | Chaque entrée contient trace_source conforme D-297-16 |
| CA-297-03 | Le rerun strictement identique ne duplique pas les prédicats | Compte stable + fingerprints (D-297-12) inchangés |
| CA-297-04 | Les 4 formalismes sont enrichis lors d’un run valide | Artefacts nouveaux détectés pour prolog/tla/alloy/z |
| CA-297-05 | Non-régression exécutée après enrichissement | Rapport de cohérence post-enrichissement présent |
| CA-297-06 | Scope contracts retourne GO ou FAIL | Aucune sortie SKIP observée |
| CA-297-07 | Scope code retourne GO ou FAIL | Aucune sortie SKIP observée |
| CA-297-08 | Scope full retourne GO ou FAIL | Aucune sortie SKIP observée |
| CA-297-09 | Toute erreur interne de vérification retourne FAIL | failure_code non-NONE et verdict FAIL |
| CA-297-10 | Contradiction non-régression bloque la clôture | État FAILED_BLOCKING, pas de transition -> DONE |
| CA-297-11 | Lock distribué bloque les runs concurrents | Second run même story rejeté CONCURRENT_RUN |
| CA-297-12 | Réconciliation force les runs orphelins en échec bloquant | Run EXTRACTING > seuil devient FAILED_BLOCKING |
| CA-297-13 | FAILED_BLOCKING -> PENDING conserve l’historique | Artefacts existants inchangés, nouvelle tentative possible |
| CA-297-14 | DONE est terminal | Toute transition sortante rejetée |
| CA-297-15 | Step 10 ne se clôture qu’en état DONE | Guard de clôture actif |
| CA-297-16 | procedures.md et workflow-rules.md reflètent le nouveau contrat PD-297 | Sections formelles mises à jour et cohérentes |
8. Scénarios de test (Given / When / Then)¶
-
TC-NOM-01
GIVEN une storyPD-XXXen step 10 avec artefacts valides
WHEN le run démarre
THENPENDING -> EXTRACTINGet lock acquis. -
TC-NOM-02
GIVEN extraction et persistance réussies sur les 4 formalismes
WHEN l’étape d’enrichissement se termine
THENEXTRACTING -> ENRICHED. -
TC-ERR-03
GIVEN un timeout d’extraction
WHENsla_extraction_windowexpire
THENEXTRACTING -> ENRICHMENT_DEGRADEDpuis blocage en vérification. -
TC-NR-04
GIVEN base étendue avec contradiction détectée
WHEN le check non-régression s’exécute
THENENRICHED -> FAILED_BLOCKINGet clôture interdite. -
TC-SCOPE-05
GIVEN scopecontractsexécuté
WHEN le moteur retourne un verdict
THEN la valeur est strictementGOouFAIL(jamaisSKIP). -
TC-SCOPE-06
GIVEN scopescontracts,code,fulltousGOet non-régressionGO
WHEN l’agrégation est effectuée
THENENRICHED -> VERIFICATION_PASSED -> DONE. -
TC-IDEMP-07
GIVEN une relance avec mêmeidempotency_keyet même payload
WHEN le run est rejoué
THEN résultat identique et aucune duplication de prédicats. -
TC-CONC-08
GIVEN deux runs simultanés sur mêmestory_id/story_version
WHEN le second tente l’acquisition lock
THEN rejetCONCURRENT_RUN. -
TC-RET-09
GIVEN étatFAILED_BLOCKINGaprès correction
WHEN une relance explicite est déclenchée
THENFAILED_BLOCKING -> PENDINGpuis reprise nominale. -
TC-TERM-10
GIVEN étatDONE
WHEN une transition sortante est demandée
THEN rejet explicite (état terminal). -
TC-FC-11
GIVENformal-verifyindisponible
WHEN un scope est invoqué
THEN verdictFAIL(TOOL_UNAVAILABLE), jamaisGO. -
TC-DATA-12
GIVEN unpredicate_atomhors regexD-297-11
WHEN persistance est demandée
THEN rejet +FAILED_BLOCKING.
9. Hypothèses explicites¶
| ID | Hypothèse | Impact si faux |
|---|---|---|
| H-297-01 | Le mapping story -> domaine -> normes/{norme}/formal est déterministe. | Cible d’enrichissement ambiguë, blocage de persistance. |
| H-297-02 | Les artefacts spec, code-contracts, code de la story sont accessibles au step 10. | Vérifications scopes impossibles, FAILED_BLOCKING. |
| H-297-03 | Les permissions d’écriture sur ProbatioVault-formal sont disponibles en step 10. | Enrichissement impossible, blocage systématique. |
| H-297-04 | Le stockage d’idempotence (fenêtre idempotency_window_h) est durable entre retries. | Déduplication non fiable. |
| H-297-05 | Le bloc {{LEARNINGS}} n’a pas fourni de règles additionnelles pour PD-297. | Risque de manque de contraintes contextuelles à intégrer. |
10. Points à clarifier¶
10.1 Contraintes techniques (stack projet cible)¶
| Projet | Stack réelle contractuelle | Indices vérifiables |
|---|---|---|
ProbatioVault-ia-governance | Shell (bash/zsh), Python 3, composant Node.js (mcp-signal), artefacts Markdown/YAML/JSON | scripts/*.sh, requirements.txt, mcp-signal/package.json |
ProbatioVault-formal | Python 3, SWI-Prolog, TLA+ (TLC), Alloy, Z-lint (Python), extraction TypeScript (ts-morph) | coherence/*.py, tools/*.jar, CLAUDE.md du repo formal |
Contrainte explicite: aucune substitution de stack n’est autorisée (pas Swift/SwiftUI, pas Spring Boot).
10.2 Questions ouvertes¶
| ID | Question | Impact |
|---|---|---|
| Q-297-01 | Référence épique Jira exacte non fournie. | Traçabilité incomplète en en-tête documentaire. |
| Q-297-02 | Convention exacte de cible norme par story (règle de routage) non formalisée. | Risque d’écritures dans mauvaise norme. |
| Q-297-03 | Stratégie de versionnement inter-repo pour append-only en concurrence non précisée. | Risque de conflits d’écriture. |
| Q-297-04 | Format canonique attendu de details dans formal_result_json non détaillé. | Hétérogénéité des preuves de verdict. |
| Q-297-05 | Politique de conservation des métadonnées d’idempotence (durée > 168h ?) non arbitrée. | Déduplication potentiellement insuffisante. |
| Q-297-06 | Condition de blocage Jira Done sur ENRICHMENT_DEGRADED doit-elle être strictement globale ? | Risque de clôture prématurée. |
Références¶
- Epic : Référence épique non fournie.
- JIRA :
PD-297. - Repos concernés :
ProbatioVault-ia-governance,ProbatioVault-formal. - Documents associés :
- PD-297-besoin.md
- PD-297-clarifications.md
- formal-check.sh
- procedures.md
- workflow-rules.md
- ProbatioVault-formal/CLAUDE.md