Gate ajouté (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 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), une fiche ne peut pas citer un job absent ; la disparition totale de la colonne échoue AUSSI. 33 références vérifiées == jobs ci.yml ; 2 morsures (token de fiche `seo-tests`→`seo-suite-tests` fantôme · job ci.yml `rbac-tests` renommé → mord SIMULTANÉMENT les 4 fiches qui le citent : erpnext_backend/ifc_speckle/mobile/rendu), restauré vert, 7 gates re-verts. ci/README.md + activity log MAJ. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 KiB
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 « Mappingscope_donnees→ mécanisme » : nomme, PAR portée, lemechanismFrappe natif (own→docperm_if_owner·entite→user_permission_company·groupe→none_consolidated·equipe→vps_confirm_team) ET le verdict « Template émis ? » (ouipourentiteseul, sinonnon (null)).- Source faisant autorité (byte-gatée par
check_artifacts) :out/user_permission_plan.json— chaque entrée portescope_donnees+mechanism+user_permission_template(null ou objet). Le mapping est une fonction : chaque portée → exactement un mécanisme ; template émis SSIentite/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 suitetests/(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ᵉ surfacerbac/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éellepython3 bancable_gen.py validate(émet le manifeste sur stdout,figures_calculees[]). Le52 %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 pipelinecheck-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 ERPNextOTO Plateforme Mobile(« Développeur Mobile » · famille/portailplateforme· entité 9060 QC · niveau 2 · scopegroupe· modulesCore+Website· permAPI Accesscustom 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 parcheck_artifacts) → le rôle d'idplateforme-mobileporte 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 lescope_donnees(groupe→entite: sur-portée inter-entités, la restriction même que le rôle pose), changer leniveau/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ôlebenchreste 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ôlefaisabilite-rendu-3d:OTO Faisabilité Rendu 3D· « Spécialiste Rendu 3D » · portailconstruction·WA SRL· niveau 2 · moduleOTOV7 Faisabilité· permsFileR/W/create +FaisabilitéR.03_agents/ifc_speckle/AGENT.md:34— cellule du rôlefaisabilite-ifc-speckle:OTO Faisabilité IFC Speckle· portailconstruction·WA SRL· niveau 2 · permsFileR/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 parcheck_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. ÉlargirFaisabilitéR→R/W (le rôle Rendu 3D gagnerait l'écriture sur un DocType qu'il ne doit que LIRE), changerniveau/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ôlesbenchreste 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 WorkspaceOTO 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 WorkspaceOTO Ventes» (assertion NÉGATIVE d'honnêteté #6).- Source faisant autorité :
frontend/portails/out/workspace.json(les 5 Workspaces natifs v15, chacun portant sa listeHas Role, byte-gaté parcheck_artifactsvia la reproductibilitéout/). L'erpnext_role_namede chaque rôle est résolu du contratrbac_50_roles.jsonparid(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 deOTO 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 suitetests/(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 deOTO 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émoireagent-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 Workspacesbenchreste 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 alignebranding.py, l'oracle du test reste périmé (rouge trompeur) ; si RIEN ne bouge, tout reste vert alors que le site publicvente.otov7.comémettrait la mauvaise couleur — invention silencieuse de la classe même que #6 interdit, qu'aucune suitetests/(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 retireFraunces; restauré = green : 4 tokens sains · constantes == #4 · docstring 4 tokens · README 2 fontes · oracle == #4 · exit 0. Working tree byte-restauré (git checkout --, JAMAISgit clean, interdit absolu) · 7 gates re-verts.
ci/README.md(table récap du pipeline + paragraphe détaillé « Tokens design canoniquespubliciste/brandingancré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 sitevente.otov7.comreste 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— bulletrole_id: « et appartenir au portailcompta— le rôle dédiécompta-fiscaliste-ecf(OTO Compta Fiscaliste eCF) ».- Sources faisant autorité (double) : (a)
out/ecf_plan.json(byte-gaté parcheck_artifacts) — CHAQUEemission_events[]porterole_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'idcompta-fiscaliste-ecfporteportail: "compta". Leportailn'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ÉPLACERcompta-fiscaliste-ecfdu portailcomptavers 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 READMEfiscal/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*-testsré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 recopierdemo-scenario-testsendemo-scenarios-testslaisse 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_integrityne regarde QUE le câblagegate.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 == sectionjobs: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.