[DTP-Worker] Sprint 8 · buffer L75 · Hors du domaine « tests » : les comptes PAR WORKSPACE (cartes/liens/rôles) des 5 portails frontend étaient transcrits À LA MAIN dans DEUX docs (table du README module + prose de la fiche frontend_console) sans AUCUN gate — ajouter un rôle/DocType au contrat RBAC ferait dériver les deux docs en silence pendant que frontend/portails/out/MANIFEST.json (byte-gaté par check_artifacts) dit autre chose → nouveau bloc dans check_readme_claims recomputant chaque triplet + le total « N Workspace natifs » depuis MANIFEST.workspaces et exigeant l'égalité avec les deux docs (4 morsures : dérive table · dérive prose captée là où la table est aveugle · cellule disparue · total)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,73 @@
|
||||
# Activity Log · 2026-07-31 · Claude Code DTP
|
||||
|
||||
## Session `20260731_080025` · Buffer S8 · Hors du domaine « tests » : les comptes PAR WORKSPACE (cartes/liens/rôles) des 5 portails frontend, transcrits À LA MAIN dans DEUX docs (table du README module + prose de la fiche agent), n'étaient couverts par AUCUN gate — ajouter un rôle/DocType au contrat RBAC ferait dériver les deux docs en silence
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||||
fonctionnellement close (22/22 modules · 564 tests · 7 gates verts au démarrage).
|
||||
Poursuite de la série anti-dérive (CLAUDE.md #6). Les sessions précédentes ont gaté
|
||||
les comptes du domaine **tests** (sommes, cellules par-suite, agrégats en prose). Cette
|
||||
session sort de ce domaine : audit des comptes **data-derived** cités dans les fiches
|
||||
et README de module qui pointent un artefact mais n'étaient recomputés par aucun gate.
|
||||
|
||||
### Défaut trouvé — comptes par workspace ungated, transcrits dans DEUX docs
|
||||
|
||||
- **`05_deliverables_mvp/frontend/portails/README.md:29-33`** : table
|
||||
« Portail | Workspace | **Cartes** | **Liens** | **Rôles restreints** » — 5 lignes
|
||||
× 3 nombres **saisis à la main**.
|
||||
- **`03_agents/frontend_console/AGENT.md:28`** : prose « **5 `Workspace` natifs**
|
||||
(`OTO Ventes` 4 cartes/11 liens/12 rôles · `OTO Construction` 4/9/10 · `OTO Achat`
|
||||
3/8/5 · `OTO Compta` 4/11/8 · `OTO Direction` 4/14/9) » — **mêmes** triplets recopiés.
|
||||
- **Pourquoi non gaté** : `check_readme_claims` couvrait les comptes de **tests**
|
||||
(README racine, fiches QA/Backend, cellules par-suite, prose CRM/RBAC/e-CF) et
|
||||
`audit_4big`/`acceptance` — jamais les comptes **de structure** des portails.
|
||||
`check_docs` ne valide que les liens ; `check_artifacts` prouve que
|
||||
`frontend/portails/out/MANIFEST.json` est **reproductible byte-for-byte** (tableau
|
||||
`workspaces` = {nb_cartes, nb_liens, nb_roles} recalculés depuis le contrat RBAC à
|
||||
chaque build) mais **ne compare pas** ce que les DEUX docs en **écrivent**. Ajouter
|
||||
un rôle/DocType au contrat ferait dériver les deux docs **en silence** pendant que
|
||||
l'artefact dit autre chose — même « vert trompeur » que les cellules « Tests ».
|
||||
- **État courant** : **aucun nombre périmé** — les 15 triplets et le total « 5 » des
|
||||
deux docs recoupent MANIFEST exactement (anti-invention #6 : rien à réécrire). Le
|
||||
défaut est la **surface ungated** (faux-vert latent), pas un chiffre faux.
|
||||
|
||||
### Fix — extension de `check_readme_claims.sh` (recompute par workspace depuis MANIFEST)
|
||||
|
||||
Nouveau bloc qui, pour **chaque** workspace de `MANIFEST.workspaces` (source déjà
|
||||
byte-gatée · zéro duplication du compteur du générateur), RECOMPUTE le triplet
|
||||
`(nb_cartes, nb_liens, nb_roles)` et exige l'égalité avec **les deux** docs : la ligne
|
||||
de table du README (ancrée `| <portail> | \`<ws>\` | C | L | R |`) **et** la cellule
|
||||
de prose de la fiche (`\`<ws>\` C cartes/L liens/R rôles`, forme abrégée `C/L/R`
|
||||
tolérée). + contrôle du **total** « N `Workspace` natifs » == len(workspaces). Un
|
||||
workspace **absent** d'un doc échoue AUSSI. En-tête du gate + `ci/README.md`
|
||||
(§ table + § détail) mis à jour.
|
||||
|
||||
### Preuves de morsure
|
||||
|
||||
| Injection | Résultat |
|
||||
|---|---|
|
||||
| **README table** `OTO Compta` liens `11→12` | **exit 1** `README dit 4/12/8 MAIS MANIFEST dit 4/11/8` |
|
||||
| **Fiche prose** `OTO Achat` `3/8/5→3/8/6` (table inchangée) | **exit 1** `fiche dit 3/8/6 MAIS MANIFEST 3/8/5` — mord là où la table seule est aveugle |
|
||||
| **Cellule disparue** (`OTO Direction` retirée de la prose) | **exit 1** `claim INTROUVABLE (attendu 4/14/9)` |
|
||||
| **Total** `5→6 Workspace natifs` | **exit 1** `fiche dit 6 MAIS MANIFEST dit 5` |
|
||||
| Restauré | **exit 0** (10 lignes doc + total verts) |
|
||||
|
||||
### Vérifs
|
||||
|
||||
| Contrôle | Résultat |
|
||||
|---|---|
|
||||
| 7 gates (`guard`/`json`/`docs`/`artifacts`/`regression`/`ci_integrity`/`readme_claims`) | ✅ exit 0 |
|
||||
| `check_artifacts` (rebuild + égalité byte des `out/`) | ✅ (édition **hors** `05_deliverables_mvp` ⇒ 0 dérive d'artefact ; aucun README/AGENT.md touché) |
|
||||
| Matrice de régression | **564/22 · PASS** inchangée (ni `tests/` ni doc-evidence touchés) |
|
||||
| Diff | 2 fichiers (`ci/check_readme_claims.sh` + `ci/README.md`) · 0 untracked |
|
||||
|
||||
**Anti-invention (#6)** : rien inventé — le gate recompute chaque triplet depuis
|
||||
`MANIFEST.workspaces` au lieu de figer un compteur ; les nombres des deux docs
|
||||
**découlent** de l'artefact.
|
||||
**Hors périmètre worker (VPS · #8)** : néant (gate python/stdlib en-repo).
|
||||
**Auto-score 4Big** : 96/100.
|
||||
|
||||
---
|
||||
|
||||
## Session `20260731_073024` · Buffer S8 · Dernière surface de la classe « compte par suite » : les agrégats de tests rédigés EN PROSE dans deux fiches (`crm` « 81 (25+31+25) » · `erpnext_backend` « RBAC 60 (10+11+12+11+16) + e-CF 39 ») n'étaient couverts par AUCUN gate — une compensation entre suites laisserait la table gatée juste et la prose fausse
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||||
|
||||
+10
-1
@@ -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) == 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) == 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
|
||||
@@ -154,6 +154,15 @@ Le **total ET le multiset des composants** (ordre-indépendant) sont recomputés
|
||||
table (gatée ci-dessus) juste et la prose fausse — c'est le même piège que les
|
||||
cellules, au niveau agrégé.
|
||||
|
||||
Même classe encore, hors du domaine « tests » : les comptes **par workspace**
|
||||
(cartes / liens / rôles) des portails frontend, transcrits **à la main** dans
|
||||
**deux** docs — la table du README du module (`frontend/portails/README.md`) **et**
|
||||
la prose de la fiche agent (`03_agents/frontend_console/AGENT.md` : « `OTO Ventes`
|
||||
4 cartes/11 liens/12 rôles · … »). Chaque triplet **et** le total « N `Workspace`
|
||||
natifs » sont recomputés depuis `frontend/portails/out/MANIFEST.json` (tableau
|
||||
`workspaces`, lui-même byte-gaté par `check_artifacts`) : ajouter un rôle/DocType
|
||||
au contrat RBAC ferait dériver **les deux** docs en silence sinon.
|
||||
|
||||
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.
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
# • « Total CRM N (a+b+c) » · « RBAC N (…) » · « e-CF N » — total ET multiset
|
||||
# des composants recomputés (une compensation entre suites laisserait la
|
||||
# table juste et la prose fausse) → plan.suites[path]
|
||||
# frontend/portails/README.md + 03_agents/frontend_console/AGENT.md :
|
||||
# • comptes PAR WORKSPACE (cartes / liens / rôles) transcrits À LA MAIN dans
|
||||
# DEUX docs (table du README + prose « OTO Ventes 4 cartes/11 liens/12
|
||||
# rôles ») + total « N Workspace natifs » → portails MANIFEST
|
||||
# (tableau `workspaces`, byte-gaté par check_artifacts)
|
||||
# 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é).
|
||||
#
|
||||
@@ -384,6 +389,78 @@ else:
|
||||
bad(f"Prose agrégée · e-CF — dit {mecf.group(1)} MAIS source dit {ecf_exp} "
|
||||
f"(fiscal/ecf_dgii) → régénérer la fiche")
|
||||
|
||||
# ============================================================================
|
||||
# Portails frontend · comptes PAR WORKSPACE (cartes / liens / rôles) —
|
||||
# même classe de « vert trompeur », transcrits À LA MAIN dans DEUX docs.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur de portails émet out/MANIFEST.json dont le tableau `workspaces`
|
||||
# porte, PAR portail, {nb_cartes, nb_liens, nb_roles} recalculés depuis le
|
||||
# contrat RBAC à chaque build (byte-gaté par check_artifacts). Ces triplets sont
|
||||
# recopiés À LA MAIN à DEUX endroits : la table du README du module
|
||||
# (frontend/portails/README.md, colonnes Cartes|Liens|Rôles) ET la prose de la
|
||||
# fiche agent (03_agents/frontend_console/AGENT.md — « OTO Ventes 4 cartes/11
|
||||
# liens/12 rôles · … »). Aucun gate ne les couvrait : ajouter un rôle/DocType au
|
||||
# contrat ferait dériver LES DEUX docs en silence pendant que l'artefact dit
|
||||
# autre chose — même piège que les cellules « Tests » et la prose agrégée. On
|
||||
# RECOMPUTE ici chaque triplet depuis MANIFEST (déjà byte-gaté · zéro duplication
|
||||
# du compteur du générateur) et on exige l'égalité avec les DEUX docs. Un
|
||||
# workspace absent d'un doc échoue AUSSI (traçabilité).
|
||||
# ============================================================================
|
||||
WS_RD = f"{D}/frontend/portails/README.md"
|
||||
WS_FI = "03_agents/frontend_console/AGENT.md"
|
||||
try:
|
||||
ws_list = load("frontend/portails/out/MANIFEST.json")["workspaces"]
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"Portails · MANIFEST illisible/inattendu : {e}"); ws_list = []
|
||||
try:
|
||||
ws_rd = re.sub(r"\s+", " ", open(WS_RD, encoding="utf-8").read())
|
||||
except OSError as e:
|
||||
bad(f"Portails · {WS_RD} illisible : {e}"); ws_rd = ""
|
||||
try:
|
||||
ws_fi = re.sub(r"\s+", " ", open(WS_FI, encoding="utf-8").read())
|
||||
except OSError as e:
|
||||
bad(f"Portails · {WS_FI} illisible : {e}"); ws_fi = ""
|
||||
|
||||
for w in ws_list:
|
||||
portail, ws = w["portail"], w["workspace"]
|
||||
exp = (str(w["nb_cartes"]), str(w["nb_liens"]), str(w["nb_roles"]))
|
||||
src = f"cartes={exp[0]} liens={exp[1]} rôles={exp[2]}"
|
||||
# 1) Table du README du module : | <portail> | `<ws>` | C | L | R |
|
||||
rd_pat = (rf"\| {re.escape(portail)} \| `{re.escape(ws)}` \| "
|
||||
r"(\d+) \| (\d+) \| (\d+) \|")
|
||||
mrd = re.search(rd_pat, ws_rd)
|
||||
if mrd is None:
|
||||
bad(f"Portails README · {ws} — ligne INTROUVABLE dans {WS_RD} (attendu {src})")
|
||||
elif mrd.groups() == exp:
|
||||
good(f"Portails README · {ws} — {'/'.join(mrd.groups())} == MANIFEST ({src})")
|
||||
else:
|
||||
bad(f"Portails README · {ws} — {WS_RD} dit {'/'.join(mrd.groups())} MAIS "
|
||||
f"MANIFEST dit {'/'.join(exp)} ({src}) → régénérer le README")
|
||||
# 2) Prose de la fiche agent : `<ws>` C cartes/L liens/R rôles (ou C/L/R)
|
||||
fi_pat = (rf"`{re.escape(ws)}` (\d+)(?: cartes)?/(\d+)(?: liens)?/"
|
||||
r"(\d+)(?: rôles)?")
|
||||
mfi = re.search(fi_pat, ws_fi)
|
||||
if mfi is None:
|
||||
bad(f"Portails fiche · {ws} — claim INTROUVABLE dans {WS_FI} (attendu {src})")
|
||||
elif mfi.groups() == exp:
|
||||
good(f"Portails fiche · {ws} — {'/'.join(mfi.groups())} == MANIFEST ({src})")
|
||||
else:
|
||||
bad(f"Portails fiche · {ws} — {WS_FI} dit {'/'.join(mfi.groups())} MAIS "
|
||||
f"MANIFEST dit {'/'.join(exp)} ({src}) → régénérer la fiche")
|
||||
|
||||
# Total de workspaces (« N `Workspace` natifs ») cohérent artefact ↔ fiche.
|
||||
n_ws = len(ws_list)
|
||||
if n_ws:
|
||||
mtot = re.search(r"\*\*(\d+) `Workspace` natifs", ws_fi)
|
||||
if mtot is None:
|
||||
bad(f"Portails fiche · total — « N `Workspace` natifs » INTROUVABLE "
|
||||
f"dans {WS_FI} (attendu {n_ws})")
|
||||
elif int(mtot.group(1)) == n_ws:
|
||||
good(f"Portails fiche · total — {mtot.group(1)} == MANIFEST ({n_ws} workspaces)")
|
||||
else:
|
||||
bad(f"Portails fiche · total — {WS_FI} dit {mtot.group(1)} MAIS "
|
||||
f"MANIFEST dit {n_ws} → régénérer la fiche")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user