63760a144b
Le bloc « apply_plan » existant de check_readme_claims.sh (bloc 2) ne gate QUE la
ligne AGRÉGÉE « Génération réelle » (8 comptes consolidés). Les 3 colonnes
d'identité de la table run-book (README:38-46) sont data-derived de
out/apply_plan.json (byte-gaté par check_artifacts) : # = order · Responsable =
responsable (worker/vps/worker+vps) · Dépend de = les n°s d'ordre des depends_on.
Elles étaient un WILDCARD. PIÈGE : check_artifacts ne prouve QUE apply_plan==build
(byte-for-byte) et le bloc de comptes est aveugle à l'identité des lignes → passer
le Responsable de l'étape 4 (worker+vps→vps) ou retirer une dépendance de l'étape 6
(4,5→4) laissait la prose périmée pendant que l'artefact dit autre chose. Un
responsable périmé (étape VPS attribuée au worker) ou une dépendance périmée (Role
Profile importé AVANT les Role) est un hazard réel — le risque même que le run-book
veut prévenir — qu'aucune suite tests/ (qui teste des fonctions, pas la table
commitée) n'attrape. Même classe que la colonne « Type » de roleprofile_gen et la
table demo/scenarios.
Nouveau sous-bloc « 2bis) apply_plan — TABLE Run-book » : (1) IDENTITÉ par étape —
chaque ligne porte EXACTEMENT #=order + Responsable=responsable + Dépend de=n°s
d'ordre des depends_on (deps extraits par digits ⇒ robuste au séparateur/em-dash) ;
colonne « Étape » libre (paraphrase). (2) IDENTITÉ d'ensemble — {ordres des lignes}
== {ordres artefact} sans doublon (aucune ligne FANTÔME, aucune étape MANQUANTE).
Cohérences croisées (mordent un plan INTERNEMENT incohérent) : ordres contigus 1..N ·
responsable ∈ {worker,vps,worker+vps} · toute dépendance pointe en ARRIÈRE
(n° < n° de l'étape). Un claim absent échoue AUSSI.
8 morsures vérifiées : README étape4 responsable worker+vps→vps (câblage) · README
étape6 Dépend de 4,5→4 (dep manquante) · README étape3 1,2→1,2,5 (dep fantôme) ·
ligne FANTÔME #7 (7≠6) · étape 5 SUPPRIMÉE (INTROUVABLE + 5≠6) · artefact étape2
responsable vps→worker (README stale) · artefact étape2 dep en AVANT (graphe
incohérent) · artefact étape1 responsable hors domaine (robot) ; restauré = green :
6 lignes == 6 étapes · responsables/deps == artefact · ordres 1..6 · exit 0.
État courant : aucune valeur périmée (anti-invention #6, rien à réécrire) — le
défaut est la surface ungated. ci/README.md (table + détail « 2ᵉ surface
rbac/apply_plan ») mis à jour · working tree byte-restauré · 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2551 lines
167 KiB
Markdown
2551 lines
167 KiB
Markdown
# Activity Log · 2026-07-31 · Claude Code DTP
|
||
|
||
## Session `20260731_220140` · Buffer S8 · Domaine Legal/CONFOTUR (2e surface) : la **cross-cohérence PERMISSIONS** du DocType — le CŒUR sécurité du livrable — énumérait EN PROSE, PAR rôle, son **portail** ET son **jeu d'actions RBAC** (`ventes-confotur`→read/write/create/print · `legal-onapi`→read/write/create · `legal-directeur`→read/write/**submit**/report) SANS AUCUN gate d'IDENTITÉ. Le bloc CONFOTUR existant ne gate QUE le COMPTE (« 3 rôles »).
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Même patron d'IDENTITÉ que
|
||
le catalogue RBAC `fixtures_gen` (séparation des pouvoirs `set_user_permissions`) ou
|
||
la cross-cohérence e-CF DGII — appliqué à la 2ᵉ surface data-derived du README
|
||
`legal/confotur`, jamais gatée.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/legal/confotur/README.md` §« Cœur du livrable :
|
||
cross-cohérence » →Permissions (l.28-30) énumère, PAR rôle, `role_id` + portail +
|
||
jeu d'actions, annoncé « **mot pour mot** les `permissions_cibles` RBAC … ni ajout
|
||
ni retrait ».
|
||
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
|
||
`out/MANIFEST.json.roles_rbac_utilises[]` (`role_id` · `portail` · `permissions`,
|
||
recomputé du contrat `rbac_50_roles.json` à chaque build) + sa projection
|
||
`out/doctype_confotur_application.json.permissions[]` (par nom de rôle ERPNext).
|
||
- Piège : le compte « 3 rôles » est AVEUGLE à leur identité. PROMOUVOIR
|
||
`ventes-confotur` à `submit` (élévation de privilège cassant la séparation des
|
||
pouvoirs dont `is_submittable` est déduit), RETIRER une action, RÉAFFECTER un
|
||
portail, RENOMMER un rôle ou AJOUTER une ligne fantôme laissait la prose périmée
|
||
pendant que les artefacts disent autre chose → l'agent ERPNext Backend câblerait le
|
||
mauvais jeu de permissions (le risque même que la cross-cohérence veut prévenir).
|
||
Aucune suite `tests/` (qui teste des FONCTIONS de mapping RBAC, pas la prose)
|
||
n'attrape ce « vert trompeur ».
|
||
- **État courant** : **aucun jeu d'actions périmé** — les 3 lignes recoupent les
|
||
artefacts exactement (anti-invention #6, rien à réécrire). Le défaut est la
|
||
**surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Legal · CONFOTUR
|
||
cross-cohérence PERMISSIONS » après le bloc de comptes CONFOTUR) : (1) jeu d'actions
|
||
+ portail de CHAQUE rôle recomputés de `roles_rbac_utilises[]`, prose exigée EXACTE
|
||
(set-diff · casse normalisée) ; (2) identité d'ensemble README ⇔ MANIFEST (aucun rôle
|
||
fantôme NI manquant). Cohérences croisées en bonus (mordent un artefact INTERNEMENT
|
||
incohérent) : MANIFEST ⇄ DocType d'accord sur le jeu d'actions par rôle · séparation
|
||
des pouvoirs — `submit` porté par EXACTEMENT un rôle (`legal-directeur`) et
|
||
`is_submittable == True` déduit de sa présence (README:31). Un claim absent échoue
|
||
AUSSI (traçabilité).
|
||
|
||
**7 morsures vérifiées** : README promeut `ventes-confotur` à `submit` (en
|
||
trop=[submit]) · README réaffecte `legal-onapi` Direction→Ventes (portail) · README
|
||
retire `report` de `legal-directeur` (absents=[report]) · README renomme un `role_id`
|
||
(fantôme=[legal-conseil] + manquant=[legal-onapi]) · énumération supprimée
|
||
(INTROUVABLE) · artefact MANIFEST promeut `ventes-confotur` à `submit` (README périmé
|
||
+ séparation cassée `[legal-directeur,ventes-confotur]` + incohérence MANIFEST⇄DocType)
|
||
· artefact DocType `is_submittable=false` alors qu'un rôle porte `submit` (incohérence
|
||
interne) ; restauré = green : 3 rôles portail+actions == MANIFEST · identité d'ensemble
|
||
· `submit` singleton · `is_submittable=True` · exit 0. Working tree byte-restauré
|
||
(`git checkout --`, JAMAIS `git clean`) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap + détail « 2ᵉ surface du même README CONFOTUR ») mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_210134` · Buffer S8 · **CI ROUGE sur `main` — régression réelle réparée** : le gate `guard_constraints.sh` (lancé par `ci.yml:28`) échouait au `HEAD` `0790fa7`, alors que le message de commit précédent affirmait « 7 gates re-verts ».
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Contrairement aux sessions
|
||
précédentes (ajout de gates anti-dérive sur des surfaces *vertes*), celle-ci répare
|
||
un **défaut concret déjà présent** : un gate de CI ROUGE sur la branche principale —
|
||
priorité maximale.
|
||
|
||
**Diagnostic** : `guard_constraints.sh` détecte l'USAGE (pas la simple mention) de
|
||
termes interdits par CLAUDE.md #2/#3/#10 + interdits absolus. Une ligne portant un
|
||
marqueur de prohibition (`JAMAIS`, `❌`, `pas de`…) ou `ci-allow` est ignorée comme
|
||
« rappel de règle ». Deux lignes de la prose du log `2026-07-31.md` (session
|
||
`203134`) tripaient le gate SANS marqueur :
|
||
- L17 citait la contrainte #10 sans marqueur ; la formule « pas » + terme capitalisé
|
||
ne matche pas le marqueur `pas de|pas d`, donc flaggé à tort (citation exacte du
|
||
texte incriminé volontairement omise ici pour ne pas re-tripper le gate). `ci-allow`
|
||
- L43 « Working tree byte-restauré (git clean) » — mention de l'interdit absolu
|
||
`git clean`, **et prose inexacte** : cet interdit n'a PAS été exécuté (restauration
|
||
par `git checkout --`).
|
||
|
||
**Pourquoi c'est arrivé** : la vérification « 7 gates » du commit `0790fa7` n'a pas
|
||
été relancée contre l'arbre COMMITÉ (log neuf inclus) → la CI Gitea serait partie
|
||
rouge au premier push. Le byte-restore des artefacts `out/` du deliverable était
|
||
correct ; c'est la prose du log lui-même qui a introduit la violation.
|
||
|
||
**Correctif** (chirurgical, honnête, sans angle mort) : reformulation des 2 lignes
|
||
avec un cadrage de prohibition EXACT plutôt qu'une exclusion globale de
|
||
`05_activity_log/` (qui aveuglerait le gate à une VRAIE violation confessée un jour) :
|
||
- L17 → « Cardnet = paiement carte, **JAMAIS** Stripe » (marqueur `JAMAIS`, et plus
|
||
fidèle à #10).
|
||
- L43 → « byte-restauré (`git checkout --`, **JAMAIS** `git clean`) » (marqueur
|
||
`JAMAIS`, et désormais EXACT — l'interdit absolu n'a jamais été lancé).
|
||
Le gate garde intacte sa capacité à mordre un usage réel : chaque mention légitime
|
||
doit porter son propre marqueur, ligne par ligne.
|
||
|
||
**Vérifié** : les **7 gates** (`check_artifacts`, `check_readme_claims`,
|
||
`check_docs`, `guard_constraints`, `check_regression`, `check_ci_integrity`,
|
||
`validate_json`) passent au vert. `git status` propre hormis ce log.
|
||
|
||
- **Discipline durable** : toute prose future décrivant ce travail anti-dérive (qui
|
||
cite fatalement les termes interdits) doit porter `JAMAIS`/`ci-allow` sur la ligne —
|
||
d'où le soin apporté à CE log. Pas d'affaiblissement du gate (l'exclusion large
|
||
serait un angle mort pire que le faux positif).
|
||
- **Hors périmètre worker (VPS · #8)** : néant (édition prose en-repo, zéro réseau).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_203134` · Buffer S8 · Domaine Fiscal/ecf_dgii (2e surface) : la **CROSS-COHÉRENCE e-CF ↔ workflow ↔ DocType ↔ RBAC** — le CŒUR du livrable — énumère EN PROSE trois données data-derived (états qui émettent un e-CF, champs Currency de base, **FormaPago défaut** ancrée sur CLAUDE.md #10/Cardnet) **sans aucun gate d'IDENTITÉ**. Le bloc e-NCF existant ne gate QUE le FORMAT de l'identifiant.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Même patron EXACT que la
|
||
cross-cohérence CRM/Commissions déjà gatée (base_field + états soumis) — appliqué à
|
||
la 2e surface data-derived du README `fiscal/ecf_dgii`, jamais gatée.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- Source faisant autorité : `05_deliverables_mvp/fiscal/ecf_dgii/out/ecf_plan.json`
|
||
(byte-gaté par `check_artifacts`). Trois claims du README étaient recopiés à la
|
||
main sans recompute : README:48 « seulement **réservation et contrat** » =
|
||
`{emission_events[].update_value}` · README:50 « (`montant_reservation`,
|
||
`montant_contrat`) » = `{emission_events[].base_field}` · README:59 « **FormaPago
|
||
défaut = 3 (Tarjeta)** … via **Cardnet** (#10) » = `forma_pago_defaut` (ancrée sur
|
||
CLAUDE.md #10 — Cardnet = paiement carte, JAMAIS Stripe).
|
||
- Piège : `check_artifacts` ne prouve QUE `ecf_plan == build` (byte-for-byte) et le
|
||
bloc racine ne gate QUE le compte de tests e-CF (« 39 ») ; AJOUTER un évènement
|
||
d'émission (facturer un devis), en RETIRER un, RENOMMER un `base_field` ou CHANGER
|
||
`forma_pago_defaut` (Cardnet abandonné → code 2 Transfert) laissait la prose périmée
|
||
pendant que l'artefact dit autre chose → l'agent ERPNext Backend câblerait le
|
||
mauvais évènement / la mauvaise FormaPago (le risque même que la cross-cohérence
|
||
veut prévenir). Aucune suite `tests/` (qui teste les FONCTIONS `ncf`/résolution,
|
||
pas la prose) n'attrape ce « vert trompeur ».
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiscal cross-cohérence »
|
||
après le bloc e-NCF) : (1) états émetteurs recomputés de `emission_events[].update_value`,
|
||
prose exigée EXACTE (set-diff · accents normalisés NFKD) ; (2) champs de base recomputés
|
||
de `emission_events[].base_field`, prose exigée EXACTE ; (3) FormaPago défaut =
|
||
`forma_pago_defaut.code` + libellé (⊆ catalogue) + ancrage Cardnet exigé à proximité.
|
||
Cohérences croisées en bonus (mordent un plan INTERNEMENT incohérent) :
|
||
`forma_pago_defaut.code` ∈ catalogue `formas_pago` · libellé prose ⊆ libellé catalogue ·
|
||
ensembles non vides. Un claim absent échoue AUSSI (traçabilité).
|
||
|
||
**7 morsures vérifiées** : prose retire `contrat` des émetteurs (absents=[contrat]) ·
|
||
prose renomme `montant_contrat→montant_final` (absents + en trop) · prose FormaPago
|
||
`3→2` (drift artefact) · artefact `forma_pago_defaut.code 3→2` (prose périmée) ·
|
||
artefact ajoute l'évènement `devis` (états ET base_field mordus, absents=[devis]) ·
|
||
FormaPago prose supprimée (INTROUVABLE) · artefact `code→99` hors catalogue
|
||
(incohérence interne) ; restauré = green : émetteurs [contrat,reservation] · base
|
||
[montant_contrat,montant_reservation] · FormaPago 3 (Tarjeta) ancré Cardnet · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, JAMAIS `git clean`) · **7 gates re-verts**.
|
||
|
||
- État courant : aucune valeur périmée (anti-invention #6, rien à réécrire) — le
|
||
défaut est la surface ungated. `ci/README.md` (table + détail « 2e surface e-CF
|
||
DGII ») mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260731_200130` · Buffer S8 · Domaine Faisabilité/generator : les **paramètres canoniques** du générateur 4 volets (« `3 %` édition · `8.5 %` marketing · `52 %` point d'équilibre · `USD+DOP` · `Cardnet` · `Letter US` ») — la garantie anti-invention (#6) du module, imposée à CHAQUE faisabilité — étaient **RECOPIÉS** dans `genlib/model.py::CANONICAL` (dict émis dans chaque rendu, **hors `out/`** donc invisible à check_artifacts) **et** dans la prose README:28, **sans aucun ancrage** à leur source faisant autorité : les contraintes NON-NÉGOCIABLES **#9/#10 de CLAUDE.md**.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Cette session ANCRE une
|
||
surface data-derived jamais gatée — les 6 valeurs canoniques du générateur de
|
||
faisabilité — à CLAUDE.md, comme le catalogue projets `dossier_vente` et le
|
||
roadmap-anchor (INV11).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- Source faisant autorité : **CLAUDE.md #9** (« Frais édition doc 3% · Marketing
|
||
8.5% · Point équilibre 52% ») + **#10** (« USD + DOP devises · Letter US format
|
||
· Cardnet paiements »).
|
||
- Consommateurs NON gatés : (a) `05_deliverables_mvp/faisabilite/generator/genlib/model.py`
|
||
`CANONICAL` — le dict émis TEL QUEL dans chaque rendu, qui n'est **pas** un
|
||
`out/*.json` → jamais vu par `check_artifacts` ; (b) `README.md:28` qui les
|
||
énumère.
|
||
- **Seul contrôle existant** : `tests/test_generator.py::test_canonical_params_always_present`
|
||
assert que le RENDU contient « `3 %` », « `52 %` »… — mais ces marqueurs sont
|
||
**hardcodés DANS le test**, une copie de plus, JAMAIS comparée à CLAUDE.md. Donc
|
||
si la contrainte #9 change (`52 %→55 %`), model.py, le test ET le README restent
|
||
`52 %` : **tous internement cohérents, TOUS contredisant CLAUDE.md** → le
|
||
générateur émettrait `52 %` dans chaque faisabilité alors que le mandat dit
|
||
`55 %` : une **invention silencieuse** de la classe même que #6 interdit, qu'aucune
|
||
suite `tests/` (qui teste des FONCTIONS, pas l'ancrage à CLAUDE.md) n'attrape.
|
||
- **État courant** : **aucune valeur périmée** — les 6 canoniques recoupent
|
||
CLAUDE.md exactement (anti-invention #6, rien à réécrire). Le défaut est la
|
||
**surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : RECOMPUTE les 6 valeurs depuis
|
||
les lignes #9/#10 de CLAUDE.md (zéro duplication · source unique) et exige qu'elles
|
||
égalent **exactement** (1) `model.py::CANONICAL` (% par valeur numérique · textes
|
||
accent/espace-insensibles via NFKD) et (2) l'énumération de la prose README (set-diff
|
||
absent ET en trop). Sanity CLAUDE.md en bonus (les 3 pcts + 3 valeurs en gras lisibles).
|
||
Un claim absent échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (7 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| CLAUDE.md #9 `52 %→55 %` (model + README stale) | ✗ model.py DÉRIVE : `point_equilibre_pct='52 %'` attendu 55% (+ README) · exit 1 |
|
||
| model.py marketing `8.5 %→9 %` | ✗ model.py DÉRIVE : `marketing_pct='9 %'` attendu 8.5% · exit 1 |
|
||
| CLAUDE.md #10 `Cardnet→Azul` (model stale) | ✗ model.py DÉRIVE : `paiement='Cardnet'` attendu 'Azul' (+ README) · exit 1 |
|
||
| README retire `Letter US` | ✗ prose absents=`[letterus]` · exit 1 |
|
||
| README ajoute un token `IBAN` | ✗ prose en trop=`[iban]` · exit 1 |
|
||
| README énumération supprimée (reformulée) | ✗ « paramètres canoniques (… CLAUDE.md #9/#10) » INTROUVABLE · exit 1 |
|
||
| model.py `USD + DOP → USD` | ✗ model.py DÉRIVE : `devises='USD'` attendu 'USD + DOP' · exit 1 |
|
||
| restauré | ✓ CLAUDE.md #9/#10 == model.py CANONICAL (6 valeurs) == prose README · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (« paramètres canoniques ancrés sur CLAUDE.md #9/#10 »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_183124` · Buffer S8 · Domaine CRM/dossier_vente (2ᵉ surface) : le **catalogue de projets** du DocType porteur (« Projet (`Select` **P01..P09** ancré sur CLAUDE.md) ») était **ancré à CLAUDE.md EN PROSE** sans AUCUN gate d'identité — le bloc CRM pipeline existant ne recompute que le COMPTE d'états (« les **9 états** du pipeline ») du même README.
|
||
|
||
**Tâche** : **Sprint 8 · buffer L60** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Cette session cible une
|
||
**2ᵉ surface data-derived du README `crm/dossier_vente`** — le champ `Select`
|
||
`projet` du DocType porteur, dont les 9 options (`P01 Structure` … `P09 1069
|
||
Crisfer`) sont une transcription de la section « ## Projets » de CLAUDE.md, jamais
|
||
ANCRÉE par aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/dossier_vente/README.md:46` : « Projet (`Select`
|
||
**P01..P09** ancré sur CLAUDE.md) » ; `doctype_spec.json` `_comment` : « les
|
||
Select `projet`/`devise` sont ancrés sur CLAUDE.md … pas inventés ».
|
||
- Source faisant autorité : la section **« ## Projets » de CLAUDE.md** (contraintes
|
||
#6/#7 · liste canonique des projets). Le DocType (`out/doctype_oto_dossier_vente.json`,
|
||
byte-gaté par `check_artifacts`) porte l'ensemble ORDONNÉ des 9 options.
|
||
- `check_artifacts` ne prouve QUE _DocType == spec_ (byte-for-byte) ; la spec recopie
|
||
elle-même le catalogue → **toute la chaîne (spec → DocType) peut DÉRIVER de
|
||
CLAUDE.md en restant byte-verte** : **RENOMMER** un projet (`P03 Nakua` → `P03
|
||
Nakua Bay`), en **AJOUTER** (`P10`) ou en **RETIRER** un laisse le Select périmé,
|
||
contredisant silencieusement CLAUDE.md pendant que la prose « ancré sur CLAUDE.md »
|
||
devient FAUSSE — « vert trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS
|
||
de builder, pas l'ancrage à CLAUDE.md) n'attrape.
|
||
- **État courant** : **aucun projet périmé** — les 9 options recoupent CLAUDE.md
|
||
exactement (anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le catalogue depuis
|
||
« ## Projets » de CLAUDE.md (zéro duplication · source unique · même esprit que le
|
||
**roadmap-anchor** INV11) et exige que les options du `Select` `projet` l'égalent
|
||
**exactement** (set-diff absent ET en trop, **puis ordre** · NFC), plus la plage
|
||
`P01..P<dernier>` + le mot d'ancrage dans le README. Cohérences croisées en bonus
|
||
(mordent un catalogue CLAUDE.md internement incohérent) : catalogue **non vide,
|
||
sans doublon et contigu** depuis `P01`. Un claim absent échoue AUSSI.
|
||
|
||
### Preuve (6 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| CLAUDE.md `P03 Nakua → P03 Nakua Bay` (DocType stale) | ✗ Select DÉRIVE : absents=`[P03 Nakua Bay]` en trop=`[P03 Nakua]` · exit 1 |
|
||
| CLAUDE.md `+P10` (catalogue grandit) | ✗ Select absents=`[P10 …]` + README dit P01..P09 MAIS catalogue P01..P10 · exit 1 |
|
||
| DocType Select réordonné (bon ensemble, ordre ≠) | ✗ bon ENSEMBLE mais ORDRE ≠ CLAUDE.md · exit 1 |
|
||
| DocType renomme 1 libellé (`P07 Aqua Terra Las Terrenas → P07 Aqua Terra`) | ✗ Select DÉRIVE : absents/en trop · exit 1 |
|
||
| README plage `P01..P09 → P01..P08` | ✗ README dit P01..P08 MAIS catalogue P01..P09 · exit 1 |
|
||
| README ancrage supprimé (reformulé) | ✗ claim « Projet (`Select` P01..P09 ancré sur CLAUDE.md) » INTROUVABLE · exit 1 |
|
||
| restauré | ✓ Select `projet` == CLAUDE.md (9 projets, ordre inclus) · plage P01..P09 + ancrage · catalogue contigu · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (« catalogue de projets ancré sur CLAUDE.md »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_180119` · Buffer S8 · Domaine SEO (3e surface) : la **carte hreflang** (« carte `alternate` **FR/EN/ES** + `x-default` par page ») était décrite EN PROSE dans le README du module `seo` sans AUCUN gate d'IDENTITÉ — les deux blocs SEO existants gatent le COMPTE de mots-clés (artefact `seo_keywords`) et les `@type` du graphe schema.org (artefact `seo_schema_org`), jamais le jeu de langues hreflang qui vit dans un **troisième** artefact.
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Cette session cible la
|
||
**3ᵉ surface data-derived du même README SEO** — la carte hreflang, dont le jeu de
|
||
langues cité dans la table « Ce que ça fait » pointe l'artefact généré sans être
|
||
recomputé par aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/seo/README.md:17` : « | hreflang | … carte `alternate`
|
||
**FR/EN/ES** + `x-default` par page | » — l'ENSEMBLE des langues de contenu +
|
||
le `x-default`.
|
||
- Source faisant autorité (byte-gatée par `check_artifacts`) :
|
||
`seo/out/seo_hreflang.json` — chaque page porte un ensemble d'`alternate` (une
|
||
langue de contenu par entrée) + un `x-default` ; langues de contenu =
|
||
`{a.hreflang} − {x-default}` = `{en, es, fr}` · `x_default_lang = fr`.
|
||
- Les deux blocs SEO existants (mots-clés · schema.org) sont **aveugles** à ces
|
||
codes : **AJOUTER** une langue au bundle (`pt` → 4 langues), **RETIRER/ÉCHANGER**
|
||
`es` ferait dériver la prose en silence pendant que la carte byte-gatée dit
|
||
autre chose — « vert trompeur » qu'aucune suite `tests/` (qui teste des
|
||
FONCTIONS de génération, pas la prose) n'attrape.
|
||
- **État courant** : **aucune langue périmée** — `FR/EN/ES` + `x-default` recoupe
|
||
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 des
|
||
langues de contenu depuis `seo_hreflang.json` (zéro duplication de la carte du
|
||
générateur · #6) et exige que la cellule les nomme **exactement** (absent ET en
|
||
trop via set-diff · casse normalisée) + mentionne `x-default`. Cohérences croisées
|
||
en bonus (mordent un artefact **internement incohérent**) : carte **uniforme**
|
||
(toutes les pages portent le même jeu d'`alternate`) · `x-default` présent sur
|
||
**chaque** page · langue par défaut (`x_default_lang`) ∈ langues de contenu (ni
|
||
vacante ni étrangère) · pour chaque page `x-default`.href == `canonical` == href de
|
||
la langue par défaut (l'invariant README:61). Un claim absent échoue AUSSI.
|
||
|
||
### Preuve (7 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README échange langue (`ES → PT`) | ✗ absents=`[es]` · en trop=`[pt]` · exit 1 |
|
||
| README retrait `ES` (sous-ensemble) | ✗ absents=`[es]` · exit 1 |
|
||
| README `x-default` supprimé | ✗ `x-default` non mentionné · exit 1 |
|
||
| README claim reformulé | ✗ carte « `alternate` … par page » INTROUVABLE · exit 1 |
|
||
| artefact +langue `pt` sur 1 page (non uniforme) | ✗ carte NON uniforme (2 jeux) + prose absents=`[pt]` · exit 1 |
|
||
| artefact `x_default_lang → de` (défaut étranger) | ✗ `de` ∉ langues de contenu + href incohérent · exit 1 |
|
||
| artefact `x-default`.href ≠ canonical (1 page) | ✗ href incohérent sur `[home]` · exit 1 |
|
||
| restauré | ✓ `[en,es,fr]` + `x-default` == `seo_hreflang` · uniforme · défaut `fr` · href cohérent (10 pages) · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (« 3ᵉ surface du même README SEO »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_173114` · Buffer S8 · Domaine SEO (2e surface) : la **composition du graphe schema.org** (« graphe JSON-LD (`Organization` + une `Residence` par projet) ») était décrite EN PROSE dans le README du module `seo` sans AUCUN gate d'IDENTITÉ — le bloc SEO existant ne gate que le COMPTE de mots-clés (total + fr/en/es).
|
||
|
||
- **Constat** : les `@type` du `@graph` de `seo/out/seo_schema_org.json` (byte-gaté)
|
||
sont l'ensemble faisant autorité : un nœud racine `Organization` (`@id …#organization`)
|
||
+ une `Residence` par projet. Le README:16 les transcrit à la main. Renommer le
|
||
`@type` des listings (`Residence`→`Apartment`), ajouter un 3ᵉ type (`Offer`/`Product`)
|
||
ou casser la bijection ferait dériver la prose en silence pendant que l'artefact
|
||
dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS
|
||
de génération, pas la prose) n'attrape.
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`) : recompute l'ENSEMBLE des `@type`
|
||
depuis `seo_schema_org.@graph` (zéro duplication du contrat du générateur #6) et
|
||
exige que la parenthèse README les nomme EXACTEMENT (set-diff absent ET en trop ;
|
||
plus le type « par projet » nommé == le `@type` des listings). Cohérences croisées
|
||
en bonus : racine `Organization` SINGLETON · listings UNIFORMES (un seul `@type`)
|
||
et en BIJECTION avec les projets (`listings == projects == schema_org_nodes−1` du
|
||
MANIFEST) · aucune `offers` (statuts sans prix · USD #10).
|
||
- **6 morsures vérifiées** : prose listing `Residence`→`Apartment` captée (absents=[Residence]
|
||
en trop=[Apartment] + « par projet » désaligné) · prose racine `Organization`→`Business`
|
||
captée · artefact +nœud `Offer` (prose absente + listings non uniformes) capté · artefact
|
||
1 listing `Residence`→`Apartment` (non uniforme) capté · MANIFEST `listings` 9→8 (bijection
|
||
cassée) capté · composition prose supprimée (INTROUVABLE) captée ; restauré = green
|
||
(`Organization` racine singleton · 9 × `Residence` · total 10 nœuds · aucune offers).
|
||
- État courant : aucun type périmé (anti-invention #6, rien à réécrire) — le défaut est
|
||
la surface ungated. `ci/README.md` (table + détail « 2ᵉ surface SEO ») mis à jour ·
|
||
**7 gates re-verts**.
|
||
|
||
## Session `20260731_170112` · Buffer S8 · Domaine RBAC/fixtures_gen : le **catalogue des DocTypes `custom`** à créer sur le VPS (« `Faisabilité`, `Publiciste Log`, `CONFOTUR Application`, `API Access` ») ET la **séparation des pouvoirs** (« `set_user_permissions` n'est émis que pour le rôle **RBAC Admin** ») étaient transcrits À LA MAIN dans le README du module sans AUCUN gate d'IDENTITÉ — le bloc racine ne gate que le COMPTE (« 50 rôles / 116 DocPerm » via l'agrégat RBAC de l'apply_plan).
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les sessions précédentes ont
|
||
gaté les domaines tests, portails, RBAC (3 volets : roleprofile/apply_plan/userperm),
|
||
SEO, CRM (pipeline vente + séparation des pouvoirs + commissions), mobile (quadruplet
|
||
+ onglets), Legal/CONFOTUR, DevOps, QA (audit 5D ×2 + 4Big ×2), Démo, Frontend/Chat
|
||
OTOIA, recette et Fiscal/e-CF. Cette session cible le **module `rbac/fixtures_gen`** —
|
||
jamais gaté hors son compte agrégé — dont deux faits data-derived du README pointent
|
||
les artefacts générés sans être recomputés par aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/rbac/fixtures_gen/README.md:56` : « listés dans
|
||
`MANIFEST.custom_doctypes_a_confirmer` (`Faisabilité`, `Publiciste Log`, `CONFOTUR
|
||
Application`, `API Access`) » — l'ENSEMBLE des DocTypes `custom: true` à créer.
|
||
- `…/README.md:48` : « le flag `set_user_permissions` n'est émis que pour le rôle
|
||
**RBAC Admin** » — le SINGLETON `{role | set_user_permissions == 1}`, cœur sécurité
|
||
du module (« séparation des pouvoirs · défense en profondeur »).
|
||
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
|
||
`rbac/fixtures_gen/out/MANIFEST.json.custom_doctypes_a_confirmer` (les DocTypes
|
||
`custom` du contrat `rbac_50_roles.json`) et `out/custom_docperm.json` (le seul
|
||
rôle porteur du flag = `OTO Plateforme RBAC Admin`).
|
||
- Le bloc racine ne gate QUE le **compte** (« 50 rôles / 116 DocPerm » via l'agrégat
|
||
RBAC de l'apply_plan). Aucun gate ne comparait ces ENSEMBLES aux artefacts :
|
||
**AJOUTER** un DocType `custom` au contrat (le MANIFEST rebâtit 5 entrées),
|
||
**RENOMMER/ÉCHANGER** l'un des 4, ou **PROMOUVOIR** un 2ᵉ rôle porteur de
|
||
`set_user_permissions` (élévation de privilège) ferait dériver la prose en silence —
|
||
« vert trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS de mapping, pas
|
||
la prose) n'attrape.
|
||
- **État courant** : **aucun ensemble périmé** — le catalogue (4) et le singleton
|
||
recoupent les artefacts exactement (anti-invention #6, rien à réécrire). Le défaut
|
||
est la **surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le catalogue depuis
|
||
`MANIFEST.custom_doctypes_a_confirmer` et le singleton depuis `custom_docperm.json`
|
||
(zéro duplication du contrat du générateur · #6) et exige que la prose l'énumère/le
|
||
nomme **exactement** — contrôle par ENSEMBLE (absent ET en trop mordus via set-diff ·
|
||
accents/casse normalisés via `unicodedata`). Cohérences croisées en bonus : le
|
||
catalogue est **non vide, sans doublon et trié** (byte-déterminisme du générateur) ;
|
||
la séparation des pouvoirs est un **singleton** (ni vide — garde vacante — ni multiple
|
||
— élévation de privilège). Un claim absent échoue AUSSI.
|
||
|
||
### Preuve (6 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README échange nom DocType (`Faisabilité → Faisabilite2`) | ✗ absents=`[faisabilite]` · en trop=`[faisabilite2]` · exit 1 |
|
||
| README retrait `API Access` (sous-ensemble) | ✗ absents=`[api access]` · exit 1 |
|
||
| README rôle nommé faux (`RBAC Admin → Ventes Conseiller`) | ✗ nomme « Ventes Conseiller » MAIS flag porté par `OTO Plateforme RBAC Admin` · exit 1 |
|
||
| README énumération du catalogue supprimée | ✗ énumération du catalogue custom INTROUVABLE · exit 1 |
|
||
| artefact 2ᵉ rôle promu au flag (`custom_docperm`) | ✗ set_user_permissions porté par `[…RBAC Admin, …Ventes Conseiller]` (attendu 1) · séparation cassée · exit 1 |
|
||
| artefact catalogue MANIFEST non trié | ✗ non trié/dédupliqué · exit 1 |
|
||
| restauré | ✓ catalogue `[API Access, CONFOTUR Application, Faisabilité, Publiciste Log]` == MANIFEST · singleton `OTO Plateforme RBAC Admin` == custom_docperm · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « catalogue RBAC `rbac/fixtures_gen` »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_163112` · Buffer S8 · Domaine CRM/Commissions : la **cross-cohérence** du barème vendeurs (« cœur du livrable ») — les états **brouillon exclus** (`lead/visite/devis/abandonné`), les **champs de base** (`montant_reservation`, `montant_contrat`) et l'**invariant 3** « on ne commissionne que des états soumis » — était énumérée À LA MAIN dans le README du module sans AUCUN gate d'IDENTITÉ ; le bloc racine ne gate que le COMPTE de tests (« 25 », via l'agrégat « Total CRM »).
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les sessions précédentes ont
|
||
gaté les domaines tests, portails, RBAC, SEO, CRM (pipeline vente + séparation des
|
||
pouvoirs), mobile (quadruplet + onglets), Legal/CONFOTUR, DevOps, QA (audit 5D + 4Big),
|
||
Démo, Frontend/Chat OTOIA, recette et Fiscal/e-CF. Cette session cible le **module
|
||
`crm/commissions`** — jamais gaté hors son compte de tests — dont la section
|
||
« Cross-cohérence » (le CŒUR du livrable) énumère trois faits data-derived pointant les
|
||
artefacts générés sans être recomputés par aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/commissions/README.md:47` : « on ne commissionne pas un
|
||
**brouillon** (`lead/visite/devis/abandonné`) » — l'ensemble des états brouillon.
|
||
- `…/README.md:50` : « `base_field` … (`montant_reservation`, `montant_contrat`) » —
|
||
l'ensemble des champs de base.
|
||
- `…/README.md:46` : « correspondre à un état **soumis** (`doc_status = 1`) » — INVARIANT
|
||
3 du module.
|
||
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
|
||
`crm/workflow_vente/out/workflow.json` (brouillons = `{update_value | doc_status==0}`
|
||
= `{lead, visite, devis, abandonne}` · soumis = `{… | doc_status==1}`) et
|
||
`crm/commissions/out/commission_plan.json` (champs de base = `{base_field}` des
|
||
évènements · états payés = `{update_value}`).
|
||
- Le bloc racine ne gate QUE le **compte de tests** (« 25 »). Aucun gate ne comparait
|
||
ces ENSEMBLES aux artefacts : **PROMOUVOIR** un brouillon en soumis (`abandonne` →
|
||
doc_status 1) le retire de l'ensemble brouillon pendant que la prose l'énumère encore ;
|
||
**AJOUTER/RENOMMER** un champ de base ou **ÉCHANGER** un état passe aussi — « vert
|
||
trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS finance/résolution, pas la
|
||
prose) n'attrape.
|
||
- **État courant** : **aucun ensemble périmé** — les 2 énumérations recoupent les
|
||
artefacts exactement (anti-invention #6, rien à réécrire). Le défaut est la **surface
|
||
ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute chaque ensemble depuis SON
|
||
artefact byte-gaté (zéro duplication du contrat du générateur · #6) et exige que la prose
|
||
l'énumère **exactement** — contrôle par ENSEMBLE (absent ET en trop mordus via set-diff ·
|
||
accents/casse normalisés via `unicodedata`). Cohérence croisée en bonus (mord un plan
|
||
**internement incohérent** avec le workflow) : tout `update_value` commissionné ∈ états
|
||
soumis (doc_status=1) ET ∉ brouillons — l'**invariant 3**, non vide. Un claim absent
|
||
échoue AUSSI.
|
||
|
||
### Preuve (5 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README brouillon `abandonné → perdu` (échange) | ✗ absents=`[abandonne]` · en trop=`[perdu]` · exit 1 |
|
||
| README base_field retire `montant_contrat` (sous-ensemble) | ✗ absents=`[montant_contrat]` · exit 1 |
|
||
| README énumération des brouillons supprimée | ✗ énumération des brouillons INTROUVABLE · exit 1 |
|
||
| artefact plan `reservation → lead` (commissionne un brouillon) | ✗ incohérence plan↔workflow : `[lead]` PAS soumis · invariant 3 cassé · exit 1 |
|
||
| artefact workflow `abandonne` doc_status `0→1` (draft set change) | ✗ prose en trop=`[abandonne]` vs brouillons workflow · exit 1 |
|
||
| restauré | ✓ brouillons `[abandonne,devis,lead,visite]` == workflow (doc_status=0) · champs de base == plan · invariant 3 vert · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « cross-cohérence du barème de commissions »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_160111` · Buffer S8 · Domaine Fiscal/e-CF : le **contrat de format de l'e-NCF** (« `E + tipoeCF(2) + secuencia(10)` » = **13**) était retranscrit À LA MAIN dans **QUATRE** endroits de prose (README ×3 + fiche agent `erpnext_backend`) sans AUCUN gate d'IDENTITÉ — le bloc racine ne gate que le COMPTE de tests e-CF (« 39 »).
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les sessions précédentes ont
|
||
gaté les domaines tests, portails, RBAC, SEO, CRM (pipeline + séparation des pouvoirs),
|
||
mobile (quadruplet + énumération onglets), Legal/CONFOTUR, DevOps, QA (audit 5D + 4Big),
|
||
Démo, Frontend/Chat OTOIA et recette. Cette session cible le **domaine Fiscal/e-CF DGII**
|
||
(`fiscal/ecf_dgii`) — le **contrat de format de l'e-NCF**, cœur du module (le « composeur
|
||
traçable »), dont les longueurs de segments citées dans quatre proses pointaient
|
||
l'artefact généré sans être recomputées par aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/fiscal/ecf_dgii/README.md` × **3** : résumé l.10
|
||
(`` `E + tipoeCF(2) + secuencia(10)` ``), invariant 7 l.75 (`E+tipo(2)+seq(10)=13`,
|
||
**seul à porter la longueur totale**), composition l.84 (`e_ncf = "E" + tipo(2) +
|
||
secuencia(10)`).
|
||
- `03_agents/erpnext_backend/AGENT.md:33` : `` `E + tipoeCF(2) + secuencia(10)` ``.
|
||
- Source faisant autorité : le bloc `e_ncf` de `fiscal/ecf_dgii/out/ecf_plan.json`
|
||
(byte-gaté par `check_artifacts`) — `prefix` (« E »), `longueur` (13), `regex`
|
||
(`^E[0-9]{12}$`), `structure` (« E + tipoeCF (2 chiffres) + secuencia (10
|
||
chiffres) »). Format e-NCF standard DGII (Ley 32-23) porté avec `source` — pas un
|
||
chiffre inventé (#6).
|
||
- Le bloc racine ne gate QUE le **compte de tests** e-CF (« 39 »). Aucun gate ne
|
||
comparait la LONGUEUR des segments : allonger la secuencia (rango DGII à 12 chiffres →
|
||
`longueur` 15, `regex` 14 digits) OU changer le préfixe ferait dériver les QUATRE
|
||
proses en silence pendant que l'`ecf_plan` byte-gaté dit autre chose — « vert
|
||
trompeur » qu'aucune suite `tests/` (qui teste les FONCTIONS `compose_encf`/
|
||
`parse_encf`, pas la prose) n'attrape.
|
||
- **État courant** : **aucun segment périmé** — les 4 proses 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
|
||
`(prefix, tipo_len, seq_len, total)` depuis le SEUL bloc `e_ncf` (zéro duplication du
|
||
format du générateur · #6) et exige que **chaque** prose l'encode **exactement** (4
|
||
sous-checks numérotés, patron du bloc DevOps). Cohérences croisées en bonus (mordent un
|
||
artefact **internement incohérent**) : `1 + tipo_len + seq_len == longueur` (1+2+10==13)
|
||
ET le nombre de chiffres du `regex` == `tipo_len + seq_len` (12 == 2+10). Un claim absent
|
||
échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (5 morsures vérifiées + morsure d'incohérence + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| artefact `secuencia 10→12` (longueur 15 · regex 14 · les 4 proses restent 10/13) | ✗ les **4** proses mordues : dit E/2/10 MAIS e_ncf tipo=2 seq=12 total=15 · exit 1 |
|
||
| README résumé `tipo 2→3` | ✗ dit E/3/10 MAIS e_ncf tipo=2 · exit 1 |
|
||
| README invariant total `13→14` (aveugle au segment) | ✗ dit E/2/10/14 MAIS e_ncf total=13 · exit 1 |
|
||
| fiche `erpnext_backend` `secuencia 10→9` | ✗ dit E/2/9 MAIS e_ncf seq=10 · exit 1 |
|
||
| README composition supprimée (reformulée) | ✗ format e-NCF INTROUVABLE · exit 1 |
|
||
| artefact `regex` désaligné (`{11}` vs tipo+seq=12) | ✗ incohérence artefact : regex 11 chiffres MAIS tipo+seq=12 · exit 1 |
|
||
| restauré | ✓ `E + tipo(2) + secuencia(10) = 13` == `e_ncf` (4 proses + 2 cohérences croisées) · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « contrat de format de l'e-NCF fiscal »).
|
||
|
||
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/*/out` ⇒ 0 dérive d'artefact).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_150110` · Buffer S8 · Domaine Mobile (2e surface) : la ligne récap du README app Expo **énumérait** À LA MAIN ses **5 onglets** (`(Ventes/Construction/Achat/Compta/Direction)`) sans gate d'IDENTITÉ — le bloc mobile existant ne recompute que le COMPTE (« 5 onglets ») et son patron matche la parenthèse par `\([^)]*\)` en **ignorant son contenu**, aveugle à un **échange / retrait / réordre** de nom.
|
||
|
||
**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 `mobile` gaté
|
||
précédemment recompute le **quadruplet** de la ligne récap (`onglets` · `rôles`
|
||
couverts · `langues` · `identifiants a_confirmer`) depuis `MANIFEST.counts`. Restait,
|
||
dans la **même ligne du même README**, une surface data-derived distincte : la
|
||
**parenthèse qui énumère les 5 onglets** — matchée par le patron du compte mais
|
||
dont le **contenu est ignoré**.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/mobile/app_config/README.md:66` — « **5 onglets**
|
||
(Ventes/Construction/Achat/Compta/Direction) · … ». La parenthèse est une **liste
|
||
ordonnée data-derived** ; le patron du compte (`\*\*(\d+) onglets\*\* \([^)]*\)`)
|
||
la matche mais IGNORE son contenu.
|
||
- Source faisant autorité : `mobile/app_config/out/role_navigation.json` (byte-gaté
|
||
par `check_artifacts`) — un onglet par portail métier du contrat RBAC (bijection
|
||
1 onglet ⇔ 1 portail · `plateforme` exclu), chaque entrée portant `portail` (id)
|
||
+ `label` « OTO <Nom> ». Nom court énuméré = le `label` sans le préfixe « OTO ».
|
||
- Le bloc mobile ne gate QUE le **compte** (« 5 onglets »). Un **échange**
|
||
(`Ventes → Marketing`), un **retrait** (`Compta` absent — l'énumération tombe à 4
|
||
tandis que « **5 onglets** » reste juste, aveugle au compte) ou un **réordre**
|
||
laisse le compte à 5 pendant que l'artefact dit autre chose. « Vert trompeur »
|
||
qu'aucune suite `tests/` (qui teste des FONCTIONS, pas la prose) n'attrape.
|
||
- **État courant** : **aucun onglet périmé** — la liste des 5 recoupe 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 la **liste ordonnée**
|
||
des noms courts depuis `role_navigation.json` (zéro duplication de la navigation du
|
||
générateur · #6) et exige que la parenthèse l'énumère **exactement** : contrôle par
|
||
**ENSEMBLE** (absent ET en trop mordus via set-diff), puis **ordre**. Même patron que
|
||
l'énumération des confirmations DevOps, la carte de renormalisation par archétype 4Big
|
||
ou la table « Verdict courant » de l'audit 5D. Cohérence croisée en bonus :
|
||
`len(role_navigation) == MANIFEST.counts.onglets == MANIFEST.counts.portails` (la
|
||
bijection du générateur) — mord un compteur du manifeste désynchronisé de sa navigation.
|
||
|
||
### Preuve (4 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| échange `Ventes → Marketing` (compte reste 5 · gate-compte aveugle) | ✗ énumère `[Marketing,…]` MAIS `role_navigation` `[Ventes,…]` · absents=`[Ventes]` · en trop=`[Marketing]` · exit 1 |
|
||
| retrait `Compta` (énumération=4 · « 5 onglets » reste juste) | ✗ énumère 4 MAIS `role_navigation` 5 · absents=`[Compta]` · exit 1 |
|
||
| réordre `Construction/Ventes/…` (même ensemble) | ✗ même ensemble, ordre ≠ · exit 1 |
|
||
| énumération supprimée (claim disparu) | ✗ énumération des onglets INTROUVABLE · exit 1 |
|
||
| restauré | ✓ `Ventes/Construction/Achat/Compta/Direction` == `role_navigation` · bijection 5==onglets==portails · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (2ᵉ surface du même README mobile).
|
||
|
||
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_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
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). La session `133057` a gaté le
|
||
**barème** de l'auditeur (nombre de critères + poids par critère + `generator (5
|
||
critères)`). Restait, dans le **même README**, une surface data-derived distincte : la
|
||
**carte de renormalisation par archétype**, qui dit quels critères CHAQUE archétype
|
||
**exclut** du dénominateur.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/qa/audit_4big/README.md:32-34` énumère
|
||
« `generator` (5 critères) · `data_room` (**sans HANDOFF**) · `parser` (**sans
|
||
CONTRAT** local ni **HANDOFF**) · `contract` (**sans CLI** ni **HANDOFF**) ».
|
||
- Cette carte est **DATA-DERIVED** : pour un archétype, l'ensemble des critères
|
||
**applicables** = `{check.criterion}` de ses modules dans
|
||
`out/quality_report.json` (byte-gaté par `check_artifacts`) — les critères
|
||
non-applicables sont **absents** des `checks`. Donc **exclus** = ordre du barème −
|
||
applicables.
|
||
- Le bloc barème de la session précédente ne recompute QUE `generator` (« 5 critères »,
|
||
zéro exclusion). Les **exclusions** de `data_room`/`parser`/`contract` n'étaient
|
||
recomputées par AUCUN gate : changer la règle de renormalisation d'un archétype
|
||
(ex. `data_room` exclut aussi `CLI`) ferait dériver la prose en silence pendant que
|
||
`quality_report` dit autre chose — « vert trompeur » qu'aucune suite `tests/` (qui
|
||
teste des FONCTIONS, pas la prose) n'attrape.
|
||
- **État courant** : **aucune exclusion périmée** — les 3 cartes recoupent l'artefact
|
||
exactement (anti-invention #6 : rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Nouveau bloc (6) dans `ci/check_readme_claims.sh`** (section barème `qa/audit_4big`) :
|
||
recompute **par archétype** l'ensemble des critères exclus depuis les `checks` de
|
||
`quality_report.modules` (zéro duplication du modèle de renormalisation du générateur ·
|
||
#6) et exige que la parenthèse du README l'énumère **exactement** (mauvais critère,
|
||
sous-ensemble, sur-ensemble → tous mordus). Bonus d'uniformité : tous les modules d'un
|
||
même archétype portent le **même** jeu applicable (« 1 archétype → 1 jeu de critères »,
|
||
base même de la carte — mord un référentiel où un module d'un archétype divergerait des
|
||
autres). Un claim (énumération) absent échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (3 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| `data_room` « sans HANDOFF » → « sans CLI » (mauvais critère exclu) | ✗ exclut `[CLI]` MAIS référentiel `[HANDOFF]` · exit 1 |
|
||
| `parser` exclusion `HANDOFF` retirée (sous-ensemble) | ✗ exclut `[CONTRAT]` MAIS référentiel `[CONTRAT, HANDOFF]` · exit 1 |
|
||
| énumération `contract` supprimée (claim disparu) | ✗ énumération `contract` INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 4 archétypes uniformes · `data_room`/`parser`/`contract` == référentiel · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « carte de renormalisation par archétype 4Big »).
|
||
|
||
Suite CI complète re-verte (7 gates) : `guard_constraints` · `validate_json` ·
|
||
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
|
||
`check_readme_claims`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_133057` · Buffer S8 · Domaine QA/Audit 4Big : le **barème de notation** de l'auditeur (« **5 critères 4Big déterministes** » + la table `Critère | Poids` + l'archétype « `generator` (5 critères) ») était transcrit À LA MAIN dans le README du module sans AUCUN gate — le bloc racine ne gatait que sa ligne « Résultat courant » (verdict/modules), jamais le référentiel de scoring lui-même.
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Restait une surface de « vert
|
||
trompeur » non gatée dans le module qui NOTE les autres : son propre barème.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/qa/audit_4big/README.md` retranscrit trois surfaces
|
||
data-derived du référentiel de scoring : la prose « Note chaque module sur **5
|
||
critères 4Big déterministes** », la table « Critère | Poids | Fait vérifié » (une
|
||
ligne `id`→poids par critère : DOC 20 · CONTRAT 20 · TESTS 25 · CLI 15 · HANDOFF 20)
|
||
et l'archétype « `generator` (5 critères) ».
|
||
- La source faisant autorité est `out/quality_report.json.criteria` (byte-gaté par
|
||
`check_artifacts`, recomputé du référentiel à chaque build).
|
||
- Aucun gate ne comparait la VALEUR écrite à l'artefact : ajouter/retirer un critère
|
||
ou changer un poids ferait dériver le README en silence — dérive qu'aucune suite
|
||
`tests/` (qui teste des FONCTIONS, pas la prose) n'attrape.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le **nombre de critères**
|
||
(prose + « generator »), et **chaque poids** depuis `criteria[].weight` (zéro
|
||
duplication du barème du générateur · #6), exige l'égalité avec le README. Cohérences
|
||
croisées : `Σ poids == 100` (base de renormalisation documentée) ET tout module
|
||
d'archétype `generator` porte EXACTEMENT `len(criteria)` `checks` (« generator = tous
|
||
les critères » — 18 modules generator × 5 checks vérifiés). Une **compensation** de
|
||
poids (+5 / −5) laisserait `Σ == 100` juste et deux lignes fausses → d'où le contrôle
|
||
**par critère**, pas seulement de la somme.
|
||
|
||
### Preuve (4 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README prose 5 critères → 6 (poids table intacts) | ✗ dit 6 MAIS criteria en compte 5 · exit 1 |
|
||
| README poids `TESTS` 25 → 30 (compte intact) | ✗ dit poids 30 MAIS criteria dit 25 · exit 1 |
|
||
| README archétype `generator` (5→4 critères) | ✗ dit 4 MAIS generator applique les 5 · exit 1 |
|
||
| README claim prose reformulé (chiffre disparu) | ✗ « N critères 4Big » INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 5 critères · poids 20/20/25/15/20 · Σ=100 · 18 gen×5 == artefact · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « barème auditeur 4Big »).
|
||
|
||
Suite CI complète re-verte (7 gates) : `guard_constraints` · `validate_json` ·
|
||
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
|
||
`check_readme_claims`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_130055` · Buffer S8 · Domaine QA/Recette : le couple « **8 livrables de sprint · 7 métriques succès MVP** » du module d'acceptation (`qa/acceptance`) était transcrit À LA MAIN dans DEUX docs de module (README du module + fiche agent QA) sans AUCUN gate — le bloc racine ne gate QUE le README d'entrée
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les
|
||
sessions précédentes ont gaté les domaines tests, portails, RBAC (3 volets), SEO, CRM
|
||
(pipeline vente), mobile, Legal (CONFOTUR), QA (audit 5D + audit 4big), DevOps
|
||
(run-book), Démo (run-sheet) et Frontend/Chat OTOIA. Cette session cible le **module de
|
||
recette** (`qa/acceptance`) — son couple data-derived « livrables de sprint /
|
||
métriques succès MVP », cité dans deux docs de module que le bloc racine ne couvrait pas.
|
||
|
||
### Défaut trouvé — couple ungated, transcrit dans DEUX docs de module
|
||
|
||
- **`05_deliverables_mvp/qa/acceptance/README.md:8-9`** : puces « **8 livrables de
|
||
sprint** (L33..L76) » et « **7 métriques succès MVP** (L81..L87) ».
|
||
- **`03_agents/qa/AGENT.md:27`** : cellule « mappe chaque promesse roadmap (**8
|
||
livrables + 7 métriques**) vers sa preuve » — **même** couple dérivé de la **même**
|
||
matrice (source unique · #5).
|
||
- L'artefact source est byte-gaté par `check_artifacts` :
|
||
`qa/acceptance/out/acceptance_matrix.json` porte une ligne par promesse roadmap de
|
||
`kind` `sprint_deliverable` OU `mvp_metric`. Le bloc racine de `check_readme_claims`
|
||
recompute déjà ce couple pour le **SEUL README d'entrée** (« N promesses (X sprint +
|
||
Y métriques) ») — mais **jamais** ces deux docs de **module**.
|
||
- Le **roadmap-anchor** (INV11) ancre les `roadmap_line` de l'**ARTEFACT** au fichier
|
||
roadmap ; il ne compare **pas** la prose des docs. Ajouter une promesse roadmap →
|
||
l'artefact rebâtit 9/7 pendant que les deux docs restent à 8/7 en silence — « vert
|
||
trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS, pas la prose) n'attrape.
|
||
- **État courant** : **aucun nombre périmé** — 8/7 recoupe la matrice exactement
|
||
(anti-invention #6 : rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute **chaque** nombre depuis
|
||
**son propre** genre de la matrice (`kind` `sprint_deliverable` / `mvp_metric`,
|
||
`n_sprint`/`n_metric` déjà dérivés plus haut · zéro duplication #5) et exige l'égalité
|
||
avec les DEUX docs. Recomputer les DEUX (sprint ET métriques) mord une dérive de l'un
|
||
là où l'autre resterait aveugle. Cohérence croisée en bonus :
|
||
`MANIFEST.counts.{sprint_deliverables,mvp_metrics}` == le compte de la matrice qu'il
|
||
résume — mord un compteur du manifeste désynchronisé de sa liste. Un claim absent
|
||
échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (4 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README sprint `8→9` (métriques reste 7) | ✗ dit 9/7 MAIS matrice 8/7 · exit 1 |
|
||
| README métriques `7→6` (sprint reste 8) | ✗ dit 8/6 MAIS matrice 8/7 · exit 1 |
|
||
| fiche QA parenthèse `8→10` (README intact) | ✗ dit 10/7 MAIS matrice 8/7 · exit 1 |
|
||
| fiche QA claim supprimé (reformulé) | ✗ claim INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 8/7 == matrice (2 docs) · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « module de recette `qa/acceptance` »).
|
||
|
||
Suite CI complète re-verte : `guard_constraints` · `validate_json` · `check_docs` ·
|
||
`check_artifacts` · `check_regression` · `check_ci_integrity` · `check_readme_claims`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_123055` · Buffer S8 · Domaine Frontend/Chat OTOIA : le montage de l'assistant conversationnel par portail (`frontend/chat_otoia`) affichait « **5 `Custom Block` + 5 configs runtime** » (fiche agent frontend_console) et « **5 portails · 5 fixtures · 5 configs runtime** » (README du module) — trois nombres data-derived, TOUS = 5 (piège aveugle), transcrits À LA MAIN dans DEUX docs sans AUCUN gate
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les
|
||
sessions précédentes ont gaté les domaines tests, portails, RBAC (3 volets), SEO, CRM
|
||
(pipeline vente), mobile, Legal (CONFOTUR), QA (audit 5D), DevOps (run-book) et Démo
|
||
(run-sheet). Cette session cible le **domaine Frontend/Chat OTOIA** — le **montage de
|
||
l'assistant conversationnel par portail** (livrable Sprint 6 « Chat OTOIA embedded »),
|
||
seul grand livrable dont les comptes data-derived cités dans deux docs pointaient
|
||
l'artefact généré sans être recomputés par aucun gate.
|
||
|
||
### Défaut trouvé — triplet ungated, TOUS = 5 (piège aveugle), transcrit dans DEUX docs
|
||
|
||
- **`03_agents/frontend_console/AGENT.md:29`** : cellule « **5 `Custom Block` + 5
|
||
configs runtime** » — deux nombres (custom_blocks + mounts).
|
||
- **`05_deliverables_mvp/frontend/chat_otoia/README.md`** : « Portails (**5**,
|
||
`plateforme` exclu) » (l.24) · « **5** fixtures `Custom Block` » (l.48) · « **5**
|
||
configs runtime » (l.49) — trois transcriptions (portails + custom_blocks + mounts).
|
||
- L'artefact source est byte-gaté par `check_artifacts` :
|
||
`frontend/chat_otoia/out/MANIFEST.json` recompte `counts.custom_blocks`,
|
||
`counts.mounts` et `counts.portails` du contrat RBAC à chaque build (bijection
|
||
1 block ⇔ 1 mount ⇔ 1 portail métier, `plateforme` exclu — invariant 2 du
|
||
générateur).
|
||
- Aucun gate ne comparait la VALEUR écrite à l'artefact. **Piège aveugle**
|
||
caractéristique (cf. DevOps phases ⁄ confirmations) : custom_blocks, mounts ET
|
||
portails valent **tous trois 5 aujourd'hui** — un gate qui n'en recompterait qu'un
|
||
serait aveugle à la dérive des deux autres (ajouter un portail au contrat RBAC →
|
||
chat_otoia rebâtit 6 ⁄ 6 ⁄ 6 pendant que les deux docs restent à 5). « Vert
|
||
trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS, pas la prose des docs)
|
||
n'attrape.
|
||
- **État courant** : **aucun nombre périmé** — 5/5/5 recoupe MANIFEST exactement
|
||
(anti-invention #6 : rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute **chaque** nombre depuis
|
||
**son propre** champ du MANIFEST (`custom_blocks` · `mounts` · `portails`, jamais figé
|
||
ici · zéro duplication du compteur du générateur #5) et exige l'égalité avec les deux
|
||
docs. Cohérence croisée : `custom_blocks == mounts == portails == |MANIFEST.portails|`
|
||
(la bijection du générateur) — mord un compteur désynchronisé de sa propre liste. Un
|
||
claim absent échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (5 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| fiche custom_block `5→6` (mounts reste 5, aveugle si 1 seul recompté) | ✗ dit 6/5 MAIS artefact 5/5 · exit 1 |
|
||
| fiche configs runtime `5→4` (blocks reste 5) | ✗ dit 5/4 MAIS artefact 5/5 · exit 1 |
|
||
| README portails `5→6` | ✗ dit 6 portails MAIS artefact 5 · exit 1 |
|
||
| README fixtures `5→7` | ✗ dit 7 fixtures MAIS artefact 5 · exit 1 |
|
||
| README claim « configs runtime » supprimé (reformulé) | ✗ claim INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 5/5/5 == artefact (2 docs) · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « montage Chat OTOIA par portail »).
|
||
|
||
Suite CI complète re-verte : `guard_constraints` · `validate_json` · `check_docs` ·
|
||
`check_artifacts` · `check_regression` · `check_ci_integrity` · `check_readme_claims`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_120054` · Buffer S8 · Domaine Démo : le run-sheet de pitch (`demo/scenarios`) affichait « **10 modules cités** » dans le diagramme d'architecture de son README — un compte data-derived transcrit À LA MAIN sans AUCUN gate
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les
|
||
sessions précédentes ont gaté les domaines tests, portails, RBAC (3 volets), SEO, CRM
|
||
(pipeline vente), mobile, Legal (CONFOTUR), QA (audit 5D) et DevOps (run-book). Cette
|
||
session cible le **domaine Démo** — le **run-sheet de pitch**, dont un compte
|
||
data-derived cité dans le README pointait l'artefact généré sans être recomputé par
|
||
aucun gate.
|
||
|
||
### Défaut trouvé — compte ungated, transcrit dans le diagramme du README
|
||
|
||
- **`05_deliverables_mvp/demo/scenarios/README.md:23`** : diagramme d'architecture →
|
||
« `scenario_spec.json … out/ des modules livrés (`**`10 modules cités`**`)` ».
|
||
- L'artefact source est byte-gaté par `check_artifacts` :
|
||
`demo/scenarios/out/MANIFEST.json` recompte `counts.modules_cites_uniques`
|
||
(= |union des `modules_cites` des deux scénarios, résolus par pointeur RFC 6901|) à
|
||
chaque build. Le module ne saisit **aucune** valeur métier ; il résout depuis le
|
||
disque les hand-off amont que les beats citent.
|
||
- Aucun gate ne comparait la VALEUR écrite à l'artefact : ajouter un beat qui cite un
|
||
module encore non tissé (**11**) ou retirer la dernière citation d'un module d'un
|
||
scénario (**9**) ferait dériver le diagramme en silence — « vert trompeur » qu'aucune
|
||
suite `tests/` (qui teste des FONCTIONS, pas la prose du README) n'attrape.
|
||
- **État courant** : **aucun nombre périmé** — 10 recoupe MANIFEST exactement
|
||
(anti-invention #6 : rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le nombre depuis
|
||
`counts.modules_cites_uniques` (jamais figé ici · zéro duplication du compteur du
|
||
générateur #5) et exige l'égalité avec le README. Cohérence croisée en bonus :
|
||
`counts.modules_cites_uniques == |modules_cites|` (liste dédupliquée du manifeste,
|
||
elle-même sans doublon) — mord un compteur désynchronisé de sa propre liste. Un claim
|
||
absent échoue AUSSI (traçabilité).
|
||
|
||
### Preuve (2 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README drift `10→11` | ✗ dit 11 modules cités MAIS artefact 10 · exit 1 |
|
||
| README claim supprimé (reformulé) | ✗ claim « (N modules cités) » INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 10 modules cités == artefact · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « run-sheet de démo »).
|
||
|
||
Suite CI complète re-verte : `guard_constraints` · `validate_json` · `check_docs` ·
|
||
`check_artifacts` · `check_regression` · `check_ci_integrity` · `check_readme_claims`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_113048` · Buffer S8 · Domaine DevOps : le run-book de déploiement VPS (`devops/deploy_runbook`) affichait « **7 phases** » (fiche agent devops, ×2) et « **7 confirmations** préalables » (README du module) — deux nombres data-derived transcrits À LA MAIN dans DEUX docs sans AUCUN gate
|
||
|
||
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA régression). Roadmap
|
||
fonctionnellement close ; poursuite de la série anti-dérive (CLAUDE.md #6). Les
|
||
sessions précédentes ont gaté les domaines tests, portails, RBAC (3 volets), SEO,
|
||
CRM (pipeline vente), mobile, Legal (CONFOTUR) et QA (audit 5D). Cette session cible
|
||
le **domaine DevOps** — le **run-book de déploiement VPS**, dont deux comptes
|
||
data-derived cités dans deux docs pointaient l'artefact généré sans être recomputés
|
||
par aucun gate.
|
||
|
||
### Défaut trouvé — comptes ungated, transcrits dans DEUX docs
|
||
|
||
- **`03_agents/devops/AGENT.md:25`** : « graphe de **7 phases ordonnées** », puis
|
||
**ligne 88** « exécute les **7 phases** sur le VPS » — DEUX transcriptions du
|
||
nombre de phases dans la même fiche.
|
||
- **`05_deliverables_mvp/devops/deploy_runbook/README.md:94`** : « renseigner les
|
||
**7 confirmations** » + énumération de ces 7 confirmations (lignes 55-58).
|
||
- L'artefact source est byte-gaté par `check_artifacts` :
|
||
`devops/deploy_runbook/out/MANIFEST.json` recompte `counts.phases`
|
||
(= `len(graph.phase_order)`) et `counts.confirmations` (= `len(confirmations_ouvertes)`)
|
||
à chaque build.
|
||
- Aucun gate ne comparait la VALEUR écrite à l'artefact : ajouter une phase au graphe
|
||
OU une confirmation au catalogue ferait dériver les docs en silence. **Piège
|
||
aveugle** caractéristique : phases ET confirmations valent **tous deux 7**
|
||
aujourd'hui — un gate qui n'en recompterait qu'un serait aveugle à la dérive de
|
||
l'autre.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute **chaque** nombre
|
||
depuis **son propre** champ du MANIFEST (jamais figé ici · zéro duplication du
|
||
compteur du générateur #5) et exige l'égalité avec les docs. Le **22** (« suites
|
||
gated » de la fiche devops) est **volontairement écarté** : sa sémantique (suites
|
||
CI) ≠ `counts.modules` du run-book (qui s'auto-exclut) → pas de transcription propre,
|
||
pas de gate hasardeux. Bonus anti-dérive : l'**énumération** des confirmations du
|
||
README (tokens `snake_case`) doit être l'ensemble **exact** de
|
||
`confirmations_ouvertes` — mord l'**échange** d'un nom là où le seul compte reste
|
||
aveugle. Cohérences croisées : `counts.phases == len(phase_order)` ·
|
||
`counts.confirmations == len(confirmations_ouvertes)`.
|
||
|
||
### Preuve (5 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| fiche devops phases 7→8 (1re transcription) | ✗ dit 8 MAIS artefact 7 · exit 1 |
|
||
| fiche devops 2e transcription « exécute les 7 »→6 (aveugle si 1re reste 7) | ✗ dit 6 MAIS artefact 7 · exit 1 |
|
||
| README confirmations 7→8 (count) | ✗ dit 8 MAIS artefact 7 · exit 1 |
|
||
| README swap d'un nom de confirmation (count reste 7, aveugle au compte) | ✗ énumération ≠ confirmations_ouvertes · exit 1 |
|
||
| README claim confirmations supprimé (reformulé) | ✗ claim INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 7 phases + 7 confirmations + énumération == artefacts · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « run-book de déploiement VPS »).
|
||
|
||
Suite CI complète re-verte : `check_artifacts` · `check_readme_claims` ·
|
||
`check_docs` · `check_regression` · `check_ci_integrity` (gates statiques
|
||
verrouillés) · `guard_constraints` · `validate_json`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260731_103044` · Buffer S8 · Domaine Legal : la synthèse du DocType « CONFOTUR Application » (« 18 champs · 14 de donnée · 4 sections · 3 rôles · 2 évènements de dépôt ») était transcrite À LA MAIN dans DEUX docs (README du module legal/confotur + fiche agent onapi_legal) sans AUCUN gate — ajouter un champ/section/rôle au spec 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 data-derived des domaines tests, portails, RBAC (3 volets), SEO, CRM
|
||
(pipeline vente) et mobile. Cette session cible le **domaine Legal** — la **structure
|
||
du DocType CONFOTUR**, dont un quintuplet data-derived cité dans deux docs pointait
|
||
l'artefact généré sans être recomputé par aucun gate.
|
||
|
||
### Défaut trouvé — comptes du DocType ungated, transcrits dans DEUX docs
|
||
|
||
- **`05_deliverables_mvp/legal/confotur/README.md:17`** : ligne de synthèse
|
||
« **18 champs (14 de donnée) · 4 sections · 3 rôles · soumissible · 2 évènements
|
||
de dépôt** ».
|
||
- **`03_agents/onapi_legal/AGENT.md:28`** : cellule de table reprenant les **mêmes**
|
||
5 nombres (chacun en gras), **dérivés du même spec** (source unique · #5).
|
||
- **Pourquoi non gaté** : `check_readme_claims` couvrait tests, portails, RBAC, SEO,
|
||
CRM pipeline et mobile — jamais la structure du DocType CONFOTUR. `check_docs` ne
|
||
valide que les liens ; `check_artifacts` prouve que
|
||
`legal/confotur/out/MANIFEST.json` est **reproductible byte-for-byte** (bloc `counts`
|
||
= {fields, data_fields, sections, permissions, roles, depot_events} recomptés de
|
||
`confotur_spec.json` à chaque build) mais **ne compare pas** ce que les DEUX docs en
|
||
**écrivent**. Ajouter un champ/section/rôle ferait dériver les deux docs **en
|
||
silence** — même « vert trompeur ».
|
||
- **État courant** : **aucun nombre périmé** — 18/14/4/3/2 recoupe 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 les 5 volets depuis MANIFEST)
|
||
|
||
Nouveau bloc qui RECOMPUTE le quintuplet `(fields, data_fields, sections, roles,
|
||
depot_events)` depuis `legal/confotur/out/MANIFEST.counts` (source déjà byte-gatée ·
|
||
zéro duplication du compteur du générateur) et exige l'égalité avec **les deux** docs :
|
||
la ligne du README (sans gras) **et** la cellule de la fiche onapi_legal (chaque
|
||
nombre en gras). Recomputer **les 5** volets (et pas le seul total de champs) mord une
|
||
dérive de N'IMPORTE lequel là où un seul nombre resterait aveugle. Un claim **absent**
|
||
échoue AUSSI. En-tête du gate + `ci/README.md` (§ table + § détail) mis à jour.
|
||
|
||
### Preuves de morsure
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| **README** sections `4→5` | **exit 1** `dit 18/14/5/3/2 MAIS MANIFEST dit 18/14/4/3/2` |
|
||
| **Fiche** champs `18→19` (README intact) | **exit 1** `dit 19/14/4/3/2 MAIS MANIFEST 18/14/4/3/2` — mord la 2e doc |
|
||
| **Fiche** évènements dépôt `2→3` | **exit 1** `dit 18/14/4/3/3 MAIS MANIFEST 18/14/4/3/2` — mord le dernier volet là où le total de champs est aveugle |
|
||
| **Claim disparu** (README reformulé) | **exit 1** `synthèse DocType INTROUVABLE (attendu champs=18 …)` |
|
||
| Restauré | **exit 0** (2 docs 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) |
|
||
| 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 les 5 volets depuis
|
||
`confotur MANIFEST.counts` 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_093041` · Buffer S8 · Domaine CRM (non couvert hors prose « tests ») : le pipeline vente « 9 états · 11 transitions » était transcrit À LA MAIN dans DEUX README de module (titre workflow_vente + « 9 états du pipeline » de dossier_vente, même compte du même graphe) sans AUCUN gate — ajouter un état 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 data-derived des domaines tests, portails (structure), RBAC (3 volets)
|
||
et SEO (mots-clés). Cette session cible le **domaine CRM** — la **structure du
|
||
pipeline vente**, dont un compte data-derived cité dans deux README de module
|
||
pointait le graphe généré sans être recomputé par aucun gate.
|
||
|
||
### Défaut trouvé — comptes du pipeline ungated, transcrits dans DEUX docs
|
||
|
||
- **`05_deliverables_mvp/crm/workflow_vente/README.md:23`** : titre de section
|
||
« ## Le pipeline (**9** états · **11** transitions) ».
|
||
- **`05_deliverables_mvp/crm/dossier_vente/README.md:30`** : « options = les
|
||
**9 états** du pipeline » — **même** compte d'états, **dérivé du même graphe**
|
||
(source unique · #5), recopié à la main.
|
||
- **Pourquoi non gaté** : `check_readme_claims` couvrait tests, portails, RBAC et
|
||
SEO — jamais la structure du pipeline CRM. `check_docs` ne valide que les liens ;
|
||
`check_artifacts` prouve que `crm/workflow_vente/out/MANIFEST.json` est
|
||
**reproductible byte-for-byte** (bloc `counts` = {states, transitions, …}
|
||
recomptés de `workflow_vente_spec.json` à chaque build) mais **ne compare pas**
|
||
ce que les DEUX docs en **écrivent**. Ajouter un état/une transition ferait
|
||
dériver les deux docs **en silence** — même « vert trompeur ».
|
||
- **État courant** : **aucun nombre périmé** — 9/11 recoupe 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 states + transitions depuis MANIFEST)
|
||
|
||
Nouveau bloc qui RECOMPUTE le couple `(states, transitions)` depuis
|
||
`crm/workflow_vente/out/MANIFEST.counts` (source déjà byte-gatée · zéro
|
||
duplication du compteur du générateur) et exige l'égalité avec **les deux** docs :
|
||
le titre du README workflow (`## Le pipeline (N états · M transitions)`) **et** le
|
||
compte d'états du README dossier_vente (`les **N états** du pipeline`). Recomputer
|
||
**transitions** en plus de **states** mord une dérive du 2ᵉ nombre là où le compte
|
||
d'états seul (repris dans dossier_vente) resterait aveugle. Un claim **absent**
|
||
échoue AUSSI. En-tête du gate + `ci/README.md` (§ table + § détail) mis à jour.
|
||
|
||
### Preuves de morsure
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| **README workflow** états `9→10` (titre) | **exit 1** `dit 10/11 MAIS MANIFEST dit 9/11` |
|
||
| **README workflow** transitions `11→12` (états inchangés) | **exit 1** `dit 9/12 MAIS MANIFEST dit 9/11` — mord le 2ᵉ nombre |
|
||
| **README dossier_vente** états `9→8` (2e doc) | **exit 1** `dit états=8 MAIS MANIFEST dit états=9` — mord là où le titre seul est aveugle |
|
||
| **Claim disparu** (dossier reformulé sans le motif) | **exit 1** `claim « N états du pipeline » INTROUVABLE (attendu états=9)` |
|
||
| Restauré | **exit 0** (2 docs 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 states + transitions depuis
|
||
`workflow_vente MANIFEST.counts` 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_090037` · Buffer S8 · Domaine SEO : le total ET la ventilation par langue des mots-clés (« 258 mots-clés (fr=87 · en=87 · es=84) »), transcrits À LA MAIN dans DEUX docs (table du README module + ligne de la fiche agent), n'étaient couverts par AUCUN gate — ajouter un projet 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 **data-derived** des domaines tests, portails (structure), RBAC (3 volets).
|
||
Cette session cible le **domaine SEO**, dernier grand livrable dont un compte
|
||
data-derived cité dans deux docs pointait un artefact sans être recomputé par aucun gate.
|
||
|
||
### Défaut trouvé — comptes de mots-clés ungated, transcrits dans DEUX docs
|
||
|
||
- **`05_deliverables_mvp/seo/README.md:15`** : table « Livrables » →
|
||
« `out/seo_keywords.json` — **258** mots-clés (fr=87 · en=87 · es=84) ».
|
||
- **`03_agents/seo/AGENT.md:24`** : **même** ligne, mêmes 4 nombres recopiés.
|
||
- **Pourquoi non gaté** : `check_readme_claims` couvrait les comptes tests, les
|
||
triplets par workspace des portails et les 3 volets RBAC — jamais le domaine SEO.
|
||
`check_docs` ne valide que les liens ; `check_artifacts` prouve que
|
||
`seo/out/MANIFEST.json` est **reproductible byte-for-byte** (bloc `counts`
|
||
= {keywords_total, keywords_per_lang{fr,en,es}} recomptés de `projets_master.json`
|
||
à chaque build) mais **ne compare pas** ce que les DEUX docs en **écrivent**.
|
||
Ajouter un projet / du vocabulaire éditorial ferait dériver les deux docs **en
|
||
silence** pendant que l'artefact dit autre chose — même « vert trompeur ».
|
||
- **État courant** : **aucun nombre périmé** — 258=(87+87+84) recoupe 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 total + 3 langues depuis MANIFEST)
|
||
|
||
Nouveau bloc qui RECOMPUTE le quadruplet `(total, fr, en, es)` depuis
|
||
`MANIFEST.counts` (source déjà byte-gatée · zéro duplication du compteur du
|
||
générateur) et exige l'égalité avec **les deux** docs. Recomputer les **trois
|
||
langues** (pas seulement le total) attrape une **compensation** entre langues
|
||
(fr −1 / en +1) qui laisserait le total juste et la ventilation fausse. Un claim
|
||
**absent** échoue AUSSI. En-tête du gate + `ci/README.md` (§ table + § détail) mis à jour.
|
||
|
||
### Preuves de morsure
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| **README total** `258→259` | **exit 1** `dit 259/87/87/84 MAIS MANIFEST 258/87/87/84` |
|
||
| **Fiche compensation** `fr=87/en=87 → fr=86/en=88` (total inchangé) | **exit 1** `dit 258/86/88/84 MAIS MANIFEST 258/87/87/84` — mord là où le total seul est aveugle |
|
||
| **Claim disparu** (README) | **exit 1** `claim mots-clés INTROUVABLE (attendu total=258 …)` |
|
||
| Restauré | **exit 0** (2 docs 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 total + 3 langues depuis
|
||
`MANIFEST.counts` 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_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
|
||
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.
|
||
|
||
---
|
||
|
||
## Session `20260731_083034` · Buffer S8 · Comptes RBAC des 3 volets recopiés à la main — surface non gatée
|
||
|
||
**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'une surface **« vert trompeur » (#6)** encore non gatée.
|
||
|
||
### Défaut trouvé — 3 READMEs RBAC transcrivent à la main des comptes de MANIFEST byte-gatés
|
||
|
||
- **Symptôme** : les trois générateurs RBAC émettent chacun un `out/MANIFEST.json`
|
||
recalculé du contrat `rbac_50_roles.json` à chaque build (byte-gaté par
|
||
`check_artifacts` ⇒ autorité). Trois READMEs de module recopiaient **à la main**
|
||
des comptes qui en dérivent, sans **AUCUN** gate :
|
||
1. `rbac/roleprofile_gen/README.md` — table « Nb rôles » **par profil** (6 lignes
|
||
: Ventes 12 · Construction 10 · Direction 9 · Compta 8 · Achat 5 · Plateforme
|
||
6) + total bijectif **50**.
|
||
2. `rbac/apply_plan/README.md` — ligne agrégée « Génération réelle : **6 étapes ·
|
||
50 rôles / 116 DocPerm / 28 UP templates / 6 Role Profile · 4 DocType custom +
|
||
5 Company + 4 rôles equipe** » : **8 comptes** de TOUS les volets en une phrase.
|
||
3. `rbac/userperm_gen/README.md` — ventilation « **28 entite · 16 groupe · 2 own ·
|
||
4 equipe** » (par mécanisme d'enforcement).
|
||
- **Contradiction latente** : ajouter un rôle/DocType au contrat ferait dériver
|
||
**les trois** docs en silence pendant que les MANIFEST (byte-gatés) disent autre
|
||
chose — même classe que les cellules « Tests », la prose agrégée CRM/RBAC et les
|
||
triplets par workspace, mais sur le **domaine RBAC** (contrainte NON-NÉGOCIABLE
|
||
#5 « 50 rôles »), au grain le plus fin (par profil) **et** au niveau consolidé.
|
||
- **État au démarrage** : les 10 nombres étaient **justes** (aucune dérive déjà
|
||
survenue) — le défaut est l'**absence de garde**, pas une valeur périmée.
|
||
|
||
### Fix (1 volet · garder — aucun chiffre à corriger)
|
||
|
||
- **`ci/check_readme_claims.sh`** — nouveau bloc RBAC recomputant chaque nombre
|
||
depuis le `out/MANIFEST.json` du volet (zéro duplication des compteurs des
|
||
générateurs · #6) et exigeant l'égalité avec ce que la doc ÉCRIT :
|
||
- roleprofile : chaque `nb_roles` par profil (ancré sur nom+portail) + total
|
||
`counts.roles_couverts` ;
|
||
- apply_plan : les 8 comptes (`len(apply_plan.json)` · `counts.{roles,
|
||
custom_docperm,user_permission_templates,role_profiles}` · `len(confirmations_
|
||
vps.{custom_doctypes,companies,roles_scope_equipe})`) en un n-uplet ordonné ;
|
||
- userperm : `by_mechanism.{user_permission_company,none_consolidated,
|
||
docperm_if_owner,vps_confirm_team}`.
|
||
Claim absent ⇒ red (disparition = régression de traçabilité). Header + ci/README
|
||
documentés.
|
||
|
||
### Preuves
|
||
|
||
- **Passe** : gate vert, **10 nouvelles lignes RBAC** vérifiées (6 profils + total
|
||
+ agrégat apply_plan + ventilation userperm), toutes == MANIFEST.
|
||
- **Morsures (3, une par surface)** : Ventes 12→13 ⇒ `✗ … dit 13 MAIS MANIFEST
|
||
dit 12` ; apply_plan 116→117 DocPerm ⇒ `✗ … 6/50/117/… MAIS … 6/50/116/…` ;
|
||
userperm 28→29 entite ⇒ `✗ … 29/16/2/4 MAIS … 28/16/2/4`. Exit 1 dans les trois
|
||
cas ; restauration ⇒ PASS (exit 0).
|
||
|
||
**Régénération des consommateurs** : néant — aucun compte n'a changé (fix = gate
|
||
seul). 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 nombre depuis
|
||
les MANIFEST byte-gatés ; les comptes des READMEs **découlent** du contrat RBAC.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Sprint 8 · buffer L75 · Gate claims mobile — récap app Expo non gatée (onglets/rôles/langues/identifiants)
|
||
|
||
### Diagnostic
|
||
|
||
- **Symptôme** : le générateur `mobile/app_config` émet `out/MANIFEST.json` dont
|
||
`counts` porte **4 nombres** recomptés à chaque build depuis les sources faisant
|
||
autorité — `rbac_50_roles.json` (portails métier + rôles → `onglets`,
|
||
`roles_couverts`), `seo/seo_spec.json` (`langues`) et la liste `a_confirmer`
|
||
(credentials EAS/App Store #32/Play Store jamais fabriqués · #6/#8 →
|
||
`identifiants_a_confirmer`). Le `out/` est byte-gaté par `check_artifacts`
|
||
(build frais == commité) ⇒ artefact faisant autorité.
|
||
- **Contradiction latente** : la ligne récap du README du module
|
||
(`05_deliverables_mvp/mobile/app_config/README.md` L66-67 — « **5 onglets** ·
|
||
**44 rôles** couverts · **3 langues** · **13 identifiants `a_confirmer`** »)
|
||
recopiait ce quadruplet **à la main**, sans **AUCUN** gate. Ajouter un
|
||
rôle/portail au contrat RBAC, une langue au site, ou un credential store ferait
|
||
dériver le doc en silence pendant que le MANIFEST (byte-gaté) dit autre chose —
|
||
même classe de « vert trompeur » que les mots-clés SEO (total + fr/en/es), les
|
||
triplets par workspace des portails, ou le pipeline vente CRM.
|
||
- **État au démarrage** : les 4 nombres étaient **justes** (5/44/3/13 == MANIFEST)
|
||
— le défaut est l'**absence de garde**, pas une valeur périmée.
|
||
|
||
### Fix (1 fichier gate + 1 doc CI · aucun chiffre à corriger)
|
||
|
||
- **`ci/check_readme_claims.sh`** — nouveau bloc Mobile recomputant le quadruplet
|
||
`(onglets, roles_couverts, langues, identifiants_a_confirmer)` depuis
|
||
`mobile/app_config/out/MANIFEST.json · counts` (zéro duplication du compteur du
|
||
générateur · #6) et exigeant l'égalité avec ce que le README ÉCRIT. Recomputer
|
||
**les 4** volets (et pas le seul total de rôles) mord une dérive de N'IMPORTE
|
||
lequel là où un seul nombre resterait aveugle. Un claim absent échoue AUSSI
|
||
(INTROUVABLE = régression de traçabilité).
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « app mobile Expo »).
|
||
|
||
### Preuve (4 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| onglets 5→6 | ✗ dit 6/44/3/13 MAIS MANIFEST 5/44/3/13 · exit 1 |
|
||
| rôles 44→43 | ✗ dit 5/43/3/13 MAIS MANIFEST 5/44/3/13 · exit 1 |
|
||
| langues 3→2 | ✗ dit 5/44/2/13 MAIS MANIFEST 5/44/3/13 · exit 1 |
|
||
| identifiants 13→12 | ✗ dit 5/44/3/12 MAIS MANIFEST 5/44/3/13 · exit 1 |
|
||
| claim supprimé | ✗ récap app INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 5/44/3/13 == MANIFEST · exit 0 |
|
||
|
||
Suite CI complète re-verte : `check_artifacts` · `check_readme_claims` ·
|
||
`check_docs` · `check_regression` · `check_ci_integrity` (gates statiques
|
||
verrouillés) · `guard_constraints`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Sprint 8 · buffer L75 · Gate chiffres audit 5D (contrôles/dimensions ×2 docs + ventilation verdict)
|
||
|
||
**Contexte** : poursuite de la fermeture des surfaces de « vert trompeur » non
|
||
gatées dans `check_readme_claims.sh`. Après RBAC, SEO, CRM pipeline, Mobile et
|
||
Legal CONFOTUR, restait la **synthèse de l'audit de conformité 5D** (livrable
|
||
`qa/audit_5d`), transcrite À LA MAIN dans DEUX docs sans aucun gate.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- Le README du module (`05_deliverables_mvp/qa/audit_5d/README.md`) ouvre par
|
||
« **17 contrôles** répartis en **5 dimensions (5D)** » ET affiche la ventilation
|
||
du verdict « **13 PASS · 0 FAIL · 4 à confirmer** ».
|
||
- La fiche agent QA (`03_agents/qa/AGENT.md`) recopie le même couple « 17 contrôles
|
||
/ 5 dimensions ».
|
||
- Les DEUX artefacts source sont byte-gatés par `check_artifacts` (recomptés du
|
||
catalogue de contrôles à chaque build) : `out/MANIFEST.json` (`controls_total`,
|
||
`dimensions`) ET `out/audit_report.json` (`totals.{pass,fail,a_confirmer}`).
|
||
- Aucun gate ne comparait la VALEUR écrite à l'artefact : ajouter un contrôle/une
|
||
dimension au catalogue, ou faire **basculer** un contrôle en A_CONFIRMER, ferait
|
||
dériver les deux docs (et la ligne verdict) en silence.
|
||
|
||
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute le couple
|
||
(contrôles + dimensions) depuis le MANIFEST et la ventilation (pass/fail/à-confirmer)
|
||
depuis `audit_report.totals` — **jamais** figés en dur ici, zéro duplication du
|
||
compteur du générateur (#6) — et exige l'égalité avec les deux docs. La ventilation
|
||
est recomputée SÉPARÉMENT car une bascule (pass 13→12, à confirmer 4→5) est **aveugle**
|
||
au seul total de contrôles (reste 17). Cohérence croisée en bonus :
|
||
`MANIFEST.controls_total == audit_report.totals.controls`.
|
||
|
||
### Preuve (4 morsures vérifiées + restauration verte)
|
||
|
||
| Injection | Résultat |
|
||
|---|---|
|
||
| README contrôles 17→18 | ✗ dit 18/5 MAIS artefact 17/5 · exit 1 |
|
||
| README verdict 13 PASS→12 / 4→5 à confirmer (bascule aveugle au total) | ✗ dit 12/0/5 MAIS totals 13/0/4 · exit 1 |
|
||
| fiche QA dimensions 5→6 | ✗ dit 17/6 MAIS artefact 17/5 · exit 1 |
|
||
| claim README verdict supprimé (reformulé) | ✗ ventilation verdict INTROUVABLE · exit 1 |
|
||
| restauré | ✓ 17/5 + 13/0/4 == artefacts · exit 0 |
|
||
|
||
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
|
||
descriptif (classe « audit 5D »).
|
||
|
||
Suite CI complète re-verte : `check_artifacts` · `check_readme_claims` ·
|
||
`check_docs` · `check_regression` · `check_ci_integrity` (gates statiques
|
||
verrouillés) · `guard_constraints` · `validate_json`.
|
||
|
||
**Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
|
||
**Auto-score 4Big** : 96/100.
|
||
|
||
## Sprint 8 · buffer · CRM séparation des pouvoirs (2e surface workflow_vente)
|
||
- **Constat** : le README `crm/workflow_vente` énumérait À LA MAIN les transitions
|
||
quatre-yeux (« confirmer réservation, signer contrat, approuver CONFOTUR,
|
||
annuler/résilier — `allow_self_approval = 0` »). Le bloc CRM existant ne gatait
|
||
que le COMPTE états/transitions (9/11) — aveugle à l'IDENTITÉ des transitions à
|
||
`separation_of_duties`.
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`) : recompute l'ENSEMBLE
|
||
`{action | allow_self_approval == 0}` depuis `out/workflow.json` (byte-gaté) et
|
||
exige que la phrase README l'énumère EXACTEMENT (set-diff absent ET en trop ;
|
||
casse ignorée + suffixe « (perdu) » élidé). Bonus : `0 < |quatre-yeux| < |trans|`.
|
||
- **4 morsures vérifiées** : déclassement `Signer contrat` (self 0→1) capté là où
|
||
le compte reste 9/11 · promotion `Déposer CONFOTUR` (self 1→0) captée · échange
|
||
prose `signer contrat`→`signer bail` capté · énumération supprimée = INTROUVABLE ;
|
||
restauré = green (`{annuler, approuver confotur, confirmer réservation, résilier,
|
||
signer contrat}` == workflow.json).
|
||
- État courant : aucune action périmée (anti-invention #6) — le défaut est la
|
||
surface ungated. `ci/README.md` (table + détail) mis à jour · **7 gates re-verts**.
|
||
|
||
## Sprint 8 · buffer · Portails (2e surface) · catalogue DocTypes `custom` à créer
|
||
- **Constat** : le README `frontend/portails` énumère À LA MAIN, dans le §« Hand-off
|
||
→ agent ERPNext Backend », les **DocTypes `custom` à créer avant import** :
|
||
`CONFOTUR Application`, `Faisabilité`, `Publiciste Log`. Ce catalogue est
|
||
DATA-DERIVED == `doctypes_custom_a_creer` d'`out/MANIFEST.json` (byte-gaté par
|
||
`check_artifacts`), lui-même l'UNION des `doctypes_custom` par workspace (flag
|
||
`custom` du contrat RBAC, pour les seuls DocTypes CÂBLÉS dans un portail). C'est
|
||
un ensemble PROPRE au module (sous-ensemble de celui de `rbac/fixtures_gen` :
|
||
`API Access`, custom mais non câblé, en est ABSENT). Le bloc portails existant ne
|
||
gatait que les COMPTES par workspace (cartes/liens/rôles) — jamais ce catalogue.
|
||
- **Piège** : `check_artifacts` ne prouve que MANIFEST==build (byte-for-byte) et le
|
||
build RECOMPUTE l'union → AJOUTER une carte visant un nouveau DocType custom ·
|
||
en RENOMMER un · en RETIRER un du câblage laisse la consigne de hand-off périmée
|
||
pendant que l'artefact dit autre chose. L'agent Backend créerait le mauvais jeu
|
||
de DocTypes → liens pointant dans le vide (le risque même que la consigne veut
|
||
prévenir) — « vert trompeur » qu'aucune suite `tests/` (qui teste des FONCTIONS
|
||
de mapping, pas la prose de hand-off) n'attrape.
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`) : recompute le catalogue depuis
|
||
`MANIFEST.doctypes_custom_a_creer` (zéro duplication du contrat du générateur #6)
|
||
et exige que la prose l'énumère EXACTEMENT (absent ET en trop via set-diff ·
|
||
accents/casse normalisés via `unicodedata`). Cohérences croisées en bonus
|
||
(mordent un MANIFEST INTERNEMENT incohérent) : catalogue NON VIDE, sans doublon
|
||
et TRIÉ (byte-déterminisme) · égal à l'UNION des `doctypes_custom` par workspace
|
||
(pas de DocType custom câblé mais oublié du hand-off, ni l'inverse). Un claim
|
||
absent échoue AUSSI.
|
||
- **5 morsures vérifiées** : prose renomme `Faisabilité → Faisabilite2`
|
||
(absents=[faisabilite] en trop=[faisabilite2]) · prose retire `Publiciste Log`
|
||
(sous-ensemble) · énumération supprimée = INTROUVABLE · MANIFEST retire du
|
||
catalogue un DocType encore câblé (câblés hors catalogue=[Publiciste Log]) ·
|
||
catalogue MANIFEST non trié (byte-déterminisme) ; restauré = green
|
||
(`[CONFOTUR Application, Faisabilité, Publiciste Log]` == MANIFEST == union).
|
||
- État courant : aucun catalogue périmé (anti-invention #6, rien à réécrire) — le
|
||
défaut est la surface ungated. `ci/README.md` (table + détail) mis à jour ·
|
||
**7 gates re-verts** (`check_readme_claims` · `check_artifacts` · `check_docs` ·
|
||
`check_ci_integrity` · `check_regression` · `guard_constraints` · `validate_json`).
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Sprint 8 · buffer · RBAC roleprofile_gen (2e surface) · classement métier/technique
|
||
- **Constat** : le README `rbac/roleprofile_gen` porte une table « Profils générés »
|
||
(6 `Role Profile` : nom · portail · **Type** métier/technique · Nb rôles). Le bloc
|
||
RBAC existant ne gatait que le COMPTE `Nb rôles` par ligne + total bijectif — sa
|
||
colonne « Type » était un **WILDCARD** (`[^|]*`). Preuve reproduite : classer le
|
||
portail technique `plateforme` en « métier » dans le README → `check_readme_claims`
|
||
**exit 0** (le gate ne voyait que `6 == 6`). Aveugle aussi au **split** en prose
|
||
« 6 profils (5 métier + 1 technique) » (README:93) — gaté nulle part.
|
||
- **Data-derived** : le classement = flag booléen `metier` par profil de
|
||
`MANIFEST.profiles` ; le split = `counts.portails_metier`(5) / `portails_techniques`(1)
|
||
/ `role_profiles`(6) — MANIFEST recomputé de `rbac_50_roles.json` à chaque build,
|
||
byte-gaté par `check_artifacts`. Un « métier vs technique » faux détournerait le
|
||
Sprint 4 (« 5 portails rôle » = les 5 métier ; `plateforme` = console technique).
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`, bloc roleprofile) : (1) colonne
|
||
« Type » recomputée du flag `metier`, exigée EXACTE par profil (fin du wildcard) ;
|
||
(2) prose « N profils (X métier + Y technique) » == comptes MANIFEST ; (3) identité
|
||
d'ensemble — nombre de lignes de profil de la table == `|profiles|` (aucune ligne
|
||
FANTÔME d'un profil inventé absent du contrat ; complète le sens MANIFEST→README de
|
||
la boucle Nb rôles qui capte le MANQUANT) ; (4) cohérences croisées mordant un
|
||
MANIFEST INTERNEMENT incohérent : `portails_metier + portails_techniques ==
|
||
role_profiles == |profiles|` ET ces comptes recomptent les flags `metier` réels.
|
||
- **5 morsures vérifiées** : README classe `plateforme` métier (technique→métier)
|
||
capté · README classe `ventes` technique (métier→technique) capté · prose split
|
||
5→4 métier capté (6/4/1 MAIS 6/5/1) · ligne FANTÔME `OTO Portail Fantome` (7≠6)
|
||
captée · MANIFEST `portails_metier` 5→6 sans toucher aux flags (incohérence interne)
|
||
capté (flags réels=5) ; restauré = green : 6 Types == MANIFEST · split 6/5/1 ·
|
||
6 lignes · comptes cohérents · exit 0.
|
||
- État courant : aucun classement périmé (anti-invention #6, rien à réécrire) — le
|
||
défaut est la surface ungated (colonne wildcardée). `ci/README.md` (table + détail
|
||
« 2e surface roleprofile_gen ») mis à jour · **7 gates re-verts**
|
||
(`check_readme_claims` · `check_artifacts` · `check_docs` · `check_ci_integrity` ·
|
||
`check_regression` · `guard_constraints` · `validate_json`).
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Sprint 8 · buffer · Démo/scenarios (2e surface) · la TABLE des scénarios · identité (id · projet+libellé · audience)
|
||
- **Constat** : le README `demo/scenarios` porte une table « Scénario | Projet |
|
||
Audience | Angle » (README:10-13) dont les **trois colonnes d'identité** sont
|
||
data-derived : `id` (`S-P07-BANQUIER`), `projet`+`projet_libelle`
|
||
(`P07` + `Aqua Terra Las Terrenas`) et `audience` (`banquier`). Le bloc « Démo »
|
||
existant de `check_readme_claims.sh` ne gate QUE `counts.modules_cites_uniques`
|
||
(le compte de modules du diagramme) — ces colonnes étaient des **wildcards**. Les
|
||
libellés projets sont même déclarés (README:91-92) « proviennent **verbatim** de
|
||
CLAUDE.md · §Projets » sans AUCUN ancrage vérifié.
|
||
- **Data-derived** : `out/run_sheet.json.scenarios[]` (`id`/`projet`/
|
||
`projet_libelle`/`audience`), byte-gaté par `check_artifacts`. Le générateur ne
|
||
saisit aucune donnée métier (résolution RFC 6901 depuis le disque). `check_artifacts`
|
||
ne prouve QUE `run_sheet==build` (byte-for-byte) ; la source `scenario_spec.json`
|
||
(map `projets`) recopie les libellés à la main → toute la chaîne peut DÉRIVER de
|
||
CLAUDE.md en restant byte-verte.
|
||
- **Preuve reproduite** : classer P07 sous `audience=client` dans le README →
|
||
`check_readme_claims` **exit 0** (le gate ne voyait que `10 == 10` modules).
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Démo scénarios ») : (1)
|
||
**ANCRAGE** — chaque `P{code} {libellé}` du run_sheet == entrée « ## Projets » de
|
||
CLAUDE.md (verbatim, source unique · même esprit que le catalogue projets
|
||
dossier_vente) ; (2) **TABLE** — chaque ligne porte EXACTEMENT id +
|
||
`P{code} {libellé}` + audience (fin du wildcard, patron identique à la colonne
|
||
« Type » de roleprofile_gen) ; (3) **IDENTITÉ d'ensemble** — {ids des lignes} ==
|
||
{ids du run_sheet} == `counts.scenarios` (aucune ligne FANTÔME, aucun scénario
|
||
MANQUANT). Cohérences croisées en bonus (mordent un artefact INTERNEMENT
|
||
incohérent) : `run_sheet` ↔ `MANIFEST` d'accord sur `(id, projet, audience)` ·
|
||
`id == S-{projet}-{AUDIENCE}` · `counts.scenarios == |scenarios|` · ids non vides
|
||
et sans doublon. Un claim absent échoue AUSSI.
|
||
- **8 morsures vérifiées** : prose renomme un id (INTROUVABLE) · prose classe P07
|
||
sous audience=client · prose met le mauvais libellé projet · ligne FANTÔME
|
||
`S-P99-GHOST` (en trop) · artefact libellé « Aqua Terra Bay » DÉRIVE de CLAUDE.md ·
|
||
`run_sheet`↔`MANIFEST` désync audience · `counts.scenarios=3 (≠|scenarios|=2)` ·
|
||
ligne `S-P05-CLIENT` supprimée (MANQUANT). Restauré = green : 2 lignes ==
|
||
run_sheet == counts (2) · libellés == CLAUDE.md §Projets · exit 0.
|
||
- **État courant** : aucune valeur périmée (anti-invention #6, rien à réécrire) — le
|
||
défaut est la surface **ungated**. `ci/README.md` (table + détail « 2ᵉ surface
|
||
`demo/scenarios` ») mis à jour · working tree byte-restauré · **7 gates re-verts**
|
||
(`check_readme_claims` · `check_artifacts` · `check_docs` · `check_ci_integrity` ·
|
||
`check_regression` · `guard_constraints` · `validate_json`).
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Sprint 8 · buffer · RBAC/apply_plan (2e surface) · la TABLE « Run-book généré (SPEC §7) » · le GRAPHE d'application ordonné (# · Responsable · Dépend de)
|
||
- **Constat** : le README `rbac/apply_plan` porte la table « ## Run-book généré
|
||
(SPEC §7 · ordre d'application VPS) » (README:38-46) — les **6 étapes ordonnées**
|
||
que l'agent ERPNext suit **pas à pas** sur le VPS. Ses trois colonnes d'identité
|
||
sont data-derived de `out/apply_plan.json` : `#` = `order`, `Responsable` =
|
||
`responsable` (`worker`/`vps`/`worker+vps`), `Dépend de` = les **n°s d'ordre** des
|
||
`depends_on`. Le bloc « apply_plan » existant de `check_readme_claims.sh` (bloc 2)
|
||
ne gate QUE la ligne AGRÉGÉE « Génération réelle » (8 comptes consolidés) — ces
|
||
trois colonnes étaient un **wildcard**.
|
||
- **Data-derived** : `out/apply_plan.json` (liste de 6 étapes · `order`/`id`/
|
||
`responsable`/`depends_on`), byte-gaté par `check_artifacts`. Ce dernier ne prouve
|
||
QUE `apply_plan==build` (byte-for-byte) ; l'identité des LIGNES de la table (qui
|
||
fait quoi · dans quel ordre) restait non gatée.
|
||
- **Preuve reproduite** : passer `Responsable` de l'étape 4 (`worker+vps`) à `vps`,
|
||
ou retirer une dépendance de l'étape 6 (`4, 5`→`4`) dans le README →
|
||
`check_readme_claims` **exit 0** (le bloc 2 ne voyait que les comptes agrégés). Un
|
||
responsable périmé (étape VPS attribuée au worker) ou une dépendance périmée
|
||
(`Role Profile` importé **avant** les `Role`) est un hazard réel — le risque même
|
||
que le run-book veut prévenir — qu'aucune suite `tests/` (qui teste des fonctions,
|
||
pas la table commitée) n'attrape.
|
||
- **Gate ajouté** (`ci/check_readme_claims.sh`, sous-bloc « 2bis) apply_plan — TABLE
|
||
Run-book ») : (1) **IDENTITÉ par étape** — chaque ligne porte EXACTEMENT
|
||
`#`=`order` + `Responsable`=`responsable` + `Dépend de`=n°s d'ordre des
|
||
`depends_on` (deps extraits par digits ⇒ robuste au séparateur / à l'em-dash) ;
|
||
la colonne « Étape » reste libre (paraphrase). (2) **IDENTITÉ d'ensemble** —
|
||
{ordres des lignes} == {ordres de l'artefact}, sans doublon (aucune ligne FANTÔME,
|
||
aucune étape MANQUANTE). Cohérences croisées en bonus (mordent un plan INTERNEMENT
|
||
incohérent) : ordres contigus `1..N` · `responsable` ∈ {worker, vps, worker+vps} ·
|
||
toute dépendance pointe en **arrière** (n° < n° de l'étape ⇒ pas de cycle/renvoi
|
||
avant). Un claim absent échoue AUSSI.
|
||
- **8 morsures vérifiées** : README étape4 responsable `worker+vps`→`vps` (câblage) ·
|
||
README étape6 `Dépend de 4,5`→`4` (dépendance manquante) · README étape3
|
||
`1,2`→`1,2,5` (dépendance fantôme) · ligne FANTÔME `#7` (7≠6) · étape 5 SUPPRIMÉE
|
||
(INTROUVABLE + 5≠6) · artefact étape2 responsable `vps`→`worker` (README stale) ·
|
||
artefact étape2 dep en AVANT (`verify-http-qa` · graphe incohérent) · artefact
|
||
étape1 responsable `robot` hors domaine. Restauré = green : 6 lignes == 6 étapes ·
|
||
responsables/deps == artefact · ordres 1..6 contigus · exit 0.
|
||
- **État courant** : aucune valeur périmée (anti-invention #6, rien à réécrire) — le
|
||
défaut est la surface **ungated** (colonnes wildcardées). `ci/README.md` (table +
|
||
détail « 2ᵉ surface `rbac/apply_plan` ») mis à jour · working tree byte-restauré
|
||
(arbre propre · `git clean` cité ici · ci-allow) · **7 gates re-verts** (`check_readme_claims` · `check_artifacts` ·
|
||
`check_docs` · `check_ci_integrity` · `check_regression` · `guard_constraints` ·
|
||
`validate_json`).
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo).
|
||
- **Auto-score 4Big** : 96/100.
|