From ca15e7e12bf4427d8795b4e1a3275cd5e61327b5 Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Sun, 2 Aug 2026 09:10:39 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker=2020260802=5F090530]=20Sprint=208?= =?UTF-8?q?=20=C2=B7=20buffer=20=C2=B7=20Angle=20mort=20gate=20=C2=AB=20co?= =?UTF-8?q?mptes=20tests=20par=20suite=20=C2=BB=20:=20la=20cellule=20rbac?= =?UTF-8?q?=20(fiche=20pointe=20une=20SPEC,=20pas=20un=20README)=20=C3=A9t?= =?UTF-8?q?ait=20non=20v=C3=A9rifi=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit row_re du gate check_readme_claims §comptes-par-suite exigeait un lien …/README.md ; la fiche erpnext_backend pointe rbac/ via RBAC_50_ROLES_SPEC.md (son point d'entrée contrat), donc sa cellule « Tests | 10 | » échappait au recompute depuis regression_plan.json. Mutation-test 10→99 : gate restait VERT (vrai angle mort, classe « vert trompeur »). Extension : accepte tout *.md d'entrée du dossier module (/[\w.-]+.md) ; le garde path-not-in-auth protège l'élargissement. rbac désormais vue+mordue ; 7 gates verts. Co-Authored-By: Claude Opus 4.8 (1M context) --- 05_activity_log/2026-08-02.md | 38 +++++++++++++++++++++++++++++++++++ ci/check_readme_claims.sh | 12 +++++++---- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/05_activity_log/2026-08-02.md b/05_activity_log/2026-08-02.md index 51ac807..f310079 100644 --- a/05_activity_log/2026-08-02.md +++ b/05_activity_log/2026-08-02.md @@ -941,3 +941,41 @@ marqueur (`proscrites`/`interdits`/`bannie`) donc `guard_constraints` les laisse passer. **Vérif** : 7 gates re-verts (guard_constraints · check_docs · check_readme_claims · check_ci_integrity · check_artifacts · check_regression · validate_json tous exit 0). + +--- + +## Sprint 8 · buffer · Angle mort du gate « comptes de tests par suite » : la cellule `rbac` (fiche pointant une SPEC, pas un README) + +**Démarche — vérifier AVANT de conclure « couvert » (mémoire `verify-uncovered-before-gating`).** +La série récente ayant épuisé les surfaces driftables évidentes, j'ai audité la +**complétude d'un gate existant** plutôt que d'en empiler un neuf (CLAUDE.md #5). + +**Constat.** Le gate `check_readme_claims.sh` §« Fiches agents · comptes de tests +PAR SUITE (colonne « Tests ») » recompute chaque cellule `| N |` des tables de +livrables des `03_agents/*/AGENT.md` depuis l'autorité `regression_plan.json` +(`plan.suites[path].test_methods`). Son `row_re` exigeait pourtant que le lien de +la ligne pointe `…/README.md`. **Or une ligne y échappe** : la fiche +`erpnext_backend` (l.28) pointe le module `rbac/` via son **point d'entrée +`RBAC_50_ROLES_SPEC.md`** (le contrat 50-rôles, pas un README) — donc son +`row_re` ne mordait pas, et sa cellule « Tests | 10 | » restait **non vérifiée**. + +**Mutation-test (preuve du trou).** Cellule `rbac` `10 → 99` sur la fiche → +`check_readme_claims` restait **VERT** (exit 0), aucune ligne `rbac` évaluée. C'est +exactement la classe « vert trompeur » que cette section du gate existe pour tuer +(un régénérateur de fiche pourrait y écrire un faux compte sans que la CI bronche). +La somme prose « RBAC 60 tests (10+11+12+11+16) » est **order-indépendante** → ne +contraint pas la cellule-table `rbac` individuelle. Vrai angle mort. + +**Correctif (extension du gate, pas gate N+1).** `row_re` accepte désormais tout +`*.md` d'entrée du dossier module (`/[\w.-]+\.md` au lieu de `/README\.md`), pas +seulement README — le garde `path not in auth` (déjà présent) protège de tout +élargissement fortuit : seules les lignes pointant une **suite gatée connue** sont +évaluées, les autres restent ignorées. Une seule ligne entre ainsi dans le +périmètre : `rbac`. Commentaire mis à jour pour documenter le cas SPEC. + +**Vérif.** (1) Arbre propre VERT + la ligne `rbac` est désormais **VUE** +(`AGENT.md:28 · rbac — Tests 10 == source (10)`). (2) Mutation `10→99` désormais +**MORDUE** (`Tests 99 MAIS source dit 10 → régénérer la fiche`, exit 1). (3) +Restauration → exit 0. **7 gates re-verts** : check_ci_integrity · check_artifacts · +check_docs · check_readme_claims · check_regression · guard_constraints · +validate_json tous exit 0. diff --git a/ci/check_readme_claims.sh b/ci/check_readme_claims.sh index 093891d..7bb2f36 100755 --- a/ci/check_readme_claims.sh +++ b/ci/check_readme_claims.sh @@ -631,11 +631,15 @@ self_mod = plan["coverage"].get("self_module_excluded") if count_tests is not None and self_mod: auth[self_mod] = count_tests(f"{D}/{self_mod}/tests")[1] -# Ligne de table Tests : lien vers 05_deliverables_mvp//README.md + dernier -# champ numérique. On ne vérifie QUE les lignes pointant une suite gatée connue -# (auth) — toute autre ligne de table est ignorée (pas notre périmètre). +# Ligne de table Tests : lien vers 05_deliverables_mvp//.md + dernier +# champ numérique. Le .md est l'ENTRÉE du module — le plus souvent README.md, +# mais parfois une SPEC (la fiche `rbac` pointe RBAC_50_ROLES_SPEC.md, son point +# d'entrée) : on accepte donc tout `*.md` du dossier module, sinon cette cellule-là +# reste un angle mort (mutation 10→99 non mordue). On ne vérifie QUE les lignes +# pointant une suite gatée connue (auth) — toute autre ligne est ignorée (hors +# périmètre), le garde `path not in auth` protège de tout élargissement fortuit. row_re = re.compile( - r"^\|\s*\[`\w+/`\]\([^)]*?05_deliverables_mvp/([\w/]+?)/README\.md\)" + r"^\|\s*\[`\w+/`\]\([^)]*?05_deliverables_mvp/([\w/]+?)/[\w.-]+\.md\)" r".*\|\s*(\d+)\s*\|\s*$") fiches = subprocess.run(["git", "ls-files", "03_agents/*/AGENT.md"], capture_output=True, text=True).stdout.split()