PD-297 — Scénarios de tests contractuels
1. Références
- Spécification : PD-297-specification.md
- Epic : EPIC-XX
2. Matrice de couverture
| ID Invariant | ID Critère | ID Test | Couverture | Commentaire |
| INV-297-01 | CA-297-03, CA-297-13 | TC-ERR-05, TC-NOM-05, TC-NR-01 | Oui | Append-only vérifié sur run nominal, rerun et cycle de correction. |
| INV-297-02 | CA-297-02 | TC-NOM-02, TC-NEG-01 | Oui | Traçabilité story_id + trace_source obligatoire pour toute persistance. |
| INV-297-03 | CA-297-03 | TC-NOM-05, TC-ERR-03 | Oui | Idempotence stricte et détection de collision couvertes. |
| INV-297-04 | CA-297-09 | TC-ERR-04 | Oui | Erreur extraction/persistance force la dégradation. |
| INV-297-05 | CA-297-09 | TC-ERR-07, TC-ERR-08, TC-ERR-13 | Oui | Fail-closed en indisponibilité, timeout et erreur interne. |
| INV-297-06 | CA-297-06, CA-297-07, CA-297-08 | TC-NOM-04, TC-ERR-09 | Oui | Sorties scopes limitées à GO|FAIL, SKIP interdit. |
| INV-297-07 | CA-297-04 | TC-NOM-03, TC-NEG-03 | Oui | Validation impossible sans 4 formalismes. |
| INV-297-08 | CA-297-05 | TC-NOM-04, TC-NR-02 | Oui | Non-régression exécutée post-enrichissement avant clôture. |
| INV-297-09 | CA-297-14 | TC-NEG-01, TC-ERR-11 | Oui | FSM fermée aux états contractuels ; état terminal respecté. |
| INV-297-10 | CA-297-14 | TC-ERR-10, TC-NEG-05 | Oui | Toute transition hors §5.5 rejetée avec état inchangé. |
| INV-297-11 | CA-297-15 | TC-NOM-01 | Oui | Entrée nominale unique validée. |
| INV-297-12 | CA-297-04 | TC-NOM-03, TC-NEG-03 | Oui | EXTRACTING -> ENRICHED uniquement si 4 formalismes OK. |
| INV-297-13 | CA-297-12 | TC-ERR-04 | Oui | Timeout/erreur extraction/persistance -> ENRICHMENT_DEGRADED. |
| INV-297-14 | CA-297-06, CA-297-07, CA-297-08 | TC-NOM-04 | Oui | VERIFICATION_PASSED uniquement si non-régression GO + 3 scopes GO. |
| INV-297-15 | CA-297-10 | TC-ERR-06, TC-ERR-08, TC-ERR-09 | Oui | Tout FAIL/ERROR/SKIP bloque le run. |
| INV-297-16 | CA-297-10 | TC-ERR-04, TC-ERR-06 | Oui | Dégradé mène obligatoirement à blocage. |
| INV-297-17 | CA-297-15 | TC-NOM-04 | Oui | Clôture réussie unique VERIFICATION_PASSED -> DONE. |
| INV-297-18 | CA-297-13 | TC-NOM-06, TC-NR-05 | Oui | Transition retour unique et conservation d’historique. |
| INV-297-19 | CA-297-14 | TC-ERR-11 | Oui | DONE terminal, aucune sortie autorisée. |
| INV-297-20 | CA-297-11, CA-297-12 | TC-ERR-02, TC-ERR-03, TC-NR-03, TC-NR-04, TC-NEG-09 | Oui | Lock, idempotence, réconciliation, rate-limit, clearing couverts. |
| INV-297-21 | CA-297-15 | TC-NOM-07, TC-NEG-04 | Oui | Guard de clôture step 10 actif tant que job_state != DONE. |
| INV-297-22 | CA-297-01..CA-297-16 | TC-NOM-01..08, TC-ERR-01..13, TC-NR-01..05, TC-NEG-01..10 | Oui | Couverture globale fournie ; ambiguïtés classées NON TESTABLE en §9. |
3. Scénarios de test – Flux nominaux
TEST-ID: TC-NOM-01
Référence spec: F-297-01, INV-297-11, CA-297-15
GIVEN
- story_id=PD-297, story_version=1, project_code=ia-governance, domain_slug=formal
- idempotency_key=1111111111111111111111111111111111111111111111111111111111111111
- Payload conforme D-297-01..D-297-21
- Aucun lock actif sur formal_enrich:PD-297:v1
WHEN
- Le trigger step 10 démarre le run
THEN
- Transition observée: PENDING -> EXTRACTING
- Lock distribué acquis avant toute écriture
AND
- Audit signé contenant story_id, lock_key, correlation_id, timestamp_utc
TEST-ID: TC-NOM-02
Référence spec: F-297-02, INV-297-02, CA-297-01, CA-297-02
GIVEN
- Story éligible à la clôture step 10
- Artefacts source (`spec_markdown`, `code_contracts`) figés
- Cible D-297-10 valide
WHEN
- Extraction Prolog et persistance append-only sont exécutées
THEN
- Fichier PD-297.pl présent dans coherence/ontology/stories
- Chaque entrée persistée porte story_id=PD-297 et trace_source conforme D-297-16
AND
- Aucun prédicat préexistant n’est modifié/supprimé
TEST-ID: TC-NOM-03
Référence spec: F-297-03, INV-297-07, INV-297-12, CA-297-04
GIVEN
- Run en EXTRACTING
- Cibles valides pour formalism=prolog,tla,alloy,z
WHEN
- L’enrichissement des invariants dérivés des code-contracts se termine sans erreur
THEN
- Nouveaux artefacts observables pour les 4 formalismes
- Transition observée: EXTRACTING -> ENRICHED
AND
- Toute absence d’un formalisme invalide le passage à ENRICHED
TEST-ID: TC-NOM-04
Référence spec: F-297-04, F-297-05, F-297-06, INV-297-06, INV-297-14, INV-297-17, CA-297-05, CA-297-06, CA-297-07, CA-297-08
GIVEN
- État ENRICHED
- Non-régression verdict=GO
- contracts=GO, code=GO, full=GO
WHEN
- Agrégation finale des vérifications
THEN
- Transitions observées: ENRICHED -> VERIFICATION_PASSED -> DONE
- Les scopes ne retournent que GO ou FAIL
AND
- Rapport de non-régression post-enrichissement archivé avant clôture
TEST-ID: TC-NOM-05
Référence spec: INV-297-01, INV-297-03, CA-297-03
GIVEN
- Run initial exécuté avec idempotency_key=1111111111111111111111111111111111111111111111111111111111111111
- Même payload, même clé, replay dans idempotency_window_h
WHEN
- Le run est rejoué strictement à l’identique
THEN
- formal_result_json identique bit-à-bit au run initial
- Compte des prédicats persistés inchangé
AND
- Fingerprints D-297-12 inchangés
TEST-ID: TC-NOM-06
Référence spec: INV-297-18, CA-297-13
GIVEN
- Run en FAILED_BLOCKING après défaut corrigé explicitement
- Historique d’exécution déjà archivé
WHEN
- Relance explicite demandée
THEN
- Transition observée: FAILED_BLOCKING -> PENDING
- Historique et artefacts existants conservés
AND
- Nouvelle tentative autorisée sous lock/rate-limit contractuels
TEST-ID: TC-NOM-07
Référence spec: INV-297-21, CA-297-15
GIVEN
- job_state != DONE
WHEN
- Une clôture step 10 est demandée
THEN
- Clôture refusée
- job_state inchangé
AND
- Refus tracé avec motif de guard cross-module
TEST-ID: TC-NOM-08
Référence spec: CA-297-16
GIVEN
- Révision figée des fichiers .claude/rules/procedures.md et .claude/rules/workflow-rules.md
WHEN
- Contrôle documentaire PD-297 exécuté
THEN
- Les deux documents reflètent le contrat PD-297 (états, fail-closed, GO|FAIL, pas SKIP)
- Cohérence inter-documents vérifiée
AND
- Tout écart est reporté comme non-conformité bloquante
4. Scénarios de test – Cas d’erreur
TEST-ID: TC-ERR-01
Référence spec: ERR-297-01, D-297-01
GIVEN
- story_id="pd-297" (invalide)
WHEN
- Soumission du run
THEN
- Rejet immédiat
- job_state=FAILED_BLOCKING, failure_code=INPUT_INVALID
AND
- Aucun lock ni write formel effectué
TEST-ID: TC-ERR-02
Référence spec: ERR-297-02, INV-297-20, CA-297-11
GIVEN
- Lock déjà détenu sur formal_enrich:PD-297:v1
WHEN
- Un second run concurrent est soumis
THEN
- Verdict FAIL, failure_code=CONCURRENT_RUN
- Run concurrent rejeté
AND
- Aucun write append-only supplémentaire
TEST-ID: TC-ERR-03
Référence spec: ERR-297-03, INV-297-03, INV-297-20
GIVEN
- Requête A avec idempotency_key=2222222222222222222222222222222222222222222222222222222222222222
- Requête B avec la même clé et payload différent
WHEN
- Soumission de la requête B dans la fenêtre d’idempotence
THEN
- Verdict FAIL, failure_code=IDEMPOTENCY_CONFLICT
- Résultat de la requête A non modifié
AND
- Aucun artefact additionnel persisté
TEST-ID: TC-ERR-04
Référence spec: ERR-297-04, INV-297-04, INV-297-13, INV-297-16
GIVEN
- Run en EXTRACTING
- Timeout ou erreur explicite sur extraction/persistance
WHEN
- Expiration de la fenêtre SLA concernée
THEN
- Transition EXTRACTING -> ENRICHMENT_DEGRADED
- Puis transition ENRICHMENT_DEGRADED -> FAILED_BLOCKING
AND
- Toute clôture reste interdite
TEST-ID: TC-ERR-05
Référence spec: ERR-297-05, INV-297-01
GIVEN
- Base formelle contenant des faits déjà persistés
WHEN
- Tentative de mutation/suppression d’un fait existant
THEN
- Verdict FAIL, failure_code=PERSISTENCE_ERROR
- État bloquant conservé
AND
- Diff stockage: 0 suppression, 0 modification
TEST-ID: TC-ERR-06
Référence spec: ERR-297-06, INV-297-15, CA-297-10
GIVEN
- État ENRICHED
- Non-régression retourne contradiction
WHEN
- Agrégation des résultats
THEN
- Transition ENRICHED -> FAILED_BLOCKING
- failure_code=NON_REGRESSION_CONTRADICTION
AND
- Clôture step 10 interdite
TEST-ID: TC-ERR-07
Référence spec: ERR-297-07, INV-297-05, CA-297-09
GIVEN
- formal-verify indisponible
WHEN
- Exécution d’un scope formel
THEN
- Verdict FAIL, failure_code=TOOL_UNAVAILABLE
- État final FAILED_BLOCKING
AND
- Aucun GO possible
TEST-ID: TC-ERR-08
Référence spec: ERR-297-08, INV-297-05, INV-297-15
GIVEN
- Un check scope/non-régression dépasse son SLA
WHEN
- Timeout atteint
THEN
- Verdict FAIL, failure_code=TIMEOUT
- Transition ENRICHED -> FAILED_BLOCKING
AND
- Aucune transition aval autorisée
TEST-ID: TC-ERR-09
Référence spec: ERR-297-09, INV-297-06, INV-297-15, CA-297-06, CA-297-07, CA-297-08
GIVEN
- Un scope retourne SKIP
WHEN
- Le résultat est traité
THEN
- SKIP est converti en FAIL
- failure_code=SKIP_FORBIDDEN
AND
- Transition ENRICHED -> FAILED_BLOCKING
TEST-ID: TC-ERR-10
Référence spec: ERR-297-10, INV-297-10
GIVEN
- Run dans un état valide
WHEN
- Demande d’une transition non listée en §5.5
THEN
- Rejet explicite de transition
- État courant conservé
AND
- Événement d’audit de rejet horodaté
TEST-ID: TC-ERR-11
Référence spec: ERR-297-11, INV-297-19, CA-297-14
GIVEN
- État DONE
WHEN
- Toute transition sortante est demandée
THEN
- Rejet explicite "état terminal"
- État DONE inchangé
AND
- Aucune sortie FSM autorisée
TEST-ID: TC-ERR-12
Référence spec: ERR-297-12, D-297-21
GIVEN
- formal_result_json sans clé obligatoire (ex: details)
WHEN
- Enregistrement du résultat demandé
THEN
- Rejet + FAILED_BLOCKING
- Résultat non conforme non archivé
AND
- Preuve d’échec de validation schéma en audit
TEST-ID: TC-ERR-13
Référence spec: INV-297-05, CA-297-09
GIVEN
- Erreur interne non mappée pendant la vérification formelle
WHEN
- Calcul du verdict final
THEN
- Verdict forcé à FAIL
- failure_code=INTERNAL_ERROR
AND
- Aucun chemin de succès tant que l’erreur persiste
5. Tests d’invariants (non négociables)
| Invariant | Test(s) dédiés | Observable | Commentaire |
| INV-297-01 | TC-ERR-05, TC-NOM-05, TC-NR-01 | Diff append-only, pas de mutation/suppression | Prévention des régressions silencieuses. |
| INV-297-02 | TC-NOM-02, TC-NEG-01 | story_id + trace_source présents sur chaque entrée | Auditabilité opposable. |
| INV-297-03 | TC-NOM-05, TC-ERR-03 | Replay identique, collision refusée | Robustesse retry. |
| INV-297-04 | TC-ERR-04 | Passage obligatoire en ENRICHMENT_DEGRADED | Dégradation contrôlée. |
| INV-297-05 | TC-ERR-07, TC-ERR-08, TC-ERR-13 | Erreur interne/outillage/timeout => FAIL | Fail-closed. |
| INV-297-06 | TC-NOM-04, TC-ERR-09 | Scopes uniquement GO|FAIL | Fermeture du trou SKIP. |
| INV-297-07 | TC-NOM-03, TC-NEG-03 | 4 formalismes présents | Couverture complète. |
| INV-297-08 | TC-NOM-04, TC-NR-02 | Non-régression post-enrichissement | Contradictions détectables. |
| INV-297-09 | TC-NEG-01, TC-ERR-11 | États autorisés uniquement | FSM fermée. |
| INV-297-10 | TC-ERR-10, TC-NEG-05 | Transitions non listées rejetées | Zéro ambiguïté FSM. |
| INV-297-11 | TC-NOM-01 | Entrée unique PENDING -> EXTRACTING | Démarrage déterministe. |
| INV-297-12 | TC-NOM-03, TC-NEG-03 | ENRICHED conditionné à 4 formalismes | Intégrité du statut. |
| INV-297-13 | TC-ERR-04 | Timeout/erreur -> ENRICHMENT_DEGRADED | Contrat de dégradation. |
| INV-297-14 | TC-NOM-04 | Non-régression GO + 3 scopes GO | Validation complète. |
| INV-297-15 | TC-ERR-06, TC-ERR-08, TC-ERR-09 | FAIL/ERROR/SKIP => FAILED_BLOCKING | Blocage non contournable. |
| INV-297-16 | TC-ERR-04, TC-ERR-06 | ENRICHMENT_DEGRADED -> FAILED_BLOCKING | Cohérence fail-closed. |
| INV-297-17 | TC-NOM-04 | VERIFICATION_PASSED -> DONE uniquement | Clôture contrôlée. |
| INV-297-18 | TC-NOM-06, TC-NR-05 | Retour unique + historique conservé | Boucle de correction maîtrisée. |
| INV-297-19 | TC-ERR-11 | DONE -> * interdit | Terminalité stricte. |
| INV-297-20 | TC-ERR-02, TC-ERR-03, TC-NR-03, TC-NR-04, TC-NEG-09 | Mécanismes distribués actifs | Robustesse multi-runs. |
| INV-297-21 | TC-NOM-07, TC-NEG-04 | Guard clôture actif hors DONE | Alignement inter-modules. |
| INV-297-22 | Matrice §2 + §3..§9 | Chaque règle couverte ou classée NON TESTABLE | Contractualisation vérifiable. |
6. Tests de non-régression
| Test ID | Objet | Observable | Commentaire |
| TC-NR-01 | Conservation append-only après cycles erreur/retry | Hash initial inchangé + ajouts uniquement | Vérifie absence de mutation historique. |
| TC-NR-02 | Contradiction détectée sur base étendue | failure_code=NON_REGRESSION_CONTRADICTION, blocage de clôture | Empêche régression logique silencieuse. |
| TC-NR-03 | Réconciliation orpheline | EXTRACTING au-delà orphan_threshold_sec => FAILED_BLOCKING | Rattrapage déterministe des runs partiels. |
| TC-NR-04 | Clearing conditionnel | Levée dégradée uniquement après clearing_success_cycles_required cycles conformes | Évite déblocage prématuré. |
| TC-NR-05 | Retour correction sans perte d’historique | Traces préexistantes conservées après FAILED_BLOCKING -> PENDING | Non-régression d’auditabilité. |
7. Tests négatifs et adversariaux
| Test ID | Entrée invalide / abus | Résultat attendu | Observable |
| TC-NEG-01 | Campagne paramétrée D-297-01..D-297-21 invalides (regex, taille, enum, format) | Rejet + FAILED_BLOCKING | Rapport détaillé des champs refusés. |
| TC-NEG-02 | Config hors bornes §5.2 (min-1 / max+1) | Rejet config + FAILED_BLOCKING | Journal de validation de configuration. |
| TC-NEG-03 | Exécution avec 3 formalismes seulement ou max_formal_scopes_per_run != 3 | Refus de validation enrichissement | Pas de transition EXTRACTING -> ENRICHED. |
| TC-NEG-04 | Tentative de clôture step 10 avec job_state=ENRICHED ou FAILED_BLOCKING | Refus de clôture | Guard cross-module tracé. |
| TC-NEG-05 | Bypass FSM (FAILED_BLOCKING -> DONE) | Rejet | État inchangé + motif explicite. |
| TC-NEG-06 | formal_scope hors enum (security) | Rejet + blocage | Validation D-297-05 échoue. |
| TC-NEG-07 | job_state hors enum (RUNNING) | Rejet + blocage | Validation D-297-06 échoue. |
| TC-NEG-08 | verdict hors enum (WARN) | Rejet + blocage | Validation D-297-07 échoue. |
| TC-NEG-09 | Dépassement rate_limit_runs_per_min_per_story | Rejet exécution (équivalent 429) | Compteur de quota + refus horodaté. |
| TC-NEG-10 | Chemins de persistance hors regex D-297-10 ou D-297-14 | Rejet + blocage | Contrôle chemin absolu et cible contractuelle. |
8. Observabilité requise pour les tests
- État système :
job_state courant, historique transitions, état lock, compteurs rate-limit, statut réconciliation. - Réponse API :
formal_result_json complet avec toutes clés D-297-21. - Journal d’audit : événements horodatés UTC, motif de décision,
story_id, correlation_id, failure_code, trace_source. - Événement signé / horodaté : preuve d’intégrité de chaque verdict et transition.
- Export probatoire : bundle corrélant entrées, artefacts enrichis, verdicts scopes, non-régression, transitions FSM, refus de clôture.
9. Règles non testables
| Règle | Raison | Impact |
NON TESTABLE — Routage canonique story_id -> norme (Q-297-02) | La règle de dérivation métier de {norme} n’est pas formalisée (seule la regex de chemin l’est). | Majeur |
NON TESTABLE — Format canonique du champ details dans formal_result_json (Q-297-04) | Présence obligatoire définie, structure sémantique non spécifiée. | Majeur |
| NON TESTABLE — Versionnement inter-repo append-only en concurrence (Q-297-03) | Stratégie de résolution de conflit/ordre d’écriture non contractuellement définie. | Majeur |
| NON TESTABLE — Référence épique Jira exacte (Q-297-01) | Identifiant d’épic absent des entrées spécifiées. | Mineur |
NON TESTABLE — Portée globale Jira Done vs ENRICHMENT_DEGRADED (Q-297-06) | Guard local spécifié, politique globale Jira non détaillée dans le contrat. | Majeur |
10. Verdict QA
- ✅ Testable intégralement : Non
- ⚠️ Testable partiellement (avec réserves listées) : Oui
- ❌ Non testable (refus contractuel) : Non