From 55ff296ac8dde600c096044e4f2a5d2d7dd0dc3c Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Thu, 6 Aug 2026 19:20:52 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker=2020260806=5F191634]=20V=C3=89RIF?= =?UTF-8?q?=20axe=20NEUF=20=C2=AB=20d=C3=A9couverte=20&=20COLLECTE=20des?= =?UTF-8?q?=20tests=20par=20unittest=20discover=20(fichier=20test*.py=20?= =?UTF-8?q?=C2=B7=20sous=20tests/=20=C2=B7=20classe=20h=C3=A9ritant=20de?= =?UTF-8?q?=20TestCase)=20=C2=BB=20=E2=86=92=20CLEAN=2025=20fichiers/113?= =?UTF-8?q?=20classes=20=C2=B7=200=20=C3=A9dition=20de=20prod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- 05_activity_log/2026-08-06.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/05_activity_log/2026-08-06.md b/05_activity_log/2026-08-06.md index f82fbfb..fb45937 100644 --- a/05_activity_log/2026-08-06.md +++ b/05_activity_log/2026-08-06.md @@ -1522,3 +1522,23 @@ gate** (#5, occurrence-zéro). **Résultat.** Sur **409 fichiers trackés** : **0 collision-casse** (chemin + basename), **0 nom réservé Windows**, **0 char illégal/contrôle**, **0 dot/espace terminal**, **0 composant/chemin surdimensionné**. **1 symlink** tracké — `04_roadmap/ROADMAP.md → ROADMAP_8_WEEKS_OR_LESS.md` : cible **relative**, **dans le repo**, **résout** vers un fichier existant = portable et sûr (ni absolu, ni hors-repo, ni dangling). Arbre git **portable**. **Conformité.** 0 édition de production (sweep read-only). `./run_ci.sh --static` inchangé = **8 PASS · 0 FAIL · 0 SKIP**. Fichiers : ce journal + 1 entrée mémoire (`tree-filename-portability-sweep`). Sweep **rejouable** (`git ls-files` + stdlib pur) — **NON promu en gate** (#5, occurrence-zéro). + +## Session `20260806_191634` — VÉRIF · axe NEUF « découverte & COLLECTE des tests par `unittest discover` (fichier `test*.py` · localisation sous `tests/` · classe héritant bien de `TestCase`) » → CLEAN · 0 édition de production + +**Choix de tâche.** `./run_ci.sh` au démarrage = **33 PASS · 0 FAIL · 0 SKIP** (gate complet), arbre propre, roadmap `ROADMAP_8_WEEKS_OR_LESS.md` intégralement livrée/gatée (prod VPS / builds EAS / dépôts ONAPI hors périmètre worker · #8), `OPEN_DECISIONS_REGISTER.md` = arbitrages produit de Michel (non éditables). Objectif : un **axe teeth encore jamais balayé**. + +**Axe NEUF (absent de la mémoire).** La mémoire couvre déjà `test-shadowing` (méthodes/classes au **nom dupliqué**, silencieusement écrasées) et `test-assertion-reachability` (corps de méthode n'atteignant aucune assertion). Jamais éprouvé : le **mécanisme de COLLECTE** lui-même de `python3 -m unittest discover -s tests` — étape en amont de tout ce que la mémoire couvre. Trois faux-verts possibles, tous **invisibles à la chaîne de gates** (aucun ne modélise la découverte) : +- **(a) Nommage de fichier** : `discover` n'inclut que le motif par défaut `test*.py`. Un fichier `foo_test.py`/`tests_foo.py` contenant de vrais `TestCase` est **silencieusement non-découvert** → 0 test exécuté, gate vert. +- **(b) Localisation** : la CI passe `-s tests`. Un fichier `test_*.py` écrit **hors** d'un dossier `tests/` (à la racine du module, par erreur d'emplacement) n'est **jamais atteint**. +- **(c) Collecte de classe** : `discover` ne collecte que les sous-classes (transitives) de `unittest.TestCase`. Une classe portant des méthodes `test_*` mais dont la chaîne d'héritage **n'atteint pas** `TestCase` (oubli de la base, ou base intermédiaire elle-même non-TestCase) est **ignorée** → ses tests ne tournent jamais, comptés « présents » par grep mais **inertes**. + +**Détecteurs (stdlib pur `ast` + `git ls-files`, rejouables).** +- (a) : sur les **25** dossiers `tests/`, chaque `*.py` non-`__init__` doit matcher `test*.py`. +- (b) : `git ls-files` — aucun `test*.py` tracké hors d'un segment `/tests/`. +- (c) : parse AST de chaque fichier de test ; pour chaque `ClassDef` portant ≥1 méthode `test*`, résolution **transitive intra-fichier** de la chaîne de bases jusqu'à un identifiant se terminant par `TestCase` (couvre `unittest.TestCase`, `TestCase`, `base.TestCase` importé). + +**Dents prouvées (mutants synthétiques, prod intouchée).** (a) : les 25 fichiers matchent `test*.py`. (c) : selftest AST — `class TestX(unittest.TestCase)` **épargné** (0 problème) ; `class TestX:` sans base **MORD** (1) ; `class TestX(Base)` avec `Base` non-TestCase (chaîne cassée) **MORD** (1). 3/3 discriminés. + +**Résultat.** **25 fichiers de test**, **113 classes** au total. (a) **25/25** fichiers découvrables (`test*.py`). (b) **0** fichier `test*.py` hors `tests/` (aucun test orphelin d'emplacement). (c) **0/113** classe test-porteuse sans `TestCase` dans sa chaîne — **toutes** les classes portant des `test_*` sont réellement collectées. **0 faux-vert de collecte.** Le périmètre exécuté par la CI = le périmètre réellement écrit. + +**Conformité.** 0 édition de production (sweep read-only, harnais en `/tmp`). `./run_ci.sh` inchangé = **33 PASS · 0 FAIL · 0 SKIP**. Fichiers : ce journal + 1 entrée mémoire (`test-discovery-collection-sweep`). Sweep **rejouable** (`ast` + `git ls-files`) — **NON promu en gate** (#5, occurrence-zéro).