c6428533a0
Classe fermée `agent-fiche-role-attrs-ungated` (sous-classe colonne CLI). La colonne « Entrée CLI » des tables de livrables cite à la main le jeu de verbes de chaque module (`publiciste.py parse|validate|generate|run`, `faisabilite_gen.py score|scaffold|generate|batch`, …). Les blocs amont gatent déjà génériquement — pour TOUTES les fiches — les colonnes « Tests » (vs regression_plan) et « Job CI » (vs ci.yml), mais RIEN ne liait les VERBES écrits aux sous-commandes que le CLI EXPOSE. Piège #6 : renommer/ajouter/retirer/réordonner un add_parser dans le .py (ou le mal recopier dans la fiche) laisse la fiche documenter une surface d'invocation FANTÔME — la doc d'identité qui dit à l'agent COMMENT lancer son livrable ment en silence, le CI reste vert (le module tourne sous le vrai verbe), aucune suite tests/ ne l'attrape. Gate ajoutée (ci/check_readme_claims.sh, bloc « colonne Entrée CLI ») : _cli_subcommands() recompute via AST l'ensemble ORDONNÉ des subparsers.add_parser("<verbe>") ; script résolu par le chemin de module de la MÊME ligne de table (lien …/<path>/README.md) + basename ; égalité EXACTE ensemble ET ordre exigée ; `|` markdown échappés `\|` dé-échappés avant découpe. 16 cellules gatées (6 fiches ; regex [a-z0-9_] capte audit_5d/4big_gen.py). 7 morsures vérifiées, restaurées vert : fiche renomme/ajoute/retire/réordonne un verbe (4) · le vrai « vert trompeur » add_parser renommé dans le .py fiche inchangée (5) · nouveau add_parser non documenté (6) · script déplacé => INTROUVABLE (7). 6 gates re-verts. ci/README.md catalogue mis à jour. Incident : un git checkout large a reverté l'edit non-commité du gate ; ré-appliqué (git clean JAMAIS utilisé · ci-allow sur le log). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1406 lines
107 KiB
Markdown
1406 lines
107 KiB
Markdown
# Activity Log · 2026-08-01 · Claude Code DTP
|
||
|
||
## Session `20260801_000201` · Buffer S8 · Domaine RBAC/userperm_gen : la **table « Mapping `scope_donnees` → mécanisme »** — la **FONCTION d'enforcement ROW-LEVEL** (quel mécanisme Frappe natif applique CHAQUE portée de données + si un `User Permission` template est émis), CŒUR sécurité du module — était transcrite EN PROSE (README:33-38) SANS AUCUN gate d'IDENTITÉ. Le bloc RBAC « 3 volets » existant ne gate QUE la **ventilation** par mécanisme (« 28 `entite` · 16 `groupe` · 2 `own` · 4 `equipe` »), un COMPTE aveugle à QUEL mécanisme applique QUELLE portée.
|
||
|
||
**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 mapping RBAC `fixtures_gen` (séparation des pouvoirs `set_user_permissions`) ou la
|
||
cross-cohérence PERMISSIONS Legal/CONFOTUR (`role_id`→actions) — appliqué à la
|
||
**surface data-derived distincte du même README `rbac/userperm_gen`** : la table
|
||
qui associe chaque portée de données à son mécanisme d'enforcement, jamais gatée hors
|
||
son compte agrégé.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/rbac/userperm_gen/README.md:33-38` — table « Mapping
|
||
`scope_donnees` → mécanisme » : nomme, PAR portée, le `mechanism` Frappe natif
|
||
(`own`→`docperm_if_owner` · `entite`→`user_permission_company` ·
|
||
`groupe`→`none_consolidated` · `equipe`→`vps_confirm_team`) ET le verdict
|
||
« Template émis ? » (`oui` pour `entite` seul, sinon `non (null)`).
|
||
- Source faisant autorité (byte-gatée par `check_artifacts`) :
|
||
`out/user_permission_plan.json` — chaque entrée porte `scope_donnees` +
|
||
`mechanism` + `user_permission_template` (null ou objet). Le mapping est une
|
||
**fonction** : chaque portée → exactement un mécanisme ; template émis SSI
|
||
`entite`/`user_permission_company`.
|
||
- Piège : le bloc de ventilation est AVEUGLE à l'identité de ces couples.
|
||
RÉAFFECTER une portée à un mécanisme plus permissif (`entite` →
|
||
`none_consolidated` : le **row-level enforcement ABANDONNÉ**, sur-exposition des
|
||
données inter-entités — la restriction même que le module pose), RENOMMER un
|
||
mécanisme ou BASCULER le verdict « Template émis ? » laisse le README périmé
|
||
pendant que l'artefact dit autre chose → l'agent ERPNext Backend câblerait le
|
||
mauvais mécanisme (le risque même que la table veut prévenir). Aucune suite
|
||
`tests/` (qui teste des FONCTIONS de mapping/résolution, pas la prose) n'attrape
|
||
ce « vert trompeur ».
|
||
- **État courant** : **aucune ligne périmée** — les 4 couples portée→mécanisme et
|
||
leurs verdicts recoupent l'artefact exactement (anti-invention #6, rien à
|
||
réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « RBAC/userperm_gen
|
||
Mapping » après le bloc CRM gardes) : (1) **par portée** — le `mechanism` (1er token
|
||
backtické de la colonne) ET le verdict « Template émis ? » (`**oui**` / `non (null)`)
|
||
recomputés de `user_permission_plan.json`, prose exigée EXACTE ; (2) **identité
|
||
d'ensemble** — portées de la table == portées de l'artefact (set-diff : ni fantôme
|
||
ni manquante). Cohérences croisées en bonus (mordent un plan INTERNEMENT incohérent) :
|
||
chaque portée mappe UN SEUL mécanisme (fonction, pas relation) · « Template émis »
|
||
UNIFORME sur les entrées d'une portée · template émis EXACTEMENT pour
|
||
`user_permission_company` (l'invariant « template SSI `entite` » du README:36/61) ·
|
||
ensemble des portées NON VIDE. Un claim absent échoue AUSSI (traçabilité).
|
||
|
||
**7 morsures vérifiées** : README réaffecte `entite`→`none_consolidated`
|
||
(mécanisme périmé · élévation de portée) · README bascule `entite` « Template
|
||
émis » oui→non (verdict périmé) · README échange une portée `groupe`→`famille`
|
||
(absents=[groupe] + en trop=[famille] + ligne INTROUVABLE) · README retire la
|
||
ligne `own` (absents=[own]) · table entière supprimée (les 4 absents + toutes
|
||
lignes INTROUVABLES) · **artefact** réaffecte toutes les entrées `entite`→
|
||
`none_consolidated` (README périmé sur mécanisme ET verdict) · **artefact** rend
|
||
une entrée `own` porteuse d'un template (« Template émis » NON uniforme
|
||
[False,True] · invariant SSI cassé) ; restauré = green : 4 portées · table ==
|
||
artefact · par-ligne exact · fonction/uniforme/SSI verts · exit 0. Working tree
|
||
byte-restauré (`git checkout --`, **JAMAIS** `git clean`) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « 2ᵉ surface
|
||
`rbac/userperm_gen` ») 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 `20260801_003201` · Buffer S8 · Domaine Faisabilité/bancable : les **4 figures « Génération réelle (fixture) »** du README (`40 unités · valeur catalogue USD 8,560,000 / DOP 505,040,000 · point d'équilibre 21 unités (⌈52 % × 40⌉)`) — les chiffres DATA-DERIVED que le **dossier bancable** (l'artefact que voit le banquier) recopie — étaient **HORS de tout gate**. Le module n'écrit son `out/` que sur disque (« out/ non commité ») ⇒ **check_artifacts est aveugle** (aucun artefact byte-gaté) et **AUCUN** gate ne le touchait.
|
||
|
||
**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 esprit que les
|
||
paramètres canoniques `faisabilite/generator` **ancrés sur CLAUDE.md #9/#10** (le
|
||
`52 %` réutilisé ici) — appliqué à une **surface encore jamais gatée** : un module
|
||
dont la source de vérité n'est PAS un `out/*.json` mais **la fixture commitée + le
|
||
générateur**.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/faisabilite/bancable/README.md:103-105` — ligne
|
||
« Génération réelle (fixture) » : `40 unités` (= Σ quantités typologies) ·
|
||
`USD 8,560,000` (= Σ qté×prix_usd) · `DOP 505,040,000` (= Σ qté×prix_dop) ·
|
||
`21 unités (⌈52 % × 40⌉)` (= ⌈point_equilibre_pct × Σ unités⌉).
|
||
- Source faisant autorité : `fixtures/brief_bancable.json` (COMMITÉE) + la
|
||
**génération réelle** `python3 bancable_gen.py validate` (émet le manifeste sur
|
||
stdout, `figures_calculees[]`). Le `52 %` est **ancré sur CLAUDE.md #9**
|
||
(« Point équilibre 52% pré-vente »), pas recopié.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS**
|
||
(l'arithmétique de recoupement `_check_derived_arithmetic`) avec des **oracles
|
||
HARDCODÉS** dans le test — une copie de plus, jamais comparée à la PROSE du
|
||
README. Éditer une typologie de la fixture (quantité/prix), en ajouter/retirer
|
||
une, ou déplacer le point d'équilibre de CLAUDE.md #9, laisse les 4 chiffres du
|
||
README périmés pendant que le générateur produit autre chose → le banquier lit
|
||
un dossier faux (l'invention même que #6 interdit).
|
||
- **État courant** : **aucun chiffre périmé** — les 4 figures recoupent la
|
||
génération réelle exactement (anti-invention #6, rien à réécrire). Le défaut est
|
||
la **surface ungated** (module entièrement hors CI).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Faisabilité/bancable
|
||
figures » avant `sys.exit`) : (1) **recompute indépendant** des 4 figures depuis
|
||
la fixture commitée ; (2) **cohérence croisée** — le manifeste GÉNÉRÉ
|
||
(`bancable_gen validate`) == le recompute (mord un générateur/fixture
|
||
incohérents) ; (3) **prose** — un seul pattern d'identité exige les 4 valeurs
|
||
EXACTES, **avec séparateur de milliers** pour USD/DOP, + la formule `⌈pct × Σ
|
||
unités⌉` dont le pct == CLAUDE.md #9 et le total == Σ unités. Un claim absent
|
||
échoue AUSSI (traçabilité). Le `out/` n'étant pas commité, le gate **exécute le
|
||
générateur** (stdlib pur, `subprocess`, `encoding="utf-8"`) au lieu de lire un
|
||
artefact byte-gaté — même patron que le bloc `faisabilite/generator` qui lit
|
||
`model.py`.
|
||
|
||
**7 morsures vérifiées** : README `USD 8,560,000→9,560,000` (figure périmée) ·
|
||
README retire le séparateur de milliers (`8,560,000→8560000`) · README breakeven
|
||
`21→20` (formule périmée) · README formule `52 %→55 %` (dérive CLAUDE.md #9) ·
|
||
README supprime la ligne entière (INTROUVABLE · claim absent) · **fixture** Studio
|
||
`qté 12→13` (5 morsures : units/USD/DOP/breakeven README périmés + manifeste) ·
|
||
**fixture** 2 Chambres `prix_usd 320000→300000` (catalogue USD périmé) ; restauré =
|
||
green : 4 figures == génération réelle · manifeste == recompute · pct 52 % ==
|
||
CLAUDE.md #9 · exit 0. Working tree byte-restauré via `git checkout --` (JAMAIS
|
||
`git clean`, interdit absolu) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (ligne récap du pipeline `check-readme-claims`) mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; conversion PDF + rebuild
|
||
Portail Bancables restent côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_010204` · Buffer S8 · Domaine Mobile/fiche agent : la **fiche d'identité du rôle RBAC `plateforme-mobile`** (`03_agents/mobile/AGENT.md:36`) — le **SEUL ancrage in-repo réellement vérifiable** de l'agent mobile (builds/soumissions stores étant hors-repo, #8) — recopiait EN PROSE, DEPUIS le contrat `rbac_50_roles.json`, TOUS les attributs data-derived du rôle (`erpnext_role_name` · `nom_fr` · `famille`/`portail` · `entite_principale` · `niveau` · `scope_donnees` · `modules` · permission `API Access` custom R/W · `description`) SANS AUCUN gate d'IDENTITÉ. Le README `mobile/app_config` n'est gaté que sur des COMPTES agrégés (« 5 onglets · 44 rôles couverts · 3 langues · 13 identifiants »), AVEUGLES à l'identité de CE rôle.
|
||
|
||
**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
|
||
la table gardes CRM/`workflow_vente` (rôle qui garde chaque transition) ou le mapping
|
||
RBAC `userperm_gen` (portée→mécanisme) — appliqué à la **surface distincte** de la
|
||
fiche agent mobile : la carte que l'agent ERPNext Backend lit pour **seeder le rôle**
|
||
(`seed_mobile_rbac.py`), jamais gatée hors les comptes agrégés de `app_config`.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/mobile/AGENT.md:36` — ligne « Points de contact réellement commités »,
|
||
cellule « Ce qu'il fixe » : nomme, PAR attribut, le rôle ERPNext
|
||
**`OTO Plateforme Mobile`** (« Développeur Mobile » · famille/portail
|
||
**`plateforme`** · entité **9060 QC** · niveau 2 · scope `groupe` · modules
|
||
`Core`+`Website` · perm `API Access` custom R/W · description « Maintient
|
||
l'app Expo/React Native et l'API mobile ; gère les builds EAS et les
|
||
soumissions stores »).
|
||
- Source faisant autorité : `05_deliverables_mvp/rbac/rbac_50_roles.json` (contrat
|
||
RBAC, schéma-validé · les 3 MANIFEST RBAC recomputés en dérivent et sont byte-gatés
|
||
par `check_artifacts`) → le rôle d'`id` `plateforme-mobile` porte chacun de ces
|
||
champs. Autres blocs du gate lisent déjà ce contrat directement (userperm,
|
||
workflow_vente, confotur).
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS** de
|
||
résolution RBAC, jamais la PROSE d'une fiche agent. Éditer le contrat — élever le
|
||
`scope_donnees` (`groupe`→`entite` : sur-portée inter-entités, la restriction même
|
||
que le rôle pose), changer le `niveau`/l'`entite_principale`, renommer le rôle,
|
||
ajouter/retirer un module ou élargir la permission (`R/W`→`R/W/D`) — laisse la fiche
|
||
périmée pendant que le contrat dit autre chose → l'agent ERPNext Backend câblerait
|
||
le mauvais rôle (le risque même que la fiche veut prévenir).
|
||
- **État courant** : **aucun attribut périmé** — les 9 attributs + la description
|
||
recoupent le contrat exactement (anti-invention #6, rien à réécrire). Le défaut est
|
||
la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiche Mobile » avant
|
||
`sys.exit`) : (1) **par attribut** — `erpnext_role_name` · `nom_fr` · `portail` ·
|
||
`entite_principale` · `niveau` · `scope_donnees` · `modules` · permission recomputés
|
||
du contrat, prose EXACTE exigée (regex par attribut, lookaheads anti-préfixe pour
|
||
niveau/modules/perm) ; (2) **permission** — le sigle des verbes est **canonique et
|
||
ordonné** (C/R/W/D/S/X/A) : élargir OU rétrécir la perm change le sigle attendu (un
|
||
préfixe `R/W` ne satisfait plus `R/W/D`, ni l'inverse) ; verbe inconnu ⇒ ROUGE
|
||
(étendre le gate) ; (3) **description** recoupée **verbatim** (emphase markdown `**` et
|
||
point final neutralisés). Cohérences croisées bonus (mordent un contrat INTERNEMENT
|
||
incohérent) : `famille == portail` (bijection portail) · permission bien `custom` ·
|
||
`role_id` présent EXACTEMENT une fois. Un claim absent échoue AUSSI (traçabilité :
|
||
ligne de rôle INTROUVABLE).
|
||
|
||
**12 morsures vérifiées** (6 côté contrat = fiche périmée · 6 côté fiche = fiche
|
||
fausse) : contrat `scope groupe→entite` (sur-portée) · contrat `niveau 2→3` · contrat
|
||
`+delete` (sigle `R/W→R/W/D`) · contrat description réécrite · contrat rôle renommé
|
||
(`OTO Plateforme Mobile→OTO Mobile Dev`) · fiche `modules Website→Selling` · fiche
|
||
`entité 9060 QC→WAF` · fiche perm `R/W→R/W/D` (sur-revendication) · fiche perm `R/W→R`
|
||
(sous-revendication) · fiche modules over-claim `+Selling` et under-claim `Core` seul ·
|
||
ligne de rôle entièrement supprimée (INTROUVABLE) ; restauré = green : 9 attributs +
|
||
description == contrat · famille==portail · perm custom · role_id singleton · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Fiche d'identité
|
||
du rôle RBAC mobile ») 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 ; le seed réel
|
||
du rôle `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_013208` · Buffer S8 · Domaine Faisabilité/fiches agents : les **deux FICHES D'IDENTITÉ** des rôles RBAC `faisabilite-rendu-3d` (`03_agents/rendu/AGENT.md:34`) et `faisabilite-ifc-speckle` (`03_agents/ifc_speckle/AGENT.md:34`) — la carte que l'agent ERPNext Backend lit pour **seeder** le rôle porteur des rendus / de l'export IFC→GLB — recopiaient EN PROSE, DEPUIS le contrat `rbac_50_roles.json`, les attributs data-derived du rôle (`erpnext_role_name` · `nom_fr`/`modules` côté rendu · `portail` · `entite_principale` · `niveau` · les **deux** `permissions_cibles` `File` R/W/create + `Faisabilité` R ou R/W) SANS AUCUN gate d'IDENTITÉ. Le README `frontend/portails` n'est gaté que sur des COMPTES de rôles par Workspace, AVEUGLES à l'identité de CE rôle.
|
||
|
||
**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 classe que la Fiche
|
||
Mobile de la session précédente (`plateforme-mobile`) — surface `03_agents/*/AGENT.md`
|
||
qui transcrit à la main les attributs d'un rôle depuis `rbac_50_roles.json`, gatée (si
|
||
tant est) seulement sur des comptes agrégés — appliquée aux **deux fiches faisabilité
|
||
construction** encore ungated. Mémoire `agent-fiche-role-attrs-ungated` mise à jour.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/rendu/AGENT.md:34` — cellule « Ce qu'il fixe » du rôle
|
||
`faisabilite-rendu-3d` : `OTO Faisabilité Rendu 3D` · « Spécialiste Rendu 3D » ·
|
||
portail `construction` · `WA SRL` · niveau 2 · module `OTOV7 Faisabilité` ·
|
||
perms `File` R/W/create + `Faisabilité` R.
|
||
- `03_agents/ifc_speckle/AGENT.md:34` — cellule du rôle `faisabilite-ifc-speckle` :
|
||
`OTO Faisabilité IFC Speckle` · portail `construction` · `WA SRL` · niveau 2 ·
|
||
perms `File` R/W/create + `Faisabilité` **R/W** (écriture en plus vs rendu).
|
||
- Source faisant autorité : `05_deliverables_mvp/rbac/rbac_50_roles.json` (contrat
|
||
RBAC schéma-validé · les 3 MANIFEST RBAC en dérivent, byte-gatés par
|
||
`check_artifacts`). Plusieurs blocs du gate lisent déjà ce contrat directement.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS** de
|
||
résolution RBAC, jamais la PROSE d'une fiche. Élargir `Faisabilité` R→R/W (le rôle
|
||
Rendu 3D gagnerait l'écriture sur un DocType qu'il ne doit que LIRE), changer
|
||
`niveau`/`entite_principale`, renommer le rôle ou permuter un module laisse la fiche
|
||
périmée pendant que le contrat dit autre chose → l'agent câblerait le mauvais rôle.
|
||
- **Constat #6 (honnêteté)** : la **DESCRIPTION** de ces deux fiches est une
|
||
**PARAPHRASE éditoriale** (le contrat porte « (… — CLAUDE.md) » / « les modèles »
|
||
que la fiche condense) — vérifié programmatiquement AVANT toute édition. Elle n'est
|
||
donc **PAS** gatée verbatim (ne rien réécrire de correct pour satisfaire un gate) ;
|
||
seuls les attributs **structurés**, eux transcrits à l'exact, sont contraints.
|
||
- **État courant** : aucun attribut structuré périmé — les 12 recomputes recoupent
|
||
le contrat exactement (anti-invention #6, rien à réécrire). Le défaut est la
|
||
**surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiches Faisabilité »
|
||
avant `sys.exit`) : table de config par fiche (fichier · role_id · liste des attributs
|
||
RESTITUÉS). Pour chaque fiche : (1) **par attribut** — `erpnext_role_name` · `nom_fr` ·
|
||
`portail` · `entite_principale` · `niveau` · `modules` · les deux permissions
|
||
recomputés du contrat, prose EXACTE exigée (regex par attribut, lookaheads
|
||
anti-préfixe niveau/module/perms) ; (2) **permissions** — chaîne
|
||
« \`Doctype\` R/W/create + \`Autre\` R » rendue en **ordre canonique** (read→R ·
|
||
write→W · create/delete/submit/… en toutes lettres) : élargir OU rétrécir change la
|
||
chaîne attendue (`R/W/create` ne satisfait plus `R/W/create/delete`) ; verbe inconnu ⇒
|
||
ROUGE. Un claim absent échoue AUSSI (ligne de contact INTROUVABLE = régression #6).
|
||
|
||
**11 morsures vérifiées** (5 côté contrat = fiche périmée · 6 côté fiche = fiche
|
||
fausse) : contrat rendu `Faisabilité +write` (sigle `R→R/W`) · contrat rendu
|
||
`niveau 2→3` · contrat rendu `WA SRL→WAF` · contrat rendu rôle renommé · contrat ifc
|
||
`Faisabilité R/W→R` · fiche rendu perm `File R/W/create→…/delete` (over-claim) · fiche
|
||
ifc perm `R/W→R/W/create` (over-claim) · fiche rendu module `Faisabilité→Selling` ·
|
||
fiche ifc `WA SRL→WAF` · fiche rendu `nom_fr` retiré (claim absent) · ligne de contact
|
||
ifc supprimée (INTROUVABLE) ; restauré = green : 12 attributs == contrat · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « deux fiches
|
||
d'identité des rôles RBAC faisabilité ») 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 ; le seed réel
|
||
des rôles `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_020209` · Buffer S8 · Domaine Fiches agents/rattachement Workspace : les **assertions d'appartenance `Has Role`** des trois fiches `03_agents/{rendu,ifc_speckle,mobile}/AGENT.md` — QUELLE CONSOLE (Workspace ERPNext natif) le rôle peut atteindre — étaient une surface data-derived **DISTINCTE du contrat** `rbac_50_roles.json` (la membership vit dans `frontend/portails/out/workspace.json`, byte-gaté) et **HORS de tout gate**. Les blocs Fiches Faisabilité / Fiche Mobile des sessions précédentes ne gataient que les attributs du **contrat** ; le bloc « triplets par workspace » ne gate que le **compte** de rôles par Workspace (`nb_roles`), AVEUGLE à QUEL rôle.
|
||
|
||
**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 famille de fiches que
|
||
les deux sessions précédentes (`agent-fiche-role-attrs-ungated`) mais **surface
|
||
orthogonale** : non plus les attributs recopiés du contrat, mais la **membership
|
||
`Has Role`** — l'accès console — qu'aucun gate ne touchait.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/rendu/AGENT.md:35` — « rattaché au Workspace `OTO Construction` »
|
||
(assertion NOMMÉE) ; `03_agents/ifc_speckle/AGENT.md:35` — « rattaché à un
|
||
Workspace » (générique) ; `03_agents/mobile/AGENT.md:41` — « **volontairement pas**
|
||
rattaché au Workspace `OTO Ventes` » (assertion NÉGATIVE d'honnêteté #6).
|
||
- Source faisant autorité : `frontend/portails/out/workspace.json` (les 5 Workspaces
|
||
natifs v15, chacun portant sa liste `Has Role`, byte-gaté par `check_artifacts` via
|
||
la reproductibilité `out/`). L'`erpnext_role_name` de chaque rôle est résolu du
|
||
contrat `rbac_50_roles.json` par `id` (zéro duplication).
|
||
- Piège : rattacher le rôle mobile à `OTO Ventes` = **sur-exposition console** (le
|
||
dev mobile gagnerait l'accès au portail Ventes — la restriction même que la note
|
||
#6 pose), retirer/**déplacer** le rôle rendu de `OTO Construction` = perte/erreur
|
||
d'accès console — laisse la fiche périmée EN SILENCE pendant que l'artefact dit
|
||
autre chose ⇒ l'agent ERPNext Backend câblerait le mauvais accès console. Aucune
|
||
suite `tests/` (qui teste des FONCTIONS de résolution, pas la prose) n'attrape ce
|
||
« vert trompeur ».
|
||
- **État courant** : aucune assertion périmée — rendu ∈ {`OTO Construction`} seul ·
|
||
ifc ∈ {`OTO Construction`} (≥1) · mobile ∈ ∅ (donc absent de `OTO Ventes`) ; les 3
|
||
recoupent workspace.json exactement (anti-invention #6, rien à réécrire). Le défaut
|
||
est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiches agents ·
|
||
rattachement Workspace (`Has Role`) » avant `sys.exit`) : index recomputé
|
||
`erpnext_role_name → {titres de Workspace le portant}` depuis workspace.json. Par
|
||
fiche, 3 formes d'assertion : **in_named** (rendu) — la prose cite CE Workspace ET la
|
||
membership == {ce Workspace} seul (membership élargie ou déplacée ⇒ ROUGE) ;
|
||
**in_any** (ifc) — membership ≥ 1 Workspace ; **not_in_named** (mobile) — rôle ABSENT
|
||
du `Has Role` du Workspace nommé. Garde anti-typo : un Workspace nommé absent de
|
||
l'artefact échoue avant tout (anti-cible fantôme). Un claim absent échoue AUSSI
|
||
(traçabilité #6).
|
||
|
||
**9 morsures vérifiées** (4 côté artefact · 5 côté fiche/bord) : artefact ajoute le
|
||
rôle mobile à `OTO Ventes` (**sur-exposition #6 VIOLÉE**) · artefact retire le rôle
|
||
rendu de `OTO Construction` · artefact déplace rendu vers `OTO Achat` · artefact
|
||
retire ifc de tous les Workspaces · fiche rendu renomme le Workspace
|
||
(`OTO Construction→OTO Ventes`, INTROUVABLE) · fiche rendu supprime l'assertion ·
|
||
fiche mobile nomme un Workspace fantôme (`OTO Marketing`, anti-typo) · fiche ifc
|
||
supprime l'assertion générique · fiche mobile passe le négatif au positif (retire
|
||
« volontairement pas ») ; restauré = green : rendu=={`OTO Construction`} · ifc≥1 ·
|
||
mobile∉`OTO Ventes` · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
||
`git clean`, interdit absolu) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « rattachement
|
||
Workspace des fiches agents ») mis à jour. Mémoire `agent-fiche-role-attrs-ungated`
|
||
à actualiser (surface membership couverte).
|
||
- **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 ; l'attachement
|
||
réel des rôles aux Workspaces `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_023211` · Buffer S8 · Domaine Publiciste/branding : les **4 TOKENS DESIGN CANONIQUES** de la marque luxury — fond dark `#0a0a12` + accent doré `#f0b429`, titres **Fraunces** + corps **Cormorant Garamond** (contrainte NON-NÉGOCIABLE **CLAUDE.md #4**) — étaient RECOPIÉS à **QUATRE** endroits **tous NON gatés** : (a) les CONSTANTES `lib/branding.py` (`COLOR_BG`/`COLOR_ACCENT`/`FONT_DISPLAY`/`FONT_BODY`), la source unique importée par le générateur & substituée dans le gabarit (`{{COLOR_BG}}…`), hors `out/` donc **invisible à check_artifacts** ; (b) le **docstring** du même fichier ; (c) le README (ligne du gabarit) ; (d) le **tuple d'oracle HARDCODÉ** de `tests/test_publiciste.py`.
|
||
|
||
**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
|
||
les paramètres canoniques `faisabilite/generator` **ancrés sur CLAUDE.md #9/#10**
|
||
(`CANONICAL` ↔ contrainte) — appliqué à la **contrainte #4** (identité visuelle) et
|
||
à son consommateur `publiciste/branding`, module **entièrement hors CI** jusqu'ici
|
||
(grep `branding|0a0a12|f0b429|Fraunces` dans `ci/` = 0 avant cette session).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/publiciste/lib/branding.py:13-20` — les 4 CONSTANTES ·
|
||
`05_deliverables_mvp/publiciste/lib/branding.py:3-4` — le docstring qui les cite ·
|
||
`05_deliverables_mvp/publiciste/README.md:43` — « Gabarit dark+doré (Fraunces +
|
||
Cormorant Garamond) » · `05_deliverables_mvp/publiciste/tests/test_publiciste.py:193`
|
||
— `for token in ("#0a0a12", "#f0b429", "Fraunces", "Cormorant Garamond")`.
|
||
- Source faisant autorité : **CLAUDE.md #4** (ligne 18) — la contrainte
|
||
constitutionnelle, comme #9/#10 le sont pour le générateur de faisabilité.
|
||
- Piège : le SEUL contrôle existant (`test_marque_luxury`) assert que le RENDU
|
||
HTML CONTIENT ces 4 marqueurs — mais ils sont **HARDCODÉS dans le test**, une
|
||
copie de plus **jamais comparée à CLAUDE.md**. Si #4 change (accent
|
||
`#f0b429`→`#c9a227`) et qu'on aligne `branding.py`, l'oracle du test reste périmé
|
||
(rouge trompeur) ; si RIEN ne bouge, tout reste vert alors que le site public
|
||
`vente.otov7.com` émettrait la mauvaise couleur — 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** : **aucun token périmé** — les 4 constantes + docstring + README
|
||
+ oracle du test recoupent CLAUDE.md #4 exactement (anti-invention #6, rien à
|
||
réécrire). Le défaut est la **surface ungated** (module hors CI).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Publiciste/branding »
|
||
avant `sys.exit`) : (0) **ancrage** — les 4 tokens recomputés de la ligne #4 de
|
||
CLAUDE.md (2 couleurs backtickées + 2 fontes de la parenthèse `(… + …)`) ; (a)
|
||
`branding.py` CONSTANTES == #4 (hex **insensible à la casse**, fontes à l'exact
|
||
strip) ; (b) **docstring** (texte AVANT les constantes) cite les 4 EXACTS ; (c)
|
||
README cite les 2 fontes ; (d) **oracle du test** — le tuple `for token in (...)`
|
||
== les 4 tokens de #4 (set-diff : absent ET en trop). Un claim absent échoue AUSSI
|
||
(traçabilité #6).
|
||
|
||
**6 morsures vérifiées** : `branding.py` accent `#f0b429→#e0a420` (constante
|
||
périmée) · `branding.py` display `Fraunces→Playfair Display` · **CLAUDE.md #4**
|
||
accent `→#c9a227` (mord **SIMULTANÉMENT** les 3 copies aval : constante + docstring
|
||
+ oracle du test — prouve la valeur de l'ANCRAGE) · docstring retire l'accent de la
|
||
prose (claim absent) · README échange une fonte (`Cormorant Garamond→Georgia`) ·
|
||
oracle du test retire `Fraunces` ; restauré = green : 4 tokens sains · constantes ==
|
||
#4 · docstring 4 tokens · README 2 fontes · oracle == #4 · exit 0. Working tree
|
||
byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) ·
|
||
**7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Tokens design
|
||
canoniques `publiciste/branding` ancrés sur CLAUDE.md #4 ») 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 ; le déploiement
|
||
réel du site `vente.otov7.com` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_030214` · Buffer S8 · Domaine Fiscal/e-CF DGII : l'**IDENTITÉ du RÔLE émetteur** e-CF — le SEUL rôle habilité à ÉMETTRE un comprobante fiscal électronique — nommé **en prose** par le bullet `role_id` du README (`fiscal/ecf_dgii/README.md:51-54`) via TROIS attributs data-derived (`role_id` `compta-fiscaliste-ecf` · `erpnext_role_name` `OTO Compta Fiscaliste eCF` · `portail` `compta`) était **HORS de tout gate d'IDENTITÉ**. Le bloc **e-NCF** gate le FORMAT de l'identifiant ; le bloc **cross-cohérence** (2e surface, session précédente) gate états émetteurs/champs de base/FormaPago ; mais AUCUN ne comparait l'IDENTITÉ de ce rôle à ses deux sources faisant autorité.
|
||
|
||
**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 classe d'IDENTITÉ**
|
||
que la Fiche Mobile / les Fiches Faisabilité (`agent-fiche-role-attrs-ungated`) ou les
|
||
gardes CRM/`workflow_vente` (rôle→transition) — appliquée à une **3e surface distincte
|
||
du MÊME README `fiscal/ecf_dgii`** : le rôle émetteur nommé dans la section
|
||
« Cross-cohérence », jamais gaté hors le FORMAT e-NCF et les ensembles états/champs.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/fiscal/ecf_dgii/README.md:53-54` — bullet `role_id` :
|
||
« **et** appartenir au portail `compta` — le rôle dédié `compta-fiscaliste-ecf`
|
||
(_OTO Compta Fiscaliste eCF_) ».
|
||
- Sources faisant autorité (double) : (a) `out/ecf_plan.json` (byte-gaté par
|
||
`check_artifacts`) — CHAQUE `emission_events[]` porte `role_id` +
|
||
`erpnext_role_name` ; (b) `rbac/rbac_50_roles.json` (contrat schéma-validé ·
|
||
les 3 MANIFEST RBAC en dérivent, byte-gatés) — le rôle d'`id`
|
||
`compta-fiscaliste-ecf` porte `portail: "compta"`. Le `portail` n'est PAS dans
|
||
l'artefact ; il n'est vérifiable QUE contre le contrat.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS**
|
||
(`ncf`/résolution RBAC), jamais la PROSE. RÉAFFECTER l'émission à un autre rôle
|
||
(dans le plan), le RENOMMER, ou DÉPLACER `compta-fiscaliste-ecf` du portail
|
||
`compta` vers un autre portail (dans le contrat : l'e-CF serait émis **HORS
|
||
Compta** — la séparation même que la cross-cohérence pose) laisse la prose périmée
|
||
EN SILENCE pendant que l'artefact/le contrat disent autre chose → l'agent ERPNext
|
||
Backend câblerait le mauvais rôle émetteur (le risque même que #6 interdit).
|
||
- **État courant** : **aucun attribut périmé** — les 3 recoupent artefact+contrat
|
||
exactement (anti-invention #6, rien à réécrire). Le défaut est la **surface
|
||
ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiscal rôle émetteur »
|
||
après le bloc FormaPago) : (1) **par attribut** — `role_id`/`erpnext_role_name`
|
||
recomputés de `emission_events` + `portail`/nom Frappe recomputés du contrat, prose
|
||
EXACTE exigée (regex par claim) ; (2) **cohérences croisées bonus** (mordent un
|
||
plan/contrat INTERNEMENT incohérent) : tous les `emission_events` pointent UN SEUL
|
||
rôle (fonction · non vide) · ce `role_id` existe EXACTEMENT une fois au contrat · le
|
||
nom résolu dans l'artefact == le contrat (zéro-duplication) · `portail == compta`
|
||
(séparation des pouvoirs). Un claim absent échoue AUSSI (traçabilité #6).
|
||
|
||
**6 morsures vérifiées** : README renomme le `role_id`
|
||
(`compta-fiscaliste-ecf→…-xxx`, prose périmée) · README renomme le nom Frappe · README
|
||
déplace le portail (`compta→ventes`) · **artefact** réaffecte les DEUX
|
||
`emission_events` à `ventes-directeur` (5 mords en cascade : nom≠contrat + portail
|
||
HORS Compta + les 3 claims de prose) · **contrat** déplace le rôle vers `ventes`
|
||
(portail HORS Compta + prose portail périmée) · **artefact** diverge du contrat sur
|
||
le nom (`OTO Compta X`, zéro-dup cassé) ; restauré = green : 3 claims == artefact/
|
||
contrat · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
||
`git clean`, interdit absolu) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « identité du RÔLE
|
||
émetteur e-CF, 3e surface du MÊME README `fiscal/ecf_dgii` ») 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 ; le seed réel
|
||
du rôle + le câblage Compupar restent côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_033217` · Buffer S8 · Domaine Fiches agents/colonne « Job CI » : chaque table de livrables de `03_agents/*/AGENT.md` porte une colonne **Job CI** qui NOMME entre backticks le job Gitea Actions exécutant la suite du module (`rbac-tests`, `fiscal-ecf-tests`, `frontend-portails-tests`…). Ce nom est **saisi à la main** ; la source de vérité est la clé `jobs:` de `.gitea/workflows/ci.yml`. Ce lien n'était couvert par **AUCUN gate** : `check_ci_integrity.sh` prouve que chaque job est CÂBLÉ dans `gate.needs` (INV-A/B) et les blocs amont de `check_readme_claims` recomputent les **comptes** de tests par suite — mais RIEN ne vérifiait que le nom ÉCRIT dans la fiche DÉSIGNE un job réel.
|
||
|
||
**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 classe de « vert
|
||
trompeur » que les cellules « Tests » par suite ou la colonne « Type » des Role
|
||
Profile — appliqué à la **surface data-derived distincte** : le NOM de job cité par
|
||
la fiche, jamais confronté à la définition réelle du workflow CI.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/*/AGENT.md` — colonne « Job CI » : 33 tokens `*-tests` répartis sur
|
||
13 fiches, chacun un nom de job Gitea Actions recopié à la main.
|
||
- Source faisant autorité : la section `jobs:` de `.gitea/workflows/ci.yml`.
|
||
- Piège : renommer un job dans ci.yml (`rbac-tests`→`rbac-role-tests`) ou mal
|
||
recopier `demo-scenario-tests` en `demo-scenarios-tests` laisse la fiche pointer
|
||
un job **fantôme** — le CI reste **vert** (le vrai job tourne sous son nouveau
|
||
nom), la doc d'identité de l'agent ment en silence. `check_ci_integrity` ne
|
||
regarde QUE le câblage `gate.needs`, aveugle au NOM cité par la prose.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Fiches agents · colonne
|
||
Job CI ») : on RECOMPUTE l'ensemble des jobs depuis la clé `jobs:` de ci.yml
|
||
(la section `on:` — push/pull_request/workflow_dispatch — est AVANT `jobs:` et donc
|
||
naturellement exclue ; jamais une liste à la main) et on exige que chaque token
|
||
`*-tests` cité dans une fiche y figure. Direction **fiche→ci.yml** (le
|
||
consommateur) : ci.yml peut définir des jobs non cités (légitime), mais une fiche
|
||
ne peut pas citer un job absent. La disparition totale de la colonne échoue AUSSI
|
||
(le recensement qui s'évapore est lui-même une régression).
|
||
|
||
**Morsures vérifiées (2)** : (1) token de fiche `seo-tests`→`seo-suite-tests`
|
||
(job fantôme, mord les 2 citations dans `seo/AGENT.md`) ; (2) job ci.yml
|
||
`rbac-tests` renommé `rbac-role-tests` → mord **SIMULTANÉMENT les 4 fiches** qui
|
||
le citent (`erpnext_backend`/`ifc_speckle`/`mobile`/`rendu`). État courant :
|
||
**33 références == jobs ci.yml**, exit 0. Working tree byte-restauré
|
||
(`cp` depuis backup + `git checkout` implicite — **JAMAIS** `git clean`, interdit
|
||
absolu). Sibling gates re-verts : `check_ci_integrity`/`check_docs`/
|
||
`guard_constraints`/`check_artifacts` = PASS.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Colonne Job CI
|
||
des fiches agents == section `jobs:` de ci.yml ») 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 ; aucun
|
||
déclenchement de workflow CI réel — analyse statique du YAML uniquement).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_040219` · Buffer S8 · Domaine CRM/DocType porteur : le **NOM du DocType porteur** `OTO Dossier Vente` — le **point d'attache** du pipeline vente (le Workflow s'y branche via son `document_type`) — était RECOPIÉ À LA MAIN à plusieurs endroits (titre + ligne « Nom du DocType » du README `crm/dossier_vente`, fiche `03_agents/crm/AGENT.md:25`, fiche `03_agents/onapi_legal/AGENT.md:50`) mais **AUCUN gate ne couvrait le NOM**. Le bloc CRM pipeline existant ne recompute que le **COMPTE d'états** (9), aveugle à l'identité ; aucune suite `tests/` (FONCTIONS de graphe) n'attrape la prose.
|
||
|
||
**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 classe d'IDENTITÉ
|
||
que les fiches de rôle RBAC (`agent-fiche-role-attrs-ungated`) ou l'identité du rôle
|
||
émetteur e-CF — appliquée à une **surface distincte** : le NOM d'un DocType porteur,
|
||
transcrit à ≥4 endroits et **asserté en prose égal** à `workflow.document_type`,
|
||
jamais confronté à l'artefact byte-gaté.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/dossier_vente/README.md:1` (titre « # DocType porteur ·
|
||
`OTO Dossier Vente` ») **et** `:29` (« **Nom du DocType** = `document_type` du
|
||
workflow (`OTO Dossier Vente`) »).
|
||
- `03_agents/crm/AGENT.md:25` — « **DocType porteur** `OTO Dossier Vente` : … sans
|
||
lui le pipeline n'a rien à quoi s'attacher ».
|
||
- `03_agents/onapi_legal/AGENT.md:50` — « cible = `workflow.document_type`
|
||
(`OTO Dossier Vente`) ».
|
||
- Source faisant autorité : `crm/dossier_vente/out/doctype_oto_dossier_vente.json`
|
||
(champ `name`, = `MANIFEST.doctype_name`, byte-gaté par `check_artifacts`). L'attache
|
||
est confirmée par `crm/workflow_vente/out/workflow.json[0].document_type` (byte-gaté).
|
||
- Piège : **RENOMMER** le DocType dans `doctype_spec.json`
|
||
(`OTO Dossier Vente`→`OTO Dossier de Vente`) reconstruit les DEUX artefacts de
|
||
façon COHÉRENTE (le `document_type` du workflow suit, les tests restent verts),
|
||
MAIS les mentions en prose se PÉRIMENT en silence → l'agent ERPNext Backend
|
||
importerait un DocType sous un nom pendant que la fiche/le README en nomment un
|
||
autre, et le Workflow s'attacherait à un DocType FANTÔME (la rupture même que
|
||
« sans lui le pipeline n'a rien à quoi s'attacher » veut prévenir).
|
||
- **État courant** : **aucun nom périmé** — les 4 mentions + les 2 artefacts
|
||
recoupent exactement (anti-invention #6, rien à réécrire). Le défaut est la
|
||
**surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM · IDENTITÉ du
|
||
DocType porteur » après le bloc CRM pipeline états) : on RECOMPUTE le nom depuis
|
||
`doctype_oto_dossier_vente.json[name]` et on exige que chaque prose le nomme EXACTEMENT
|
||
(regex backtické par mention). Cohérences croisées bonus (mordent un artefact
|
||
INTERNEMENT incohérent) : `DocType.name == MANIFEST.doctype_name` (cohérence interne)
|
||
· `== workflow.document_type` (**l'attache porteur↔workflow** — sinon le Workflow vise
|
||
un DocType fantôme). Un claim absent échoue AUSSI (traçabilité #6).
|
||
|
||
**7 morsures vérifiées** (3 côté artefact · 4 côté prose) : nom artefact renommé
|
||
(`name`→`OTO Dossier de Vente`) → mord **6 lignes en cascade** (incohérence interne +
|
||
attache rompue + les 4 mentions périmées) · `workflow.document_type` divergent →
|
||
**attache ROMPUE** seule · `MANIFEST.doctype_name` divergent → **incohérence interne**
|
||
seule · fiche `crm/AGENT.md:25` renommée · fiche `onapi_legal:50` renommée · ligne
|
||
« Nom du DocType » périmée · titre du README périmé ; restauré = green : 6 ✓ · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/
|
||
`check_docs`/`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (ligne récap du pipeline + paragraphe détaillé « IDENTITÉ du DocType
|
||
porteur `crm/dossier_vente` ») 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 ; l'import réel
|
||
du DocType puis du Workflow reste côté agent ERPNext Backend / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_043224` · Buffer S8 · Fiches agents/citation CLAUDE.md #10 : la prose « Anti-invention » de DEUX fiches — `03_agents/erpnext_backend/AGENT.md:57` (devises **USD + DOP** · format **Letter US** · paiements **Cardnet**, pas Stripe) et `03_agents/crm/AGENT.md:37` (devises **USD + DOP** · format **Letter US**) — RECOPIE À LA MAIN les valeurs canoniques de la contrainte NON-NÉGOCIABLE CLAUDE.md #10 en AFFIRMANT « cités depuis CLAUDE.md #10, jamais réinventés », mais AUCUN gate ne liait cette citation à #10.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement close ;
|
||
poursuite de la série anti-dérive d'ANCRAGE à CLAUDE.md (classe [[claude-md-constant-anchor-gate]]).
|
||
Même patron EXACT que le bloc « paramètres canoniques » faisabilite/generator (model.py
|
||
CANONICAL ↔ #9/#10) et publiciste/branding (4 tokens ↔ #4) — appliqué à une SURFACE
|
||
distincte : la prose des fiches agents qui se réclame de #10.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/erpnext_backend/AGENT.md:57` + `03_agents/crm/AGENT.md:37` — prose
|
||
« Anti-invention (#6) » citant en gras les tokens #10 (devises/format/paiement).
|
||
- Source faisant autorité : la contrainte NON-NÉGOCIABLE **CLAUDE.md #10**
|
||
(`**USD + DOP**` devises · `**Letter US**` format · `**Cardnet**` paiements (pas Stripe)).
|
||
- Le seul contrôle amont (bloc « paramètres canoniques ») n'ancre QUE
|
||
`faisabilite/generator/genlib/model.py` CANONICAL + son README — AVEUGLE à ces fiches.
|
||
Aucune suite `tests/` (FONCTIONS, jamais l'ancre à CLAUDE.md) n'attrape la prose.
|
||
- Piège #6 : RENOMMER le prestataire (`Cardnet`→`Azul`) ou changer une devise/format dans
|
||
CLAUDE.md #10 laisse ces citations PÉRIMÉES en silence, contredisant le mandat pendant
|
||
que la prose se réclame de « CLAUDE.md #10 » — « vert trompeur ».
|
||
|
||
**Gate ajouté** (bloc « Fiches agents · CITATION des constantes CLAUDE.md #10 ») :
|
||
réutilise les valeurs `exp` déjà recomputées de #9/#10 (zéro duplication) + le prestataire
|
||
EXCLU (`(pas X)`) recomputé de #10 ; config table par-fiche du SOUS-ENSEMBLE de tokens
|
||
qu'elle cite (crm omet le paiement) ; exige de chaque fiche l'ancre « CLAUDE.md #10 » +
|
||
chaque token en gras `**<valeur>**` == #10 (casse tolérée) + l'exclusion pour erpnext.
|
||
|
||
**5 morsures vérifiées** (restauré vert après chacune, 7 gates re-verts) :
|
||
1. CLAUDE.md #10 `Cardnet`→`Azul` → mord erpnext SEUL (crm ne cite pas le paiement) ✓
|
||
2. CLAUDE.md #10 devises `USD + DOP`→`USD + EUR` → mord les DEUX fiches ✓
|
||
3. CLAUDE.md #10 `(pas Stripe)`→`(pas PayPal)` → mord l'exclusion erpnext ✓
|
||
4. fiche crm `Letter US`→`Letter USA` → mord CRM (format) ✓
|
||
5. fiche erpnext supprime l'ancre `CLAUDE.md #10` → mord INTROUVABLE ✓
|
||
|
||
## Session `20260801_050225` · Buffer S8 · SEO/schema.org · IDENTITÉ du nœud racine `Organization` ancrée sur CLAUDE.md §Entités : le nom de marque **`Helios RD`** (la *marque publique* · **CLAUDE.md §Entités** « **Helios RD** (marque publique) sous WAG ») et son `url` == base_url du site, portés par le nœud racine du graphe JSON-LD `05_deliverables_mvp/seo/out/seo_schema_org.json`, étaient **byte-gatés pour la REPRODUCTIBILITÉ** (`check_artifacts` prouve que l'artefact se reconstruit depuis `seo_spec.json`) mais **JAMAIS ANCRÉS à CLAUDE.md**. Le bloc SEO schema.org amont gate la COMPOSITION (`@type` + bijection un-listing-par-projet), aveugle à l'IDENTITÉ de la marque que Google indexe.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive d'ANCRAGE à CLAUDE.md (classe
|
||
[[claude-md-constant-anchor-gate]]). **Même patron EXACT** que les tokens branding
|
||
`publiciste/branding` ancrés sur CLAUDE.md #4 et les paramètres canoniques
|
||
`faisabilite/generator` ancrés sur #9/#10 (`CANONICAL` ↔ contrainte) — appliqué à
|
||
une **surface distincte** : l'identité de marque émise dans le JSON-LD **public** de
|
||
`vente.otov7.com`, dont la reproductibilité byte était gatée mais pas l'ancrage.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/seo/out/seo_schema_org.json` `@graph` — nœud racine
|
||
`Organization` : `name: "Helios RD"` + `url: "https://vente.otov7.com"` +
|
||
`@id: ".../#organization"` ; chaque nœud `Residence` (listing) porte
|
||
`brand.@id == org.@id` + `address.addressCountry == "DO"`.
|
||
- `05_deliverables_mvp/seo/seo_spec.json[schema_org]` — l'INPUT du générateur :
|
||
`organization.name == "Helios RD"`, `country_code == "DO"`, et un bullet `source`
|
||
qui DÉCLARE l'ancrage « CLAUDE.md §Entites (Helios RD = marque publique sous WAG) ».
|
||
- Source faisant autorité : **CLAUDE.md §Entités** (« **Helios RD** (marque publique)
|
||
sous WAG ») pour la marque + `MANIFEST.base_url` (byte-gaté) pour le base_url + le
|
||
`country_code` du spec pour le géo-ciblage.
|
||
- Piège #6 : la byte-gate prouve que l'artefact se reconstruit **fidèlement… depuis
|
||
un spec dérivé**, PAS que le nom == CLAUDE.md. RENOMMER la marque dans
|
||
`seo_spec.json` (ou dans CLAUDE.md §Entités) puis régénérer laisse le JSON-LD
|
||
**public** émettre un nom de marque qui CONTREDIT le mandat pendant que
|
||
`check_artifacts` reste **VERT** — « vert trompeur ». Aucune suite `tests/`
|
||
(FONCTIONS de génération, jamais l'ancrage à CLAUDE.md) ne l'attrape.
|
||
- **État courant** : aucune valeur périmée — `name`/`url`/`@id`/rattachements/
|
||
`addressCountry`/déclaration du spec recoupent CLAUDE.md+MANIFEST+spec exactement
|
||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « SEO org » après le bloc
|
||
composition schema.org) : la marque est **re-dérivée** de CLAUDE.md §Entités
|
||
(parenthèse « (marque publique) », exigée présente 1× exactement · zéro duplication),
|
||
puis : **(a)** `Organization.name` == marque CLAUDE.md ; **(b)** `Organization.url`
|
||
== `MANIFEST.base_url` et `@id` sous base_url ; **(c)** chaque listing rattaché à
|
||
CETTE Organization (`brand.@id` == `org.@id`) et sous base_url ; **(d)**
|
||
`addressCountry` UNIFORME == `country_code` du spec (code ISO 2 lettres, géo-ciblage
|
||
appliqué à l'identique) ; **(e)** le spec DÉCLARE l'ancrage (`organization.name` ==
|
||
marque + `source` cite CLAUDE.md + la marque). Racine `Organization` exigée singleton
|
||
en pré-requis.
|
||
|
||
**6 morsures vérifiées** (restauré vert après chacune, 7 gates re-verts) :
|
||
1. **artefact** `Organization.name`→`Helios DR` → mord (a) anchor ✓
|
||
2. **CLAUDE.md §Entités** rename `Helios RD`→`Helios Dominicana` → mord
|
||
**SIMULTANÉMENT** (a) artefact ET (e) spec — l'ancre est vive ✓
|
||
3. **artefact** `Organization.url` divergent → mord (b) url/@id ✓
|
||
4. **artefact** un `addressCountry` `DO`→`US` → mord (d) uniformité géo ✓
|
||
5. **spec** `organization.source` supprime l'ancre CLAUDE.md → mord (e) déclaration ✓
|
||
6. **artefact** un listing `brand.@id`→`#phantom` → mord (c) rattachement ✓
|
||
|
||
Restauré = green : `Helios RD` == CLAUDE.md · url == base_url · 9 listings rattachés
|
||
sous base_url · addressCountry uniforme `DO` · spec déclare l'ancrage · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/
|
||
`check_docs`/`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé
|
||
« Identité du nœud racine `Organization` ancrée sur CLAUDE.md §Entités ») 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 ; l'injection
|
||
réelle du `<script type="application/ld+json">` dans les pages `vente.otov7.com`
|
||
reste côté agent Frontend/SEO / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_053228` · Buffer S8 · Legal/CONFOTUR · IDENTITÉ des ENTITÉS porteuses ancrée sur CLAUDE.md §Entités : le champ Select **`entite_porteuse`** du DocType `CONFOTUR Application` — le **menu déroulant** qui fixe QUELLE entité juridique porte chaque dossier d'incitation touristique — offre pour options les **7 entités canoniques** du mandat (`WAF` · `WA SRL` · `AC Arias Cuevas` · `Consortium ECR DR` · `Helios RD` · `Ploutos` · `9060 QC`). Ces options sont DÉRIVÉES via `options_source` de `confotur_spec.json[entites]` et **byte-gatées pour la REPRODUCTIBILITÉ** par `check_artifacts` (l'artefact `doctype_confotur_application.json` se reconstruit depuis le spec) mais **JAMAIS ANCRÉES** à CLAUDE.md §Entités, leur source faisant autorité. Les blocs CONFOTUR amont ne gatent que le COMPTE de champs/rôles et la cross-cohérence des PERMISSIONS, AVEUGLES à l'identité de cette liste d'entités.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive d'ANCRAGE à CLAUDE.md (classe
|
||
[[claude-md-constant-anchor-gate]]). **Même patron EXACT** que la marque SEO org
|
||
ancrée sur CLAUDE.md §Entités (session précédente `050225`) et les tokens branding
|
||
`publiciste/branding` ancrés sur #4 — appliqué à une **surface distincte du MÊME
|
||
§Entités** : le déroulant que l'agent ERPNext Backend importe (`bench
|
||
import-fixtures`), dont la reproductibilité byte était gatée mais pas l'ancrage.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/legal/confotur/out/doctype_confotur_application.json` — champ
|
||
`entite_porteuse` (Select · `reqd`), `options` = les 7 entités séparées par `\n`.
|
||
- `05_deliverables_mvp/legal/confotur/confotur_spec.json` — l'INPUT : `entites` (la
|
||
liste) + `entites_source` (DÉCLARE « CLAUDE.md #Entites (…) ») + le champ dont
|
||
`options_source: "entites"` (wiring : le déroulant DÉRIVE de la liste).
|
||
- `05_deliverables_mvp/legal/confotur/README.md:37-38` — prose « `entite_porteuse`
|
||
(Select) : entités CLAUDE.md (WAF · WA SRL · **AC** · Consortium ECR DR · Helios
|
||
RD · Ploutos · 9060 QC) » (abréviation éditoriale « AC » pour « AC Arias Cuevas »).
|
||
- Source faisant autorité : **CLAUDE.md §Entités** — les 7 tokens en gras
|
||
`**...**` de la section « ## Entités », dans l'ordre.
|
||
- Piège #6 : la byte-gate prouve que l'artefact se reconstruit **fidèlement… depuis
|
||
un spec dérivé**, PAS que la liste == CLAUDE.md. RENOMMER une entité dans
|
||
CLAUDE.md §Entités (`9060 QC`→`9061 QC`) OU dans `confotur_spec.json[entites]`
|
||
puis régénérer laisse le DocType offrir un menu qui CONTREDIT/omet une entité
|
||
canonique du mandat pendant que `check_artifacts` reste VERT — « vert trompeur ».
|
||
L'agent ERPNext Backend importerait un DocType dont le déroulant liste une entité
|
||
FANTÔME ou en omet une (la restriction même que `reqd` pose). Aucune suite
|
||
`tests/` (FONCTIONS de génération) ne l'attrape.
|
||
- **État courant** : aucune valeur périmée — options artefact / `entites` du spec /
|
||
déclaration / README recoupent CLAUDE.md §Entités 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 —
|
||
IDENTITÉ des ENTITÉS porteuses » avant `sys.exit`) : les 7 entités sont
|
||
**re-dérivées** des tokens en gras de la section « ## Entités » de CLAUDE.md
|
||
(uniques, non vides), puis : **(a)** options du Select de l'artefact == entités
|
||
CLAUDE.md (ORDRE exact) ; **(b)** `spec[entites]` == CLAUDE.md (l'INPUT ancré) ;
|
||
**(c)** le spec DÉCLARE l'ancrage (`entites_source` cite CLAUDE.md + chaque
|
||
entité) ; **(d)** wiring intact (`options_source == "entites"` — sinon le déroulant
|
||
est DÉCROCHÉ de la liste ancrée) ; **(e)** README cite l'ancre « CLAUDE.md » +
|
||
nomme chaque entité par **nom complet OU 1er token** (l'abréviation « AC » tolérée ·
|
||
#6, pas de réécriture d'une prose correcte pour satisfaire un gate). Un claim absent
|
||
échoue AUSSI (traçabilité #6).
|
||
|
||
**7 morsures vérifiées** (restauré vert après chacune, 7 gates re-verts) :
|
||
1. **CLAUDE.md §Entités** `9060 QC`→`9061 QC` → mord SIMULTANÉMENT (a) artefact +
|
||
(b) spec + (c) déclaration + (e) README = **4 bites** — l'ancre est vive ✓
|
||
2. **artefact** retire la dernière option → mord (a) ✓
|
||
3. **artefact** permute 2 options → mord (a) ORDRE ✓
|
||
4. **spec** `entites` renomme `Ploutos`→`Ploutos SA` → mord (b) ✓
|
||
5. **spec** `entites_source` retire « CLAUDE.md » → mord (c) ✓
|
||
6. **spec** champ `options_source`→`hardcoded` → mord (d) wiring ✓
|
||
7. **README** retire l'entité `Ploutos` de la ligne → mord (e) ✓
|
||
|
||
Restauré = green : options == CLAUDE.md (7, ordre) · spec == CLAUDE.md · spec
|
||
déclare l'ancrage · wiring == "entites" · README nomme les 7 · exit 0. Working tree
|
||
byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) ·
|
||
**7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/`check_docs`/
|
||
`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé
|
||
« Entités porteuses du DocType CONFOTUR ancrées sur CLAUDE.md §Entités ») 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 ; l'import réel
|
||
du DocType `CONFOTUR Application` reste côté agent ERPNext Backend / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_060234` · Buffer S8 · Legal/CONFOTUR — cross-cohérence PERMISSIONS répliquée dans la FICHE AGENT `03_agents/onapi_legal/AGENT.md:43-45` : la MÊME table role→portail→actions que le README du module, jamais gatée
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Classe explicitement
|
||
notée en mémoire (`agent-fiche-role-attrs-ungated`) : une fiche `03_agents/*/AGENT.md`
|
||
peut restituer la MÊME donnée data-derived qu'un README déjà gaté, sur une **surface
|
||
distincte** que le gate README ne voit pas.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/onapi_legal/AGENT.md:43-45` — §Permissions de la fiche de l'agent
|
||
ONAPI/Legal, annoncée « **mot pour mot** les `permissions_cibles` RBAC des 3
|
||
rôles » : `ventes-confotur` (portail Ventes) → read/write/create/print ·
|
||
`legal-onapi` (portail Direction) → read/write/create · `legal-directeur`
|
||
(portail Direction) → read/write/**submit**/report. Convention DIFFÉRENTE du
|
||
README du module (` / ` espacé · `**submit**` en gras).
|
||
- Source faisant autorité : `legal/confotur/out/MANIFEST.json`
|
||
(`roles_rbac_utilises[]` : `role_id` · `portail` · `permissions`, recomputé du
|
||
contrat `rbac_50_roles.json` à chaque build · byte-gaté par check_artifacts).
|
||
- Piège : le bloc « Legal confotur perms · cross-cohérence » existant ne gate QUE
|
||
la §Permissions du README du MODULE (`legal/confotur/README.md`), AVEUGLE à la
|
||
fiche. PROMOUVOIR `ventes-confotur` à `submit` (élévation de privilège · casse
|
||
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
|
||
dans la FICHE laisse celle-ci périmée pendant que l'artefact (et le README, lui
|
||
gaté) disent autre chose → l'agent ONAPI/Legal lirait sa PROPRE doc d'identité
|
||
mentant sur le jeu de permissions qu'il porte (le risque même que « mot pour
|
||
mot » promet d'écarter) — « vert trompeur » qu'aucune suite `tests/` (FONCTIONS
|
||
de mapping RBAC, jamais la prose de fiche) n'attrape.
|
||
- **État courant** : **aucune ligne périmée** — les 3 couples portée→actions et
|
||
leurs portails recoupent l'artefact exactement (anti-invention #6). Le défaut
|
||
est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Legal · CONFOTUR —
|
||
cross-cohérence PERMISSIONS répliquée dans la FICHE AGENT » après le bloc
|
||
cross-cohérence du README) : RÉUTILISE `conf_perm_by_id`/`conf_portail_by_id`
|
||
déjà dérivés du MANIFEST par le bloc README (ZÉRO duplication du contrat #6) ;
|
||
regex tolérant l'espacement ` / ` et le gras `**` ; PAR rôle le portail (casse
|
||
normalisée) ET le jeu d'actions exigés EXACTS (set-diff : absent ET en trop) ;
|
||
identité d'ensemble fiche⇔MANIFEST (aucun rôle fantôme ni manquant). Un claim
|
||
absent échoue AUSSI (traçabilité).
|
||
|
||
**6 morsures vérifiées** : fiche promeut `ventes-confotur`→`submit` (en trop) ·
|
||
fiche retire `create` de `legal-onapi` (absent) · fiche réaffecte portail
|
||
Ventes→Direction · fiche renomme `legal-directeur`→`legal-boss` (ligne
|
||
INTROUVABLE + ensemble absents/fantôme) · sous-liste entière supprimée (3
|
||
INTROUVABLES + ensemble vide) · **artefact** promeut `ventes-confotur`→`submit`,
|
||
fiche stale (le vrai « silent green » : source change, fiche fige) ; restauré =
|
||
green : 3 rôles portail+actions == MANIFEST · identité d'ensemble · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`) · **7
|
||
gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline · clause « 3e surface » 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 `20260801_063234` · Buffer S8 · Chat OTOIA/persona+capabilities : l'**IDENTITÉ de la persona** (`Amélie` / voix `multilingual_v2`) et des **4 CAPABILITIES OTOIA** (`aec.py` + `knowledge.py` + `prompt_engine.py` + `chat.py`) du montage Chat par portail `frontend/chat_otoia` — portées par `out/chat_mount.json` (5 configs runtime) + `out/MANIFEST.json`, **byte-gatés pour la reproductibilité** (`check_artifacts` prouve la reconstruction depuis `chat_spec.json`) mais **JAMAIS ANCRÉES à CLAUDE.md §Architecture cible**, leur source faisant autorité (« Voix Amélie QC (multilingual_v2) » l.30 · « OTOIA capabilities : aec.py + knowledge.py + prompt_engine.py + chat.py » l.28).
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive d'ANCRAGE à CLAUDE.md (classe
|
||
[[claude-md-constant-anchor-gate]]). **Même patron EXACT** que les tokens branding
|
||
`publiciste/branding` ancrés sur CLAUDE.md #4, la marque SEO `Organization` ancrée sur
|
||
§Entités, les paramètres canoniques `faisabilite/generator` ancrés sur #9/#10 —
|
||
appliqué à une **surface distincte** : la persona + les capabilities émises dans CHAQUE
|
||
portail rôle, dont la reproductibilité byte était gatée mais pas l'ancrage.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/frontend/chat_otoia/out/chat_mount.json` — les 5 mounts,
|
||
chacun `persona: {nom: "Amélie", voix: "multilingual_v2"}` +
|
||
`capabilities: [aec.py, knowledge.py, prompt_engine.py, chat.py]` ; idem
|
||
`out/MANIFEST.json` ; l'INPUT `chat_spec.json` (persona + `capabilities[].module`) ;
|
||
la table README:28-29 (« Persona `Amélie` / `multilingual_v2` » · « Capabilities
|
||
`aec/knowledge/prompt_engine/chat.py` » toutes deux annotées « `CLAUDE.md
|
||
§Architecture cible` »).
|
||
- Source faisant autorité : **CLAUDE.md §Architecture cible** (l.28 capabilities ·
|
||
l.30 « Voix Amélie QC (multilingual_v2) »).
|
||
- Piège #6 : le SEUL contrôle d'identité vit dans `tests/`
|
||
(`test_persona_amelie_sourcee` / `test_capabilities_sourcees_sans_ajout`) mais son
|
||
**ORACLE est HARDCODÉ** (`self.assertEqual(spec["persona"]["nom"], "Amélie")` ·
|
||
`caps == ["aec.py", …]`) — une **copie de plus, jamais comparée à CLAUDE.md**.
|
||
Renommer la persona (`Amélie`→`Sophie`), changer la voix, ou renommer/RETIRER une
|
||
capability dans `chat_spec.json` (ou dans CLAUDE.md) reconstruit l'artefact
|
||
fidèlement (byte-gate VERTE) sans toucher l'oracle du test (tests VERTS) → le chat
|
||
monté dans CHAQUE portail annoncerait une persona/voix/capabilities qui CONTREDIT le
|
||
mandat — « vert trompeur » qu'aucune suite `tests/` (FONCTIONS de génération, jamais
|
||
l'ancre à CLAUDE.md) n'attrape.
|
||
- **État courant** : **aucune valeur périmée** — persona + capabilities recoupent
|
||
CLAUDE.md exactement (anti-invention #6, rien à réécrire). Le défaut est l'**ancrage
|
||
ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Chat OTOIA · persona +
|
||
capabilities ancrées CLAUDE.md » avant `sys.exit`) : persona+capabilities re-dérivées
|
||
de CLAUDE.md §Architecture cible (regex `Voix … QC (…)` + `OTOIA capabilities : …`
|
||
split `+`, NFC), puis : **(a)** `chat_spec.json` persona/capabilities == CLAUDE.md
|
||
(ordre exact) ; **(b)** le spec DÉCLARE l'ancrage (`persona.source` + chaque
|
||
`capability.source` citent CLAUDE.md) ; **(c)** CHACUN des 5 mounts + le MANIFEST
|
||
portent persona/capabilities == CLAUDE.md ; **(d)** README cite l'ancre §Architecture
|
||
cible + nomme persona (`Amélie`+`multilingual_v2`) + chaque capability (notation
|
||
compacte matchée par radical) ; **(e)** l'ORACLE du test == CLAUDE.md (set-diff). Un
|
||
claim absent échoue AUSSI (traçabilité #6).
|
||
|
||
**8 morsures vérifiées** : CLAUDE.md `Amélie→Sophie` (mord SIMULTANÉMENT
|
||
spec/mount/README/oracle — 5 fails, l'ancre est vive) · CLAUDE.md retire `chat.py`
|
||
(3 fails) · spec `aec.py→exfil.py` (**capability injectée**) · spec `persona.source`
|
||
sans CLAUDE.md · **UN SEUL** mount à voix altérée (byte-gate aveugle) · README retire
|
||
le radical `prompt_engine` · oracle du test persona `Amélie→Bob` · oracle du test
|
||
capabilities réordonné/tronqué ; restauré = green : 5 sous-checks (a/b/c/d/e) verts ·
|
||
exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts** · unittest module `chat_otoia` re-vert.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Persona &
|
||
capabilities du Chat OTOIA ancrées sur CLAUDE.md §Architecture cible ») 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 ; l'import réel des
|
||
`Custom Block` + le câblage de l'endpoint OTOIA restent côté agent ERPNext Backend / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_070237` · Buffer S8 · Mobile/app_config : le **SDK MAJEUR Expo** (« Expo 54 ») — la version majeure que l'app compagnon cible, **ANCRÉE sur la roadmap Sprint 5 l.56** « Rebuild Expo 54 » — était transcrite À LA MAIN **cinq fois** dans le README SANS AUCUN gate d'IDENTITÉ ni d'ANCRAGE. Le bloc « Mobile · récap de l'app Expo » existant ne gate QUE le quadruplet onglets/rôles/langues/identifiants `a_confirmer` (comptes de `MANIFEST.counts`), AVEUGLE au majeur du SDK.
|
||
|
||
**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'ANCRAGE que
|
||
la marque SEO §Entités (`Helios RD` ancrée sur CLAUDE.md) ou les `roadmap_line` de la
|
||
recette `qa/acceptance` — appliqué ici à une valeur ancrée sur la **ROADMAP** (source
|
||
faisant autorité de la version Expo, CLAUDE.md ne la spécifiant pas).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/mobile/app_config/README.md:4/19/35/72` — « Expo 54 »
|
||
(×4 mentions) + la ligne de source « Expo SDK **54** | roadmap Sprint 5 l.56 ».
|
||
- Chaîne de dérivation (byte-gatée par `check_artifacts`) : roadmap Sprint 5 l.56
|
||
« Rebuild Expo 54 » (INPUT faisant autorité) → `mobile_spec.json[app]`
|
||
(`expo_sdk_major = 54` + `expo_sdk_source` cite la roadmap) →
|
||
`out/app_config.json.expo.extra.expoSdkMajor = 54` + `out/MANIFEST.json
|
||
.app.expo_sdk_major = 54`.
|
||
- Piège #6 : BUMPER le SDK (Expo 55 sort · `eas build` cible 55) dans le
|
||
spec/artefact SANS toucher au README (ou l'inverse), ou DÉRIVER la roadmap de
|
||
l'artefact, laisse la prose PÉRIMÉE en silence pendant que le graphe byte-gaté
|
||
dit autre chose → l'agent Mobile lancerait `eas build` sur le MAUVAIS SDK (le
|
||
rebuild même que la ligne roadmap prescrit). Aucune suite `tests/` (FONCTIONS de
|
||
génération, jamais la prose ni l'ancre à la roadmap) n'attrape ce « vert
|
||
trompeur ».
|
||
- **État courant** : aucune mention périmée — les 4 « Expo 54 », le spec, le
|
||
MANIFEST et la roadmap concordent (anti-invention #6, rien à réécrire). Le défaut
|
||
est la **surface ungated + non ancrée à la roadmap**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Mobile · le SDK MAJEUR
|
||
Expo … ANCRÉ sur la roadmap Sprint 5 l.56 », inséré avant `sys.exit`) : le majeur
|
||
`sdk` re-dérivé de `app_config.json` byte-gaté, puis (a) **cohérence interne**
|
||
artefact ⇔ `MANIFEST.app.expo_sdk_major` ⇔ `spec.app.expo_sdk_major` ; (b)
|
||
**ancrage roadmap** — `re.search("Rebuild Expo (\d+)")` sur
|
||
`04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` == `sdk` (ancre vive) ; (c) le spec DÉCLARE
|
||
l'ancrage (`expo_sdk_source` cite « roadmap » + « Expo N ») ; (d) **toute** mention
|
||
prose « Expo [SDK] N » (regex `Expo(?:\s+SDK)?\s*\*{0,2}(\d+)`) == `sdk` (aucune
|
||
périmée) ; (e) la ligne de source du tableau cite l'ancre `roadmap` à côté du majeur.
|
||
Un claim absent échoue AUSSI (traçabilité).
|
||
|
||
**7 morsures vérifiées** : README `Expo SDK **54**→**55**` (prose périmée) ·
|
||
**artefact** `54→55` (README + roadmap périmés = le vrai *silent green*) ·
|
||
**roadmap** `Rebuild Expo 54→55` (artefact périmé · ancre qui dérive) ·
|
||
**MANIFEST** `54→55` (chaîne interne incohérente) · spec `expo_sdk_source` sans
|
||
« roadmap » (ancrage déclaré manquant) · README ligne de source sans « roadmap »
|
||
(ancrage prose manquant) · README retire TOUTE mention « Expo N » (claim absent) ;
|
||
restauré = green : cohérence interne · ancre roadmap vive · spec déclare · 4
|
||
mentions == 54 · ligne source cite roadmap · exit 0. Working tree byte-restauré
|
||
(`git checkout --`, **JAMAIS** `git clean`) · **7 gates re-verts**.
|
||
|
||
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « SDK majeur Expo
|
||
de l'app mobile ancré sur la roadmap Sprint 5 l.56 ») 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 ; `eas build`/
|
||
`eas submit` App Store #32 / Play Store restent côté agent Mobile · VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_073239` · Buffer S8 · Fiscal/ecf_dgii : le JEU DE DEVISES `moneda` (`USD`/`DOP`) ANCRÉ sur CLAUDE.md #10 — le champ que `TipoMoneda` porte dans chaque e-CF DGII, byte-gaté pour la REPRODUCTIBILITÉ mais JAMAIS ancré à la contrainte. Le README s'en réclame « #10 » (README:37/57/77) ; les blocs fiscaux amont gatent le FormaPago (Cardnet · #10) + états/champs émetteurs, AVEUGLES au jeu de devises ; le bloc « Fiches #10 » ancre les fiches ERPNext/CRM, AVEUGLE au module fiscal.
|
||
|
||
**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'ANCRAGE que
|
||
les paramètres canoniques `faisabilite/generator` (#9/#10), la marque SEO §Entités
|
||
(`Helios RD`), la persona Chat OTOIA (§Architecture cible) ou les tokens branding #4
|
||
— appliqué ici à une valeur ancrée sur **CLAUDE.md #10** (« **USD + DOP** devises »).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/fiscal/ecf_dgii` — `moneda.options = ["USD","DOP"]` dans le
|
||
spec ET (byte-gaté par `check_artifacts`) dans `out/ecf_plan.json`.
|
||
- Chaîne de dérivation : CLAUDE.md #10 « **USD + DOP** devises » (INPUT faisant
|
||
autorité) → `ecf_spec.json[moneda].options` → `out/ecf_plan.json.moneda.options`
|
||
(copie verbatim par `ecflib/builder.py:79`).
|
||
- Piège #6 : **byte-gater une constante prouve la REPRODUCTIBILITÉ, PAS l'ANCRAGE**.
|
||
`check_artifacts` prouve `ecf_plan==build` depuis le spec, JAMAIS que
|
||
`spec[moneda]==#10`. RENOMMER/ÉTENDRE les devises dans CLAUDE.md #10
|
||
(`USD + DOP`→`USD + EUR`, ou +`EUR`) ET dans le spec de façon cohérente reste
|
||
byte-VERT tout en faisant émettre à l'e-CF un `TipoMoneda` d'une devise qui
|
||
CONTREDIT le mandat — « vert trompeur » qu'aucune suite `tests/` (FONCTIONS de
|
||
génération, jamais l'ancre à CLAUDE.md) n'attrape. L'agent ERPNext Backend
|
||
câblerait `Encabezado.TipoMoneda` sur une devise hors mandat (le risque même que
|
||
la cross-cohérence e-CF veut prévenir).
|
||
- **État courant** : aucune dérive — spec/artefact/README concordent avec #10
|
||
(anti-invention #6). Le défaut était la **surface byte-gatée mais non ancrée** +
|
||
l'absence de déclaration d'ancrage (`moneda.source` legitimement `null` car il
|
||
source le **taux TipoCambio**, à confirmer côté VPS · #8 — l'ancre des OPTIONS
|
||
devait vivre dans un champ DISTINCT).
|
||
|
||
**Correctif de déclaration** : nouveau champ `moneda.options_source` dans
|
||
`ecf_spec.json` (+ requis dans `ecf.schema.json`) citant « CLAUDE.md #10 — devises
|
||
**USD + DOP** » ; distinct de `source` (taux, reste `null`/`a_confirmer`). Artefact
|
||
`out/ecf_plan.json` régénéré (byte-gate re-verte · 39 tests module verts · le compte
|
||
`a_confirmer` inchangé, il ne teste que `moneda.a_confirmer`).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Fiscal · ecf_dgii — le JEU DE
|
||
DEVISES `moneda` … ANCRÉ sur CLAUDE.md #10 », inséré après la famille « Fiches
|
||
#10 ») : RÉUTILISE `exp["devises"]` déjà recomputé depuis #10 (zéro duplication),
|
||
`want_cur = re.findall("[A-Z]{3}", exp["devises"])`, puis (a) `spec[moneda].options`
|
||
== `want_cur` ORDRE EXACT (mord ajout/retrait/réordonnancement) ; (b) l'artefact
|
||
byte-gaté idem ; (c) `moneda.options_source` cite `CLAUDE.md #10` + chaque devise ;
|
||
(d1) la ligne README « devise (…USD/DOP… · #10) » cite le jeu EXACT ; (d2) toute
|
||
mention `moneda`/`devise` d'une paire de devises (scan ancré sur le contexte, évite
|
||
le faux positif `RNC / ITBIS`) == le jeu (aucune périmée). Un claim absent échoue
|
||
AUSSI (traçabilité).
|
||
|
||
**7 morsures vérifiées** : CLAUDE.md #10 `USD+DOP→USD+EUR` (l'ancre est vive →
|
||
mord a+b+c+d1 en cascade) · **spec** `options USD/DOP→USD/EUR` régénéré (le vrai
|
||
*silent green* → mord a) · **artefact** seul `USD→EUR` (spec+README périmés → mord
|
||
b) · **reorder** spec `[DOP,USD]` (ordre exact → mord a) · `options_source` sans
|
||
« CLAUDE.md #10 » (ancre déclarée manquante → mord c) · **README** ligne #10
|
||
`USD/DOP→USD/EUR` (prose périmée → mord d1) · **README** table `moneda USD/DOP→
|
||
USD/EUR` (mention périmée → mord d2) ; restauré = vert (a+b+c+d, 3 mentions
|
||
README concordantes · exit 0). Working tree byte-restauré (`git checkout --`,
|
||
**JAMAIS** `git clean`) · **7 gates re-verts** (validate_json · check_artifacts ·
|
||
check_readme_claims · check_docs · guard_constraints · check_ci_integrity ·
|
||
check_regression).
|
||
|
||
- `ci/README.md` (clause de récap du pipeline + paragraphe détaillé « jeu de
|
||
DEVISES `moneda` … 4e surface du MÊME README, ancré sur #10 ») mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
la confirmation du **TipoCambio** USD→DOP + l'émission réelle via Compupar
|
||
restent côté agent ERPNext Backend / Compta · VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session `20260801_080244` · Buffer S8 · SEO/projets_master — IDENTITÉ du CATALOGUE PROJETS (P01..P09) ANCRÉE sur CLAUDE.md §Projets
|
||
|
||
**Domaine** : SEO · `05_deliverables_mvp/seo/fixtures/projets_master.json` + artefacts `out/seo_schema_org.json`.
|
||
|
||
**Constat (anti-drift #6)** : la matière première du worker SEO est `projets_master.json` — 9 projets (`code` + `nom`) que le bundle SEO expose à Google (un listing `Residence` par projet dans le JSON-LD indexé sous `vente.otov7.com/projets/…`). Chaque entrée **DÉCLARE** `source.fichiers: ["CLAUDE.md#Projets"]` et le README:80 l'affirme (« 9 projets P01..P09 · noms sourcés de `CLAUDE.md §Projets` ») — **MAIS AUCUN gate ne le VÉRIFIAIT**. `check_artifacts` prouve QUE les `out/` se reconstruisent depuis la fixture (byte-for-byte), PAS que ses `code`/`nom` == CLAUDE.md §Projets ; les blocs SEO amont gatent les COMPTES de mots-clés, la COMPOSITION du graphe schema.org (bijection un-listing-par-projet) et l'IDENTITÉ de la marque racine `Helios RD` (§Entités) — tous AVEUGLES à l'identité de la **liste de projets**.
|
||
|
||
**Vert trompeur** : RENOMMER un projet dans CLAUDE.md §Projets (« Aqua Terra Las Terrenas » → « … Bay »), le RENOMMER/AJOUTER/RETIRER dans la fixture, puis régénérer, laisse le JSON-LD PUBLIC lister un projet FANTÔME ou en OMETTRE un canonique pendant que la byte-gate reste VERTE (l'artefact se reconstruit fidèlement… depuis une fixture DÉRIVÉE) et que le compte reste 9. Même classe EXACTE que la marque org (§Entités · session 050225), les entités CONFOTUR (§Entités · 053228) et les libellés projets du run_sheet démo (§Projets · déjà gaté). Aucune suite `tests/` (FONCTIONS de génération, jamais l'ancrage à CLAUDE.md) ne l'attrape.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « SEO · l'IDENTITÉ du CATALOGUE PROJETS ») — RE-DÉRIVE le catalogue de CLAUDE.md §Projets (zéro duplication · source unique), puis exige :
|
||
- **(a)** identité d'ensemble des codes fixture ⇔ CLAUDE.md §Projets (aucun fantôme/manquant · pas de doublon) ;
|
||
- **(b)** `nom` de chaque entrée == CLAUDE.md §Projets (accent-**insensible** : la fixture normalise « Xamaná »→« Xamana ») ;
|
||
- **(c)** chaque entrée DÉCLARE l'ancrage `CLAUDE.md#Projets` dans `source.fichiers` ;
|
||
- **(d)** les `name` des listings du graphe schema.org PUBLIC == l'ensemble des noms CLAUDE.md §Projets + bijection (1 listing/projet) + `MANIFEST.counts` projects/listings == |§Projets| ;
|
||
- **(e)** le README cite l'ancrage CLAUDE.md §Projets. Un claim absent échoue AUSSI (disparition = régression).
|
||
|
||
**Vérif** : 13 confirmations vertes (9 noms + set codes + listings schema.org + MANIFEST + README) ; **7 morsures vérifiées puis restaurées** — CLAUDE.md rename P07 (bite b+d simultanés, l'ancre est vive) · fixture nom drift P03 · fixture drop P09 (set manquant) · fixture add fantôme P10 (set fantôme) · fixture strip `source.fichiers` P01 · artefact schema.org rename `Structure`→`Estructura` (le vrai silent-green public) · README retire la citation §Projets. Restauré vert. **7 gates CI re-verts** (`check_readme_claims`, `check_artifacts`, `check_docs`, `check_ci_integrity`, `guard_constraints`, `check_regression`, `validate_json`).
|
||
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_083254` · Buffer S8 · DevOps/deploy_runbook — IMPUTABILITÉ des CONFIRMATIONS préalables VPS (owner + réf-contrôle) ancrée sur out/deploy_runbook.json ⨯ qa/audit_5d
|
||
|
||
**Domaine** : DevOps · `05_deliverables_mvp/devops/deploy_runbook/README.md:55-58`
|
||
(ligne « Confirmations préalables VPS ») ⨯ `out/deploy_runbook.json` (byte-gaté) ⨯
|
||
`05_deliverables_mvp/qa/audit_5d/out/audit_report.json` (byte-gaté).
|
||
|
||
**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 classe de « vert
|
||
trompeur » que la table run-book (2e surface `deploy_runbook`) ou l'identité du RÔLE
|
||
émetteur e-CF — appliquée à une **3e surface distincte du MÊME README `deploy_runbook`** :
|
||
non plus le COMPTE de confirmations ni l'ENSEMBLE de leurs noms (déjà gatés), mais
|
||
l'**imputabilité** de chacune — QUI la porte et QUEL contrôle audit_5d la trace.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `devops/deploy_runbook/README.md:55-58` — la ligne « Confirmations préalables VPS »
|
||
annote CHAQUE confirmation réglementaire d'un COUPLE data-derived
|
||
`nom` (**owner** · **réf-contrôle**) : `taux_commission` (Direction · audit_5d D1.1) ·
|
||
`rnc_emisor` (Compta · D1.2) · `itbis_tipocambio` (Fiscaliste eCF · D1.3) ·
|
||
`seuil_uaf` (Oficial de Cumplimiento · D2.3) · `endpoint_otoia` (ERPNext Backend ·
|
||
session 19). L'OWNER = qui doit confirmer le paramètre avant déploiement ; la RÉF =
|
||
le contrôle qa/audit_5d (`D#.#`) — ou la session — qui en assure le suivi.
|
||
- Sources faisant autorité (double, byte-gatées par `check_artifacts`) : (a) les
|
||
`confirmations` de `out/deploy_runbook.json` — chaque item porte `owner` + `source` ;
|
||
(b) `qa/audit_5d/out/audit_report.json` — chaque `control` (`D1.1`..`D5.3`) porte
|
||
SON PROPRE `owner`. L'owner et le contrôle ne vivent PAS dans le MANIFEST
|
||
(`confirmations_ouvertes` n'est qu'une liste de NOMS) : ils ne sont vérifiables que
|
||
contre ces deux artefacts croisés.
|
||
- Piège #6 : les blocs DevOps amont ne gatent que le COMPTE (2) et l'ENSEMBLE des
|
||
noms — AVEUGLES à QUI porte chaque confirmation et à QUEL contrôle la trace.
|
||
RÉAFFECTER `taux_commission` de Direction à Ventes (mauvais responsable escaladé →
|
||
confirmation jamais obtenue · séparation des pouvoirs cassée), MISATTRIBUER le
|
||
contrôle (`D1.1`→`D2.1`, pointant un contrôle qui ne trace PAS ce paramètre) ou
|
||
citer un contrôle FANTÔME (`D9.9`, absent d'audit_5d) laisse la prose périmée EN
|
||
SILENCE pendant que l'artefact/l'audit disent autre chose → l'agent DevOps
|
||
escaladerait le mauvais owner / le mauvais contrôle. Aucune suite `tests/`
|
||
(FONCTIONS de graphe) n'attrape ce « vert trompeur ».
|
||
- **État courant** : aucune annotation périmée — les 5 couples owner/réf recoupent
|
||
`deploy_runbook.json`, et les 4 réf `D#.#` existent dans audit_5d avec un owner
|
||
compatible (`Oficial de Cumplimiento` ⊆ `Oficial de Cumplimiento / UAF`, `Fiscaliste
|
||
eCF` ⊂ `Compta Fiscaliste eCF`) (anti-invention #6, rien à réécrire). Le défaut est
|
||
la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « 2ter) deploy_runbook —
|
||
IMPUTABILITÉ des CONFIRMATIONS » après le bloc table de phases) : confirmations
|
||
aplaties de `deploy_runbook.json` (unicité inter-phases), contrôle audit_5d résolu de
|
||
la `source` (`D#.#`), annotations README parsées `nom` (owner · réf), puis **(a)**
|
||
cross-module — chaque confirmation tracée porte un contrôle audit_5d RÉEL dont l'owner
|
||
est COMPATIBLE avec l'owner run-book (sous-ensemble de tokens · tolère « / UAF ») ET
|
||
elle reste ANNOTÉE au README ; **(b)** chaque annotation désigne une confirmation
|
||
RÉELLE (pas fantôme), owner README ⊆ owner run-book (tolère l'abréviation), et la réf
|
||
== contrôle réel (présent audit_5d + source) ou, pour une réf textuelle
|
||
(« session 19 »), présente dans la source. Un claim absent échoue AUSSI (traçabilité #6).
|
||
|
||
**9 morsures vérifiées** (4 côté README · 3 côté artefact · 2 réf) : README réaffecte
|
||
owner `Direction→Ventes` (mauvais responsable) · README misattribue `D1.1→D2.1`
|
||
(contrôle périmé vs source) · README cite contrôle fantôme `D9.9` · README retire
|
||
l'annotation de `taux_commission` (tracée par D1.1, INTROUVABLE) · **artefact**
|
||
réaffecte `taux_commission` owner→Ventes (README stale = le vrai *silent green* · mord
|
||
cross-module ET README⊆) · **artefact** audit_5d D1.1 owner `Direction→Finanzas`
|
||
(divergence inter-modules) · **artefact** source `seuil_uaf` `D2.3→D9.9` (contrôle
|
||
FANTÔME cité par la source) · README annotation fantôme (`endpoint_otoia→endpoint_xxx`) ·
|
||
README réf textuelle `session 19→session 42` (absente de la source) ; restauré = green :
|
||
5 couples owner/réf == artefacts croisés · 4 réf `D#.#` présentes audit_5d + source ·
|
||
exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit
|
||
absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/`check_docs`/
|
||
`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé « 3ᵉ
|
||
surface `devops/deploy_runbook` — imputabilité des confirmations ») 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 ; l'obtention
|
||
réelle des 7 confirmations auprès de leurs owners reste côté agent DevOps / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_093301` · Buffer S8 · RBAC/RBAC_50_ROLES_SPEC §3 — DÉFAUT FACTUEL corrigé + gate d'identité par portail
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6). Cette fois la surface data-derived non gatée était
|
||
**FAUSSE**, pas seulement à risque : la table §3 « Cartographie portails ↔ familles »
|
||
de `RBAC_50_ROLES_SPEC.md` (colonne « Nb rôles » PAR portail) avait dérivé du contrat
|
||
`rbac_50_roles.json` **en préservant le total 50**, donc en silence.
|
||
|
||
**Défaut factuel trouvé & corrigé** :
|
||
- `05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md:47` — portail `direction` affichait
|
||
**10** rôles ; le contrat en compte **9** (6 direction + CFO/finance + analyste
|
||
faisabilité + 2 legal).
|
||
- `…:52` — portail `plateforme` affichait **5** ; le contrat en compte **6** (devops ·
|
||
rbac-admin · qa · otoia · mobile · bi).
|
||
- L'erreur était compensée (10+5 vs 9+6) → total 50 exact → invisible aux gates
|
||
agrégés. Le MANIFEST roleprofile (byte-gaté) disait déjà 9 et 6 : la SPEC seule
|
||
avait dérivé. Corrigé pour refléter la source.
|
||
|
||
**Dérive silencieuse fermée (gate durable)** :
|
||
- `ci/check_readme_claims.sh` — nouveau bloc « 1quater) RBAC_50_ROLES_SPEC §3 » : RECOMPTE
|
||
le nombre de rôles PAR portail depuis `rbac/rbac_50_roles.json` (source de vérité,
|
||
byte-gatée par `check_artifacts`) et exige l'égalité avec CHAQUE ligne de la table §3
|
||
**plus le total** `**Total** | **50**`. Un portail absent de la table échoue aussi
|
||
(disparition = régression de traçabilité). Complète le gate roleprofile (qui gate le
|
||
MANIFEST, un doc distinct) sur une 2ᵉ surface transcrivant la même ventilation.
|
||
- Vérif négative : réintroduire `direction=10` fait échouer le gate (exit 1, message
|
||
« dit 10 MAIS rbac_50_roles.json compte 9 ») ; restauré → vert.
|
||
|
||
**Artefact régénéré (reproductibilité #artifact-reproducibility-gate)** :
|
||
- `qa/audit_4big/out/quality_report.json` — l'`evidence` DOC cite la taille en octets de
|
||
la SPEC (10040 → 10039 octets après correction −1 o) ; rebuild `audit_4big_gen.py build
|
||
-o out` byte-identique. `check_artifacts` re-vert.
|
||
|
||
**CI** : les 7 gates PASS (validate_json · check_artifacts · check_docs ·
|
||
check_readme_claims · guard_constraints · check_regression · check_ci_integrity).
|
||
|
||
- **Hors périmètre worker (VPS · #8)** : néant (correction d'un doc en-repo + gate
|
||
bash/python3 stdlib ; l'unique artefact `out/` touché a été régénéré à l'identique).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_100301` · Buffer S8 · RBAC/RBAC_50_ROLES_SPEC §7 — comptes du run-book d'application ancrés sur le contrat rbac_50_roles.json
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6). Même classe que le §3 gaté à la session précédente
|
||
(`093301`, per-portail) : une **2ᵉ surface de la MÊME SPEC** transcrivant à la main des
|
||
comptes data-derived, déjà gatés ailleurs mais AVEUGLES à cette note (mémoire
|
||
[[rbac-spec-portail-count-gate]]).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md` §7 — la NOTE « ✅ … est **livré**
|
||
en-repo » restitue TROIS comptes du run-book d'application sur une **surface
|
||
DISTINCTE** des READMEs `userperm_gen` / `roleprofile_gen` (déjà gatés) et du §3
|
||
(ventilation par portail, bloc `1quater`) : « **28** templates `Company` (portée
|
||
`entite`) » · « **6 profils** (**5** portails métier + console technique
|
||
`plateforme`) » · « **50 rôles de façon bijective** ».
|
||
- Source faisant autorité : `rbac/rbac_50_roles.json` (contrat, byte-gaté par
|
||
`check_artifacts`). Recomputes : 28 == |`scope_donnees == entite`| (= nombre de
|
||
`User Permission` templates) · 6 == |portails distincts| (1 `Role Profile` par
|
||
portail) · 5 == portails **métier** (hors `plateforme`) · 50 == |rôles|.
|
||
- Piège #6 : BUMPER une portée `entite`→`groupe` (le décompte de templates change) ou
|
||
AJOUTER/RETIRER un portail (le décompte de profils change) dans le contrat périme la
|
||
note EN SILENCE pendant que les READMEs de volet et le §3 restent verts → l'agent
|
||
ERPNext Backend lirait un run-book promettant un décompte faux. Aucune suite `tests/`
|
||
(FONCTIONS de génération/résolution RBAC, jamais la prose de la SPEC) n'attrape ce
|
||
« vert trompeur ».
|
||
- **État courant** : aucun compte périmé — 28/6/5/50 recoupent le contrat exactement
|
||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « 1quinquies) RBAC_50_ROLES_SPEC §7 »
|
||
après le bloc §3) : réutilise `src_roles` (contrat) + `spec_rd` (déjà chargés par le
|
||
§3, zéro duplication). Le blockquote markdown `> ` de la note survit au collapse de
|
||
`read_norm` et fragmente la prose (« 28 > templates ») ⇒ **neutralisé** (`spec7 =
|
||
spec_rd.replace("> ", "")`) avant match. Exige : (a) « N templates `Company` (portée
|
||
`entite`) » == |scope==entite| ; (b) « **N profils** (M portails métier + console
|
||
technique `plateforme`) couvrant les **K rôles de façon bijective** » == |portails
|
||
distincts|/|métier hors plateforme|/|rôles|. Garde anti-typo : `plateforme` doit exister
|
||
au contrat (sinon la note « console technique plateforme » est fausse). Un claim absent
|
||
échoue AUSSI (INTROUVABLE = régression #6).
|
||
|
||
**6 morsures vérifiées** (restauré vert après chacune) : SPEC `28→27` (prose périmée) ·
|
||
SPEC `6 profils→7` · SPEC `5 portails métier→4` · SPEC `50→49` · **contrat** une portée
|
||
`entite→groupe` (28→27 · README stale = le vrai *silent green* · « SPEC dit 28 MAIS
|
||
compte 27 ») · SPEC retire « 28 templates » (claim absent = INTROUVABLE) ; restauré =
|
||
green : UP templates 28 == |entite| · Role Profiles 6 (métier 5) bijectifs sur 50 ==
|
||
contrat · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`,
|
||
interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/
|
||
`check_docs`/`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé « Comptes
|
||
du run-book d'application `RBAC_50_ROLES_SPEC.md` §7 ») mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; l'application `bench` réelle
|
||
reste côté agent ERPNext Backend / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_103304` · Buffer S8 · Chat OTOIA — IDENTITÉ des configs runtime (persona · langues · endpoint) dans la fiche Frontend Console
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6, classe « fiche agent qui restitue des attributs
|
||
data-derived, gatée uniquement sur des COMPTES agrégés » — mémoire
|
||
[[agent-fiche-role-attrs-ungated]]).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/frontend_console/AGENT.md:29` — la cellule « Métrique vérifiée » du
|
||
livrable `chat_otoia` restitue TROIS attributs data-derived du montage OTOIA :
|
||
« persona **Amélie** … · langues **FR/EN/ES** · `` `endpoint: null` `` ». Le bloc
|
||
chat_otoia amont (`ci/check_readme_claims.sh`) ne recompute que le **COMPTE**
|
||
blocks/mounts/portails (tous = 5) — AVEUGLE à CE QUE dit chaque config runtime.
|
||
- Le gate persona/capabilities « ancré sur CLAUDE.md §Architecture cible » vise le
|
||
spec, les 5 mounts, le MANIFEST, le README et l'oracle du test — **JAMAIS** cette
|
||
cellule de fiche, et il ignore langues comme endpoint. La cellule était donc une
|
||
surface data-derived ungated de plus.
|
||
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
|
||
`frontend/chat_otoia/out/chat_mount.json` (une config par portail · 5) +
|
||
`out/MANIFEST.json` (persona/langues/endpoint_statut consolidés).
|
||
- **`endpoint: null` = AFFIRMATION D'HONNÊTETÉ #6/#8** : l'endpoint OTOIA n'est PAS
|
||
fabriqué (renseigné côté VPS · agent Frontend). Qu'une config gagne un endpoint réel
|
||
dans l'artefact et la fiche « endpoint: null » devient un MENSONGE en silence.
|
||
- **État courant** : aucun attribut périmé — persona `Amélie` · langues `fr/en/es` ·
|
||
`endpoint == null` sur les 5 mounts ET le MANIFEST (anti-invention #6, rien à
|
||
réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Chat OTOIA · IDENTITÉ des configs
|
||
runtime (persona · langues · endpoint) » après le bloc de COMPTE chat_otoia) : charge
|
||
`MANIFEST.json` + `chat_mount.json` (5 configs) et exige, sur la cellule de la fiche
|
||
(regex `persona (\S+) QC · langues ([A-Z/]+) · \`endpoint: ([^\`]+)\``, ne matche QUE
|
||
la ligne :29, pas la prose Scope :12) : (a) persona == `MANIFEST.persona.nom` (le
|
||
« QC » est le qualificatif de marque `Voix Amélie QC` de CLAUDE.md, gardé en littéral
|
||
NON gaté) ; (b) langues `FR/EN/ES` == `MANIFEST.langues` en majuscule ; (c) `endpoint:
|
||
null` avec `all(m.endpoint is None)` sur les 5 mounts (sinon `exp_endpoint` devient
|
||
`NON-null(...)` ⇒ morsure d'honnêteté). Cohérences croisées : `MANIFEST.persona.nom`
|
||
et `MANIFEST.langues` == CHAQUE mount (montage désynchronisé mordu) ·
|
||
`endpoint_statut == 'a_confirmer'` ⇔ endpoints TOUS null (incohérence interne
|
||
artefact sinon). Un claim absent échoue AUSSI (INTROUVABLE = régression #6). Aucune
|
||
suite `tests/` (FONCTIONS du builder, jamais la prose de la fiche) n'attrape ce
|
||
« vert trompeur ».
|
||
|
||
**6 morsures vérifiées** (restauré vert après chacune) : fiche persona `Amélie→Amelia`
|
||
(mismatch) · fiche langues `FR/EN/ES→FR/EN` · fiche `endpoint: null→endpoint: fixé` ·
|
||
**artefact** un mount `endpoint null→URL réelle` (bascule d'honnêteté ET incohérence
|
||
`endpoint_statut='a_confirmer'` — le vrai *silent green* : l'endpoint fabriqué pendant
|
||
que la fiche promet `null`) · fiche retire le bloc attributs (claim absent =
|
||
INTROUVABLE) · **artefact** un mount `persona Amélie→Nadia` (montage désynchronisé du
|
||
MANIFEST). Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`,
|
||
interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_artifacts`/
|
||
`check_docs`/`guard_constraints`/`check_regression`/`check_ci_integrity`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé sous le
|
||
bloc de COMPTE chat_otoia, avec renvoi au gate persona/capabilities distinct) mis à
|
||
jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; le câblage réel de l'endpoint
|
||
OTOIA + web-component reste côté agent Frontend / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_110311` · Buffer S8 · SEO — IDENTITÉ des 2 métriques data-derived (schema.org · hreflang) de la fiche agent
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6, classe « fiche agent qui restitue des attributs
|
||
data-derived, gatée uniquement en AGRÉGAT » — mémoire
|
||
[[agent-fiche-role-attrs-ungated]] ; même patron que la cellule chat_otoia de la
|
||
fiche Frontend Console traitée à la session précédente).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/seo/AGENT.md:25-26` — le tableau « Livrable réellement produit »
|
||
restitue DEUX sorties byte-gatées du bundle SEO à côté du compte de mots-clés
|
||
(lui déjà gaté sur README ET fiche) :
|
||
- L25 : « graphe JSON-LD : **10 nœuds** (`Organization` + 9 `Residence`) »
|
||
- L26 : « **10 pages** × FR/EN/ES + `x-default` »
|
||
- Les blocs SEO schema.org (`SEO_SG_RD`) et hreflang (`SEO_HL_RD`) amont ne lisent
|
||
QUE `seo/README.md` — JAMAIS la fiche. `SEO_FI` n'était utilisé que par le bloc
|
||
de COMPTE de mots-clés. Ces deux cellules étaient donc des surfaces data-derived
|
||
ungated : RENOMMER le `@type` des listings, AJOUTER/RETIRER un projet (→ N nœuds
|
||
& N pages dérivent) ou ÉCHANGER une langue de contenu périme la fiche pendant que
|
||
les trois artefacts byte-gatés (`seo_schema_org.json`/`MANIFEST.json` et
|
||
`seo_hreflang.json`) disent autre chose — « vert trompeur » qu'aucune suite
|
||
`tests/` (FONCTIONS du builder, jamais la prose de la fiche) n'attrape.
|
||
- **État courant** : aucune métrique périmée — 10 nœuds (1 `Organization` + 9
|
||
`Residence`) · 10 pages · langues `fr/en/es` + `x-default` (anti-invention #6,
|
||
rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « SEO · FICHE AGENT » inséré
|
||
après le bloc hreflang README, réutilise les vérités déjà recomputées par les blocs
|
||
schema.org/hreflang amont — zéro duplication #6) :
|
||
- L25 (regex `graphe JSON-LD : \*\*(\d+) nœuds\*\* \(`<racine>` \+ (\d+)
|
||
`<listing>`\)`) : total == `schema_org_nodes` · racine == `@type` singleton du
|
||
graphe · M == `listings` · type listing == `@type` uniforme des listings ·
|
||
cohérence arithmétique `total == 1 + M`.
|
||
- L26 (regex `\*\*(\d+) pages\*\* × ([A-Z/]+) \+ `x-default``) : `|pages|` == carte
|
||
hreflang · jeu de langues (lower) == langues de contenu de l'artefact (set-diff :
|
||
absent ET en trop).
|
||
- Un claim absent échoue AUSSI (INTROUVABLE = régression #6).
|
||
|
||
**8 morsures vérifiées** (restauré vert après chacune) : nœuds `10→11` · listing
|
||
`Residence→Apartment` · racine `Organization→LocalBusiness` · listings `9→8`
|
||
(casse l'arithmétique ET la bijection) · pages `10→12` · langue `es→pt` · retrait
|
||
`es` (`FR/EN`) · retrait du claim L25 (INTROUVABLE). Working tree byte-restauré
|
||
(`git checkout --`, **JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts**
|
||
(`check_readme_claims`/`check_artifacts`/`check_docs`/`guard_constraints`/
|
||
`check_regression`/`check_ci_integrity`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé « Fiche
|
||
agent SEO — 2 métriques data-derived » après le paragraphe hreflang) mis à jour.
|
||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; l'injection réelle des
|
||
balises hreflang/JSON-LD dans les pages reste côté agent Frontend/SEO / VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_113314` · Buffer S8 · RBAC/RBAC_50_ROLES_SPEC §4 — colonne « Entité » de la « Cartographie rôles ↔ entités » ancrée sur CLAUDE.md §Entités ⨯ rbac_50_roles.json
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6, double classe « ANCRAGE à CLAUDE.md »
|
||
([[claude-md-constant-anchor-gate]]) **et** « identité d'ensemble recomputée du
|
||
contrat RBAC » [[rbac-spec-portail-count-gate]]). Même patron que les entités CONFOTUR
|
||
`entite_porteuse` (session 053228, §Entités) et les comptes SPEC §3/§7 — appliqué à
|
||
une **section encore ungated de la MÊME SPEC** : la table §4.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md` §4 « Cartographie rôles ↔ entités » —
|
||
la **colonne de tête** liste les entités porteuses (`entite_principale`) : les **7
|
||
entités NOMMÉES** du mandat (`WAF` (holding) · `WA SRL` · `AC Arias Cuevas` ·
|
||
`Consortium ECR DR` (paymaster RH) · `Helios RD` (marque publique) · `Ploutos`
|
||
(patrimoine/monétaire) · `9060 QC` (World Activities Cdn.)) + le périmètre consolidé
|
||
« **Groupe** (consolidé) ».
|
||
- **Deux sources faisant autorité** : (i) **CLAUDE.md §Entités** — l'orthographe + le
|
||
descripteur parenthétique de chaque entité nommée ; (ii) `rbac_50_roles.json`
|
||
(byte-gaté via les 3 MANIFEST) — l'ENSEMBLE des `entite_principale` réellement portées
|
||
par les 50 rôles (distinct = 11 Helios RD · 11 WA SRL · 10 AC Arias Cuevas · 8 Groupe ·
|
||
5 9060 QC · 3 WAF · 1 Ploutos · 1 Consortium ECR DR = 50).
|
||
- Piège : le §3 gate les comptes par **portail**, le §7 les comptes du run-book, les
|
||
blocs fiches l'`entite` d'**UN** rôle ; tous **aveugles à l'identité de CETTE liste**.
|
||
AJOUTER au contrat un rôle porté par une entité absente de §4 (menu périmé), RENOMMER
|
||
une entité dans CLAUDE.md §Entités (`9060 QC→9061 QC`) ou DÉRIVER un descripteur laisse
|
||
la SPEC contredire le mandat/le contrat EN SILENCE — « vert trompeur » qu'aucune suite
|
||
`tests/` (FONCTIONS RBAC, jamais la prose de la SPEC) n'attrape.
|
||
- **État courant** : aucune ligne périmée — §4 == distinct contrat (8 entités) · les 7
|
||
descripteurs == CLAUDE.md §Entités · aucune entité décorative (anti-invention #6, rien
|
||
à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc `1sexies` après le §7, réutilise
|
||
`src_roles`/`spec_rd`/`SPEC_RD` déjà en scope · extraction fraîche de CLAUDE.md §Entités
|
||
— `_nfc` défini plus bas, non requis, entités ASCII) :
|
||
- **(a) ENSEMBLE** — entités de la colonne §4 (`| **Entité** (desc)? |`) == distinct
|
||
`entite_principale` du contrat (set-diff : `manquantes` = portées mais hors §4 ·
|
||
`fantômes` = listées mais jamais portées).
|
||
- **(b) ANCRAGE** — chaque entité NOMMÉE de CLAUDE.md §Entités (tokens en gras) est une
|
||
ligne §4 ET son descripteur parenthétique == CLAUDE.md **EXACT** (absence comprise :
|
||
`WA SRL`/`AC Arias Cuevas` = sans descripteur des deux côtés).
|
||
- **(c)** chaque entité nommée du mandat est PORTÉE ≥1× par le contrat (`cm_ents ⊆
|
||
contrat`, aucune décorative).
|
||
- Section `## 4.` INTROUVABLE = claim absent = régression #6.
|
||
|
||
**8 morsures vérifiées** (4 côté contrat/CLAUDE.md · 4 côté SPEC) : contrat +rôle porté
|
||
par entité `Fantasia` absente de §4 (`(a)` manquante) · contrat `Ploutos→Ploutos SRL`
|
||
sur tous les rôles (`(a)` fantôme+manquante · `(c)` `Ploutos` décorative) · CLAUDE.md
|
||
`9060 QC→9061 QC` (`(b)` absent · `(c)` décorative) · CLAUDE.md descripteur
|
||
`(holding)→(holding co)` (`(b)` mismatch) · SPEC §4 `AC Arias Cuevas→AC Arias` (`(a)`
|
||
fantôme+manquante · `(b)` absent) · SPEC §4 descripteur `marque publique→marque privée`
|
||
(`(b)` mismatch) · SPEC §4 retire la ligne « Groupe » (`(a)` manquante) · SPEC supprime
|
||
l'en-tête `## 4.` (INTROUVABLE) ; restauré = green : 9 ✓ (`(a)` 8 entités · `(b)` 7
|
||
descripteurs · `(c)` 7 portées) · exit 0. Working tree byte-restauré (`git checkout --`,
|
||
**JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts** (`check_readme_claims`/
|
||
`check_artifacts`/`check_docs`/`guard_constraints`/`check_regression`/
|
||
`check_ci_integrity`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la ligne récap du pipeline + paragraphe détaillé « Colonne
|
||
Entité de la §4 ancrée sur CLAUDE.md §Entités ») 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 ; le seed réel des
|
||
rôles/entités `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_120319` · Buffer S8 · Frontend Console/AGENT.md — IDENTITÉ de l'ENSEMBLE des portails métier + exclusion nommée de la console technique
|
||
|
||
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
|
||
série anti-dérive CLAUDE.md #6 — fiche-agent qui restitue une donnée gatée seulement
|
||
en AGRÉGAT/COMPTE, cf. [[agent-fiche-role-attrs-ungated]]). Même patron que
|
||
l'énumération ordonnée des onglets Mobile (`role_navigation`) et la colonne « Entité »
|
||
de la SPEC §4 ([[rbac-spec-portail-count-gate]]) — appliqué à une surface encore ungated
|
||
de la fiche **Frontend Console**.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/frontend_console/AGENT.md` restitue à la main, en **deux endroits**
|
||
data-derived, l'IDENTITÉ de l'ensemble des portails — jamais gatée hors le COMPTE :
|
||
- **L11** « **5 portails rôle métier** (Ventes / Construction / Achat / Compta /
|
||
Direction) » — l'ENSEMBLE ORDONNÉ des noms courts.
|
||
- **L46** « la console technique `plateforme` (**6ᵉ portail RBAC**) est **exclue** »
|
||
— l'identité + le rang + la non-appartenance au métier de la console exclue.
|
||
- **Deux artefacts faisant autorité** : (i) `frontend/portails/out/MANIFEST.json`
|
||
(byte-gaté) — les workspaces métier (`OTO Ventes` … → noms courts sans le préfixe
|
||
« OTO ») ; (ii) `rbac_50_roles.json` — `portails_business` (l'ordre du contrat) + les
|
||
portails distincts des rôles (6 : 5 métier + `plateforme`).
|
||
- Piège : le bloc « triplets par workspace » recompute cartes/liens/rôles **par**
|
||
portail mais reste **aveugle à QUELS portails** composent l'ensemble ; les autres
|
||
gates comptent « 5 » sans jamais confronter le SET. Un ÉCHANGE (Achat→Marketing),
|
||
RETRAIT, RÉORDRE, RENOMMAGE de la console technique dans le contrat
|
||
(`plateforme`→`console`) ou un contrat qui PROMEUT `plateforme` en métier laisse la
|
||
fiche contredire les artefacts EN SILENCE — « vert trompeur » qu'aucune suite
|
||
`tests/` (FONCTIONS RBAC, jamais la prose) n'attrape.
|
||
- **État courant** : aucune dérive — L11 == workspaces frontend == `portails_business` ·
|
||
L46 `plateforme` == unique portail RBAC hors métier == 6ᵉ. Le défaut est la **surface
|
||
ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Portails ensemble » juste après le
|
||
bloc triplets, réutilise `ws_list`/`ws_fi`/`WS_FI` déjà en scope · relit le contrat
|
||
`rbac_50_roles.json`) :
|
||
- **(a) ENSEMBLE** — noms courts ordonnés (label `MANIFEST.workspaces[].workspace` sans
|
||
« OTO ») == énumération L11 (compte + absents/en trop + ordre) **ET DOUBLE ANCRAGE**
|
||
les ids workspaces frontend == `portails_business` du contrat (l'« égalité stricte »
|
||
que la fiche revendique en L47).
|
||
- **(b) EXCLUSION** — `plateforme` == l'UNIQUE portail RBAC hors métier
|
||
(`distinct(roles.portail) ∖ portails_business`, len==1), nommé EXACTEMENT dans L46,
|
||
de rang == `|distinct|` (6ᵉ), avec `**exclue**` structurellement exigé (regex `\S*`
|
||
absorbe l'exposant « ᵉ » multi-octets sans le coder en dur).
|
||
- Claim absent (L11 ou L46 INTROUVABLE) = régression #6.
|
||
|
||
**8 morsures vérifiées** (6 côté fiche · 2 côté contrat) : L11 `Achat→Marketing`
|
||
(`(a)` en trop/absent) · L11 retire `Compta` (`(a)` compte+absent) · L11 réordonne
|
||
`Ventes↔Construction` (`(a)` ordre) · L46 `plateforme→console` (`(b)` nom) · L46
|
||
`6ᵉ→7ᵉ` (`(b)` rang) · L46 retire `**exclue**` (INTROUVABLE) · contrat réordonne
|
||
`portails_business` (ancrage rompu) · contrat `ventes→sales` dans `portails_business`
|
||
(ancrage rompu + `plateforme` n'est plus l'unique hors-métier ⇒ 2 fails) ; restauré =
|
||
green (3 ✓ : double ancrage · énumération L11 · console technique L46) · exit 0.
|
||
Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) ·
|
||
**7 gates re-verts** (`check_readme_claims`/`check_artifacts`/`check_docs`/
|
||
`guard_constraints`/`check_regression`/`check_ci_integrity`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause de la ligne récap du pipeline + paragraphe détaillé « Ensemble
|
||
des portails métier + exclusion nommée de la console technique ») 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 ; le seed réel des
|
||
Workspaces/rôles `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Sprint 8 · buffer · Gate d'IDENTITÉ de la colonne « Entrée CLI » des fiches agents — verbes documentés == subparsers argparse réels
|
||
|
||
**Classe fermée** : `agent-fiche-role-attrs-ungated` (mémoire) — sous-classe « colonne
|
||
CLI ». Chaque table de livrables des fiches `03_agents/*/AGENT.md` porte une colonne
|
||
« Entrée CLI » citant, entre backticks, le point d'entrée du module ET son jeu de
|
||
verbes (`publiciste.py parse|validate|generate|run`, `faisabilite_gen.py
|
||
score|scaffold|generate|batch`, `rbac_apply_plan.py build|validate`, …). Cette liste
|
||
est **saisie à la main**. Les gates amont couvrent déjà génériquement — pour TOUTES les
|
||
fiches, via `git ls-files` — la colonne « Tests » (recomputée depuis `regression_plan`)
|
||
et la colonne « Job CI » (contre `ci.yml`), mais **RIEN** ne vérifiait que les VERBES
|
||
écrits sont ceux que le CLI **expose réellement**.
|
||
|
||
**Piège** : renommer une sous-commande (`generate`→`render`), en AJOUTER une
|
||
(`publish`), en RETIRER une ou les RÉORDONNER laisse la fiche documenter une surface
|
||
d'invocation **fantôme** : le module tourne (le CI appelle le vrai verbe), la doc
|
||
d'identité de l'agent — celle qui lui dit COMMENT lancer son propre livrable — ment en
|
||
silence. Aucune suite `tests/` (FONCTIONS du module, jamais la prose de fiche) ne
|
||
l'attrape. Classe explicitement notée en mémoire.
|
||
|
||
**Gate ajoutée** (`ci/check_readme_claims.sh`, bloc « colonne Entrée CLI », après le
|
||
bloc « Job CI fiches ») : `_cli_subcommands()` **RECOMPUTE** via **AST** l'ensemble
|
||
ORDONNÉ des `subparsers.add_parser("<verbe>")` de chaque script (jamais une liste à la
|
||
main · #6). Résolution du script : chemin du module de la MÊME ligne de table (lien
|
||
`…/05_deliverables_mvp/<path>/README.md`) + basename du CLI → `{D}/<path>/<file>.py`
|
||
(chaque cellule liée à SON module · pas de collision de basename). Égalité EXIGÉE
|
||
**exacte** — ensemble ET ordre (l'ordre de `add_parser` == ordre de l'aide argparse).
|
||
Les `|` séparateurs markdown sont échappés `\|` dans les cellules : dé-échappés avant
|
||
découpe. Direction fiche→CLI : la fiche ne peut pas mentir sur les verbes du script.
|
||
**16 cellules** gatées (6 fiches : crm×3 · devops · erpnext_backend×5 · faisabilite×2 ·
|
||
publiciste · qa×4 — dont `audit_5d_gen.py`/`audit_4big_gen.py` que les regex `[a-z_]`
|
||
manquaient, d'où `[a-z0-9_]`). Actuellement **toutes exactes** — la gate verrouille
|
||
l'état correct.
|
||
|
||
**7 morsures vérifiées** (restaurées vert après chaque) :
|
||
1. FICHE renomme verbe (`generate→render`) → manquants/en trop, `seul_ordre_diffère=False`.
|
||
2. FICHE ajoute verbe fantôme (`publish`) → en trop.
|
||
3. FICHE retire un verbe (`batch`) → manquant.
|
||
4. FICHE réordonne (`parse|validate`↔) → `seul_ordre_diffère=True` (ordre discriminé).
|
||
5. **Le vrai « vert trompeur »** : `add_parser("generate")→("render")` dans le `.py`,
|
||
fiche INCHANGÉE → red (la source de vérité a bougé sous la fiche).
|
||
6. Nouveau `add_parser("audit")` dans le `.py` non documenté → manquant côté fiche.
|
||
7. Script déplacé/renommé (`publiciste.py→publiciste_v2.py`) → « script INTROUVABLE ».
|
||
|
||
**Incident process** : un `git checkout .` de nettoyage d'un scénario adverse a reverté
|
||
l'edit **non-commité** de `ci/check_readme_claims.sh` (bloc effacé). Ré-appliqué à
|
||
l'identique puis re-vérifié. Leçon : ne jamais `git checkout .`/`--` large avec un edit
|
||
de gate non commité en cours ; restaurer par chemin ciblé uniquement. (`git clean` <!-- ci-allow : mention de l'interdit absolu, jamais exécuté -->
|
||
reste l'interdit absolu — non utilisé.)
|
||
|
||
- **6 gates re-verts** : `check_artifacts` · `check_docs` · `guard_constraints` ·
|
||
`check_readme_claims` (16 ✓ Entrée CLI) · `check_regression` · `check_ci_integrity`.
|
||
Aucun hash-lock sur les scripts de gate → rien d'autre à régénérer.
|
||
- **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.
|