[DTP-Worker 20260806_124544] VÉRIF axe NEUF « atteignabilité transitive d'une assertion » → CLEAN 0/651 (aucun test run-only faux-vert) + 1 durcissement : test_validate_exits_zero passait sans assertion explicite (mordait implicitement via SystemExit) → assertEqual(main(["validate"]),0) strictement plus fort ; détecteur AST teeth-prouvé, résolution transitive du graphe d'appels (évite 40 faux-positifs de délégation _expect_error/_breaks), 0 logique de prod touchée, run_ci 33 PASS 0 FAIL 0 SKIP, pas de gate (#5)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-06 12:50:26 +00:00
parent 4aea5bddf7
commit bea5d49aab
2 changed files with 42 additions and 2 deletions
+37
View File
@@ -1079,3 +1079,40 @@ jsonschema ne masque AUCUN écart enum/const/schéma.**
VPS** (#8). `./run_ci.sh` inchangé = **33 PASS · 0 FAIL · 0 SKIP**. Fichiers touchés : ce journal +
1 entrée mémoire (`schema-oracle-enum-const-vs-S-skip`). Sweep rejouable tel quel (jsonschema 3.2.0
local ; stdlib pur sinon ; sans réseau) — **NON promu en gate** (#5, occurrence-zéro).
## Session `20260806_124544` — VÉRIF axe NEUF « atteignabilité transitive d'une assertion » (aucun test run-only faux-vert) → CLEAN 0/651 + 1 durcissement (implicite→explicite)
**Choix de tâche.** `./run_ci.sh` au démarrage = **33 PASS · 0 FAIL · 0 SKIP**, arbre propre, roadmap
`ROADMAP_8_WEEKS_OR_LESS.md` intégralement livrée/gatée (Sprints 1→7 ; prod VPS / builds EAS / dépôts
ONAPI hors périmètre worker · #8). Registre `OPEN_DECISIONS_REGISTER.md` = 3 arbitrages produit
appartenant à Michel (non éditables). Objectif : un **axe teeth encore jamais balayé**.
**Axe NEUF (absent de la mémoire).** `test-shadowing-sweep` couvre les tests **jamais exécutés** (dup de
nom/classe). Distinct et complémentaire : un test **exécuté** mais qui **n'atteint aucune assertion**
(run-only) reste vert même si le code casse = faux-vert. Détecteur AST (stdlib pur) : une méthode
`test*` est **édentée** si elle ne contient NI assertion directe (`self.assert*`/`self.fail`/
`assertRaises`/`pytest.raises`), NI appel levant (`jsonschema.validate`, `_validate(...)`,
`check_output/call`, `raise`), NI délégation à un helper de sa classe lui-même édenté-négatif
(`self._expect_error`/`_breaks`…), NI appel à une fonction nommée assert/expect/breaks/reject/check.
Résolution **transitive** du graphe d'appels intra-classe (sinon 40 faux positifs sur les batteries
d'injections négatives qui délèguent à `_expect_error`/`_breaks`).
**Dents prouvées.** Mutants : un `test_bad` qui ne fait que `print(compute(3))` → **MORD** (True) ;
`self.assertEqual(...)` → non signalé ; délégation helper (par set toothed OU par nom) → non signalé
(3/3 discriminés).
**Résultat & durcissement.** Sur **651 méthodes** de test : **1 seul** candidat →
`qa/acceptance/tests/test_acceptance.py::TestCLI.test_validate_exits_zero`, qui appelait `gen.main(
["validate"])` **sans assertion explicite**. Investigation : ce n'était PAS un faux-vert réel — il mord
**implicitement** via `SystemExit` (`cmd_validate`→`_validate_or_die`→`sys.exit(1)` si erreurs). MAIS
fragilité latente : un refactor remplaçant `sys.exit(1)` par un `return 1` **silencieux** rendrait le
test édenté sans que rien ne rougisse. **Durcissement** (strictement plus fort, aucun inconvénient) :
`self.assertEqual(gen.main(["validate"]), 0)` — mord désormais AUSSI sur le chemin retour-non-zéro, et
rend les dents **visibles** (aligné sur le style `test_build_writes_outputs` voisin). `main` retourne 0
en succès (`cmd_validate` → `return 0`), assertion correcte.
**Conclusion.** **CLEAN 0/651** après durcissement (le détecteur re-passé confirme 0 édenté). Axe
teeth-prouvé. Édition minimale : **1 test durci** (pas de logique de production touchée · #8), suite
`qa-acceptance` OK, `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP**. Fichiers : ce journal + le test
durci + 1 entrée mémoire (`test-assertion-reachability-sweep`). Sweep **rejouable** (AST stdlib pur) —
**NON promu en gate** (#5, occurrence-quasi-zéro après fix).
@@ -373,8 +373,11 @@ class TestCLI(unittest.TestCase):
self.assertTrue(os.path.exists(os.path.join(tmp, "MANIFEST.json")))
def test_validate_exits_zero(self):
# cmd_validate ne lève pas sur le dépôt réel (sinon SystemExit).
gen.main(["validate"])
# cmd_validate ne lève pas sur le dépôt réel (sinon SystemExit via
# _validate_or_die) ET retourne le code 0. On l'asserte explicitement :
# ainsi le test mord aussi si un refactor remplaçait sys.exit(1) par un
# `return 1` silencieux (le SystemExit ne serait alors plus levé).
self.assertEqual(gen.main(["validate"]), 0)
if __name__ == "__main__":