From 327aa298a2105a65f4200ce4d480bbed4fe71412 Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Fri, 31 Jul 2026 13:37:10 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker]=20Sprint=208=20=C2=B7=20buffer=20L?= =?UTF-8?q?75=20=C2=B7=20Domaine=20QA/Audit=204Big=20:=20le=20BAR=C3=88ME?= =?UTF-8?q?=20de=20notation=20de=20l'auditeur=20(=C2=AB=205=20crit=C3=A8re?= =?UTF-8?q?s=204Big=20d=C3=A9terministes=20=C2=BB=20+=20la=20table=20Crit?= =?UTF-8?q?=C3=A8re|Poids=20DOC=2020/CONTRAT=2020/TESTS=2025/CLI=2015/HAND?= =?UTF-8?q?OFF=2020=20+=20l'arch=C3=A9type=20=C2=AB=20generator=20(5=20cri?= =?UTF-8?q?t=C3=A8res)=20=C2=BB)=20=C3=A9tait=20transcrit=20=C3=80=20LA=20?= =?UTF-8?q?MAIN=20dans=20le=20README=20du=20module=20sans=20AUCUN=20gate?= =?UTF-8?q?=20=E2=80=94=20ironie=20du=20module=20qui=20NOTE=20les=20autres?= =?UTF-8?q?=20retranscrivant=20son=20propre=20r=C3=A9f=C3=A9rentiel=20de?= =?UTF-8?q?=20scoring.=20Le=20bloc=20racine=20de=20check=5Freadme=5Fclaims?= =?UTF-8?q?=20ne=20gatait=20que=20la=20ligne=20=C2=AB=20R=C3=A9sultat=20co?= =?UTF-8?q?urant=20=C2=BB=20(verdict/modules/min=5Fscore),=20jamais=20le?= =?UTF-8?q?=20bar=C3=A8me=20lui-m=C3=AAme,=20alors=20que=20qa/audit=5F4big?= =?UTF-8?q?/out/quality=5Freport.json=20(byte-gat=C3=A9=20par=20check=5Far?= =?UTF-8?q?tifacts,=20criteria[]=20recomput=C3=A9=20du=20r=C3=A9f=C3=A9ren?= =?UTF-8?q?tiel=20=C3=A0=20chaque=20build)=20fait=20autorit=C3=A9.=20Ajout?= =?UTF-8?q?er/retirer=20un=20crit=C3=A8re=20OU=20changer=20un=20poids=20fe?= =?UTF-8?q?rait=20d=C3=A9river=20le=20README=20en=20silence=20pendant=20qu?= =?UTF-8?q?e=20l'artefact=20dit=20autre=20chose=20=E2=80=94=20=C2=AB=20ver?= =?UTF-8?q?t=20trompeur=20=C2=BB=20qu'aucune=20suite=20tests/=20(qui=20tes?= =?UTF-8?q?te=20des=20FONCTIONS,=20pas=20la=20prose)=20n'attrape=20?= =?UTF-8?q?=E2=86=92=20nouveau=20bloc=20recomputant=20le=20nombre=20de=20c?= =?UTF-8?q?rit=C3=A8res=20(prose=20=C2=AB=20N=20crit=C3=A8res=204Big=20d?= =?UTF-8?q?=C3=A9terministes=20=C2=BB=20+=20arch=C3=A9type=20=C2=AB=20gene?= =?UTF-8?q?rator=20(N=20crit=C3=A8res)=20=C2=BB,=20generator=20appliquant?= =?UTF-8?q?=20TOUS=20les=20crit=C3=A8res)=20et=20CHAQUE=20poids=20depuis?= =?UTF-8?q?=20criteria[].weight=20(z=C3=A9ro=20duplication=20du=20bar?= =?UTF-8?q?=C3=A8me=20du=20g=C3=A9n=C3=A9rateur=20#6),=20exigeant=20l'?= =?UTF-8?q?=C3=A9galit=C3=A9=20avec=20le=20README.=20Contr=C3=B4le=20PAR?= =?UTF-8?q?=20CRIT=C3=88RE=20et=20pas=20seulement=20de=20la=20somme=20:=20?= =?UTF-8?q?une=20compensation=20de=20poids=20(+5/=E2=88=925)=20laisserait?= =?UTF-8?q?=20=CE=A3=3D=3D100=20juste=20et=20deux=20lignes=20fausses.=20Co?= =?UTF-8?q?h=C3=A9rences=20crois=C3=A9es=20en=20bonus=20:=20=CE=A3=20poids?= =?UTF-8?q?=20=3D=3D=20100=20(base=20de=20renormalisation=20document=C3=A9?= =?UTF-8?q?e)=20ET=20tout=20module=20d'arch=C3=A9type=20generator=20porte?= =?UTF-8?q?=20EXACTEMENT=20len(criteria)=20checks=20(=C2=AB=20generator=20?= =?UTF-8?q?=3D=20tous=20les=20crit=C3=A8res=20=C2=BB=20=E2=80=94=2018=20mo?= =?UTF-8?q?dules=20generator=20=C3=97=205=20checks=20v=C3=A9rifi=C3=A9s).?= =?UTF-8?q?=20Un=20claim=20absent=20=C3=A9choue=20AUSSI=20(4=20morsures=20?= =?UTF-8?q?v=C3=A9rifi=C3=A9es=20:=20prose=205=E2=86=926=20capt=C3=A9e=20l?= =?UTF-8?q?=C3=A0=20o=C3=B9=20les=20poids=20restent=20justes=20=C2=B7=20po?= =?UTF-8?q?ids=20TESTS=2025=E2=86=9230=20capt=C3=A9=20l=C3=A0=20o=C3=B9=20?= =?UTF-8?q?le=20compte=20reste=205=20=C2=B7=20generator=205=E2=86=924=20?= =?UTF-8?q?=C2=B7=20claim=20prose=20disparu=20=3D=20red=20;=20restaur?= =?UTF-8?q?=C3=A9=20=3D=20green).=20ci/README.md=20(table=20+=20d=C3=A9tai?= =?UTF-8?q?l)=20mis=20=C3=A0=20jour=20=C2=B7=207=20gates=20re-verts.?= 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-07-31.md | 50 ++++++++++++++++++++++ ci/README.md | 24 ++++++++++- ci/check_readme_claims.sh | 78 +++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/05_activity_log/2026-07-31.md b/05_activity_log/2026-07-31.md index 7a0a07c..39a148b 100644 --- a/05_activity_log/2026-07-31.md +++ b/05_activity_log/2026-07-31.md @@ -1,5 +1,55 @@ # Activity Log · 2026-07-31 · Claude Code DTP +## Session `20260731_133057` · Buffer S8 · Domaine QA/Audit 4Big : le **barème de notation** de l'auditeur (« **5 critères 4Big déterministes** » + la table `Critère | Poids` + l'archétype « `generator` (5 critères) ») était transcrit À LA MAIN dans le README du module sans AUCUN gate — le bloc racine ne gatait que sa ligne « Résultat courant » (verdict/modules), jamais le référentiel de scoring lui-même. + +**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement +close ; poursuite de la série anti-dérive (CLAUDE.md #6). Restait une surface de « vert +trompeur » non gatée dans le module qui NOTE les autres : son propre barème. + +**Dérive silencieuse fermée** : +- `05_deliverables_mvp/qa/audit_4big/README.md` retranscrit trois surfaces + data-derived du référentiel de scoring : la prose « Note chaque module sur **5 + critères 4Big déterministes** », la table « Critère | Poids | Fait vérifié » (une + ligne `id`→poids par critère : DOC 20 · CONTRAT 20 · TESTS 25 · CLI 15 · HANDOFF 20) + et l'archétype « `generator` (5 critères) ». +- La source faisant autorité est `out/quality_report.json.criteria` (byte-gaté par + `check_artifacts`, recomputé du référentiel à chaque build). +- Aucun gate ne comparait la VALEUR écrite à l'artefact : ajouter/retirer un critère + ou changer un poids ferait dériver le README en silence — dérive qu'aucune suite + `tests/` (qui teste des FONCTIONS, pas la prose) n'attrape. + +**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le **nombre de critères** +(prose + « generator »), et **chaque poids** depuis `criteria[].weight` (zéro +duplication du barème du générateur · #6), exige l'égalité avec le README. Cohérences +croisées : `Σ poids == 100` (base de renormalisation documentée) ET tout module +d'archétype `generator` porte EXACTEMENT `len(criteria)` `checks` (« generator = tous +les critères » — 18 modules generator × 5 checks vérifiés). Une **compensation** de +poids (+5 / −5) laisserait `Σ == 100` juste et deux lignes fausses → d'où le contrôle +**par critère**, pas seulement de la somme. + +### Preuve (4 morsures vérifiées + restauration verte) + +| Injection | Résultat | +|---|---| +| README prose 5 critères → 6 (poids table intacts) | ✗ dit 6 MAIS criteria en compte 5 · exit 1 | +| README poids `TESTS` 25 → 30 (compte intact) | ✗ dit poids 30 MAIS criteria dit 25 · exit 1 | +| README archétype `generator` (5→4 critères) | ✗ dit 4 MAIS generator applique les 5 · exit 1 | +| README claim prose reformulé (chiffre disparu) | ✗ « N critères 4Big » INTROUVABLE · exit 1 | +| restauré | ✓ 5 critères · poids 20/20/25/15/20 · Σ=100 · 18 gen×5 == artefact · exit 0 | + +- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe + descriptif (classe « barème auditeur 4Big »). + +Suite CI complète re-verte (7 gates) : `guard_constraints` · `validate_json` · +`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` · +`check_readme_claims`. + +**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo). + +**Auto-score 4Big** : 96/100. + +--- + ## Session `20260731_130055` · Buffer S8 · Domaine QA/Recette : le couple « **8 livrables de sprint · 7 métriques succès MVP** » du module d'acceptation (`qa/acceptance`) était transcrit À LA MAIN dans DEUX docs de module (README du module + fiche agent QA) sans AUCUN gate — le bloc racine ne gate QUE le README d'entrée **Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap diff --git a/ci/README.md b/ci/README.md index 2baae98..1d1b06e 100644 --- a/ci/README.md +++ b/ci/README.md @@ -20,7 +20,7 @@ et manuellement (`workflow_dispatch`). Jobs statiques (+ une suite `unittest` pa | `check-artifacts` | `ci/check_artifacts.sh` | Reproductibilité : chaque `out/*.json` versionné == build frais | ✅ oui | | `check-regression` | `ci/check_regression.sh` | Fraîcheur : `qa/regression/out/regression_run.json` (`run`) == run frais + verdict PASS | ✅ oui | | `check-ci-integrity` | `ci/check_ci_integrity.sh` | Intégrité du câblage : `gate.needs` == tous les jobs non-manuels · chaque `ci/*.sh` câblé au gate | ✅ oui | -| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) **et** du montage Chat OTOIA par portail (`Custom Block`/configs runtime/portails, tous = 5 aujourd'hui, ×2 docs) **et** du module de recette `qa/acceptance` (couple livrables de sprint + métriques succès MVP, ×2 docs de module au-delà du README d'entrée) == artefact cité (#6) | ✅ oui | +| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) **et** du montage Chat OTOIA par portail (`Custom Block`/configs runtime/portails, tous = 5 aujourd'hui, ×2 docs) **et** du module de recette `qa/acceptance` (couple livrables de sprint + métriques succès MVP, ×2 docs de module au-delà du README d'entrée) **et** du barème de l'auditeur 4Big (nombre de critères en prose + poids par critère de la table + « generator (N critères) », recomputés de `quality_report.criteria`) == artefact cité (#6) | ✅ oui | | `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui | Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec @@ -289,6 +289,28 @@ comparé aux deux docs. Cohérence croisée en bonus : `MANIFEST.counts.{sprint_deliverables,mvp_metrics}` == le compte de la matrice qu'il résume — mord un compteur du manifeste désynchronisé de sa liste. +Même classe enfin sur le **barème de l'auditeur 4Big** (livrable `qa/audit_4big`). +Ironie déjà notée : le module qui NOTE les autres retranscrit son propre référentiel +de scoring **à la main** dans son README (`05_deliverables_mvp/qa/audit_4big/README.md`) +— la prose « Note chaque module sur **N critères 4Big déterministes** », la table +« Critère | Poids | … » (une ligne `id`→poids par critère) et l'archétype +« `generator` (**N** critères) ». Ces trois surfaces DÉRIVENT de +`quality_report.json.criteria` (byte-gaté par `check_artifacts`, recomputé du +référentiel à chaque build) ; ajouter/retirer un critère ou changer un poids ferait +dériver le README en silence pendant que l'artefact dit autre chose — dérive qu'aucune +suite `tests/` (qui teste des FONCTIONS, pas la prose) n'attrape. Le bloc racine ne +gate que la ligne « Résultat courant » (verdict/modules), jamais le barème. On +recompute donc le **nombre de critères** (prose + « generator »), et **chaque poids** +depuis `criteria[].weight` (zéro duplication du barème du générateur · #6). Cohérences +croisées : `Σ poids == 100` (base de renormalisation documentée) ET tout module +d'archétype `generator` porte EXACTEMENT `len(criteria)` `checks` — c.-à-d. +« generator = tous les critères », ce qui rend le « generator (N critères) » du README +vérifiablement vrai (mord une dérive du modèle qui le rendrait faux). Une **compensation** +(un poids +5 / un autre −5) laisserait `Σ == 100` juste et deux lignes fausses : d'où +le contrôle **par critère**, pas seulement de la somme. 4 morsures vérifiées : dérive +prose `5→6` (poids intacts) · dérive poids `TESTS 25→30` (compte intact) · dérive +`generator (5→4)` · claim prose disparu ; restauré = vert. + Un claim **absent** échoue aussi (la dérive de formulation qui ferait disparaître un chiffre est elle-même une régression de traçabilité). stdlib pur (bash/git/python3), zéro réseau. diff --git a/ci/check_readme_claims.sh b/ci/check_readme_claims.sh index 09f76e5..8889937 100755 --- a/ci/check_readme_claims.sh +++ b/ci/check_readme_claims.sh @@ -301,6 +301,84 @@ else: bad(f"README audit_4big · {A4} dit {'/'.join(ma4.groups())} MAIS quality_report " f"dit {'/'.join(a4_exp)} ({a4_src}) → régénérer le README") +# ============================================================================ +# README de l'auditeur 4Big · BARÈME de notation (N critères + poids par critère) +# — même classe de « vert trompeur », au grain du référentiel de scoring. +# ---------------------------------------------------------------------------- +# Le barème 4Big est DATA-DERIVED : quality_report.json.criteria (byte-gaté par +# check_artifacts, RECOMPUTÉ du référentiel à chaque build) porte la liste des +# critères et leur poids. Le README les RETRANSCRIT À LA MAIN à trois endroits : +# • la prose « Note chaque module sur N critères 4Big déterministes », +# • la table « Critère | Poids | Fait vérifié » (une ligne id→poids par critère), +# • l'archétype « generator (N critères) » (generator applique TOUS les critères). +# Ajouter/retirer un critère ou changer un poids ferait dériver ces trois surfaces +# en silence pendant que l'artefact dit autre chose — aucune suite tests/ (qui teste +# des FONCTIONS, pas la prose du README) ne l'attrape. On RECOMPUTE ici chaque nombre +# depuis `criteria` (zéro duplication du barème du générateur · #6) et on exige +# l'égalité avec ce que la doc ÉCRIT. Cohérences croisées : Σ poids == 100 (base de +# renormalisation) ET tout module d'archétype `generator` porte EXACTEMENT +# len(criteria) checks — c.-à-d. « generator = tous les critères » (mord une dérive +# du modèle qui rendrait le « generator (N critères) » du README faux). Un claim +# absent échoue AUSSI (disparition = régression de traçabilité). +# ============================================================================ +try: + qr_crit = load("qa/audit_4big/out/quality_report.json") + criteria = qr_crit["criteria"] +except (OSError, KeyError, ValueError) as e: + bad(f"README audit_4big · quality_report illisible : {e}"); criteria = None +if criteria is not None and a4_txt: + n_crit = len(criteria) + # 1) prose « N critères 4Big déterministes » + mc = re.search(r"sur (\d+) critères 4Big déterministes", a4_txt) + if mc is None: + bad(f"README audit_4big · prose « N critères 4Big » — claim INTROUVABLE dans " + f"{A4} (attendu {n_crit})") + elif mc.group(1) == str(n_crit): + good(f"README audit_4big · prose critères — {mc.group(1)} == criteria ({n_crit})") + else: + bad(f"README audit_4big · prose critères — {A4} dit {mc.group(1)} MAIS criteria " + f"en compte {n_crit} → régénérer le README") + # 2) table « Critère | Poids | … » — une ligne id→poids par critère + for c in criteria: + cid, w = c["id"], str(c["weight"]) + mw = re.search(rf"\| `{re.escape(cid)}` \| (\d+) \|", a4_txt) + if mw is None: + bad(f"README audit_4big · critère {cid} — ligne INTROUVABLE dans {A4} " + f"(attendu poids={w})") + elif mw.group(1) == w: + good(f"README audit_4big · critère {cid} — poids {mw.group(1)} == criteria ({w})") + else: + bad(f"README audit_4big · critère {cid} — {A4} dit poids {mw.group(1)} MAIS " + f"criteria dit {w} → régénérer le README") + # 3) archétype « generator (N critères) » — generator applique TOUS les critères + mg = re.search(r"`generator` \((\d+) critères\)", a4_txt) + if mg is None: + bad(f"README audit_4big · archétype « generator (N critères) » — claim " + f"INTROUVABLE dans {A4} (attendu {n_crit})") + elif mg.group(1) == str(n_crit): + good(f"README audit_4big · generator — {mg.group(1)} critères == criteria ({n_crit})") + else: + bad(f"README audit_4big · generator — {A4} dit {mg.group(1)} MAIS l'archétype " + f"generator applique les {n_crit} critères → régénérer le README") + # 4) cohérence croisée : Σ poids == 100 (base de renormalisation) + w_sum = sum(c["weight"] for c in criteria) + if w_sum == 100: + good(f"README audit_4big · Σ poids critères == {w_sum} (base 100 cohérente)") + else: + bad(f"README audit_4big · Σ poids critères == {w_sum} ≠ 100 — barème incohérent " + f"avec la renormalisation documentée") + # 5) cohérence croisée : tout module `generator` porte len(criteria) checks + gen = [m for m in qr_crit["modules"] if m.get("archetype") == "generator"] + gen_bad = [m["id"] for m in gen if len(m.get("checks", [])) != n_crit] + if not gen: + good("README audit_4big · aucun module d'archétype generator (rien à recouper)") + elif gen_bad: + bad(f"README audit_4big · modules generator avec ≠ {n_crit} checks : {gen_bad} " + f"→ « generator = tous les critères » violé") + else: + good(f"README audit_4big · {len(gen)} module(s) generator portent {n_crit} " + f"checks (« generator = tous les critères » vérifié)") + # ============================================================================ # Fiches agents · comptes de tests PAR SUITE (colonne « Tests » des tables) — # même classe de « vert trompeur », au grain le PLUS FIN.