d7fc6bab26
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
916 lines
58 KiB
Markdown
916 lines
58 KiB
Markdown
# Activity Log · 2026-07-31 · Claude Code DTP
|
||
|
||
## 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
|
||
fonctionnellement close (22/22 modules · 564 tests · 7 gates verts au démarrage).
|
||
Poursuite de la série anti-dérive (CLAUDE.md #6). La session précédente a gaté les
|
||
**cellules** « Tests » par suite des tables de fiches (recompute générique depuis
|
||
`plan.suites[path].test_methods`), motivée par le fait qu'une **compensation** +1/−1
|
||
entre deux suites passerait sous la seule somme agrégée. Recherche de la **même classe
|
||
un cran au-dessus** : les agrégats **rédigés en prose** (hors table) que ce recompute
|
||
par-cellule ne voit pas.
|
||
|
||
### Défaut trouvé — 2 agrégats en PROSE ungated (total + composants saisis à la main)
|
||
|
||
- **`03_agents/crm/AGENT.md:32`** : « Total CRM : **81 tests** (25 + 31 + 25) ».
|
||
- **`03_agents/erpnext_backend/AGENT.md:39`** : « Total backend **RBAC 60 tests**
|
||
(10 + 11 + 12 + 11 + 16) + **e-CF 39 tests** ».
|
||
- **Pourquoi non gaté** : `check_readme_claims` recompute les **cellules de table**
|
||
(`row_re` exige un lien `…/README.md` + dernier champ numérique) — ces phrases en
|
||
prose n'en sont pas. Le total agrégé du repo (564) est gaté ailleurs mais ne couvre
|
||
pas ces **sous-totaux par domaine** ni leurs **composants**. Une compensation entre
|
||
deux suites CRM (l'une +1, l'autre −1) laisserait la table (gatée) juste, la somme
|
||
repo (564) juste, et la prose « (25 + 31 + 25) » **fausse en silence** — exactement
|
||
le piège per-suite corrigé la session précédente, au niveau **agrégé**.
|
||
- **État courant** : **aucun nombre périmé** — 81=(25+31+25), RBAC 60=(10+16+11+11+12),
|
||
e-CF 39=fiscal/ecf_dgii, tous recoupés sur `plan.suites`. Le défaut est la **surface
|
||
ungated** (faux-vert latent), pas un chiffre faux (anti-invention #6 : rien à réécrire).
|
||
|
||
### Fix — extension de `check_readme_claims.sh` (recompute total + multiset composants)
|
||
|
||
Nouveau bloc qui, pour chaque agrégat en prose, **RECOMPUTE** depuis `auth`
|
||
(`plan.suites[path].test_methods`, déjà chargé · zéro duplication) :
|
||
- le **total** == somme des suites du domaine ;
|
||
- le **multiset des composants** (trié, **ordre-indépendant**) == multiset des comptes
|
||
par suite — c'est ce qui attrape la **compensation** que la somme seule rate ;
|
||
- la **cohérence interne** (total == somme des composants écrits).
|
||
+ un contrôle à **suite unique** pour e-CF (pas de parenthèses). Un claim **absent**
|
||
échoue AUSSI. En-tête du gate + `ci/README.md` (§ table + § détail) mis à jour.
|
||
|
||
### Preuves de morsure
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| **Total périmé** `81→82` | **exit 1** `dit total=82 … MAIS source dit total=81 (interne_ok=False)` |
|
||
| **Compensation** `(25+31+25)→(24+31+26)` (somme=81 **inchangée**) | **exit 1** `composants=[24,26,31] MAIS source [25,25,31]` — le multiset mord là où la somme est aveugle |
|
||
| **Claim e-CF disparu** | **exit 1** `claim INTROUVABLE (attendu 39)` |
|
||
| Restauré | **exit 0** |
|
||
|
||
### 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 `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 total ET composants depuis
|
||
`plan.suites` au lieu de figer un compteur ; les nombres de prose **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_070019` · Buffer S8 · « Vert trompeur » ironique : le README de l'auditeur 4Big — le module qui COMPTE les modules — figeait son PROPRE total à la main (« 17/17 modules ») alors que son artefact `quality_report.json` en dit 22 ; ungated
|
||
|
||
**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 agrégés/par-suite des **docs d'entrée** (README racine, fiches QA/Backend, tables
|
||
« Tests »). Recherche du même faux-vert **hors de ce périmètre** : audit des comptes
|
||
`N modules` / `N/N` dans les **README de module** (pas seulement l'entrée + les fiches).
|
||
|
||
### Défaut trouvé — 2 comptes vivants « 17 » périmés dans `qa/audit_4big/README.md`
|
||
|
||
- **`05_deliverables_mvp/qa/audit_4big/README.md:68`** (« Résultat courant ») :
|
||
« **Verdict `PASS`** — **17/17** modules à **100/100** » — compte **vivant saisi à la
|
||
main**, périmé (17 → 22 au fil des ajouts de modules). **Ironie complète** : c'est le
|
||
README du module qui **COMPTE les modules** ; son propre artefact faisant autorité
|
||
`qa/audit_4big/out/quality_report.json` (`totals.modules`) dit **22** depuis longtemps.
|
||
- **`…/README.md:38`** (règle du verdict global) : « `PASS` **ssi** couverture 100 % **et**
|
||
les **17** modules ≥ 95/100 » — la **règle** (« TOUS les modules ≥ 95 ») ne dépend pas
|
||
d'un compte ; le « 17 » n'était qu'une **surface de dérive** de plus.
|
||
- **Pourquoi non gaté** : `check_readme_claims` recomputait `22/22` pour le **README
|
||
d'entrée** (racine) mais ne couvrait **pas** ce README **de module**. `check_docs` ne
|
||
valide que les liens ; l'auditeur s'**auto-exclut** (SoD) donc son propre `out/` ne
|
||
reflète pas l'édition de son README → aucun signal.
|
||
|
||
### Fix (2 volets · CLAUDE.md #4 — corriger + supprimer la surface + garder)
|
||
|
||
1. **`README.md:38`** : retrait du compte figé → « **tous** les modules gated ≥ 95/100 »
|
||
(la règle, count-free ⇒ **zéro surface de dérive**, précédent `050007`/`053011`).
|
||
2. **`README.md:68`** : `17/17` → **22/22** (compte courant, désormais gaté).
|
||
3. **`ci/check_readme_claims.sh`** : nouveau bloc qui **RECALCULE** verdict + `pass/modules/
|
||
min_score` depuis `quality_report.json` (`totals`, déjà chargé dans `q`/`qv` · zéro
|
||
duplication) et exige l'égalité avec ce que « Résultat courant » **écrit**. Un claim
|
||
absent échoue AUSSI. Header du gate mis à jour (doc couverte).
|
||
|
||
### Preuves de morsure
|
||
|
||
- **Bite 1** (valeur périmée) : réinjecté `17/17` ⇒ gate **exit 1** `✗ … dit PASS/17/17/100
|
||
MAIS quality_report dit PASS/22/22/100 → régénérer le README`.
|
||
- **Bite 2** (claim disparu) : reformulé sans le motif ⇒ **exit 1** `✗ … claim INTROUVABLE`.
|
||
- **Restauré** ⇒ **exit 0**.
|
||
|
||
### 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/`) | ✅ (auditeur **auto-exclu** SoD ⇒ `quality_report.json` **byte-identique** ; 0 régénération) |
|
||
| Matrice de régression | **564/22 · PASS** inchangée (README édité, aucun `tests/`) |
|
||
| Résidu `17` vivant repo-wide | **aucun** (seul restant = daily_report `2026-07-30` point-in-time, conservé) |
|
||
| Diff | 2 fichiers · +39/−3 · 0 untracked |
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **recompute** la vérité depuis `totals`
|
||
au lieu de figer un compteur ; le `22/22` du README **découle** de l'artefact.
|
||
**Hors périmètre worker (VPS · #8)** : néant (doc + gate bash/stdlib en-repo).
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_053011` · Buffer S8 · Comptes vivants « 551 tests » périmés DANS la machinerie CI elle-même (`.gitea/workflows/ci.yml` + `ci/check_regression.sh` + `ci/check_readme_claims.sh`) — non couverts par aucun gate
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close (22/22 modules · **558** tests · 7 gates verts). Poursuite de
|
||
la série anti-dérive (CLAUDE.md #6). Les sessions précédentes ont gaté les comptes vivants
|
||
des **docs** d'entrée (README, fiches QA/Backend) puis nettoyé la **doc du CI** (`ci/README.md`,
|
||
session `050007`). Recherche du même faux-vert **hors de ce périmètre** : audit `git grep '551'`
|
||
repo-wide (pas seulement `*.md`) → la machinerie CI **opérationnelle** (workflow + headers de
|
||
gates), qu'**aucun gate ne couvre**.
|
||
|
||
### Défauts trouvés — 3 comptes vivants « 551 » périmés (→ 558), dans le code des gates
|
||
|
||
- **`.gitea/workflows/ci.yml:67`** : le commentaire du job `check-regression` décrivait
|
||
l'artefact commité comme « **22 suites · 551 tests · PASS**, cité dans toute la doc » —
|
||
compte **vivant figé** périmé (matrice 534 → 551 → **558**).
|
||
- **`ci/check_regression.sh:8`** (l'ironie, encore) : le **header du gate de fraîcheur de
|
||
la matrice** — dont le rôle même est d'empêcher le compte agrégé de se périmer —
|
||
s'illustrait par « totaux « **22 suites · 551 tests · verdict PASS** » cité partout ».
|
||
Le gardien anti-péremption avait lui-même péri.
|
||
- **`ci/check_readme_claims.sh:152`** : l'anecdote décrivant le défaut QA disait « … alors
|
||
que **le run dit 22 / 551** » — présent de l'indicatif ⇒ prétention **vivante** du compte
|
||
courant, désormais fausse (558). *(Le « 21 suites · 534 tests » de la même ligne est
|
||
l'anecdote historique point-in-time du défaut corrigé — conservé.)*
|
||
- **Pourquoi non gaté** : `check_readme_claims` ne couvre que README + fiches QA/Backend ;
|
||
ces fichiers **mélangent** narratifs historiques figés volontaires (progression
|
||
« 534 → 551 → 558 ») et comptes vivants — exactement le motif qui a laissé `ci/README.md`
|
||
dériver (session `050007`).
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : supprimer la surface de dérive · précédent `050007`)
|
||
|
||
Plutôt que réécrire 551→558 (qui re-dériverait au prochain ajout de suite), **retrait du
|
||
nombre vivant figé** au profit d'un renvoi à l'artefact — « les totaux agrégés (suites · tests ·
|
||
verdict) dont la doc dérive, **jamais figés en dur ici** ». Zéro nombre à périmer = **zéro
|
||
surface de dérive**, structurellement plus fort qu'un gate sur de la prose (#6).
|
||
- `ci.yml:67` & `check_regression.sh:8` : compte figé → renvoi descriptif à `regression_run.json`.
|
||
- `check_readme_claims.sh:152` : « le run dit 22 / 551 » → « le run agrégé faisant autorité
|
||
en disait déjà **davantage** (recompté ci-dessous, jamais figé ici) » — formulation
|
||
identique à celle appliquée à `ci/README.md` en session `050007`. Le **534** point-in-time
|
||
reste comme valeur du défaut.
|
||
- *(Alt. écartée : étendre `check_readme_claims` à `ci.yml`/`ci/*.sh` — fragile, il faudrait
|
||
distinguer chaque progression historique figée d'un compte vivant ; le retrait est plus fort.)*
|
||
|
||
### Preuves
|
||
|
||
| Contrôle | Résultat |
|
||
|---|---|
|
||
| `git grep '551'` hors logs/daily_reports/progression `534→551→558` | **aucun** compte vivant résiduel ✅ |
|
||
| 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) |
|
||
| `check_ci_integrity` (câblage `gate.needs` inchangé) | ✅ |
|
||
| Diff | 3 fichiers · +9/−6 · 0 untracked |
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (commentaires CI en-repo, aucun touch prod).
|
||
**Anti-invention (#6)** : rien inventé — retrait de nombres figés, la vérité reste recomputée
|
||
par les gates depuis `regression_run.json`.
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_050007` · Buffer S8 · Chiffre vivant périmé DANS la doc du CI (`ci/README.md`) — le gate `check_regression` était illustré par un compte de tests faux, et `check_readme_claims` sous-décrit (2 docs au lieu de 3)
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close (22/22 modules · 558 tests · **7** gates verts au démarrage).
|
||
Poursuite de la série anti-dérive : la classe « chiffre inventé/périmé » (README, fiche
|
||
QA, fiche Backend) est gatée sur 3 docs ; recherche d'un **même faux-vert hors de ce
|
||
périmètre**. Audit repo-wide des agrégats (`git grep '<N> suites|<N> modules|551|534'`
|
||
sur `*.md` hors logs/archives) + relecture des 7 gates pour un **bug de logique**.
|
||
|
||
### Défauts trouvés — 3 dérives réelles, toutes dans `ci/README.md` (doc du livrable DevOps)
|
||
|
||
- **`ci/README.md:80`** (le pire) : la section décrivant `check_regression` — le gate
|
||
*censé empêcher les compteurs de se périmer* — s'illustrait elle-même par un **compte
|
||
vivant périmé** : « 22 suites · **551 tests** · PASS ». La matrice faisant autorité
|
||
(`qa/regression/out/regression_run.json`) dit **558** depuis la session `043004`
|
||
(534 → 551 → 558) ; l'exemple appariait le compte de **suites courant** (22) à un
|
||
compte de **tests périmé** (551). Ironie complète : la doc du gate anti-dérive avait
|
||
elle-même dérivé.
|
||
- **`ci/README.md:130`** : la ligne anecdote de la fiche QA citait « le run réel
|
||
`22 / 551` » au **présent** — 551 ne correspond plus à rien (→ 558).
|
||
- **`ci/README.md:121-131`** : la section `§check_readme_claims` affirmait garder « les
|
||
**deux** docs d'entrée » (README + fiche QA) et **omettait la fiche ERPNext Backend**
|
||
— 3ᵉ doc pourtant ajouté à la couverture du gate en session `043004`. Le **header du
|
||
script** `check_readme_claims.sh` (source de vérité · l.23/29/32) liste bien les 3 ;
|
||
seul `ci/README.md` a dérivé → **doc qui sous-décrit son propre code**.
|
||
- **Pourquoi non gaté** : session `030001` a délibérément laissé `ci/README.md` **hors**
|
||
de `check_readme_claims` car il porte des **chiffres historiques figés** volontaires
|
||
(anecdotes « demo 18→21 », « 21 suites · 534 tests »). C'est ce mélange
|
||
historique/vivant qui a laissé le compte **vivant** (551) se périmer en silence.
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : supprimer la surface de dérive + réaligner)
|
||
|
||
- **Correctif de fond (l.80)** : le compte **vivant** figé « 22 suites · 551 tests » est
|
||
**supprimé** au profit d'un renvoi — « le compte agrégé (suites · tests · passés ·
|
||
verdict) … **recompté par `check_readme_claims`** dans les fiches d'entrée, jamais figé
|
||
en dur ici ». Plus de nombre à périmer = **zéro surface de dérive** (plus robuste qu'un
|
||
gate sur une prose ; #6). *(Alt. écartée : étendre `check_readme_claims` à `ci/README.md`
|
||
— fragile, il faudrait distinguer chaque anecdote historique figée d'un compte vivant ;
|
||
supprimer le nombre est structurellement plus fort.)*
|
||
- **Anecdote historique (l.130)** : « le run réel `22 / 551` » (chiffre vivant faux)
|
||
remplacé par « alors que le run agrégé faisant autorité en disait davantage » ; le
|
||
**534** est **conservé** comme valeur point-in-time du défaut corrigé (comme « demo
|
||
18→21 »), désormais sans nombre concurrent périmé.
|
||
- **Réalignement (l.121-134)** : « les **deux** docs d'entrée » → « les **trois** » +
|
||
**ajout du bloc fiche Backend** (`N tests · M suites · verdict → regression_run.json`),
|
||
miroir du header du script. La doc décrit à nouveau exactement le code.
|
||
|
||
### Preuves
|
||
|
||
| Contrôle | Résultat |
|
||
|---|---|
|
||
| `git grep '551' *.md` (hors logs/archives) | **aucun** chiffre vivant résiduel ✅ |
|
||
| `534` restant | **1 seule** ligne = anecdote historique explicite (l.131) ✅ |
|
||
| « trois docs » + fiche Backend décrite dans `ci/README.md` | ✅ |
|
||
| 7 gates (`guard`/`json`/`docs`/`artifacts`/`regression`/`ci_integrity`/`readme_claims`) | ✅ exit 0 |
|
||
| `check_artifacts` (rebuild + égalité byte de tous les `out/`) | ✅ (édition **hors** `05_deliverables_mvp` ⇒ 0 dérive d'artefact) |
|
||
| Arbre de travail | ✅ 1 fichier modifié, 0 untracked |
|
||
|
||
**Anti-invention (#6)** : rien inventé — la vérité (558) vient de `regression_run.json`
|
||
(gaté par `check_regression`) ; le fix **retire** le compteur figé plutôt que d'en poser
|
||
un nouveau. Matrice **558/22 · PASS inchangée**.
|
||
|
||
**Non-régression** : édition **doc pure hors `05_deliverables_mvp`** → `qa/audit_4big`
|
||
ne la lit pas comme evidence ⇒ `quality_report.json` **inchangé** ; aucune régénération
|
||
de consommateur nécessaire.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (doc en-repo ; runner Gitea = DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_040004` · Sprint 7/8 · Livrable démo : ajout du **prompteur Markdown** (`out/run_sheet.md`) — le support texte lisible manquait au « scénario démo prêt à jouer »
|
||
|
||
**Tâche** : **Sprint 7 l.68** (« CRM + Faisabilité : Scénarios démo P07 banquier ·
|
||
P05 client ready ») × **Sprint 8 buffer**. Après audit : les 7 gates CI étaient
|
||
verts, 15 promesses `in_repo`, faisabilité 4 volets complète. Le seul livrable démo
|
||
(`demo/scenarios`) ne produisait qu'un **run-sheet JSON machine** — aucun support
|
||
**lisible par un présentateur**. Son propre README plafonnait l'auto-score à 96/100
|
||
en qualifiant le « prompteur » de **hors périmètre (VPS)**. Or rendre un Markdown
|
||
in-repo depuis le JSON est exactement le pattern déjà utilisé par `faisabilite`
|
||
(rend des `.md`) — **aucune écriture VPS**. Gap réel, borné, à forte valeur.
|
||
|
||
### Livraison
|
||
|
||
- **`scenlib/render.py`** (nouveau) — `render_markdown(run_sheet) -> str` **pur et
|
||
déterministe**. Ne lit **que** le run-sheet (déjà résolu, déjà anti-inventé) :
|
||
aucun chiffre nouveau, aucun recalcul (anti-invention #6). `_fmt` : bool→oui/non,
|
||
liste→jointe, placeholder survivant rendu entre back-ticks (jamais promu en nombre).
|
||
- **`demo_scenario_gen.py build`** émet désormais `out/run_sheet.md` en plus des deux
|
||
JSON. Le rendu est un prompteur par scénario : en-tête (audience/projet/durée/
|
||
objectif), puis chaque beat en table « À dire | Chiffre | Source (preuve) » —
|
||
chaque ligne trace son pointeur RFC 6901 amont.
|
||
- **`out/run_sheet.md`** (nouveau, commité) — 2 scénarios · 12 beats · 24 min cumulés.
|
||
|
||
### Compatibilité architecture (vérifiée AVANT d'écrire)
|
||
|
||
- **HANDOFF 4Big** (`q4lib/criteria.py:91`) ne `json.load` que les fichiers `.json` —
|
||
un `.md` dans `out/` est **ignoré**, aucune casse du critère.
|
||
- **`ci/check_artifacts.sh`** diffe **tout** fichier produit par `build` → il exige
|
||
désormais `run_sheet.md` **commité + reproductible byte-for-byte** (render
|
||
déterministe ⇒ OK). Preuve de morsure implicite : fichier non suivi ⇒ gate exit 1
|
||
(constaté puis corrigé par `git add`).
|
||
|
||
### Consommateurs régénérés (dérive maîtrisée)
|
||
|
||
- +7 méthodes test (`TestRenderMarkdown`) → **régression 551→558 tests** (22 suites,
|
||
PASS) : `regression run` + `build` régénérés (`regression_run/plan/MANIFEST.json`).
|
||
- `demo/scenarios` : README `5011→5575` octets + `32→39` test_* → **`quality_report.json`
|
||
régénéré** (evidence DOC+TESTS) · verdict **PASS · 22/22 · min 100** inchangé.
|
||
- `03_agents/qa/AGENT.md` : verdict agrégé `551→558` (gate `check_readme_claims` vert).
|
||
- README démo : Fichiers (+`render.py`, +`run_sheet.md`), chaîne de valeur, « hors
|
||
périmètre » (seul l'**habillage visuel** reste VPS), auto-score **96→97**.
|
||
|
||
### Vérifs
|
||
|
||
| Contrôle | Résultat |
|
||
|---|---|
|
||
| 7 gates CI (`guard`/`json`/`docs`/`artifacts`/`regression`/`readme_claims`/`ci_integrity`) | ✅ exit 0 |
|
||
| Tests démo | ✅ 39/39 |
|
||
| Tests audit_4big | ✅ 34/34 |
|
||
| Régression exhaustive | ✅ 22/22 suites · 558 tests · PASS |
|
||
| `run_sheet.md` reproductible (build frais == commité) | ✅ (gate artifacts) |
|
||
| Arbre de travail | ✅ 0 fichier untracked |
|
||
|
||
**Hors périmètre worker (VPS · #8)** : habillage visuel deck / page démo `otov7.com` +
|
||
branchement `data_room` réel — inchangé. Le prompteur texte est le rendu de référence
|
||
in-repo que ce visuel habillera.
|
||
|
||
**Auto-score 4Big** : 97/100.
|
||
|
||
## Session `20260731_033001` · Buffer S8 · « Vert trompeur » : la fiche QA affichait un « verdict agrégé courant » PÉRIMÉ (21/534) en se disant « jamais compté à la main » — hors du périmètre du gate README
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close (22/22 modules 100/100, 551 tests verts, **7** gates statiques). Poursuite de la
|
||
série anti-dérive : le gate `check_readme_claims` créé la session précédente ne garde que
|
||
`README.md` ; recherche d'une **même classe de faux-vert hors de son périmètre**.
|
||
|
||
### Défaut trouvé — 3 chiffres périmés en SILENCE dans `03_agents/qa/AGENT.md` et `ci/README.md`
|
||
|
||
- **Mécanisme** : la session `030001` a corrigé le README **et** claimé avoir corrigé « 3
|
||
commentaires CI (21 suites · 534 tests) dans `ci.yml` et `check_regression.sh` ». Mais
|
||
son propre gate ne couvre **que** `README.md`. Deux autres docs d'entrée portaient
|
||
encore le compte **périmé** — invisibles pour tous les gates (`check_docs` ne valide que
|
||
les liens) :
|
||
- **`03_agents/qa/AGENT.md:35`** (le pire) : section « Verdict agrégé courant » →
|
||
*« **21 suites gated · 534 tests · 534 passés · 0 échec · 0 erreur → verdict `PASS`** »*
|
||
en déclarant, ligne suivante, *« jamais compté à la main »*. C'était pourtant un
|
||
compte **figé à la main** qui cite `qa/regression/out/regression_run.json` comme
|
||
source — alors que le run réel dit **22 / 551**. Une fiche d'agent QA qui **affirme
|
||
une matrice verte avec des chiffres faux** est le « vert trompeur » le plus grave.
|
||
- **`ci/README.md:80`** : exemple « compteurs cités partout » figé à « 21 suites · 534
|
||
tests · PASS » (→ 22 · 551).
|
||
- **`ci/README.md:184`** : checklist DevOps « les **6 gates** statiques » (→ **7** depuis
|
||
l'ajout de `check-readme-claims`).
|
||
- **Preuve au sol** : `git grep -nE '534|21 suites|6 gates'` sur `*.md` (hors logs)
|
||
ramenait les 3 lignes ; `regression_run.json` recalculé = **22 suites · 551 tests · 551
|
||
passés · 0 échec · 0 erreur · PASS** (somme des 22 suites du run commité).
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : correction + extension du gate au-delà du README)
|
||
|
||
- **Correction des 3 chiffres** pour refléter les artefacts (fiche QA 21/534→22/551 ;
|
||
`ci/README.md` exemple 21·534→22·551 et checklist 6→7 gates). Ligne 132 « Les 6 gates
|
||
commençaient… » → « Les gates… » (le compte historique contredisait la table §1 à 7).
|
||
- **Correctif de fond** : **extension de `ci/check_readme_claims.sh`** (7ᵉ gate) au-delà du
|
||
README. Il **RECOMPUTE** désormais aussi le « Verdict agrégé courant » de la fiche QA
|
||
depuis `regression_run.json` (compte agrégé faisant autorité, commité · déterministe) :
|
||
`N suites · M tests · M passés · E échec · E erreur · verdict`, exige l'égalité avec ce
|
||
qui est **écrit** dans `03_agents/qa/AGENT.md`. Un claim **absent** échoue AUSSI. *(Alt.
|
||
écartée : 2ᵉ gate dédié — même classe de contrôle « valeur↔artefact » ; l'ajouter au gate
|
||
existant évite un doublon de câblage CI · #5.)* Le nom de fichier reste inchangé (pas de
|
||
ré-câblage `ci.yml`/INV-B) ; en-tête du script + `ci/README.md` §1 table + §2 détail mis
|
||
à jour pour la portée élargie (README **et** fiche QA).
|
||
|
||
### Preuves de morsure
|
||
|
||
- **Bite 1** (valeur périmée) : réintroduit « 21 suites · 534 tests » ⇒ gate **exit 1**
|
||
`✗ Fiche QA … dit 21/534/534/0/0/PASS MAIS regression_run dit 22/551/551/0/0/PASS`.
|
||
- **Bite 2** (claim disparu) : retire toute la ligne « Verdict agrégé » ⇒ **exit 1**
|
||
`✗ Fiche QA · verdict agrégé — claim INTROUVABLE`.
|
||
- **Restauré** ⇒ **exit 0** (les 6 claims README + le claim QA verts).
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **recompute** la vérité depuis
|
||
`regression_run.json` (somme des suites du run commité) au lieu de figer un compteur ; les
|
||
3 chiffres corrigés sont tous recoupés sur cet artefact.
|
||
|
||
**Non-régression** : **7 gates** locaux verts, dont `check_artifacts` (rebuild + égalité
|
||
byte de tous les `out/`) ⇒ **aucune dérive d'artefact** (l'audit_4big ne lit ni `03_agents/`
|
||
ni `ci/` comme evidence → pas de régénération `quality_report`). Matrice **551/22 · PASS
|
||
inchangée**. Unique « 534 » résiduel = description **historique** volontaire du défaut
|
||
corrigé (`ci/README.md:130`, comme l'anecdote « demo 18→21 »).
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib pur en-repo ; runner Gitea toujours
|
||
du ressort DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_030001` · Buffer S8 · « Vert trompeur » : le README (point d'entrée) affichait des chiffres PÉRIMÉS que sa propre source contredisait — aucun gate ne les enforçait
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close (22/22 modules 100/100, 551 tests verts, 6 gates statiques). Poursuite de la
|
||
série anti-dérive : recherche d'un **faux-vert réel** (une affirmation présentée comme
|
||
vérifiée mais qu'aucun gate ne vérifie), même classe que les bugs `regression_run.json`
|
||
/ `out/` RBAC / `cd ""` des sessions précédentes.
|
||
|
||
### Défaut trouvé — les chiffres du README dérivaient en SILENCE vs leurs artefacts cités
|
||
|
||
- **Mécanisme** : `README.md` est le **point d'entrée** du mandat ; sa section « État
|
||
courant (sourcé) » déclare mot pour mot *« Chaque chiffre ci-dessous est sourcé vers
|
||
un artefact commité (anti-invention #6) ; ce README n'introduit aucune donnée
|
||
nouvelle. »* Cette promesse n'était gardée par **aucun** gate : `check_docs.sh` ne
|
||
valide que les **liens** (la cible existe), **jamais la VALEUR** des nombres. Quand un
|
||
module + son job CI ont été ajoutés au fil des sprints, les chiffres du README se sont
|
||
**périmés en silence** tout en restant « sourcés » vers un artefact qui, lui, dit
|
||
autre chose — un README qui se **contredit avec sa propre source** est le pire « vert
|
||
trompeur » (CLAUDE.md #6 : « zéro invention de chiffres »), appliqué à la doc d'entrée.
|
||
- **Preuve au sol (3 dérives réelles constatées)** :
|
||
- README : « **21/21** modules gated à 100/100 » — `qa/audit_4big/out/quality_report.json`
|
||
`totals` dit **22/22** (min_score 100, verdict PASS) ;
|
||
- README : « **21** suites gated » — `qa/regression/out/regression_plan.json`
|
||
`totals.suites` dit **22** (551 tests) ;
|
||
- README : « 15 promesses… **14 `in_repo`** prouvées + **1 `out_of_scope`** » —
|
||
`qa/acceptance/out/acceptance_matrix.json` a **15 `in_repo`** (M5 est désormais
|
||
`in_repo` avec son hors-périmètre tracé per-promesse ; 0 promesse hors `in_repo`).
|
||
Les liens étaient tous verts (`check_docs` OK) : la dérive était **invisible**.
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : correction README + gate qui l'enforce)
|
||
|
||
- **Correction des 3 chiffres** du README (21→22 modules, 21→22 suites, « 14+1 » → « 15
|
||
in_repo ») pour refléter les artefacts.
|
||
- **Correctif de fond** : nouveau gate **`ci/check_readme_claims.sh`** (7ᵉ gate statique)
|
||
qui **RECOMPUTE** chaque chiffre depuis l'artefact cité (jamais une liste à la main ·
|
||
#6) et exige l'égalité avec ce qui est **écrit** dans le README : modules/verdict
|
||
(audit_4big), suites (régression), promesses/statuts/verdict (acceptance), nombre
|
||
d'`AGENT.md` (×2 : nav + titre). Un claim **absent** du README échoue AUSSI (la dérive
|
||
de formulation qui ferait disparaître un chiffre est elle-même une régression de
|
||
traçabilité). *(Alt. écartée : régénérer le README depuis un template — surdimensionné
|
||
et fragile pour une section en prose ; un gate qui compare valeur↔source est la preuve
|
||
la plus forte et la moins couplée à la mise en forme.)*
|
||
- **Câblage CI** : job `check-readme-claims` ajouté à `ci.yml` + inséré dans
|
||
`gate.needs` (30 jobs bloquants désormais). `check_ci_integrity` (INV-A/INV-B) valide
|
||
le câblage : `gate.needs` == 32 jobs − 1 (gate) − 1 manuel ; `ci/check_readme_claims.sh`
|
||
lancé par `check-readme-claims` ∈ gate, et **source `ci/lib.sh`** (pas de code mort,
|
||
échoue en `exit 3` hors arbre git comme les 6 autres).
|
||
|
||
### Preuves de morsure
|
||
|
||
- **Bite 1** (valeur périmée) : réintroduit « 21/21 modules » ⇒ gate **exit 1**
|
||
`✗ README dit 21/21/100 MAIS artefact dit 22/22/100 → régénérer README`.
|
||
- **Bite 2** (claim disparu) : retire `**22 suites gated**` ⇒ gate **exit 1**
|
||
`✗ claim INTROUVABLE dans README (attendu suites=22)`.
|
||
- **Restauré** ⇒ **exit 0** vert. Gate inerte tant que README == artefacts.
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **recompute** la vérité depuis les
|
||
artefacts au lieu de figer un compteur ; les 3 chiffres corrigés sont tous **recoupés**
|
||
sur `quality_report`/`regression_plan`/`acceptance_matrix`.
|
||
|
||
**Nettoyage cohérence (#5 · éliminer le vieux)** : 3 commentaires CI mentionnaient
|
||
encore « 21 suites · 534 tests » (désormais 22 · 551) — corrigés dans
|
||
`.gitea/workflows/ci.yml` et `ci/check_regression.sh`. `ci/README.md` : table §1 + détail
|
||
§2 + commande §3 du nouveau gate ajoutés.
|
||
|
||
**Vérifs** : **7 gates** locaux verts (`guard_constraints`/`validate_json`/`check_docs`/
|
||
`check_artifacts`/`check_regression`/`check_ci_integrity`/**`check_readme_claims`**) ;
|
||
`ci.yml` **YAML valide** ; `check_ci_integrity` : `gate.needs` = **30 jobs** (32 − gate
|
||
− e2e-baseline manuel), 7 `ci/*.sh` câblés + `lib.sh` sourcée par les 7. Artefacts `out/`
|
||
inchangés (aucun module `05_deliverables_mvp/` touché ⇒ pas de régénération).
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib pur en-repo ; enregistrement du
|
||
runner Gitea toujours du ressort DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_015954` · Buffer S8 · « Vert trompeur » : les 6 gates `ci/*.sh` passaient VERT hors d'un arbre git en ne contrôlant RIEN
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps
|
||
CI/CD)**. Roadmap fonctionnellement close (21/21 modules 100/100, 534 tests verts,
|
||
6 gates statiques). Poursuite de la série anti-dérive : recherche d'un **faux-vert
|
||
réel** (gate qui passe sans rien vérifier), même classe que les bugs
|
||
`regression_run.json` / `out/` RBAC des sessions précédentes.
|
||
|
||
### Défaut trouvé — `cd "$(git rev-parse --show-toplevel)"` échoue en SILENCE hors d'un checkout git
|
||
|
||
- **Mécanisme** : les **6** gates commençaient par
|
||
`cd "$(git rev-parse --show-toplevel)"`. HORS d'un arbre de travail git (tarball,
|
||
`git archive | tar -x`, `git` absent du PATH, working-dir erroné), `git rev-parse`
|
||
n'écrit **rien** sur stdout → la commande devient `cd ""`, un **no-op qui RETOURNE
|
||
SUCCÈS** (le script reste dans le cwd au lieu d'échouer). Les gates poursuivaient
|
||
sur un `git ls-files` renvoyant une liste **VIDE** →
|
||
`validate_json` (« Aucun fichier .json suivi — rien à valider »),
|
||
`guard_constraints` et `check_docs` sortaient **exit 0 VERT en ayant contrôlé
|
||
ZÉRO fichier** (≈50 JSON non validés, contraintes CLAUDE.md non vérifiées). Un
|
||
gate qui passe au vert sans rien enforcer est le **pire** « vert trompeur » —
|
||
précisément ce que la série buffer traque.
|
||
- **Preuve au sol (avant fix)** : copie de l'arbre **sans `.git`** →
|
||
`validate_json` **exit 0** « rien à valider » ; `guard_constraints` **exit 0**
|
||
« Contraintes respectées » ; `check_docs` **exit 0**. Ce piège avait déjà faussé
|
||
une vérif « 6 gates verts sur git archive » d'une session antérieure (un `git
|
||
archive | tar -x` n'a **pas** de `.git`, alors que le runner Gitea a un vrai
|
||
`.git` via `actions/checkout@v4` — donc la méthode « archive » n'est PAS
|
||
équivalente au runner pour tout check qui interroge git).
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : helper partagé DRY + durcissement INV-B)
|
||
|
||
- **Correctif de fond** : nouveau helper **`ci/lib.sh`** (sourcé, jamais exécuté
|
||
seul) exposant **`cd_repo_root`** — se positionne à la racine, ou **échoue
|
||
bruyamment** (`exit 3`, code distinct d'un échec de contrôle `1`) avec un message
|
||
clair si `git rev-parse` ne renvoie rien. Les 6 gates remplacent leur
|
||
`cd "$(git rev-parse …)"` par `source "$(dirname "${BASH_SOURCE[0]}")/lib.sh" ||
|
||
exit 3 ; cd_repo_root`. *(Alt. écartée : inliner le garde de 4 lignes × 6 fichiers
|
||
= doublon, contraire à CLAUDE.md #5 · préférence lib partagée.)*
|
||
- **Durcissement du gate de câblage (INV-B · `check_ci_integrity.sh`)** : INV-B
|
||
exigeait que **chaque** `ci/*.sh` soit lancé par un job — `ci/lib.sh` (jamais dans
|
||
un `run:`) aurait été flaggé « gate mort ». INV-B accepte désormais un `ci/*.sh`
|
||
câblé de **deux** façons : lancé par un job du gate, **OU sourcé** par ≥1 gate
|
||
script (détecté par grep d'une ligne `source …/<base>` / `. …/<base>`, `#` exclu).
|
||
C'est un **renforcement** réel : le gate prouve maintenant aussi que les libs
|
||
partagées sont **effectivement sourcées** (pas du code mort).
|
||
|
||
### Preuves de morsure
|
||
|
||
- **Faux-vert corrigé** : arbre copié **sans `.git`** → les 6 gates sortent
|
||
désormais **exit 3** avec « ❌ ERREUR gate : hors d'un arbre de travail git »
|
||
(avant : `validate_json`/`guard_constraints`/`check_docs` = **exit 0 vert**).
|
||
Idem sur `git archive HEAD | tar -x` **après commit**.
|
||
- **INV-B reconnaît la lib** : `ci/lib.sh — lib sourcée par [les 6 gates] · non
|
||
exécutée en propre (OK)` → **exit 0**.
|
||
- **INV-B attrape une lib morte** : `ci/_dead.sh` (sourcé par personne) ⇒
|
||
`✗ … lancé/sourcé par AUCUN job CI (gate mort)` ⇒ **exit 1**.
|
||
|
||
**Non-régression** : **6 gates verts** dans l'arbre de travail (= ce que voit le
|
||
runner via `actions/checkout@v4`, avec un vrai `.git`) ; matrice **534/21 · PASS
|
||
inchangée** ; `qa/audit_4big` **out/ inchangé** (les édits `ci/` sont **hors**
|
||
`05_deliverables_mvp` → aucune dérive de consommateur) ; `ci.yml` YAML **valide**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — garde purement défensif (bash/git stdlib),
|
||
INV-B relit `ci.yml` + grepe les gates sur disque à chaque run.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib en-repo ; enregistrement du
|
||
runner Gitea toujours du ressort DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_012944` · Buffer S8 · Reproductibilité en CHECKOUT PROPRE — le hand-off out/ des 4 générateurs RBAC était `.gitignore`é → gate rouge en CI, vert en local seulement
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps
|
||
CI/CD)**. Roadmap fonctionnellement close (21/21 modules 100/100, 534 tests verts,
|
||
6 gates statiques). Poursuite de la série anti-dérive : recherche d'un **écart
|
||
green-local / red-en-CI réel** (même classe que le bug `regression_run.json`
|
||
corrigé plus tôt aujourd'hui) plutôt qu'un correctif cosmétique.
|
||
|
||
### Défaut trouvé — 2 gates ROUGES en checkout propre (`check-artifacts` + `check-regression`)
|
||
|
||
- **Méthode** : test au sol par `git archive HEAD | tar -x` (= exactement ce que
|
||
voit le runner Gitea), et non `bash ci/*.sh` dans l'arbre de travail.
|
||
- **Constat** : les 4 générateurs RBAC (`rbac/fixtures_gen`, `userperm_gen`,
|
||
`roleprofile_gen`, `apply_plan`) **`.gitignore`aient leur `out/`** (« re-générable
|
||
à la demande ») — alors qu'ils sont audités en archétype **`generator`** (critère
|
||
**HANDOFF** = `out/MANIFEST.json` + ≥1 artefact JSON). En checkout **propre**,
|
||
leur `out/` est **absent** → l'audit 4Big (`qa/audit_4big`, dont le `build`
|
||
**relit le `out/` de CHAQUE module**) les note **80 < 95** ⇒ **INV7** ⇒ build
|
||
**refusé**. Cascade : `check-artifacts` **rouge** (rebuild audit_4big + demo
|
||
échouent) et `check-regression` **rouge**. Ça ne « passait » qu'en **local**,
|
||
grâce aux `out/` **non suivis** laissés sur disque par des `build` manuels —
|
||
**exactement** la classe du bug `regression_run.json` (green-local/red-CI).
|
||
- **Preuve au sol** : `git archive` de `HEAD` → `check_artifacts` **exit 1**
|
||
(`INV7 rbac-* note 80 < 95` · `demo/scenarios build a échoué`) et
|
||
`check_regression` **exit 1**. Les 15 autres générateurs commettent bien leur
|
||
`out/` → seuls les 4 RBAC étaient l'exception.
|
||
|
||
### Fix (2 solutions · CLAUDE.md #4 — retenu : aligner sur les 15 autres modules)
|
||
|
||
- **Correctif de fond** : **committer** le `out/` des 4 générateurs RBAC (retrait
|
||
de `out/` des 4 `.gitignore` + `git add`). Faisabilité **prouvée** : chaque
|
||
`build` est **byte-déterministe** (2 builds successifs identiques ; tri stable,
|
||
zéro horodatage). `apply_plan` lit ses frères **en process** (imports), pas via
|
||
leur `out/` — committer le `out/` sert **uniquement** le contrat HANDOFF audité.
|
||
L'audit note désormais les 4 modules **100/100** en checkout propre. *(Alt.
|
||
écartée : reclasser les 4 en archétype sans HANDOFF — diverge du reste des
|
||
générateurs et laisse `check_artifacts` les ignorer, moins cohérent · #5.)*
|
||
- **Durcissement du gate (empêche la récidive)** : `ci/check_artifacts.sh`
|
||
comparait le build frais au fichier de l'**arbre de travail** — donc un `out/`
|
||
**non suivi** (ignoré / jamais `git add`) le rendait **vert en local** alors
|
||
qu'il serait **absent en CI**. Ajout d'une assertion **`git ls-files
|
||
--error-unmatch`** : tout fichier produit par `build` DOIT être **suivi par git**
|
||
→ l'écart devient une **erreur locale honnête**, plus une surprise en CI.
|
||
- **Régénération des consommateurs (mémoire projet)** : l'édition des 4 README RBAC
|
||
(en-tête `out/` « non commité » → « commité · byte-déterministe », +18 o chacun)
|
||
a fait dériver `qa/audit_4big/out/quality_report.json` (evidence DOC = taille
|
||
README) — **régénéré** (PASS · 21/21 · min 100). `demo` + `regression run`
|
||
rejoués : **inchangés** (ils lisaient déjà l'état correct).
|
||
|
||
**Preuve de morsure du durcissement** : `git rm --cached role.json` (fichier laissé
|
||
sur disque, simulant un `out/` ignoré) ⇒ `check_artifacts` **exit 1** (`✗ … NON
|
||
SUIVI par git → absent en CI propre`) ; re-`git add` ⇒ **exit 0**. Avant le
|
||
durcissement, ce même état passait **vert**.
|
||
|
||
**Vérifs** : **6 gates verts sur `git archive` propre** (guard/json/docs/artifacts/
|
||
regression/ci_integrity) ; suites harnais **OK** (fixtures/userperm/roleprofile/
|
||
apply_plan/audit_4big/regression/demo · 32/32) ; matrice **534/21** **inchangée** ;
|
||
build de TOUS les consommateurs → **zéro dérive résiduelle**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — `out/` RBAC = sortie déterministe des
|
||
générateurs ; `quality_report` recalculé depuis les faits du dépôt.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib pur en-repo ; les fixtures
|
||
Frappe côté VPS restent `.gitignore`ées, hors de ce correctif).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_005934` · Buffer S8 · Intégrité du câblage CI — le gate d'agrégat verrouille TOUS les jobs (gates statiques compris)
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps
|
||
CI/CD)**. Roadmap fonctionnellement close (21/21 modules à 100/100, 534 tests
|
||
verts, **5** gates statiques tous verts au démarrage). Poursuite de la série
|
||
anti-dérive (INV4, fraîcheur matrice, reproductibilité artefacts) : recherche d'un
|
||
**trou de câblage réel** plutôt qu'un correctif cosmétique.
|
||
|
||
### Défaut trouvé — les gates STATIQUES n'étaient gardés par aucun invariant d'appartenance au gate
|
||
|
||
- **Constat** : le job `gate` (`needs: [...]`) est le **seul verrou de merge** — un
|
||
check absent de son `needs:` ne bloque **rien**, même rouge. Les deux couvertures
|
||
existantes (`audit_4big/registry.coverage_report`, `qa/regression/discovery.
|
||
coverage_report`) prouvent l'appartenance au gate **uniquement** pour les jobs de
|
||
**module** (ceux portant un `working-directory:` sous `05_deliverables_mvp`). Les
|
||
**5 gates statiques** (`constraints-guard`/`validate-json`/`check-docs`/
|
||
`check-artifacts`/`check-regression` → scripts `ci/*.sh`) **n'ont pas** de
|
||
working-directory : **rien** ne garantissait qu'ils alimentent le gate. Retirer
|
||
l'un d'eux de `needs:` (ou une **typo** dans la liste, ou un `ci/*.sh` **décâblé**)
|
||
rendait le gate **vert en se court-circuitant** — même classe de dérive silencieuse
|
||
que INV4 (orphan_tests_dirs), côté **câblage CI**.
|
||
- **Fix** : nouveau gate `ci/check_ci_integrity.sh` (bash/awk/git, stdlib pur, zéro
|
||
réseau) + job CI `check-ci-integrity`, lui-même ajouté à `gate.needs`. Deux
|
||
invariants, lus par FAITS dans `ci.yml` (jamais une liste à la main) :
|
||
- **INV-A** : `gate.needs` == { tous les jobs définis } − { `gate` } − { jobs
|
||
**manuels** `if: … workflow_dispatch …`, ex. `e2e-baseline` légitimement hors du
|
||
gate push/PR }. Détecte **MISSING** (job oublié → ne bloque pas), **DANGLING**
|
||
(référence fantôme : typo / job supprimé) et **MANUAL-IN-GATE** (job manuel dans
|
||
`needs` → gate en attente perpétuelle sur push).
|
||
- **INV-B** : chaque `ci/*.sh` du dépôt est lancé par exactement un job
|
||
(`run: bash ci/<script>`), lui-même dans `gate.needs` — un gate statique **non
|
||
câblé** (script mort) ou **décâblé** casse le check.
|
||
- **Preuve de morsure (5 modes, tous exit 1)** :
|
||
- MISSING : `check-artifacts` retiré de `needs` ⇒ `✗ ABSENT de gate.needs` + `✗`
|
||
INV-B sur `check_artifacts.sh` ;
|
||
- DANGLING : `seo-tests`→`seo-testz` dans `needs` ⇒ `✗ référence 'seo-testz' non
|
||
définie` + `✗ seo-tests ABSENT` ;
|
||
- MANUAL-IN-GATE : `e2e-baseline` ajouté à `needs` ⇒ `✗ job manuel … gate en
|
||
attente` ;
|
||
- SCRIPT-MORT : `ci/check_phantom.sh` commité sans job ⇒ `✗ lancé par AUCUN job` ;
|
||
- DÉCÂBLÉ : couvert par le mode MISSING (job hors `needs`).
|
||
État nominal restauré ⇒ **exit 0** (`gate.needs = 28 jobs = 30 définis − 1 (gate)
|
||
− 1 manuel [e2e-baseline]`).
|
||
|
||
**Non-régression** : le nouveau job est **statique** (aucun `working-directory`) →
|
||
comme les 5 autres, il **n'entre pas** dans la matrice de régression ni le registre
|
||
`audit_4big` (dérivés des seuls jobs de module). Totaux **534/21 inchangés**.
|
||
Suites harnais **OK** : `qa/regression` (21 suites · 534), `qa/audit_4big` (21/21 ·
|
||
min 100), `qa/acceptance` (bijectif=True). `ci.yml` YAML **valide**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **relit** `ci.yml` et recalcule les
|
||
ensembles à chaque run (aucun compteur figé).
|
||
|
||
**Vérifs** : **6 gates** statiques verts (`guard_constraints`/`validate_json`/
|
||
`check_docs`/`check_artifacts`/`check_regression`/`check_ci_integrity`) ; doc
|
||
`ci/README.md` mise à jour (tableau des jobs, section 2 détaillée, exécution locale,
|
||
checklist « 6 gates »).
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib en-repo ; enregistrement du
|
||
runner Gitea toujours du ressort DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_002924` · Buffer S8 · Intégrité de la matrice de régression (bug CI réel + invariant disque→CI)
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs » · DevOps
|
||
CI/CD)** — roadmap fonctionnellement close (21/21 modules gated à 100/100, 534
|
||
tests verts, 5 gates statiques). Recherche d'une **incohérence de reproductibilité
|
||
réelle** plutôt qu'un correctif doc cosmétique. **Deux** défauts réels trouvés et
|
||
corrigés, tous deux dans `qa/regression`.
|
||
|
||
### Défaut #1 (PRIORITAIRE · bug CI réel) — le gate `check-regression` était cassé en checkout propre
|
||
|
||
- **Symptôme** : `ci/check_regression.sh` (l.52-53) **exige** que
|
||
`qa/regression/out/regression_run.json` **existe dans le dépôt**, puis compare un
|
||
`run` frais à ce fichier commité (baseline byte-identique).
|
||
- **Contradiction** : ce même fichier était **`.gitignore`é** (« non déterministe
|
||
(temps machine) → jamais commitée ») → **jamais présent dans un checkout propre**.
|
||
Le job Gitea `check-regression` ne fait que `checkout` + `bash check_regression.sh`,
|
||
**aucune étape ne génère** le fichier. **Conséquence** : le gate **échouait sur
|
||
CHAQUE run CI propre** (`artefact absent du dépôt`). Il ne « passait » qu'en local,
|
||
par la présence d'un `regression_run.json` **non suivi** laissé par un `run` manuel.
|
||
Le commentaire de `ci.yml` disait déjà « le regression_run.json **commité** » —
|
||
intention claire du commit précédent, jamais concrétisée (fichier resté ignoré).
|
||
- **Vérif de faisabilité (#1 analyser)** : l'artefact `run` est **byte-déterministe** —
|
||
clés `{ran,passed,failures,...}` + `path` **relatif**, **aucun** horodatage/hôte/
|
||
durée. Deux `run` successifs **byte-identiques** (vérifié). Le committer est donc
|
||
**licite** et complète l'intention du gate.
|
||
- **Fix** : `run` est désormais **commité** (baseline du gate) →
|
||
- `.gitignore` : retrait de `out/regression_run.json` + note expliquant qu'il est
|
||
commité *parce que* déterministe ;
|
||
- `README.md` : section `run` réécrite (byte-déterministe · commité · baseline
|
||
`check_regression` · distinction d'avec `check_artifacts` qui ne rejoue que
|
||
`build`) ;
|
||
- `out/regression_run.json` : **ajouté au suivi** (21 suites · 534 tests · PASS).
|
||
- **Preuve de morsure** : fichier retiré (simule checkout propre) ⇒ gate **exit 1**
|
||
(`artefact absent`) — l'état exact en CI ; restauré ⇒ **exit 0** (`run == commité`).
|
||
|
||
### Défaut #2 (invariant manquant) — dérive silencieuse disque→CI non gardée
|
||
|
||
- **Gap** : `discovery.coverage_report` prouvait le sens **CI→disque** (tout module
|
||
gated a un `tests/`) mais **pas l'inverse** : un module gagnant un `tests/` sur
|
||
disque **sans job CI** n'entrait jamais dans la matrice, ses tests **ne tournaient
|
||
jamais**, et la couverture ne le voyait pas (elle n'itère que les suites dérivées du
|
||
CI) — la matrice restait « PASS » en **sous-comptant** en silence. Même classe de
|
||
dérive que « demo 18→21 », direction opposée.
|
||
- **Fix** : nouvel invariant **INV4** —
|
||
- `discovery.disk_test_modules()` : marche disque pure listant tout module portant
|
||
un `tests/` (POSIX, trié, déterministe) ;
|
||
- `coverage_report` : champ `orphan_tests_dirs = disk − ci_paths` ; `ok` exige
|
||
désormais `not orphan_tests_dirs` ;
|
||
- `regression.schema.json` : `orphan_tests_dirs` ajouté (required · strict) ;
|
||
- `regression_gen.py` : message INV4 surface les orphelins ;
|
||
- `tests/test_regression.py` : +2 tests (sous-ensemble disque⊆CI sur le dépôt réel ;
|
||
preuve de morsure monkeypatch d'un orphelin ⇒ `ok=False`).
|
||
- **Preuve de morsure end-to-end** : `mkdir zz_orphan/tests` + `build` ⇒ **build
|
||
refusé** `INV4 … orphan_tests_dirs=['zz_orphan']` ; répertoire retiré ⇒ build OK.
|
||
|
||
**Anti-invention (#6)** : rien inventé — les deux gates **régénèrent** la vérité (run
|
||
frais / couverture recomputée) au lieu de figer un compteur.
|
||
|
||
**Régénération des consommateurs (mémoire projet)** : l'édition des tests + du README
|
||
de `qa/regression` a fait dériver `qa/audit_4big/out/quality_report.json` (evidence
|
||
« README.md 3710→4236 octets » et « 24→26 méthodes test_* ») — **régénéré**, verdict
|
||
**PASS · 21/21 · min 100**. Totaux matrice **534/21** **inchangés** : le harnais
|
||
`qa/regression` est **self-exclu** (INV3) → +2 méthodes test_* n'affectent pas la
|
||
matrice.
|
||
|
||
**Vérifs** : **5 gates** locaux verts (`guard_constraints`/`validate_json`/`check_docs`/
|
||
`check_artifacts`/`check_regression`) ; `ci.yml` **YAML valide** ; tests harnais
|
||
**26/26 OK** (régression) + **34/34 OK** (audit_4big) ; matrice **534/534 · 21/21 ·
|
||
PASS** ; artefacts `out/` reproductibles à l'identique.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib pur en-repo ; enregistrement du
|
||
runner Gitea toujours du ressort DevOps).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_043004` · Buffer S8 · Chiffre périmé dans une fiche agent (vert-trompeur ungated) + extension du gate
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs »)** — roadmap
|
||
fonctionnellement close (22/22 modules gated · 558 tests · 7 gates statiques verts).
|
||
Recherche d'un **défaut réel** (chiffre inventé/périmé · CLAUDE.md #6) plutôt qu'un
|
||
correctif cosmétique.
|
||
|
||
### Défaut trouvé — `03_agents/erpnext_backend/AGENT.md` : « repo : **560 tests** au total »
|
||
|
||
- **Symptôme** : la ligne « source unique » situait les tests backend dans le repo
|
||
par un compte agrégé **saisi à la main** (« repo : 560 tests au total »).
|
||
- **Contradiction** : `560` ne correspond **à AUCUN** compte courant —
|
||
- matrice de régression faisant autorité (`qa/regression/out/regression_run.json`) :
|
||
**558 tests · 22 suites · PASS** ;
|
||
- repo-wide (méthodes `test_*` sur disque, 23 fichiers) : **584**.
|
||
`560` = ancien `534` (matrice d'alors) `+ 26` (harnais `qa/regression`, self-exclu
|
||
INV3) — **périmé en silence** au fil de 534 → 551 → 558. Même classe de « vert
|
||
trompeur » que la fiche QA (21/534) corrigée la session précédente, mais dans une
|
||
fiche agent qu'**aucun gate ne couvrait**.
|
||
- **Vérif ciblée (#1 analyser)** : recomputé **toutes** les autres bornes chiffrées
|
||
des 13 `AGENT.md` — `crm 81=(25+31+25)`, `RBAC 60=(10+16+11+11+12)`, `e-CF 39`,
|
||
`portails 19`, `chat 31`, `confotur 44`, `seo 36` : **toutes exactes**. Le `560`
|
||
était le **seul** nombre dérivé.
|
||
|
||
### Fix (2 volets · corriger + garder)
|
||
|
||
1. **`03_agents/erpnext_backend/AGENT.md`** : `560` → **« matrice de régression du
|
||
repo : 558 tests · 22 suites · verdict PASS, source
|
||
`qa/regression/out/regression_run.json` — jamais compté à la main · #6 »** (le
|
||
nombre pointe désormais vers l'artefact gaté, pas une saisie).
|
||
2. **`ci/check_readme_claims.sh`** : nouveau bloc qui **recalcule** tests+suites+
|
||
verdict depuis `regression_run` (même source que la fiche QA) et exige l'égalité
|
||
avec ce que la fiche backend **écrit** ; un claim absent échoue aussi. Header du
|
||
gate mis à jour (liste des docs couverts).
|
||
|
||
### Preuves
|
||
|
||
- **Passe** : `Fiche Backend · … 558/22/PASS == regression_run` (✓).
|
||
- **Morsure** : `560` réinjecté ⇒ gate **rouge** (`dit 560/22/PASS MAIS regression_run
|
||
dit 558/22/PASS → régénérer la fiche`) ; restauré ⇒ vert.
|
||
- **Régression nulle** : édition d'un `AGENT.md` (doc) → **aucune dérive** d'artefact
|
||
`out/` (`check_artifacts` vert : `quality_report.json` inchangé).
|
||
|
||
**Vérifs** : **7 gates** locaux verts (`guard_constraints` · `validate_json` ·
|
||
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
|
||
`check_readme_claims`) ; matrice **558/22 · PASS**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **régénère** la vérité (matrice
|
||
re-agrégée) au lieu de figer un compteur ; le chiffre de la fiche **découle** de
|
||
l'artefact.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (docs + gate bash/stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_060012` · Buffer S8 · Traçabilité NON vérifiée : les n° de ligne `roadmap_line` de la matrice d'acceptation pouvaient pointer à côté en silence
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs »)** — roadmap
|
||
fonctionnellement close (22/22 modules gated · 558 tests · 7 gates verts au démarrage).
|
||
Recherche d'un **défaut réel** (traçabilité `CLAUDE.md` #6) plutôt qu'un cosmétique.
|
||
|
||
### Défaut trouvé — `qa/acceptance` : `roadmap_line` déclaré, jamais ancré
|
||
|
||
- **Symptôme** : chaque promesse de `acceptance_spec.json` (8 livrables S1..S8 + 7
|
||
métriques M1..M7) porte un `roadmap_line` (33, 39, … 87) censé pointer son bullet
|
||
dans `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md`. Le docstring promet des « CITATIONS
|
||
verbatim de la roadmap » (#6), mais le **seul** invariant (INV10) ne vérifiait que
|
||
« `roadmap_line` est un entier positif ».
|
||
- **Contradiction** : si la roadmap est éditée (une ligne insérée/retirée, un sprint
|
||
ré-ordonné), **tous** les `roadmap_line` se décalent en silence — ils pointeraient un
|
||
bullet qui n'existe plus, tout en restant « vert ». Même classe de « vert trompeur »
|
||
que les compteurs périmés (534→551→558) ou l'`orphan_tests_dirs`, appliquée cette
|
||
fois à une **référence de ligne** (traçabilité déclarée mais non prouvée).
|
||
- **Vérif (#1 analyser)** : recomputé la structure réelle → 8 bullets `**DELIVERABLE**`
|
||
(S1@33 … S8@76) + 7 bullets métrique `- ✅` (81..87). Les `roadmap_line` du spec sont
|
||
**exacts aujourd'hui** — la faille est l'absence de garde, pas une valeur fausse.
|
||
|
||
### Fix (2 volets · vérifier + garder)
|
||
|
||
1. **`acclib/deps.py`** — nouveau `parse_roadmap_anchors(roadmap_ref)` qui **DÉRIVE**
|
||
la structure de la roadmap (jamais une liste de n° saisie · #6) : `{SX → ligne du
|
||
DELIVERABLE}` (SX **lu** dans le titre `## SPRINT n · SX (…`) + lignes ordonnées des
|
||
bullets métrique. `OSError` honnête si la roadmap est absente (référence fantôme = red).
|
||
2. **`acceptance_gen.py` · INV11 (ancrage roadmap)** — exige que (a) le nombre de bullets
|
||
DELIVERABLE == nb de livrables du spec et nb de bullets métrique == nb de métriques
|
||
(le **« 8 + 7 » devient dérivé du fichier**, plus un compte figé), (b) chaque livrable
|
||
SX pointe le DELIVERABLE de SX, (c) chaque métrique (dans l'ordre) pointe le k-ième
|
||
bullet `- ✅`. Docstring #6 mis à jour (« n° de ligne VÉRIFIÉ, pas déclaré »).
|
||
3. **Tests** — fixture roadmap **synthétique** (temp file, mêmes motifs en miniature :
|
||
S2@L3, S3@L5, M1@L7) pour contrôler l'écart injecté ; classe `TestRoadmapAnchor`
|
||
(+6 méthodes) : parse réel (8+7), DELIVERABLE désancré, métrique décalée, mauvais
|
||
propriétaire de sprint, compte en trop, roadmap absente. **37 méthodes** (31→37).
|
||
|
||
### Preuves
|
||
|
||
- **Passe** : build/validate réel **vert** ; `parse_roadmap_anchors` réel = {S1:33 …
|
||
S8:76} + métriques [81..87] ; les 15 `roadmap_line` du spec **matchent**.
|
||
- **Morsure (spec RÉEL)** : `S1.roadmap_line=999` ⇒ `roadmap: S1: … ne pointe pas le
|
||
DELIVERABLE de S1 (ligne 33)` ; `M3=200` ⇒ `… ≠ 3e bullet métrique (ligne 83)`.
|
||
|
||
**Régénération des consommateurs (mémoire projet)** : +6 méthodes test dans
|
||
`qa/acceptance` → matrice **558→564** (22 suites inchangées). Régénérés :
|
||
`qa/regression/out/{regression_run,regression_plan,MANIFEST}.json` (564/564 · PASS),
|
||
`qa/audit_4big/out/quality_report.json` (evidence acceptance « 31→37 méthodes », score
|
||
**100/100 inchangé**), fiches **QA** et **Backend** (`558→564`, gate `check_readme_claims`
|
||
vert), README acceptance (« 10→11 invariants »). L'artefact `acceptance_matrix.json` est
|
||
**byte-identique** (INV11 ne change que la validation, pas la sortie).
|
||
|
||
**Vérifs** : **7 gates** locaux verts (`guard_constraints` · `validate_json` ·
|
||
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
|
||
`check_readme_claims`) ; matrice **564/22 · PASS** ; 22/22 modules **100/100**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — INV11 **dérive** la vérité de la roadmap et
|
||
compare ; le « 8 + 7 » cesse d'être un compte à la main.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (stdlib pur en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_063014` · Buffer S8 · Comptes de tests PAR SUITE périmés dans la fiche QA — dérive silencieuse (aucun gate ne couvrait le grain fin)
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75 (« Regression tests exhaustifs »)** — roadmap
|
||
fonctionnellement close (22/22 modules gated · 564 tests · 7 gates verts au démarrage).
|
||
Chasse d'un **défaut réel** de la classe « vert trompeur » (#6) plutôt qu'un cosmétique.
|
||
|
||
### Défaut trouvé — fiche QA : colonne « Tests » par suite figée, DÉJÀ fausse
|
||
|
||
- **Symptôme** : le tableau des livrables de `03_agents/qa/AGENT.md` (col « Tests »)
|
||
affichait un compte par suite saisi à la main. Trois lignes étaient **déjà
|
||
périmées** au démarrage : `audit_4big` **35** (réel 34), `regression` **25**
|
||
(réel 26), `acceptance` **31** (réel 37 — la session précédente avait fait 31→37
|
||
sans propager à cette table).
|
||
- **Contradiction** : le gate amont `check_readme_claims` ne couvrait que la **somme
|
||
agrégée** (« 564 tests »). Une **compensation** entre deux suites (+1 / −1)
|
||
laisserait la somme juste et **les deux lignes fausses** — même classe de « vert
|
||
trompeur » que les compteurs agrégés périmés (534→551→558→564) ou INV11, mais au
|
||
**grain le plus fin** (par suite), et non gardée.
|
||
- **Vérif systématique (#1 analyser)** : recomputé la carte faisant autorité des 22
|
||
suites gated + le self_module → diffusée contre **toutes** les tables de fiches
|
||
(`03_agents/*/AGENT.md`). Seule la fiche **QA** dérivait (3 lignes) ; CRM (3),
|
||
faisabilité (2), publiciste (1) étaient justes. READMEs de module : justes aussi.
|
||
|
||
### Fix (2 volets · corriger + garder)
|
||
|
||
1. **`03_agents/qa/AGENT.md`** — 3 nombres corrigés vers le réel : 35→34, 25→26,
|
||
31→37.
|
||
2. **`ci/check_readme_claims.sh`** — nouveau bloc générique : scanne **toutes** les
|
||
fiches, extrait chaque ligne de table pointant `05_deliverables_mvp/<path>/README.md`
|
||
+ sa cellule « Tests », et **recompute** l'attendu depuis la source faisant
|
||
autorité — `regression_plan.json` (`suites[path].test_methods`) pour les 22 suites
|
||
gated, et **`reglib.discovery.count_tests`** (même fonction que le plan · zéro
|
||
duplication · #5) pour le `self_module` `qa/regression` exclu de la matrice par SoD.
|
||
Table « Tests » absente ⇒ red (disparition = régression de traçabilité).
|
||
|
||
### Preuves
|
||
|
||
- **Passe** : gate vert, **10 lignes par-suite** vérifiées (crm×3 · faisabilite×2 ·
|
||
publiciste×1 · qa×4), toutes == source.
|
||
- **Morsure** : `acceptance` reforcé à 31 ⇒ `✗ … Tests 31 MAIS source dit 37
|
||
(plan.suites/count_tests) → régénérer la fiche` + verdict ❌ ; restauration ⇒ PASS.
|
||
|
||
**Régénération des consommateurs** : néant — aucun compte de test n'a changé (fix
|
||
= docs + gate). Artefacts `out/` **byte-identiques** (`check_artifacts` vert) ;
|
||
matrice **564/22 PASS** inchangée.
|
||
|
||
**Vérifs** : **7 gates** locaux verts (`guard_constraints` · `validate_json` ·
|
||
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
|
||
`check_readme_claims`) ; matrice **564/22 · PASS** ; 22/22 modules **100/100**.
|
||
|
||
**Anti-invention (#6)** : rien inventé — le gate **recompute** chaque cellule depuis
|
||
plan.suites / count_tests ; les nombres de la fiche **découlent** de la source.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (docs + gate bash/stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|