From 6a40bfcccecde3f6b65fed8d8d3bfc4078e1f00f Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Fri, 31 Jul 2026 14:39:58 +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=205D=20(2e=20surface)=20:=20la?= =?UTF-8?q?=20TABLE=20=C2=AB=20Verdict=20courant=20=C2=BB=20de=20l'audit?= =?UTF-8?q?=20de=20conformit=C3=A9=20=C3=A9num=C3=A9rait=20=C3=80=20LA=20M?= =?UTF-8?q?AIN=20ses=204=20open=20items=20(control=20=E2=86=92=20dimension?= =?UTF-8?q?=20=E2=86=92=20propri=C3=A9taire)=20sans=20AUCUN=20gate=20d'IDE?= =?UTF-8?q?NTIT=C3=89.=20Le=20bloc=20audit=5F5d=20existant=20gate=20=C2=AB?= =?UTF-8?q?=2017=20contr=C3=B4les=20/=205=20dimensions=20=C2=BB=20(=C3=972?= =?UTF-8?q?=20docs)=20ET=20la=20ventilation=20du=20verdict=20=C2=AB=2013?= =?UTF-8?q?=20PASS=20=C2=B7=200=20FAIL=20=C2=B7=204=20=C3=A0=20confirmer?= =?UTF-8?q?=20=C2=BB=20(recomput=C3=A9e=20d'audit=5Freport.totals)=20mais?= =?UTF-8?q?=20PAS=20l'identit=C3=A9=20des=204=20contr=C3=B4les=20ouverts?= =?UTF-8?q?=20ni=20leur=20(dimension,=20propri=C3=A9taire)=20=E2=80=94=20s?= =?UTF-8?q?urface=20data-derived=20distincte=20du=20M=C3=8AME=20README.=20?= =?UTF-8?q?Cette=20table=20d=C3=A9rive=20d'audit=5Freport.json.open=5Fitem?= =?UTF-8?q?s[]=20(byte-gat=C3=A9=20par=20check=5Fartifacts=20:=20chaque=20?= =?UTF-8?q?item=20=3D=20{control,=20dimension,=20owner,=20detail}=20recalc?= =?UTF-8?q?ul=C3=A9=20en=20rejouant=20les=20contr=C3=B4les=20sur=20les=20h?= =?UTF-8?q?and-off=20amont).=20Le=20bloc=20de=20VENTILATION=20ne=20recompu?= =?UTF-8?q?te=20que=20le=20COMPTE=20(=C2=AB=204=20=C3=A0=20confirmer=20?= =?UTF-8?q?=C2=BB)=20:=20un=20=C3=89CHANGE=20d'open=20item=20(ex.=20D2.3?= =?UTF-8?q?=20=E2=86=92=20D3.1)=20laisse=20le=20compte=20=C3=A0=204=20?= =?UTF-8?q?=E2=80=94=20le=20compteur=20reste=20AVEUGLE=20=E2=80=94=20penda?= =?UTF-8?q?nt=20que=20l'artefact=20dit=20autre=20chose=20;=20idem=20une=20?= =?UTF-8?q?dimension=20mal=20=C3=A9tiquet=C3=A9e=20(D1.3=20rang=C3=A9=20so?= =?UTF-8?q?us=20D2)=20ou=20un=20propri=C3=A9taire=20r=C3=A9attribu=C3=A9?= =?UTF-8?q?=20=E2=80=94=20=C2=AB=20vert=20trompeur=20=C2=BB=20qu'aucune=20?= =?UTF-8?q?suite=20tests/=20(qui=20teste=20des=20FONCTIONS,=20pas=20la=20p?= =?UTF-8?q?rose)=20n'attrape=20=E2=86=92=20nouveau=20bloc=20dans=20check?= =?UTF-8?q?=5Freadme=5Fclaims=20recomputant=20l'ensemble=20{control:(dimen?= =?UTF-8?q?sion,=20propri=C3=A9taire)}=20depuis=20audit=5Freport.open=5Fit?= =?UTF-8?q?ems=20(z=C3=A9ro=20duplication=20du=20mod=C3=A8le=20de=20l'audi?= =?UTF-8?q?teur=20#6)=20et=20exigeant=20que=20la=20table=20README=20l'?= =?UTF-8?q?=C3=A9num=C3=A8re=20EXACTEMENT.=20Contr=C3=B4le=20par=20ENSEMBL?= =?UTF-8?q?E=20(absent=20ET=20en=20trop=20mordus,=20pas=20seulement=20pr?= =?UTF-8?q?=C3=A9sence),=20puis=20(dimension,=20propri=C3=A9taire)=20PAR?= =?UTF-8?q?=20LIGNE.=20M=C3=AAme=20patron=20que=20l'=C3=A9num=C3=A9ration?= =?UTF-8?q?=20des=20confirmations=20DevOps=20ou=20la=20carte=20de=20renorm?= =?UTF-8?q?alisation=20par=20arch=C3=A9type=204Big.=20Coh=C3=A9rence=20cro?= =?UTF-8?q?is=C3=A9e=20en=20bonus=20:=20l'ensemble=20des=20control=20=3D?= =?UTF-8?q?=3D=20MANIFEST.open=5Fitems=20(le=20manifeste=20qui=20r=C3=A9su?= =?UTF-8?q?me=20le=20rapport)=20=E2=80=94=20mord=20un=20manifeste=20d?= =?UTF-8?q?=C3=A9synchronis=C3=A9=20de=20son=20rapport.=20Un=20claim=20abs?= =?UTF-8?q?ent=20=C3=A9choue=20AUSSI=20(4=20morsures=20v=C3=A9rifi=C3=A9es?= =?UTF-8?q?=20:=20=C3=A9change=20D2.3=E2=86=92D3.1=20capt=C3=A9=20l=C3=A0?= =?UTF-8?q?=20o=C3=B9=20le=20compte=20reste=204=20=C2=B7=20dimension=20D1.?= =?UTF-8?q?3=E2=86=92D2=20capt=C3=A9e=20=C2=B7=20propri=C3=A9taire=20D1.1?= =?UTF-8?q?=20Direction=E2=86=92Compta=20capt=C3=A9=20=C2=B7=20ligne=20D1.?= =?UTF-8?q?2=20supprim=C3=A9e=20=3D=20sous-ensemble=20capt=C3=A9=20;=20res?= =?UTF-8?q?taur=C3=A9=20=3D=20green=20:=20[D1.1,D1.2,D1.3,D2.3]=20control?= =?UTF-8?q?=E2=86=92dimension=E2=86=92propri=C3=A9taire=20=3D=3D=20audit?= =?UTF-8?q?=5Freport.open=5Fitems).=20=C3=89tat=20courant=20:=20aucun=20op?= =?UTF-8?q?en=20item=20p=C3=A9rim=C3=A9=20(anti-invention=20#6,=20rien=20?= =?UTF-8?q?=C3=A0=20r=C3=A9=C3=A9crire)=20=E2=80=94=20le=20d=C3=A9faut=20e?= =?UTF-8?q?st=20la=20surface=20ungated.=20ci/README.md=20(table=20+=20d?= =?UTF-8?q?=C3=A9tail)=20mis=20=C3=A0=20jour=20=C2=B7=207=20gates=20re-ver?= =?UTF-8?q?ts.?= 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 | 58 +++++++++++++++++++++++++++++++ ci/README.md | 17 +++++++++- ci/check_readme_claims.sh | 64 +++++++++++++++++++++++++++++++++++ 3 files changed, 138 insertions(+), 1 deletion(-) diff --git a/05_activity_log/2026-07-31.md b/05_activity_log/2026-07-31.md index 8b40cf8..1cb5c98 100644 --- a/05_activity_log/2026-07-31.md +++ b/05_activity_log/2026-07-31.md @@ -1,5 +1,63 @@ # Activity Log · 2026-07-31 · Claude Code DTP +## Session `20260731_143104` · Buffer S8 · Domaine QA/Audit 5D (2e surface) : la **table « Verdict courant »** de l'audit de conformité énumérait À LA MAIN ses **4 open items** (`control → dimension → propriétaire`) sans gate d'IDENTITÉ — le bloc existant ne recompute que le COMPTE (« 4 à confirmer »), aveugle à un **échange** d'open item. + +**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement +close ; poursuite de la série anti-dérive (CLAUDE.md #6). Le bloc `audit_5d` gaté +précédemment couvre « 17 contrôles / 5 dimensions » (×2 docs) **et** la ventilation +du verdict « **13 PASS · 0 FAIL · 4 à confirmer** » (recomputée d'`audit_report.totals`). +Restait, dans le **même README**, une surface data-derived distincte : la **table +« Verdict courant »** qui énumère les 4 contrôles ouverts avec leur dimension et leur +propriétaire. + +**Dérive silencieuse fermée** : +- `05_deliverables_mvp/qa/audit_5d/README.md:51-56` énumère 4 lignes + `| D1.1 · … | D1 | Direction |` … — chacune porte trois faits data-derived : + l'`id` du contrôle, sa **dimension**, son **propriétaire**. +- Source faisant autorité : `qa/audit_5d/out/audit_report.json.open_items[]` + (byte-gaté par `check_artifacts`, chaque item = `{control, dimension, owner, detail}` + recalculé en rejouant les contrôles sur les hand-off amont). +- Le bloc de **ventilation** ne gate QUE le **compte** (« 4 à confirmer »). Un + **échange** d'open item (ex. `D2.3 → D3.1`) laisse le compte à 4 — le compteur + reste AVEUGLE — pendant que l'artefact dit autre chose ; idem une **dimension** + mal étiquetée (`D1.3` rangé sous `D2`) ou un **propriétaire** réattribué. « Vert + trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS, pas la prose) n'attrape. +- **État courant** : **aucun open item périmé** — les 4 lignes recoupent l'artefact + exactement (anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**. + +**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute l'ensemble +`{control:(dimension, propriétaire)}` depuis `audit_report.open_items` (zéro +duplication du modèle de l'auditeur · #6) et exige que la table README l'énumère +**exactement** : contrôle par **ENSEMBLE** (absent ET en trop mordus, pas seulement +présence), puis `(dimension, propriétaire)` **par LIGNE**. Même patron que +l'énumération des confirmations DevOps ou la carte de renormalisation par archétype +4Big. Cohérence croisée en bonus : l'ensemble des `control` == `MANIFEST.open_items` +(le manifeste qui résume le rapport) — mord un manifeste désynchronisé de son rapport. + +### Preuve (4 morsures vérifiées + restauration verte) + +| Injection | Résultat | +|---|---| +| échange `D2.3 → D3.1` (compte reste 4 · gate-compte aveugle) | ✗ énumère `[…,D3.1]` MAIS référentiel `[…,D2.3]` · exit 1 | +| dimension `D1.3` étiquetée `D2` (compte + ids intacts) | ✗ open item D1.3 dit dimension=D2 MAIS artefact D1 · exit 1 | +| propriétaire `D1.1` `Direction → Compta` (compte + ids + dims intacts) | ✗ D1.1 dit propriétaire=Compta MAIS artefact Direction · exit 1 | +| ligne `D1.2` supprimée (sous-ensemble) | ✗ énumère `[D1.1,D1.3,D2.3]` MAIS référentiel `[D1.1,D1.2,D1.3,D2.3]` · exit 1 | +| restauré | ✓ `[D1.1,D1.2,D1.3,D2.3]` (control→dimension→propriétaire) == `audit_report.open_items` · exit 0 | + +- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe + descriptif (2e surface du même README audit 5D). + +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 ; +édition **hors** `05_deliverables_mvp` ⇒ 0 dérive d'artefact). + +**Auto-score 4Big** : 96/100. + +--- + ## Session `20260731_140101` · Buffer S8 · Domaine QA/Audit 4Big (2e surface) : la **carte de renormalisation PAR ARCHÉTYPE** de l'auditeur (« `data_room` (sans HANDOFF) · `parser` (sans CONTRAT … ni HANDOFF) · `contract` (sans CLI ni HANDOFF) ») était transcrite À LA MAIN dans le README du module — la session précédente a gaté le barème (critères + poids + `generator (N critères)`) mais PAS les exclusions des trois autres archétypes. **Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement diff --git a/ci/README.md b/ci/README.md index 1369397..16d8f0e 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) **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`) **et** de la carte de renormalisation par archétype de l'auditeur 4Big (critères EXCLUS de `data_room`/`parser`/`contract`, recomputés des `checks` par archétype de `quality_report.modules`) == 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 + énumération des open items `control→dimension→propriétaire` recomputée de `audit_report.open_items`) **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`) **et** de la carte de renormalisation par archétype de l'auditeur 4Big (critères EXCLUS de `data_room`/`parser`/`contract`, recomputés des `checks` par archétype de `quality_report.modules`) == 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 @@ -233,6 +233,21 @@ contrôle en A_CONFIRMER (pass 13→12, à confirmer 4→5) là où le total de reste 17 et resterait aveugle. Cohérence croisée en bonus : `controls_total` du MANIFEST doit égaler `totals.controls` du rapport. +Deuxième surface du **même README** de l'audit 5D : la **table « Verdict courant »** +énumère **à la main** les 4 open items (`| D1.1 · … | D1 | Direction |` …), chacun +portant trois faits data-derived — l'`id` du contrôle, sa **dimension** et son +**propriétaire**. Le bloc de ventilation ci-dessus ne gate que le **compte** (« 4 à +confirmer ») : un **échange** d'open item (ex. `D2.3 → D3.1`), une **dimension** mal +étiquetée (`D1.3` rangé sous `D2`) ou un **propriétaire** réattribué laisserait le +compte à 4 et **passerait en silence**. On RECOMPUTE l'ensemble +`{control:(dimension, propriétaire)}` depuis `qa/audit_5d/out/audit_report.json` +(`open_items[]`, byte-gaté) et on exige que la table README l'énumère **exactement** : +contrôle par **ensemble** (absent **et** en trop mordus, pas seulement présence), +puis `(dimension, propriétaire)` **par ligne** — même patron que l'énumération des +confirmations DevOps ou la carte de renormalisation par archétype 4Big. Cohérence +croisée en bonus : l'ensemble des `control` == `MANIFEST.open_items` (le manifeste qui +résume le rapport) — mord un manifeste désynchronisé de son propre rapport. + Même classe enfin sur le **run-book de déploiement VPS** (livrable `devops/deploy_runbook`) : le compte de **phases** (fiche agent `devops` — « graphe de **7 phases ordonnées** » **et** « exécute les 7 phases sur le VPS ») **et** le diff --git a/ci/check_readme_claims.sh b/ci/check_readme_claims.sh index 575dc52..8b5fa3f 100755 --- a/ci/check_readme_claims.sh +++ b/ci/check_readme_claims.sh @@ -1024,6 +1024,70 @@ if a5_ctl is not None: bad(f"Audit 5D · {A5D_FI} — dit {'/'.join(m.groups())} MAIS artefact dit " f"{a5_ctl}/{a5_dim} ({a5_src}) → régénérer la fiche") +# ============================================================================ +# Audit 5D (2e surface du MÊME README) · ÉNUMÉRATION des open items du « Verdict +# courant » (control → dimension → propriétaire) — même classe de « vert trompeur ». +# ---------------------------------------------------------------------------- +# Le bloc précédent gate le COMPTE de la ventilation (« 13 PASS · 0 FAIL · 4 à +# confirmer », pass/fail/à confirmer recomputés d'audit_report.totals) mais PAS +# l'IDENTITÉ des 4 contrôles ouverts ni leur (dimension, propriétaire). La table +# « Verdict courant » du README (05_deliverables_mvp/qa/audit_5d/README.md) énumère +# ces 4 lignes À LA MAIN, alors que audit_report.open_items[] (byte-gaté par +# check_artifacts ⇒ faisant autorité, chaque item = {control, dimension, owner, +# detail} recalculé en rejouant les contrôles) fait foi. Un ÉCHANGE d'open item +# (ex. D2.3 → D3.1) laisse le compte à 4 — le bloc de ventilation reste AVEUGLE — +# pendant que l'artefact dit autre chose ; idem une dimension mal étiquetée +# (D1.3 rangé sous D2) ou un propriétaire réattribué. « Vert trompeur » qu'aucune +# suite tests/ (qui teste des FONCTIONS, pas la prose) n'attrape. On RECOMPUTE +# l'ensemble {control:(dimension, owner)} depuis open_items (zéro duplication du +# modèle de l'auditeur · #6) et on exige que la table README l'énumère EXACTEMENT : +# contrôle par ENSEMBLE (absent ET en trop mordus, pas seulement présence), puis +# (dimension, propriétaire) par LIGNE. Même patron que l'énumération des +# confirmations DevOps ou la carte de renormalisation par archétype 4Big. Cohérence +# croisée en bonus : l'ensemble des `control` == MANIFEST.open_items (le manifeste +# qui résume le rapport) — mord un manifeste désynchronisé de son propre rapport. +# ============================================================================ +try: + a5_oi = load("qa/audit_5d/out/audit_report.json")["open_items"] + a5_oi_exp = {o["control"]: (o["dimension"], o["owner"]) for o in a5_oi} + a5_oi_man = set(load("qa/audit_5d/out/MANIFEST.json")["open_items"]) + if a5_oi_man != set(a5_oi_exp): + bad(f"Audit 5D · incohérence artefacts : MANIFEST open_items {sorted(a5_oi_man)} " + f"MAIS audit_report open_items {sorted(a5_oi_exp)}") +except (OSError, KeyError, ValueError) as e: + bad(f"Audit 5D · open_items illisible/inattendu : {e}"); a5_oi_exp = None +if a5_oi_exp is not None: + try: + a5_lines = open(f"{D}/qa/audit_5d/README.md", + encoding="utf-8").read().splitlines() + except OSError as e: + bad(f"Audit 5D · README illisible : {e}"); a5_lines = None + if a5_lines is not None: + # ligne de table = « | · | | | » + a5_row_re = re.compile( + r"^\|\s*(D\d+\.\d+)\b[^|]*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*$") + a5_seen = {} + for ln in a5_lines: + m = a5_row_re.match(ln) + if m: + a5_seen[m.group(1)] = (m.group(2).strip(), m.group(3).strip()) + a5_exp_set, a5_got_set = set(a5_oi_exp), set(a5_seen) + if a5_got_set != a5_exp_set: + bad(f"Audit 5D · énumération open items — table README énumère " + f"{sorted(a5_got_set)} MAIS audit_report dit {sorted(a5_exp_set)} " + f"→ régénérer le README") + else: + a5_mism = [c for c in sorted(a5_exp_set) if a5_seen[c] != a5_oi_exp[c]] + if a5_mism: + for c in a5_mism: + bad(f"Audit 5D · open item {c} — README dit " + f"(dimension={a5_seen[c][0]}, propriétaire={a5_seen[c][1]}) MAIS " + f"audit_report dit (dimension={a5_oi_exp[c][0]}, " + f"propriétaire={a5_oi_exp[c][1]})") + else: + good(f"Audit 5D · énumération open items {sorted(a5_exp_set)} " + f"(control→dimension→propriétaire) == audit_report.open_items") + # ============================================================================ # DevOps · run-book de déploiement VPS (phases ordonnées / confirmations # préalables) — même classe de « vert trompeur », transcrite À LA MAIN dans