d20d37607d
Surface ungatée fermée : `03_agents/onapi_legal/AGENT.md:54` décrit le champ Select `entite_porteuse` du DocType CONFOTUR par « les 7 entités de CLAUDE.md #Entités (WAF · WA SRL · AC Arias Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060 QC) » — un COMPTE littéral + l'énumération complète du même menu. Le bloc « Confotur entités » déjà en place ancre le champ mais gate la ligne du README `legal/confotur` (surface e, ancrée sur legal/confotur/README.md) ; le motif ne vise PAS 03_agents/ ⇒ la fiche restait hors de tout gate. Dérive #6 : ajouter/retirer/renommer une entité dans CLAUDE.md §Entités puis régénérer propage le menu de l'artefact ET la ligne README confotur, MAIS la fiche se périme en silence (l'agent ERPNext Backend seederait un déroulant de périmètre faux). Aucune suite tests/ (FONCTIONS de build, pas la prose) ne l'attrape. Gate ajouté (ci/check_readme_claims.sh) : re-dérive la liste depuis les tokens gras de « ## Entités » de CLAUDE.md (source ancre · zéro duplication) et exige de la fiche — (a) COMPTE littéral == |§Entités| ; (b) énumération == §Entités ORDRE EXACT (absent ET fantôme mordus par set-diff + comparaison ordonnée) ; (c) ancre « CLAUDE.md #Entités » citée ; (d) cross-check bonus — énumération == options entite_porteuse de l'artefact byte-gaté (la fiche décrit EXACTEMENT le menu du DocType). Ligne absente = échec (#6). 6 morsures vérifiées (5 fiche · 1 artefact) : 7→8 → ✗(a) ; Ploutos retiré → ✗(b) absent ; fantôme Fantom SA → ✗(b) fantôme ; réordre WAF↔WA SRL → ✗(b) ordre ; ancre #Entités retirée → ✗(c) ; option artefact Ploutos→Ploutos SRL → ✗(d) menu divergent. Restauré = green (a/b/c/d ✓ · exit 0). Working tree byte-restauré via git checkout -- <fichier précis> (JAMAIS git checkout . / git clean). 7 gates re-verts. ci/README.md étendu (clause « 2ᵉ surface prose (fiche ONAPI/Legal) »). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2382 lines
188 KiB
Markdown
2382 lines
188 KiB
Markdown
# Activity Log · 2026-08-01 · Claude Code DTP
|
||
|
||
## Session `20260801_210434` · Buffer S8 · Domaine CRM/commissions : l'**IDENTITÉ du CHAMP DEVISE** — la clause `devise_field` = le champ `devise` (`Select` **USD/DOP** · #10) du DocType Dossier Vente, transcrite **en prose** dans la §« Cross-cohérence » (`crm/commissions/README.md:54`) — était **HORS de tout gate**. Les trois blocs commissions déjà en place gatent les états soumis / brouillons exclus, les champs de base Currency, l'identité des rôles payés (portail `ventes`) et la promesse anti-taux #6 — mais **aucun** ne touchait ce couple champ↔devises (l'**invariant CLI #8** du générateur).
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive (CLAUDE.md #6). **4e surface distincte du
|
||
MÊME livrable `crm/commissions`** (après états/champs, anti-taux, rôles payés) — le
|
||
« **sur quelle devise** » du calcul `base × taux`. Surface DISTINCTE du bloc « Fiches
|
||
#10 » (prose ERPNext/CRM) et du bloc e-CF `TipoMoneda` (options du spec fiscal) :
|
||
ici c'est le champ `devise` du DocType Dossier Vente + la clé racine `devise_field`
|
||
du plan, ancrés sur **CLAUDE.md #10** (« **USD + DOP** devises »).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/commissions/README.md:54` — clause « `devise_field` = le
|
||
champ `devise` (`Select` **USD/DOP** · #10) du DocType » : NOMME le champ (`devise`),
|
||
son fieldtype (`Select`), ses options (`USD/DOP`) et tague `#10`.
|
||
- Sources faisant autorité : (a) `out/commission_plan.json` (byte-gaté par
|
||
`check_artifacts`) — clé RACINE `devise_field` (le champ du Dossier Vente qui porte
|
||
la devise d'un montant commissionné) ; (b) `crm/dossier_vente/doctype_spec.json`
|
||
(l'INPUT du générateur) — le champ `devise` de fieldtype `Select` + ses `options` ;
|
||
(c) **CLAUDE.md #10** (ligne 24 : « **USD + DOP** devises ») — les 2 devises
|
||
canoniques. L'invariant CLI #8 (`commissions_gen.py:151-158`) exige les trois
|
||
simultanément ; le gate re-dérive INDÉPENDAMMENT.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS**
|
||
finance/résolution, jamais la PROSE vs l'artefact. RENOMMER le champ (`devise`→
|
||
`moneda`), changer son fieldtype (`Select`→`Data` : énumération PERDUE, montant en
|
||
monnaie libre) ou altérer ses options (`USD/DOP`→`USD/EUR` : devise HORS #10 → le
|
||
calcul commissionnerait dans une monnaie non prévue) laisse la prose périmée EN
|
||
SILENCE. `devise_field` n'apparaissait NULLE PART dans `ci/` (grep = 0).
|
||
- **État courant** : **aucune valeur périmée** — `plan.devise_field == "devise"` ==
|
||
champ DocType `devise` (`Select`, options `[USD, DOP]`) == CLAUDE.md #10 ; la prose
|
||
README recoupe tout exactement (anti-invention #6, rien à réécrire). Le défaut est
|
||
la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||
IDENTITÉ du CHAMP DEVISE » après le bloc rôles payés) : (0) **ANCRAGE** — les 2
|
||
devises depuis le segment gras « USD + DOP » de CLAUDE.md #10 ; (a) **CROSS-ARTEFACT**
|
||
— `plan.devise_field == "devise"` == fieldname du champ DocType, fieldtype `Select`,
|
||
`options` (ORDRE inclus) == devises #10 ; (b) **PROSE** — README:54 nomme le champ
|
||
`devise`, le dit `Select`, cite `USD/DOP` == #10 et tague `#10`. Un claim absent
|
||
échoue AUSSI (traçabilité #6). Direction plan/DocType/#10 → README.
|
||
|
||
**7 morsures vérifiées** (4 côté README · 1 DocType · 1 CLAUDE.md · 1 plan) : README
|
||
champ `devise→moneda` (prose périmée) · README `Select→Data` (type périmé) · README
|
||
`USD/DOP→USD/EUR` (devises périmées) · README tag `· #10` retiré (claim INTROUVABLE) ·
|
||
**DocType** `options USD→EUR` (hors #10, cross-artefact) · **CLAUDE.md #10**
|
||
`USD+DOP→USD+EUR` (ancrage VIVANT · mord le cross-artefact) · **plan** `devise_field
|
||
devise→moneda` (invariant #8) ; restauré = green : plan.devise_field == DocType ==
|
||
#10 · prose == artefacts · 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é
|
||
« Quatrième surface du MÊME livrable `crm/commissions` · identité du champ devise »)
|
||
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 ; la création du
|
||
champ `devise` du DocType `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_183412` · Buffer S8 · Domaine Legal/CONFOTUR : les **deux champs du DocType `CONFOTUR Application` DÉRIVÉS du pipeline vente** — `dossier_vente` (Link → cible `workflow.document_type` = `OTO Dossier Vente`) et `estado` (Select → options = les états `confotur_*` du **workflow vente**), transcrits **en prose** dans la §« Cœur du livrable : cross-cohérence » (`legal/confotur/README.md:33-36`) — étaient **HORS de tout gate d'IDENTITÉ**. Les blocs CONFOTUR amont gatent le **compte** de champs/rôles, la cross-cohérence des **PERMISSIONS** (rôle→actions) et l'ancrage des **ENTITÉS** (`entite_porteuse`→CLAUDE.md §Entités) — mais **aucun** ne touchait `dossier_vente`/`estado`.
|
||
|
||
**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 EXACTE** que
|
||
l'ancrage `entite_porteuse` du MÊME README (session `20260801` entités CONFOTUR) —
|
||
appliqué à la **surface distincte** des deux AUTRES champs data-derived du même
|
||
DocType, jamais gatés hors comptes/permissions/entités.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/legal/confotur/README.md:35-36` — bullet `dossier_vente`
|
||
(Link) : « cible = `workflow.document_type` (= `OTO Dossier Vente`) » (valeur
|
||
NOMMÉE en clair) · `:33-34` — bullet `estado` (Select) : « options = les états
|
||
`confotur_*` du **workflow vente** … dérivées — jamais réécrites en dur ».
|
||
- Source faisant autorité : `crm/workflow_vente/workflow_vente_spec.json` — l'**INPUT**
|
||
que le builder confotur LIT (déclaré `workflow_source` dans le MANIFEST), d'où il
|
||
tire `document_type` (= cible du Link) et les `update_value` d'états commençant par
|
||
`confotur` (= options du Select). L'artefact `out/doctype_confotur_application.json`
|
||
porte `dossier_vente.options`/`estado.options`, byte-gaté par `check_artifacts`.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS** de
|
||
génération, jamais la PROSE du README. RENOMMER le DocType porteur côté workflow
|
||
(`OTO Dossier Vente`→`OTO Dossier de Vente`) ou AJOUTER/RENOMMER un état CONFOTUR
|
||
régénère l'artefact confotur (`check_artifacts` reste VERT — il se reconstruit
|
||
depuis le spec workflow) MAIS laisse la prose README « (= `OTO Dossier Vente`) »
|
||
périmée EN SILENCE → l'agent ONAPI/Legal câblerait une cible de Link / un menu
|
||
d'états que le pipeline ne porte plus (l'invention #6 interdit).
|
||
- **État courant** : **aucune valeur périmée** — `dossier_vente` Link → « OTO
|
||
Dossier Vente » == workflow `document_type` · `estado` options
|
||
`[confotur_depose, confotur_approuve]` == états `confotur_*` du workflow (ordre
|
||
pipeline) · la prose README recoupe l'artefact/le workflow exactement
|
||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Confotur champs
|
||
dérivés » avant `sys.exit`) : (0) **traçabilité** — MANIFEST `workflow_source` cite
|
||
bien `crm/workflow_vente/workflow_vente_spec.json` ; (a) **cross-artefact** —
|
||
`dossier_vente.options` (Link) == workflow `document_type` ; (b) **prose** — la
|
||
valeur README « (= `…`) » == workflow `document_type` ; (c) **cross-artefact** —
|
||
`estado.options` == `update_value` des états `confotur_*` du workflow (ORDRE
|
||
pipeline) ; (c′) toute option `estado` porte le préfixe `confotur` (le README
|
||
l'affirme) ; (d) **prose** — le bullet `estado` DÉCLARE la dérivation (`confotur_*`
|
||
+ workflow vente). Un claim absent échoue AUSSI (traçabilité #6). Direction
|
||
README/artefact→workflow spec.
|
||
|
||
**6 morsures vérifiées** : README `dossier_vente` valeur `OTO Dossier Vente→OTO
|
||
Dossier de Vente` (prose périmée, b) · README bullet `estado` supprimé (claim
|
||
INTROUVABLE, d) · **artefact** `estado.options` +`brouillon` (options ≠ workflow, c
|
||
ET hors-préfixe, c′) · **artefact** `dossier_vente.options→OTO Autre Doc` (Link ≠
|
||
document_type, a) · **MANIFEST** `workflow_source` déréférencé (dérivation non
|
||
déclarée, 0) · **spec workflow** `document_type→OTO Dossier de Vente` (mord
|
||
SIMULTANÉMENT l'artefact a ET la prose b — l'ancre est vive) ; restauré = green :
|
||
6 checks verts · 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é
|
||
« Champs `dossier_vente`/`estado` du DocType CONFOTUR dérivés du workflow 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 `bench import-fixtures` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_173409` · Buffer S8 · Fiches agents/pied de page voix OTOIA : le **PIED DE PAGE CANONIQUE** « - Voix **Amélie QC** (**multilingual_v2**) pour toute interaction OTOIA » — répété à l'identique dans **11 des 13 fiches** `03_agents/*/AGENT.md` (toutes sauf `faisabilite`/`publiciste`, qui n'orchestrent pas OTOIA) — RECOPIE À LA MAIN les **trois** tokens de la contrainte **CLAUDE.md §Architecture cible** « Voix Amélie QC (multilingual_v2) » : prénom persona (`Amélie`), qualificatif de marque (`QC`), modèle de voix ElevenLabs (`multilingual_v2`). Cette surface était **HORS de tout gate**.
|
||
|
||
**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 persona/capabilities
|
||
`frontend/chat_otoia` ancrées sur §Architecture cible, la marque SEO org (§Entités) et
|
||
les tokens branding (#4) — appliqué à une **surface distincte encore ungated** : les 11
|
||
pieds de page de fiches, jamais confrontés à CLAUDE.md.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/{bim,crm,devops,erpnext_backend,frontend_console,ifc_speckle,mobile,
|
||
onapi_legal,qa,rendu,seo}/AGENT.md` — ligne « - Voix Amélie QC (multilingual_v2)
|
||
pour toute interaction OTOIA ».
|
||
- Source faisant autorité : **CLAUDE.md §Architecture cible** (ligne 30) « Voix
|
||
Amélie QC (multilingual_v2) ».
|
||
- Piège : le bloc « Chat OTOIA · IDENTITÉ de la persona » RE-DÉRIVE bien persona+voix
|
||
de CLAUDE.md mais ne confronte QUE le module `chat_otoia` (spec + `out/` + son propre
|
||
README + l'oracle du test) — **AVEUGLE aux 11 pieds de page** ; le bloc « configs
|
||
runtime » note même explicitement que le « QC » est « gardé en littéral — non gaté
|
||
ici ». Le jour où ElevenLabs déprécie `multilingual_v2` (→`multilingual_v3`) ou qu'on
|
||
renomme la persona/le qualificatif dans CLAUDE.md, ces 11 fiches annonceraient EN
|
||
SILENCE une voix/persona que le mandat ne prescrit plus, chacune affirmant orchestrer
|
||
« toute interaction OTOIA » avec le mauvais modèle. Aucune suite `tests/` (FONCTIONS
|
||
du builder, jamais la prose des fiches) n'attrape ce « vert trompeur ».
|
||
- **État courant** : **aucune valeur périmée** — les 11 pieds de page recoupent
|
||
CLAUDE.md §Architecture cible 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 · pied de
|
||
page voix » après le bloc persona/capabilities Chat OTOIA) : on RE-DÉRIVE le triplet
|
||
(persona · qualif · voix) de CLAUDE.md §Architecture cible **INDÉPENDAMMENT** du parse
|
||
persona amont (dont la regex fige `QC` en dur — un renommage du qualificatif doit mordre
|
||
ICI, pas seulement via l'INTROUVABLE du bloc persona) ; pour CHAQUE fiche git-trackée
|
||
portant le pied de page, on exige ses **3 tokens == CLAUDE.md**. Une fiche avec prose
|
||
« interaction OTOIA » mais pied de page malformé échoue ; la **disparition totale** du
|
||
recensement échoue AUSSI (surface évaporée = régression #6). Direction fiche→CLAUDE.md.
|
||
|
||
**6 morsures vérifiées** : CLAUDE.md `multilingual_v2→v3` (mord les 11 fiches +, en
|
||
cascade, le bloc persona amont — 15 fails, l'ancre est vive) · CLAUDE.md qualif `QC→BC`
|
||
(mord les 11 pieds de page — bloc INDÉPENDANT, ne s'appuie pas sur le parse persona qui
|
||
fige QC) · fiche `seo` voix `v2→v1` (1 fail) · fiche `crm` persona `Amélie→Sophie`
|
||
(1 fail) · fiche `bim` pied de page malformé, parenthèses retirées (1 fail INTROUVABLE) ·
|
||
pied de page retiré de TOUTES les fiches (surface évaporée, 1 fail) ; restauré = green :
|
||
11 pieds de page == CLAUDE.md · 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é « Pied de
|
||
page Voix Amélie QC (multilingual_v2) des fiches agents ancré 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 ; le runtime réel
|
||
de la voix OTOIA reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_170404` · Buffer S8 · Domaine QA/audit_4big : la colonne **« Fait vérifié »** de la table du barème (`qa/audit_4big/README.md:24,26`) — les **DEUX SEUILS STRUCTURELS** que le scorer applique réellement (`DOC` « ≥ **400 octets** » · `TESTS` « ≥ **8 méthodes** `def test_*` »), transcrits À LA MAIN — étaient **HORS de tout gate**. Le bloc BARÈME existant recompute la 2e colonne (**poids** : DOC 20 · CONTRAT 20 · TESTS 25 · CLI 15 · HANDOFF 20) mais son regex (`| \`DOC\` | 20 |`) est **AVEUGLE à la 3e cellule** ; ces deux nombres sont DATA-DERIVED de `quality_spec.json[thresholds]` (`min_doc_bytes`/`min_test_methods`).
|
||
|
||
**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 le
|
||
bloc BARÈME (poids) et la carte de renormalisation par archétype du MÊME README —
|
||
appliqué à une **3e surface distincte du MÊME README `qa/audit_4big`** : les seuils
|
||
de la colonne « Fait vérifié », jamais gatés hors leur poids voisin.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/qa/audit_4big/README.md:24` — cellule DOC « un `*.md`
|
||
(README/SPEC) ≥ **400 octets** à la racine » (= `thresholds.min_doc_bytes`) ·
|
||
`:26` — cellule TESTS « ≥ **8 méthodes** `def test_*` dans `tests/` » (=
|
||
`thresholds.min_test_methods`).
|
||
- Source faisant autorité : `05_deliverables_mvp/qa/audit_4big/quality_spec.json`
|
||
`[thresholds]` — l'**INPUT** du générateur, byte-gaté indirectement par
|
||
`check_artifacts` qui prouve que `out/quality_report.json` se **rebuild** depuis
|
||
lui. Les seuils ne sont PAS émis en clair dans le report ; seule l'**evidence
|
||
`TESTS`** de chaque module porte « (seuil N) » (émise par `crit_tests`), ce qui en
|
||
fait un **ancrage croisé** du seuil réellement APPLIQUÉ.
|
||
- Piège : la seule vérification existante (`tests/`) teste des **FONCTIONS** de
|
||
scoring (`crit_doc`/`crit_tests` avec seuil paramétré), jamais la PROSE du README.
|
||
Élever `min_test_methods` (8→12 : un module de 8-11 tests tomberait sous `FAIL` —
|
||
la barre même que le critère pose) ou changer `min_doc_bytes` dans le spec rebuild
|
||
le report SANS TOUCHER au README → prose « ≥ 8 méthodes »/« ≥ 400 octets » périmée
|
||
en silence, l'auditeur documentant un barème qu'il **n'applique plus** (l'invention
|
||
#6 interdit).
|
||
- **État courant** : **aucun seuil périmé** — les 2 cellules recoupent le spec
|
||
exactement, et le seuil TESTS appliqué (evidence report) == spec sur les 22 modules
|
||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « README audit_4big ·
|
||
SEUILS STRUCTURELS » après le bloc renormalisation par archétype) : (1) **cross-check
|
||
d'ancrage** — le seuil `TESTS` APPLIQUÉ (regex `(seuil N)` sur l'evidence de CHAQUE
|
||
module du report) == `spec.min_test_methods` pour tous (mord une divergence
|
||
spec↔report) ; (2) **prose DOC** — cellule « ≥ N octets » recomputée du spec, exacte ;
|
||
(3) **prose TESTS** — cellule « ≥ N méthodes » recomputée du spec, exacte. Un claim
|
||
absent échoue AUSSI (traçabilité #6).
|
||
|
||
**5 morsures vérifiées** : README `DOC 400→450` (prose périmée) · README `TESTS 8→10`
|
||
(prose périmée) · README ligne DOC vidée du seuil (claim INTROUVABLE) · **spec**
|
||
`min_test_methods 8→12` + rebuild (README périmé ET cross-check evidence[8]≠spec[12]
|
||
spec↔report) · **spec** `min_doc_bytes 400→500` + rebuild (README DOC périmé) ;
|
||
restauré = green : seuil TESTS appliqué == spec (8) · DOC « ≥ 400 octets » == spec ·
|
||
TESTS « ≥ 8 méthodes » == spec · 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 `check-readme-claims` + paragraphe détaillé
|
||
« troisième surface · colonne Fait vérifié / seuils structurels ») 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 branchement
|
||
du gate 4Big sur le pipeline de release reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## 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.
|
||
|
||
## Session `20260801_130325` · Buffer S8 · Fiches agents + master prompt/infra GPU : l'**IDENTITÉ de l'endpoint RunPod ComfyUI** — l'ID du pod `t68akvx80wv092` + le tag modèle **« Flux dev fp8 »** qui exécute le rendu Flux — était RECOPIÉE À LA MAIN en **6 citations** (`03_agents/bim/AGENT.md:32,67` · `03_agents/rendu/AGENT.md:19,55,91` · `02_master_prompt/MASTER_PROMPT_DTP_v2.md:24`) mais **HORS de tout gate**. La source de vérité in-repo est le bullet §1 de `AGENTS_EXISTING_ASSETS.md:15` — « le fichier maître » que les fiches CITENT explicitement comme leur ancre.
|
||
|
||
**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 colonne « Job CI » ou « Entrée CLI » des fiches (surface data-derived
|
||
recopiée à la main, jamais confrontée à sa source) — appliquée à une **surface distincte
|
||
encore jamais gatée** : l'**infra GPU** (l'endpoint RunPod que l'agent Rendu/BIM câble
|
||
pour le batch Flux). Classe `agent-fiche-role-attrs-ungated`.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/bim/AGENT.md` (table modules L32 + coordination L67) · `03_agents/rendu/AGENT.md`
|
||
(principe L19 + table L55 + coordination L91) · `02_master_prompt/MASTER_PROMPT_DTP_v2.md:24`
|
||
(bloc infra « GPU ») — chacun NOMME entre backticks l'id `t68akvx80wv092` et/ou le tag
|
||
« Flux dev fp8 ».
|
||
- Source faisant autorité : `AGENTS_EXISTING_ASSETS.md:15` §1 BIM
|
||
(« - **RunPod ComfyUI** endpoint `t68akvx80wv092` (Flux dev fp8) »).
|
||
- Piège : un pod RunPod est **RE-CRÉÉ avec un NOUVEL id** (cas le plus courant) ou le
|
||
modèle Flux est bumpé (`dev fp8`→autre quant) : l'inventaire maître se met à jour, les
|
||
6 citations se PÉRIMENT en silence pendant que l'agent Rendu/BIM câblerait le batch vers
|
||
un **endpoint GPU MORT** — l'invention même que #6 interdit. `check_docs` ne voit qu'un
|
||
lien, `guard_constraints` qu'un terme interdit, `check_artifacts` qu'un `out/` — un ID de
|
||
pod n'est aucun des trois ; aucune suite `tests/` (FONCTIONS du module) n'attrape la prose.
|
||
- **État courant** : **aucune citation périmée** — les 6 recoupent l'inventaire exactement
|
||
(anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « RunPod endpoint » avant
|
||
`sys.exit`) : (0) **ancrage** — id + tag recomputés du bullet §1 (garde : bullet EXACTEMENT
|
||
une fois, sinon ancre morte) ; (1) **direction fiche→inventaire** — toute fiche/master
|
||
prompt qui MENTIONNE RunPod doit citer l'id EXACT (tout token backtické de forme pod —
|
||
alphanum minuscule ≥12 **avec un chiffre**, forme qui n'entre en collision avec aucun autre
|
||
token backtické du corpus : vérifié) == canonique, ET le tag Flux EXACT (substring
|
||
normalisé, insensible casse) ; (2) **disparition totale** — plus aucune mention RunPod
|
||
échoue AUSSI (traçabilité #6).
|
||
|
||
**6 morsures vérifiées** : inventaire re-crée le pod (id change → mord les **3 fiches** en
|
||
cascade) · inventaire bump le tag (`dev fp8→schnell fp8` → 3 fiches) · fiche rendu mistype
|
||
une citation (id fantôme, mord rendu seul) · fiche bim retire le tag (tag absent) · master
|
||
prompt retire l'id backtické (citation incomplète) · inventaire supprime le bullet canonique
|
||
(ancre morte, recompute impossible) ; restauré = green : 3 fiches · id == inventaire · tag ==
|
||
inventaire · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`,
|
||
interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_docs`/`guard_constraints`/
|
||
`check_artifacts`/`check_ci_integrity`/`validate_json`/`check_regression`).
|
||
|
||
- `ci/README.md` (clause récap du pipeline `check-readme-claims` + paragraphe détaillé
|
||
« IDENTITÉ de l'endpoint GPU RunPod ComfyUI ancrée sur l'inventaire maître ») 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 pod RunPod réel + le
|
||
batch ComfyUI Flux restent côté VPS/RunPod).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_133334` · Buffer S8 · Domaine CRM/Commissions : la **PROMESSE ANTI-INVENTION (#6)** du barème vendeurs — la **RAISON D'ÊTRE** du module — était HORS de tout gate. Aucun taux de commission n'étant documenté dans CLAUDE.md, le README §« Anti-invention » promet (README:22-23) que « le barème livré porte `taux_pct: null` + `source: null` + `a_confirmer: true` pour **chaque** évènement », et l'invariant CLI #7 REFUSE tout `taux_pct` fourni **sans `source`**. Le bloc cross-cohérence commissions existant ne gate QUE brouillons/champs de base ; le bloc racine QUE le compte de tests (« 25 »). RIEN ne confrontait cette promesse à l'artefact 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 surface `crm/commissions`
|
||
que le bloc cross-cohérence (états soumis/base_field) mais **axe orthogonal et plus
|
||
grave** : non plus QUEL état paie, mais la garantie que le module **n'invente aucun
|
||
chiffre** — la classe même que #6 pose, appliquée au livrable dont c'est la mission.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/commissions/README.md:22-23` — la promesse « `taux_pct:
|
||
null` + `source: null` + `a_confirmer: true` pour **chaque** évènement ».
|
||
- Source faisant autorité : `out/commission_plan.json` (byte-gaté par
|
||
`check_artifacts`) — chaque `evenements[]` porte `taux_pct`/`source`/`a_confirmer` ;
|
||
`out/MANIFEST.json[counts]` recompte `taux_a_confirmer`/`evenements`.
|
||
- Piège #6, la dérive la plus dommageable possible ici : qu'un `taux_pct` DEVIENNE
|
||
non-null (taux INVENTÉ, ou valeur remplie **sans `source`**) pendant que le README
|
||
affirme encore « tout `null` » → le calcul `base × taux` (`commlib/finance.py`)
|
||
émettrait une commission fondée sur un chiffre inventé — l'invention EXACTE que le
|
||
module promet d'écarter. Aucune suite `tests/` (FONCTIONS de calcul/résolution,
|
||
jamais la promesse du README vs l'artefact commité) ne l'attrape.
|
||
- **État courant** : les 5 évènements sont bien tout-`null` (`taux_pct`/`source`
|
||
null · `a_confirmer` true), `counts.taux_a_confirmer == 5 == |plan|`, `note_taux`
|
||
cohérente ; rien de périmé (anti-invention #6, rien à réécrire). Le défaut est la
|
||
**surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||
ANTI-INVENTION (#6) » après le bloc cross-cohérence commissions) : on RECOMPUTE
|
||
l'état null/confirmé depuis l'artefact, puis (a) **invariant #7 permanent** — aucun
|
||
`taux_pct` renseigné **sans `source`** (taux inventé) ; (b) **cohérence** `a_confirmer`
|
||
⟺ `taux_pct is null` (un taux confirmé n'est plus « à confirmer », et inversement) ;
|
||
(c) **`MANIFEST.counts`** recoupe le plan (`taux_a_confirmer` == nb à confirmer ·
|
||
`evenements` == |plan|) ; (d) **la promesse #6 du README REFLÈTE l'artefact dans les
|
||
DEUX SENS** — si tout-null, la promesse DOIT être présente (sinon la raison d'être
|
||
disparaît · #6) ; si un taux est un jour confirmé, la promesse « tout null » DOIT
|
||
avoir été retirée (sinon « vert trompeur ») — **zéro faux négatif** quand la
|
||
Direction remplira les taux ; (e) `note_taux` du MANIFEST cohérente avec l'état.
|
||
|
||
**5 morsures vérifiées** : `taux_pct` rempli SANS source (invariant #7 · invention
|
||
+ cascade b/d) · `taux_pct` rempli AVEC source (invariant #7 OK mais `a_confirmer`
|
||
resté true → b, + README périmé → d — prouve que #7 et la cohérence sont distincts) ·
|
||
`a_confirmer=false` sur taux null (b + counts périmés c + d) · `MANIFEST.counts.
|
||
taux_a_confirmer` périmé 5→4 (c seul) · promesse anti-invention retirée du README
|
||
(d · INTROUVABLE) ; restauré = green : invariant #7 · cohérence · counts · promesse
|
||
== artefact · 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` (cellule récap du pipeline + paragraphe détaillé « promesse
|
||
anti-invention #6 du barème `crm/commissions` ») 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 ; la
|
||
confirmation réelle des taux + le câblage du calcul restent côté Direction/VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_140334` · Buffer S8 · Domaine Fiscal/e-CF DGII : l'**IDENTITÉ des ÉVÈNEMENTS D'ÉMISSION** — la section §Cross-cohérence présentée comme **« le cœur du livrable »** (README:40-59) — était transcrite À LA MAIN SANS aucun gate d'identité. Le SEUL gate fiscal existant couvre le **contrat de format e-NCF** (`E+tipo(2)+seq(10)=13`) + le compte de tests ; le bloc racine, le seul agrégat « e-CF 39 tests ». RIEN ne confrontait à l'artefact byte-gaté QUEL évènement du pipeline émet un e-CF, sur quel `base_field`, par quel rôle Compta, ni la FormaPago défaut.
|
||
|
||
**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 « identité
|
||
d'un ENSEMBLE » que la colonne « Entité » de la SPEC §4, l'énumération des onglets
|
||
Mobile ou les transitions à séparation des pouvoirs du workflow — appliquée à la
|
||
**surface data-derived la plus critique du module fiscal** : les `emission_events`
|
||
d'`ecf_plan.json`, jamais gatés hors le format e-NCF et le compte de tests.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/fiscal/ecf_dgii/README.md:40-59` (§Cross-cohérence, « le cœur
|
||
du livrable ») — transcrit À LA MAIN : (L48) l'ENSEMBLE des évènements émetteurs
|
||
(« seulement réservation et contrat ») + l'ENSEMBLE exclu des brouillons (« on ne
|
||
facture pas un brouillon (lead/visite/devis) ») ; (L50) l'ENSEMBLE des `base_field`
|
||
(`montant_reservation`/`montant_contrat`) ; (L53-54) le rôle UNIQUE
|
||
(`compta-fiscaliste-ecf` · « OTO Compta Fiscaliste eCF » · portail compta) ;
|
||
(L59) la FormaPago défaut (« = 3 (Tarjeta) » · Cardnet #10).
|
||
- Source faisant autorité (byte-gatée par `check_artifacts`) :
|
||
`out/ecf_plan.json` — `emission_events[]` (`update_value`/`base_field`/`role_id`/
|
||
`erpnext_role_name`), `forma_pago_defaut` + catalogue `formas_pago`. Double
|
||
ancrage du rôle sur `rbac/rbac_50_roles.json` (id → `portail` compta → nom ERPNext).
|
||
- Piège #6/#5, la dérive la plus dommageable ici : **AJOUTER un `emission_event` sur
|
||
un état BROUILLON** (ex. `devis`) — l'anti-pattern EXACT que le module interdit
|
||
(« on ne facture pas un brouillon ») — pendant que L48 dit encore « seulement
|
||
réservation et contrat » → l'agent ERPNext Backend câblerait une **facture émise
|
||
avant soumission/encaissement**. Aucune suite `tests/` (FONCTIONS de résolution/
|
||
composition, jamais la prose vs l'artefact) ne l'attrape.
|
||
- **État courant** : émetteurs `{contrat, reservation}`, base_field
|
||
`{montant_contrat, montant_reservation}`, rôle unique `compta-fiscaliste-ecf`
|
||
(portail compta · RBAC concordant), FormaPago défaut `3`/Tarjeta/Cardnet —
|
||
tout recoupe 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 « Fiscal · e-CF DGII —
|
||
IDENTITÉ des ÉVÈNEMENTS D'ÉMISSION » avant `sys.exit`) : (0) **cohérence interne** —
|
||
rôle UNIQUE sur tous les évènements · défaut ∈ catalogue FormaPago ; (1) **ENSEMBLE
|
||
émetteurs** — set-diff README `seulement …` == `update_value` de l'artefact (ni
|
||
fantôme ni manquant · accents/casse normalisés) ; (2) **DISJONCTION** — l'ensemble
|
||
exclu `(lead/visite/devis)` ∩ émetteurs = ∅ (jamais de facture sur brouillon — mord
|
||
un `devis` émetteur ET la self-contradiction du README) ; (3) **ENSEMBLE `base_field`**
|
||
— set-diff README == artefact ; (4) **rôle unique** cité backtické + nom ERPNext,
|
||
**double-ancré** sur `rbac_50_roles` (id → portail compta → nom concordant) ; (5)
|
||
**FormaPago défaut** — code == artefact · label ∈ catalogue · motif cite Cardnet (#10).
|
||
Un claim absent échoue AUSSI (traçabilité #6).
|
||
|
||
**6 morsures vérifiées** : artefact facture un BROUILLON (`devis` émetteur → mismatch
|
||
d'ensemble **ET** clash de disjonction · 2 morsures en une) · artefact renomme un
|
||
`base_field` (`montant_reservation→montant_acompte`) · artefact change FormaPago défaut
|
||
`3→1` (Efectivo) · artefact casse le rôle unique (2ᵉ évènement → `compta-comptable`) ·
|
||
README périmé « seulement contrat » (réservation retiré) · motif du défaut ne cite
|
||
plus « Cardnet » (#10) ; restauré = green : émetteurs · disjonction · base_field ·
|
||
rôle == RBAC · FormaPago == artefact · exit 0. Working tree byte-restauré
|
||
(`git checkout --`, **JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts**
|
||
(`check_readme_claims`/`check_docs`/`guard_constraints`/`check_artifacts`/
|
||
`check_ci_integrity`/`validate_json`/`check_regression`).
|
||
|
||
- `ci/README.md` (clause récap du pipeline `check-readme-claims` + paragraphe détaillé
|
||
« IDENTITÉ des évènements d'émission e-CF ancrée sur `ecf_plan.json` ») 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 ; la connexion
|
||
Compupar réelle + l'émission e-CF en production restent côté ERPNext Backend/VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_143341` · Buffer S8 · Domaine Faisabilité/generator : les **TROIS copies aval** des 6 MARQUEURS CANONIQUES (`3 %`/`8.5 %`/`52 %` · `USD+DOP`/`Letter US`/`Cardnet`, contraintes NON-NÉGOCIABLES **CLAUDE.md #9/#10**) — l'**oracle d'enforcement** `genlib/renderer.py::_CANONICAL_MARKERS` (la liste que `check_canonical()` PARCOURT pour PROUVER que chaque rendu de faisabilité porte les 6 marqueurs), les **DEUX docstrings** de `genlib/scorer.py` (barème axe 4 + `_score_parametres_canoniques`) et l'**oracle du test** `tests/test_generator.py` (`for marker in [...]`) — étaient **HORS de tout ancrage**. Le bloc « paramètres canoniques » existant n'ancre QUE `model.py::CANONICAL` + le README à #9/#10 ; son propre commentaire NOMMAIT pourtant le défaut (« ces marqueurs sont HARDCODÉS DANS LE TEST, une copie de plus, JAMAIS comparée à CLAUDE.md ») sans le fermer.
|
||
|
||
**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 tuple d'oracle du
|
||
test `publiciste/branding` ancré sur #4 (une copie hardcodée dans un test, gatée) —
|
||
appliqué aux **trois copies aval encore ungated du MÊME module** `faisabilite/generator`
|
||
dont le bloc canonique n'ancrait que 2 des 5 copies.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/faisabilite/generator/genlib/renderer.py:275` —
|
||
`_CANONICAL_MARKERS = ["3 %", "8.5 %", "52 %", "USD + DOP", "Cardnet", "Letter US"]`,
|
||
la LISTE que `check_canonical()` parcourt pour vérifier que le volet ingénierie
|
||
du rendu porte les 6 marqueurs. C'est l'**enforcement même** de l'« axe 4
|
||
honnêteté ».
|
||
- `05_deliverables_mvp/faisabilite/generator/genlib/scorer.py:7` (barème axe 4) **et**
|
||
`:109` (`_score_parametres_canoniques`) — deux docstrings énumérant
|
||
« 3 % / 8.5 % / 52 % · USD+DOP · Letter US · Cardnet ».
|
||
- `05_deliverables_mvp/faisabilite/generator/tests/test_generator.py:103` —
|
||
`for marker in ["3 %", "8.5 %", "52 %", "USD + DOP", "Cardnet", "Letter US"]` :
|
||
l'oracle du test lui-même, celui que le commentaire du bloc amont dénonçait.
|
||
- Source faisant autorité : **CLAUDE.md #9/#10** (les 6 valeurs), déjà recomputées
|
||
en `exp` par le bloc « paramètres canoniques » — RÉUTILISÉES ici (zéro duplication).
|
||
- Piège #6 : l'oracle `_CANONICAL_MARKERS` est le juge de l'honnêteté du rendu. S'il
|
||
DÉRIVE de `CANONICAL` (donc de #9/#10), le contrôle devient FAUX de deux façons :
|
||
soit il exige un marqueur périmé (`Cardnet` alors que le rendu, issu d'un CANONICAL
|
||
mis à jour, porterait `Azul` → **faux rouge**), soit on retire un marqueur et le
|
||
contrôle **NE VÉRIFIE PLUS RIEN** (vert vacux). La seule suite `tests/` teste des
|
||
FONCTIONS (dont `check_canonical` — AVEC son propre oracle hardcodé), jamais
|
||
l'ancrage à CLAUDE.md.
|
||
- **État courant** : **aucun marqueur périmé** — `set(renderer._CANONICAL_MARKERS) ==
|
||
set(model.CANONICAL.values())` vérifié programmatiquement AVANT toute édition ; les
|
||
3 copies recoupent #9/#10 exactement (anti-invention #6, rien à réécrire). Le défaut
|
||
est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Faisabilité/generator
|
||
(2e surface) » après le bloc « paramètres canoniques ») : RÉUTILISE `exp` +
|
||
`_want6` (6 valeurs normalisées de #9/#10, zéro duplication). Helper `_list_vs_want6`
|
||
pour les copies-LISTES : (c) `renderer.py::_CANONICAL_MARKERS` et (e) l'oracle du test
|
||
sont parsés (`ast.literal_eval`) puis comparés à l'ensemble EXACT (set-diff : absent
|
||
ET en trop · anti-doublon). Pour les copies-DOCSTRINGS (d), chaque valeur normalisée
|
||
(`_pnorm`/`_ai` — espaces/accents-insensibles ⇒ `USD+DOP`==`USD + DOP`) doit être
|
||
substring de la ligne normalisée ; ≥2 énumérations exigées (barème + fonction). Un
|
||
claim/ligne absent échoue AUSSI (traçabilité #6).
|
||
|
||
**4 morsures vérifiées** : (M1) `renderer._CANONICAL_MARKERS` `Cardnet→Azul`
|
||
(absents=[cardnet] · en trop=[azul]) · (M2) oracle du test retire `8.5 %`
|
||
(absents=[8.5%]) · (M3) scorer docstring L7 `52 %→55 %` (n'énumère plus [52%]) ·
|
||
(M4) **CLAUDE.md #10 `Cardnet→Azul` → mord SIMULTANÉMENT model.py + renderer + test +
|
||
les DEUX docstrings** (5 morsures en cascade — la valeur MÊME de l'ancrage à la
|
||
source constitutionnelle) ; restauré = green : renderer/test == #9/#10 (6 marqueurs) ·
|
||
2 docstrings == #9/#10 · exit 0. Working tree byte-restauré (`git checkout --`,
|
||
**JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts**
|
||
(`check_readme_claims`/`check_artifacts`/`check_ci_integrity`/`check_docs`/
|
||
`guard_constraints`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (clause récap du pipeline `check-readme-claims` + paragraphe détaillé
|
||
« 2ᵉ surface du MÊME module : les 3 copies aval des marqueurs canoniques ») 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 ; la génération
|
||
réelle des faisabilités reste côté BIM/Faisabilité).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_150344` · Buffer S8 · Domaine DevOps CI/CD : gate d'**IDENTITÉ des IDENTIFIANTS D'INFRASTRUCTURE VPS** (IP `153.75.250.214` + les DEUX conteneurs Docker `erpnext-backend-1`/`erpnext-frontend-1`) ancré sur **CLAUDE.md §VPS** — surface data-derived jusqu'ici **HORS de tout ancrage**.
|
||
|
||
**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]] + [[agent-fiche-role-attrs-ungated]], surface
|
||
**infra ~ endpoint RunPod**). **Même patron EXACT** que le gate « endpoint GPU
|
||
RunPod » (session 130325 : un identifiant d'infra hand-transcrit dans N docs,
|
||
recomputé de la source in-repo faisant autorité) — appliqué ici aux identifiants
|
||
**serveur** dont la source de vérité est **constitutionnelle** (CLAUDE.md §VPS).
|
||
|
||
**Dérive silencieuse fermée** : CLAUDE.md §VPS FIXE l'IP du VPS `153.75.250.214`
|
||
et les 2 conteneurs Docker `erpnext-backend-1`/`erpnext-frontend-1`. Ces
|
||
identifiants sont RECOPIÉS À LA MAIN dans ~10 endroits, sans AUCUN ancrage :
|
||
- `README.md` (×2 · VPS hors périmètre + dépôt Gitea) · `02_master_prompt/
|
||
MASTER_PROMPT_DTP_v2.md` (IP ×2 + les 2 conteneurs) · `AGENTS_EXISTING_ASSETS.md`
|
||
(IP + 2 conteneurs) · `03_agents/mobile/AGENT.md` (`erpnext-backend-1`, backend
|
||
cible de l'API) · `05_deliverables_mvp/rbac/RBAC_50_ROLES_SPEC.md` (run-book
|
||
d'import) · `05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md` · `tests/README.md`
|
||
(base URL Playwright) · `ci/README.md` (instance Gitea).
|
||
- Aucun gate ne couvrait ce lien : `check_docs` ne voit qu'un lien Markdown,
|
||
`guard_constraints` qu'un terme interdit, `check_artifacts` qu'un `out/` — une IP
|
||
ni un nom de conteneur n'est aucun des trois. Aucune suite `tests/` (FONCTIONS
|
||
des modules, jamais la prose infra) ne l'attrape.
|
||
- Drift la plus réaliste, #6 : une **MIGRATION serveur** (nouvelle IP) ou un
|
||
**RENOMMAGE du projet compose** (`erpnext-*` → `oto-*`) — évènement ops COURANT :
|
||
CLAUDE.md §VPS se met à jour, les ~10 copies se PÉRIMENT en silence → un agent
|
||
câblerait l'API mobile / les tests e2e / le hand-off d'import vers un serveur
|
||
MORT ou un conteneur FANTÔME (l'invention même que #6 interdit).
|
||
- **État courant** : aucune copie périmée — l'unique IPv4 du corpus == canonique,
|
||
les seuls conteneurs cités ⊆ l'ensemble canonique (vérifié programmatiquement
|
||
AVANT édition). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CLAUDE.md §VPS · IDENTITÉ
|
||
des IDENTIFIANTS D'INFRASTRUCTURE » avant `sys.exit`) : RE-DÉRIVE l'IP + l'ENSEMBLE
|
||
des conteneurs de CLAUDE.md §VPS (`^## VPS` → `IP <v4>` + `Docker (…)`, jamais une
|
||
liste à la main · #6 ; garde « section/format introuvable » = ancre morte).
|
||
Direction copie→source sur `git ls-files '*.md'` (hors `CLAUDE.md` = source, hors
|
||
`05_activity_log/` + `daily_reports/` = journaux figés à ne pas réécrire) : tout
|
||
token **IPv4** DOIT == l'IP canonique ; tout token **conteneur** DOIT ∈ l'ensemble
|
||
canonique. Garde anti-évaporation (IP ET ≥1 conteneur restent cités quelque part).
|
||
Le write-path interdit `/var/www/html/static` reste du ressort de
|
||
`guard_constraints`, non de ce gate d'identité.
|
||
|
||
**Piège de conception CORRIGÉ en vérif adversariale** : 1ʳᵉ version ancrait
|
||
l'enveloppe conteneur sur le préfixe LITTÉRAL `erpnext-[a-z]+-1` → un renommage de
|
||
projet compose dans une copie (`erpnext-backend-1` → `oto-backend-1`, le drift MÊME
|
||
qu'on vise) ne matchait plus le shape et **PASSAIT en silence** (M2 vert à tort).
|
||
Correctif : l'enveloppe est DÉRIVÉE des **stems de service** canoniques
|
||
(`backend`/`frontend`) via `[a-z0-9]+-(?:backend|frontend)-1`, PAS du préfixe →
|
||
`oto-backend-1` est vu comme fantôme. Le filtre source est lui aussi générique
|
||
(`[a-z0-9]+-[a-z]+-1`) pour que M4 (renommage DANS §VPS) cascade avec un message
|
||
utile plutôt qu'un « format modifié » crude.
|
||
|
||
**5 morsures vérifiées** (mutations sur fichiers DONNÉES uniquement, restaurées par
|
||
`git checkout -- <path>` ciblé — **JAMAIS** `git clean`/`checkout` large avec le
|
||
gate décommité en cours, interdit absolu + incident process en mémoire) : (M1) IP
|
||
périmée dans `README.md` (serveur migré, copie non mise à jour) → stale · (M2)
|
||
conteneur `erpnext-backend-1→oto-backend-1` dans le master prompt (compose renommé)
|
||
→ fantôme (après correctif) · (M3) IP changée DANS CLAUDE.md §VPS → **cascade sur
|
||
les 5 docs citant l'IP** · (M4) conteneurs renommés DANS §VPS → **cascade fantôme
|
||
sur les 4 docs citant un conteneur** avec message utile · (M5) header `## VPS`
|
||
retiré → ancre morte. Restauré = green : 10 assertions VPS infra (5 IP + 5
|
||
conteneur) · exit 0. **7 gates re-verts** (`check_readme_claims`/`check_artifacts`/
|
||
`check_ci_integrity`/`check_docs`/`guard_constraints`/`check_regression`/
|
||
`validate_json`).
|
||
|
||
- `ci/README.md` (clause récap du pipeline `check-readme-claims` : sous-clause
|
||
« identité d'infrastructure VPS ») mise à jour — et désormais **elle-même couverte
|
||
par le gate** (elle gagne les tokens conteneur/IP canoniques, tous verts).
|
||
- **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 ; la migration
|
||
serveur réelle + le renommage compose restent côté DevOps/VPS production).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_153345` · Buffer S8 · Domaine CRM/Commissions : l'**IDENTITÉ des RÔLES PAYÉS** du barème vendeurs — le « **à quel rôle** » de la question fondatrice (« quel évènement paie, à quel RÔLE, sur quel montant », README:8-9) — était HORS de tout gate. La §Cross-cohérence promet (README:51-53) que chaque `role_id` commissionné « doit être résolu depuis `rbac_50_roles.json` … **ET appartenir au portail `ventes`** » (invariant CLI #5) avec un `erpnext_role_name` « cohérent avec RBAC » (invariant #6 · le « nom Frappe résolu » du README:36). C'est une **SÉPARATION DES POUVOIRS** : on ne commissionne QUE des rôles du portail ventes. Les DEUX blocs commissions existants (cross-cohérence états/base_field + anti-invention taux) NE couvraient PAS cette appartenance-portail ni la résolution du nom.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (ERPNext Backend / CRM · #6). Roadmap fonctionnellement
|
||
close ; poursuite de la série anti-dérive. **Troisième surface data-derived** du même
|
||
livrable `crm/commissions` (après états/base_field et anti-taux) — le troisième tiers
|
||
de la question fondatrice du module (« à quel rôle »), le seul jamais confronté à
|
||
l'artefact. Classe [[agent-fiche-role-attrs-ungated]] : une propriété-rôle
|
||
data-derived affirmée en prose mais gatée par rien.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/crm/commissions/README.md:51-53` — « `role_id` … résolu depuis
|
||
`rbac_50_roles.json` … ET appartenir au portail `ventes` » + README:36 « nom Frappe
|
||
résolu ».
|
||
- Sources faisant autorité (toutes byte-gatées par `check_artifacts`) :
|
||
`out/commission_plan.json[evenements[].{role_id,erpnext_role_name}]` (les rôles
|
||
RÉELLEMENT payés) · `rbac/rbac_50_roles.json[roles[].{id,portail,erpnext_role_name}]`
|
||
+ `[portails_business]` (le contrat) · `out/MANIFEST.json[roles_rbac_utilises,counts.roles]`
|
||
(le récap).
|
||
- Piège #6, les dérives les plus graves ici : **(a)** commissionner un rôle d'un
|
||
AUTRE portail (payer un fiscaliste `compta` → la prose « portail `ventes` » devient
|
||
un MENSONGE, pouvoirs mélangés) ; **(b)** un `role_id` FANTÔME absent du contrat
|
||
(rôle inventé — l'invention même que #6 interdit) ; **(c)** un `erpnext_role_name`
|
||
figé en dur dans le plan qui dérive quand le contrat renomme le rôle (nom Frappe
|
||
périmé → `Has Role` importé sur un rôle INEXISTANT côté VPS). Aucune suite `tests/`
|
||
(FONCTIONS de résolution/calcul, jamais la prose vs l'artefact) ne l'attrape ; ce
|
||
n'est ni un lien (`check_docs`), ni un terme interdit (`guard_constraints`), ni un
|
||
`out/` dérivé (`check_artifacts`) → invisible aux trois.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « CRM/Commissions ·
|
||
IDENTITÉ des RÔLES PAYÉS » après le bloc anti-invention) : RE-DÉRIVE tout des
|
||
artefacts byte-gatés (zéro dup du contrat du générateur · #6). **(a)** chaque
|
||
`role_id` du plan ∈ contrat (sinon fantôme) ; **(b)** `erpnext_role_name` du plan ==
|
||
contrat pour chaque évènement (nom Frappe résolu · invariant #6) ; **(c)** le portail
|
||
des rôles payés est un **SINGLETON** ∈ `portails_business`, ET == le portail nommé au
|
||
README (`appartenir au portail \`([a-z-]+)\`` — le littéral `ventes`) : payer un rôle
|
||
d'un autre portail casse le singleton, renommer le portail au contrat désaccorde le
|
||
littéral README ; **(d)** `MANIFEST.roles_rbac_utilises` == l'ensemble distinct
|
||
`(role_id, nom)` réellement payé + `counts.roles` recoupé.
|
||
|
||
**6 morsures vérifiées** (mutations sur fichiers DONNÉES uniquement — plan/contrat/
|
||
MANIFEST/README — restaurées par `git checkout -- <path>` **ciblé** ; **JAMAIS**
|
||
`git checkout .`/large avec le gate décommité en cours d'édition, interdit absolu +
|
||
incident process en mémoire) : (M1) `role_id` fantôme dans le plan → absent du contrat ·
|
||
(M2) `erpnext_role_name` dérivé dans le plan → ≠ contrat · (M3) rôle **`compta`**
|
||
commissionné → portails `{compta, ventes}`, séparation des pouvoirs rompue (+ cascade
|
||
MANIFEST) · (M4) littéral portail README `ventes→sales` → dit `sales` MAIS rôles du
|
||
portail `ventes` · (M5) `roles_rbac_utilises` amputé → ≠ rôles payés · (M6) renommage
|
||
du rôle DANS le contrat (`ventes-conseiller`) → cascade double (nom plan≠contrat +
|
||
MANIFEST périmé). Restauré = vert : 4 assertions vertes · exit 0. **7 gates re-verts**
|
||
(`check_readme_claims`/`check_artifacts`/`check_ci_integrity`/`check_docs`/
|
||
`guard_constraints`/`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (ligne récap du pipeline `check-readme-claims` : sous-clause « rôles
|
||
payés » ; + paragraphe prose « troisième surface du même livrable `crm/commissions` »)
|
||
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 ; la confirmation
|
||
des taux réels + le câblage du calcul restent côté ERPNext Backend/VPS production).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_160354` · Buffer S8 · Domaine QA/comptes de tests · Fiches agents : CINQ **comptes de tests PAR SUITE** écrits HORS de la colonne « Tests » des tables de fiches — `seo` « **36 tests** » (`03_agents/seo/AGENT.md:31`, prose libre) · `frontend_console` « **19 tests** » (portails) & « **31 tests** » (chat_otoia) (`:32`/`:34`, prose libre) · `onapi_legal` « **44 tests** » (`:32`, prose libre) · `devops` « 29 (dont 14 injections négatives) » (`:25`, **cellule de table à suffixe**) — étaient **HORS de tout gate**. Les DEUX blocs de comptes de tests existants ne les atteignent PAS : le bloc **cellules « Tests »** (`row_re`) n'accepte qu'une ancre de lien `` `<mot>/` `` ET une cellule ENTIER NU ; le bloc **agrégats en prose** ne couvre que `crm` (Total CRM) et `erpnext_backend` (RBAC + e-CF).
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA — « Regression tests
|
||
exhaustifs »). Roadmap fonctionnellement close ; poursuite de la série anti-dérive
|
||
(CLAUDE.md #6). **Même classe EXACTE** que le bloc « comptes de tests PAR SUITE »
|
||
(cellules de table) et le bloc « agrégats EN PROSE » (Total CRM/RBAC/e-CF) — appliquée
|
||
à la **dernière poche** de la même surface : les claims per-suite que ces deux blocs
|
||
ne balaient pas par construction de leurs regex.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/seo/AGENT.md:31` — « **36 tests**, gated dans le pipeline » (suite `seo`).
|
||
- `03_agents/frontend_console/AGENT.md:32` — « **19 tests** · job CI
|
||
`frontend-portails-tests` » (suite `frontend/portails`) · `:34` — « **31 tests** ·
|
||
job CI `chat-otoia-tests` » (suite `frontend/chat_otoia`).
|
||
- `03_agents/onapi_legal/AGENT.md:32` — « **44 tests** (dont 8 négatifs) · job CI
|
||
`legal-confotur-tests` » (suite `legal/confotur`).
|
||
- `03_agents/devops/AGENT.md:25` — cellule « Tests » du run-book :
|
||
« 29 (dont 14 injections négatives) » (suite `devops/deploy_runbook`). Cette ligne
|
||
échappe à `row_re` **DEUX fois** : (a) l'ancre de lien est un CHEMIN complet
|
||
(`05_deliverables_mvp/devops/deploy_runbook/`, pas `` `<mot>/` ``) et (b) la cellule
|
||
n'est PAS un entier nu (suffixe « (dont …) »).
|
||
- Source faisant autorité : `qa/regression/out/regression_plan.json`
|
||
(`suites[].test_methods` · byte-gaté par `check_artifacts`), déjà chargée dans le
|
||
dict `auth` que les deux blocs amont utilisent (zéro duplication #6). Les 5 recomputes :
|
||
`seo`=36 · `frontend/portails`=19 · `frontend/chat_otoia`=31 · `legal/confotur`=44 ·
|
||
`devops/deploy_runbook`=29.
|
||
- Piège : ajouter/retirer un `def test_` à l'une de ces 5 suites fait DÉRIVER en
|
||
silence le nombre de la fiche pendant que la matrice de régression dit autre chose.
|
||
Une compensation entre deux suites (l'une +1, l'autre −1) laisserait même la SOMME
|
||
agrégée (« 564 tests · 22 suites », elle gatée) juste ET ces lignes fausses —
|
||
exactement le motif per-suite que le bloc des cellules corrige, sur des surfaces
|
||
qu'il ne balaie pas. Aucune suite `tests/` (qui teste des FONCTIONS, pas la prose
|
||
des fiches) n'attrape ce « vert trompeur ».
|
||
- **État courant** : **aucun compte périmé** — les 5 recoupent
|
||
`plan.suites[].test_methods` 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 · comptes
|
||
de tests PAR SUITE écrits HORS de la colonne Tests » après le bloc des agrégats en
|
||
prose e-CF) : table de config `PER_SUITE_HORS_TABLE` = (fiche · suite_path · motif ·
|
||
label). Pour chaque claim : (1) on RECOMPUTE `exp = auth[suite_path]` (même source
|
||
byte-gatée déjà chargée · zéro duplication) ; (2) motif ANCRÉ sur le nom de job CI
|
||
adjacent (ou le lien du module pour devops) pour viser LA bonne suite SANS ambiguïté
|
||
(les deux claims `frontend_console` 19/31 sont désambiguïsés par leurs job CI
|
||
distincts) ; (3) claim absent ⇒ ROUGE (traçabilité #6). Garde `suite_path ∈ auth`
|
||
(anti-câblage-rompu).
|
||
|
||
**7 morsures vérifiées** : (M1) fiche seo `36→35` · (M2) fiche portails `19→20` ·
|
||
(M3) fiche onapi `44→43` · (M4) **cellule devops** `29→30` (prouve que le suffixe
|
||
« (dont …) » + ancre chemin-complet est bien couvert) · (M5) **SOURCE drift** —
|
||
`plan.suites[seo].test_methods 36→37` ⇒ fiche périmée (prouve que le gate suit
|
||
l'ARTEFACT, pas un oracle figé) · (M6) ligne prose seo retirée ⇒ INTROUVABLE
|
||
(traçabilité) · (M7) fiche chat_otoia `31→32` ⇒ mord SEULE la ligne chat_otoia sans
|
||
toucher portails (prouve la désambiguïsation par job CI). Restauré = green : 5 claims
|
||
== `plan.suites[].test_methods` · exit 0. Working tree byte-restauré
|
||
(`git checkout --`, **JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts**
|
||
(`check_readme_claims`/`check_docs`/`guard_constraints`/`validate_json`/
|
||
`check_artifacts`/`check_ci_integrity`/`check_regression`).
|
||
|
||
- `ci/README.md` (clause du récap `check-readme-claims` : « comptes de tests par
|
||
suite écrits HORS de cette colonne ») mis à jour.
|
||
- **Observé, hors périmètre de CE gate** : `03_agents/devops/AGENT.md:24` cellule
|
||
« 22 suites gated » = COMPTE de suites (`plan.totals.suites`), classe DISTINCTE du
|
||
`test_methods` per-suite ; déjà ancré via l'agrégat QA « 22 suites gated · 564
|
||
tests » — candidat propre pour une session future si confirmé ungated.
|
||
- **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 ; les suites
|
||
réelles tournent côté runner Gitea).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_163401` · Buffer S8 · Domaine QA/audit_5d : l'**IDENTITÉ des 5 DIMENSIONS** du cadre d'audit — le **libellé** (`titre`) ET la **norme de référence** (`reference`) de chacune, énumérés à la main dans la table « ## Les 5 dimensions » (`05_deliverables_mvp/qa/audit_5d/README.md:15-19`) — était **HORS de tout gate d'IDENTITÉ**. Le tout premier bloc audit_5d ne recompute que le **COMPTE** (« **5 dimensions (5D)** ») — un WILDCARD aveugle à QUELLE dimension ; les 2 autres blocs audit_5d gatent la ventilation du verdict et l'énumération des open items, jamais la carte des dimensions.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA — « Audit UAF + normes ISA/IFRS
|
||
5D »). Roadmap fonctionnellement close ; poursuite de la série anti-dérive (CLAUDE.md
|
||
#6). **Même patron EXACT** que l'énumération des open items (2e surface du MÊME
|
||
README) ou les triplets par workspace des portails — appliqué à une **3e surface
|
||
distincte du MÊME README `qa/audit_5d`** : la table des 5 dimensions, gatée jusqu'ici
|
||
seulement sur son COMPTE agrégé.
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `05_deliverables_mvp/qa/audit_5d/README.md:15-19` — table « ## Les 5 dimensions » :
|
||
chaque ligne `| **D1** | Traçabilité & anti-invention | ISA 500 — Éléments probants |`
|
||
transcrit PAR LIGNE le triplet (`id`, `titre`, `reference`) d'une dimension.
|
||
- Source faisant autorité : `qa/audit_5d/out/audit_report.json[dimensions]`
|
||
(byte-gaté par `check_artifacts` ⇒ chaque dimension recomposée du catalogue de
|
||
contrôles à chaque build), chaque entrée portant `id` + `titre` + `reference`.
|
||
L'INPUT `audit_spec.json[dimensions]` (dont le rapport DÉRIVE) sert de cohérence
|
||
croisée.
|
||
- Piège : l'audit 5D est l'audit de **SECOND NIVEAU** que l'auditeur/banquier lit.
|
||
RENOMMER un libellé (« Traçabilité & anti-invention » → …) ou PERMUTER une norme
|
||
de référence (D3 fiscal citant la mauvaise `Ley 32-23`, D2 AML la mauvaise
|
||
`Ley 155-17`, D1 probatoire `ISA 501` au lieu d'`ISA 500`) laisse le compte à 5 —
|
||
le bloc de comptage reste AVEUGLE — pendant que l'artefact dit autre chose ⇒ une
|
||
AFFIRMATION de conformité fausse (l'invention même que #6 interdit). Aucune suite
|
||
`tests/` (qui teste des FONCTIONS de contrôle, pas la prose) n'attrape ce « vert
|
||
trompeur ».
|
||
- **État courant** : **aucune dimension périmée** — les 5 triplets 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 « Audit 5D (3e surface du
|
||
MÊME README) · IDENTITÉ des 5 DIMENSIONS » après le bloc open items) : on RECOMPUTE
|
||
la liste ORDONNÉE `{id:(titre, reference)}` depuis `audit_report.dimensions[]` (zéro
|
||
duplication du modèle de l'auditeur) et on exige que la table README l'énumère
|
||
EXACTEMENT : (1) identité par **ENSEMBLE d'`id`** (absent ET en trop mordus) ; (2)
|
||
**ORDRE** préservé (D1→D5) ; (3) `(titre, reference)` **par ligne**. Regex de ligne
|
||
`| **Dn** | … | … |` (gras + PAS de sous-point ⇒ distingue des lignes open items
|
||
`| D1.1 · … |`). Cohérence croisée bonus : `audit_report.dimensions` ==
|
||
`audit_spec.json[dimensions]` (l'INPUT dont le rapport dérive · mord un builder qui
|
||
renommerait/permuterait une dimension en aval du spec). Table disparue = échec
|
||
(traçabilité #6).
|
||
|
||
**8 morsures vérifiées** (5 côté README · 1 réordonnancement · 2 côté artefact/spec) :
|
||
README renomme D1 titre (`& anti-invention→et non-invention`) · README permute la
|
||
norme D1 (`ISA 500→ISA 501`) · README permute la norme fiscale D3 (`Ley 32-23→Ley
|
||
33-23`, affirmation de conformité fausse) · README supprime la ligne D5 (absent) ·
|
||
README réordonne D1↔D2 (ORDRE cassé) · **artefact** renomme le titre D2 (README périmé
|
||
+ divergence spec↔rapport) · **spec** renomme la référence D4 (divergence spec↔rapport)
|
||
· README supprime la table entière (INTROUVABLE, énumère `[]`) ; restauré = green :
|
||
5 dimensions `[D1..D5]` (id→titre→reference) == artefact · ordre == artefact ·
|
||
spec == rapport · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS**
|
||
`git clean`, interdit absolu) · **7 gates re-verts** (`check_readme_claims`/
|
||
`check_docs`/`guard_constraints`/`check_ci_integrity`/`check_artifacts`/
|
||
`check_regression`/`validate_json`).
|
||
|
||
- `ci/README.md` (recap `check-readme-claims` + paragraphe détaillé « 3e surface du
|
||
MÊME README de l'audit 5D · IDENTITÉ des 5 dimensions ») 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 ; la confirmation
|
||
des 4 open items réglementaires reste côté métier/VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_190412` · Buffer S8 · Domaine Fiches agents/RBAC : l'**appartenance à `roles_allowed` du chat OTOIA** — QUI peut **invoquer** l'assistant OTOIA embarqué dans un portail — asserée EN PROSE par 2 fiches (`03_agents/rendu/AGENT.md:36` positive · `03_agents/mobile/AGENT.md:41` négative) était **HORS de tout gate d'appartenance**. C'est une **3e surface d'appartenance** DISTINCTE des deux déjà gatées : le **contrat** `rbac_50_roles.json` (attributs du rôle, blocs Fiches Faisabilité/Mobile) et le **`Has Role`** `workspace.json` (accès console, bloc Fiches Workspace). Le contrôle d'invocation du chat vit dans un 3e artefact — `frontend/chat_otoia/out/chat_mount.json` (`roles_allowed` par portail) — que le bloc Chat OTOIA amont ne gate que sur l'IDENTITÉ persona/capabilities + la COMPOSITION (5 mounts ⇔ 5 portails), AVEUGLE à QUEL rôle figure dans quelle `roles_allowed`.
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (QA/DevOps — série anti-dérive CLAUDE.md #6, roadmap fonctionnellement close). **Même patron EXACT** que le bloc de membership `Has Role` (juste au-dessus dans `check_readme_claims.sh`) — appliqué à un **artefact + une sémantique DIFFÉRENTS** : accès console (`Has Role`) ≠ droit d'invocation du chat (`roles_allowed`).
|
||
|
||
**Dérive silencieuse fermée** :
|
||
- `03_agents/rendu/AGENT.md:36` — POSITIVE : rôle « OTO Faisabilité Rendu 3D » ∈ `roles_allowed` du portail NOMMÉ `construction` (déclenchement des rendus assistés).
|
||
- `03_agents/mobile/AGENT.md:41` — NÉGATIVE d'honnêteté (#6) : rôle « OTO Plateforme Mobile » (famille `plateforme`) dans AUCUNE `roles_allowed` (le chat ne couvre que les portails métier).
|
||
- Source faisant autorité : `frontend/chat_otoia/out/chat_mount.json[].roles_allowed` (byte-gaté par `check_artifacts`), `erpnext_role_name` résolu du contrat par `id` (zéro duplication).
|
||
- Piège : ajouter le rôle mobile à une `roles_allowed` = **SUR-EXPOSITION** (le dev mobile gagnerait le droit de piloter l'IA d'un portail métier — l'escalade même que #6 refuse) ; retirer le rôle rendu de la `roles_allowed` construction = perte du déclenchement assisté ; DÉPLACER le rôle vers un autre portail — laisse la fiche périmée EN SILENCE pendant que l'artefact dit autre chose. Aucune suite `tests/` (qui teste des FONCTIONS de montage, pas la prose d'une fiche) n'attrape ce « vert trompeur ».
|
||
- **État courant** : aucune valeur périmée — rendu ∈ construction (et lui seul), mobile ∉ tout (anti-invention #6, rien à réécrire). Le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiches agents · appartenance à `roles_allowed` du chat OTOIA » après le bloc Fiches Workspace) : index recomputé `erpnext_role_name → {portails autorisant}`, puis (a) **in_named_portail** (rendu) — le portail nommé est data-derived (== `portail` du rôle au contrat, **triple ancrage** : nommé == contrat == unique portail autorisant), membership == {ce portail}, prose citant « invoquer le chat OTOIA » ; (b) **not_in_any** (mobile) — rôle ABSENT de TOUTE `roles_allowed`. Portail nommé fantôme (absent des mounts) = échec (anti-typo). Claim absent = échec (traçabilité #6). Invariant vérifié en amont : chaque rôle ∈ ≤1 `roles_allowed`, == son `portail` contrat.
|
||
|
||
**6 morsures vérifiées** (3 côté artefact · 3 côté fiche/bord) : artefact retire rendu de `construction` (∉ aucun portail) · artefact ajoute mobile à `ventes` (SUR-EXPOSITION #6 VIOLÉE) · artefact ajoute AUSSI rendu à `compta` (droit élargi, fiche nomme 1 seul) · fiche rendu nomme le mauvais portail (`construction→compta`, INTROUVABLE) · fiche mobile retire le token `roles_allowed` (INTROUVABLE) ; restauré = green : rendu ∈ `{construction}` · mobile ∉ tout · exit 0. Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) · **7 gates re-verts** (`validate_json`/`check_docs`/`guard_constraints`/`check_artifacts`/`check_ci_integrity`/`check_readme_claims`/`check_regression`).
|
||
|
||
- `ci/README.md` (recap `check-readme-claims` + paragraphe détaillé « 3e surface d'appartenance · `roles_allowed` du chat OTOIA ») mis à jour.
|
||
- **Note memory** : la classe « agent-fiche-role-attrs-ungated » est désormais CLOSE (attributs contrat = Fiches Faisabilité/Mobile ; `Has Role` = Fiches Workspace ; `roles_allowed` chat = ce bloc). Candidat propre restant : la fiche `ifc_speckle:34` (attributs contrat déjà gatés) + la row acceptance S3 « viewer 3D » (déjà gatée QA).
|
||
- **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 montage réel du chat reste côté runner/VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
---
|
||
|
||
## Session 20260801_193414 · Sprint 8 · buffer · Gate d'IDENTITÉ des comptes de tests self-reportés par les README de MODULE (#6)
|
||
|
||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre sa source de vérité. Tous les blocs de **comptes de tests** existants (`ci/check_readme_claims.sh`) visent `03_agents/*/AGENT.md` : la cellule « Tests » des tables via `row_re`, les agrégats prose de `crm`/`erpnext_backend`, et les cinq claims per-suite « hors table » (seo/portails/chat_otoia/confotur/deploy_runbook). AUCUN ne touche le README du **MODULE** lui-même — pourtant `05_deliverables_mvp/<suite>/README.md` se re-déclare, en propre, le compte de SA suite à plusieurs endroits.
|
||
|
||
**Surface trouvée (ungated)** : **27 claims sur 16 READMEs de module**, sous trois formulations récurrentes :
|
||
- commentaire de la commande unittest : `discover -s tests -v # N tests (…)` ;
|
||
- bullet « Vérification en-repo » : `→ **N/N verts**` (six modules RBAC/faisabilité/CRM) ;
|
||
- justification d'auto-score 4Big : `Validé statiquement en-repo (N tests verts + …)`.
|
||
Ces nombres sont SAISIS À LA MAIN dans le doc d'entrée de chaque module et se périment dès qu'un `def test_` est ajouté/retiré : la source faisant autorité (`qa/regression/out/regression_plan.json` → `auth = plan.suites[path].test_methods`, recomptée à chaque build par découverte réelle, byte-gatée par `check_artifacts` + fraîcheur du run par `check_regression`) se met à jour tandis que la prose du README rote EN SILENCE — « vert trompeur » de la MÊME classe que la cellule « Tests » des fiches, mais sur la surface que `row_re` n'atteint pas (il ne lit le README de module QUE comme *cible de lien*). Aucune suite `tests/` (qui teste des FONCTIONS de génération, jamais la prose du README) n'attrape ce périmé.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « READMEs de MODULE · comptes de tests self-reportés » juste après le bloc per-suite « hors table », d'où `auth` est déjà en portée · zéro rechargement · #6) : table de config `MODULE_README_TESTS` = liste `(suite_path, [motifs ancrés])`. Pour chaque module : `auth[suite_path]` recomputé, chaque motif DOIT matcher (claim absent = régression #6) ET tous ses groupes capturés == `auth`. Le motif `**N/N verts**` capture DEUX groupes → les deux doivent valoir `auth` : un `25/24 verts` internement incohérent mord aussi. Chaque motif est ancré sur un contexte distinctif (`discover -s tests…# N tests`, `**N/N verts**`, `en-repo (N tests verts`, `test_confotur.py # N tests`…) pour viser LE compte de CETTE suite sans capter un autre nombre.
|
||
- **Cinq modules volontairement HORS table** (`frontend/chat_otoia`, `mobile/app_config`, `publiciste`, `qa/acceptance`, `qa/audit_4big`) : leur README ne self-reporte AUCUN compte de tests (vérifié) — rien à ancrer ; un futur claim = l'ajouter à la table. Noté dans le commentaire du bloc.
|
||
|
||
**4 morsures vérifiées** (chaque README restauré depuis backup — **JAMAIS** `git checkout .`/`git clean`, interdits absolus) :
|
||
1. drift commentaire (`faisabilite/generator` 16→17 tests) → ✗ « dit 17 MAIS source dit 16 » ;
|
||
2. incohérence interne `N/N` (`rbac/apply_plan` `16/16`→`16/17 verts`) → ✗ « dit 16/17 MAIS source dit 16 » ;
|
||
3. disparition de claim (`legal/confotur` prose auto-score « diffable, 44 tests (dont… » retirée) → ✗ « claim INTROUVABLE (attendu 44) » ;
|
||
4. drift auto-score prose (`rbac/fixtures_gen` `(11 tests verts`→`(12 tests verts`) → ✗ « dit 12 MAIS source dit 11 ».
|
||
Restauré = green : `rc=0`, **440 checks de base intacts (diff vide) + 27 nouveaux**. Gates sœurs re-verts : `check_ci_integrity` rc=0 · `check_docs` rc=0.
|
||
|
||
- En-tête du gate mis à jour (inventaire des surfaces couvertes : nouvelle entrée « comptes de tests self-reportés par MODULE »).
|
||
- **Note memory** : classe « comptes de tests » — désormais couverte sur TROIS surfaces (cellule « Tests » des fiches via `row_re` · agrégats prose fiches · **README de module**, ce bloc) + les cinq claims per-suite hors table. Source unique = `auth` (plan.suites[].test_methods).
|
||
- **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_200419` · Buffer S8 · Fiche DevOps : gate du **COMPTE de suites gated** (« 22 suites gated ») — sémantique DISTINCTE des comptes de tests par suite
|
||
|
||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre
|
||
sa source de vérité (CLAUDE.md #6, roadmap fonctionnellement close). Tous les blocs de
|
||
comptes de tests de `ci/check_readme_claims.sh` recomputent un compte de **méthodes**
|
||
`def test_` (`auth[path]` = `plan.suites[path].test_methods`) : la cellule « Tests »
|
||
des tables via `row_re`, les agrégats prose crm/erpnext_backend, les 5 claims per-suite
|
||
« hors table », et les READMEs de module. Une surface d'une **classe voisine mais
|
||
distincte** restait ungated.
|
||
|
||
**Surface trouvée (ungated)** : `03_agents/devops/AGENT.md:24` — dans la table des
|
||
livrables DevOps, la cellule « Tests » de la row du **pipeline CI**
|
||
(`.gitea/workflows/ci.yml` + `ci/`) affiche « **22 suites gated** » : non pas un compte
|
||
de tests, mais le **nombre de SUITES** que la CI passe au crible, soit
|
||
`regression_plan.totals.suites`. Ce nombre est saisi À LA MAIN et **aucun** gate ne
|
||
l'atteignait :
|
||
- `row_re` échoue DEUX fois : l'ancre de lien est `ci.yml`/`ci/` (pas un module de
|
||
`auth`) ET la cellule porte le suffixe « suites gated » (pas un entier nu) ;
|
||
- l'agrégat de la fiche QA (`03_agents/qa/AGENT.md:35` « **22 suites gated · 564
|
||
tests…** », gaté sur `regression_run`) est une **surface distincte** (autre fichier,
|
||
autre motif). La MÊME valeur 22 vit donc à DEUX endroits — **un seul** était gaté.
|
||
|
||
**Dérive silencieuse fermée** : ajouter/retirer un module gated fait bouger
|
||
`reg["suites"]` (recompté à chaque build par découverte réelle des suites, byte-gaté par
|
||
`check_artifacts`) tandis que cette cellule DevOps rote EN SILENCE ⇒ la doc d'identité de
|
||
l'agent DevOps affirmerait un **périmètre de couverture CI faux** — le « vert trompeur »
|
||
que #6 interdit. Aucune suite `tests/` (FONCTIONS, pas la prose de fiche) ne l'attrape.
|
||
**État courant** : valeur exacte (22 == 22), le défaut est la **surface ungated** (rien
|
||
à réécrire · anti-invention #6).
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiche DevOps · COMPTE de
|
||
suites gated » juste après le bloc per-suite « hors table », d'où `reg` est déjà en
|
||
portée · zéro rechargement) : on RECOMPUTE depuis `reg["suites"]`
|
||
(`regression_plan.totals.suites`, source unique) et on exige que la cellule l'écrive
|
||
EXACTEMENT. Motif ANCRÉ sur le label de rôle « CI/CD Gitea Actions » de CETTE row →
|
||
vise la bonne cellule. Claim absent = échec (traçabilité #6). **Cohérence croisée** :
|
||
`reg["suites"]` == `regression_run` `len(suites)` (la source du compte de la fiche QA)
|
||
⇒ une divergence plan↔run mord ici aussi.
|
||
|
||
**5 morsures vérifiées** (2 côté fiche · 2 côté artefact · 1 cross-cohérence) :
|
||
1. cellule 22→23 → ✗ « dit 23 MAIS source dit 22 » ;
|
||
2. claim retiré (`| gated |`) → ✗ « cellule « N suites gated » INTROUVABLE » ;
|
||
3. `plan.totals.suites` 22→21 (fiche périmée) → ✗ divergence SOURCE + ✗ « dit 22 MAIS
|
||
source dit 21 » ;
|
||
4. `regression_run` privé d'une suite (plan↔run divergent) → ✗ « incohérence SOURCE :
|
||
plan.suites=22 ≠ run len=21 » ;
|
||
5. restauré = green (rc=0).
|
||
Working tree byte-restauré via `git checkout -- <fichier précis>` (**JAMAIS**
|
||
`git checkout .` / `git clean`, interdits absolus). **7 gates re-verts** :
|
||
`validate_json` / `check_docs` / `guard_constraints` / `check_artifacts` /
|
||
`check_ci_integrity` / `check_readme_claims` / `check_regression` (tous rc=0).
|
||
|
||
- En-tête du gate mis à jour (inventaire des surfaces couvertes : nouvelle entrée
|
||
« COMPTE de suites gated de la fiche devops ») + `ci/README.md` (recap
|
||
`check-readme-claims` : nouvelle clause du compte de suites gated).
|
||
- **Note memory** : la classe « comptes de tests » (méthodes `def test_`) est couverte
|
||
sur 4 surfaces + les 5 per-suite ; le COMPTE de **suites** (`plan.totals.suites`) est
|
||
une classe voisine — désormais gaté sur ses DEUX surfaces (fiche QA agrégat déjà gaté ·
|
||
fiche DevOps cellule, ce bloc).
|
||
- **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_203424` · Buffer S8 · Audit 5D (4e surface du même README) : gate de l'IDENTITÉ des **LIVRABLES AUDITÉS** — la liste des hand-off `out/*.json` que l'audit de second niveau LIT comme matière première
|
||
|
||
**Contexte** : la série anti-dérive Sprint-8 gate chaque surface data-derived contre
|
||
sa source de vérité (CLAUDE.md #6, roadmap fonctionnellement close). Trois blocs
|
||
`audit_5d` de `ci/check_readme_claims.sh` couvrent déjà le MÊME README : la **synthèse**
|
||
(17 contrôles / 5 dimensions + ventilation verdict), l'**énumération des open items**
|
||
(`control→dimension→propriétaire`) et l'**IDENTITÉ des 5 dimensions** (`id→titre→
|
||
reference`). Une **4e surface** du même README restait ungated.
|
||
|
||
**Surface trouvée (ungated)** : `05_deliverables_mvp/qa/audit_5d/README.md:21-27` —
|
||
section « ## Livrables audités (source = leur `out/`) » : une **liste de 5 puces** qui
|
||
énumère À LA MAIN les hand-off `out/*.json` que l'auditeur charge réellement
|
||
(`crm/workflow_vente/out/workflow.json` · `crm/dossier_vente/out/doctype_oto_dossier_
|
||
vente.json` · `crm/commissions/out/commission_plan.json` · `fiscal/ecf_dgii/out/
|
||
ecf_plan.json` · `legal/confotur/out/doctype_confotur_application.json`). Aucun bloc ne
|
||
la touchait — vérifié : le seul `audited_artifacts` de tout le gate était dans un
|
||
**commentaire** ; les 3 blocs audit_5d ne `load()` que `controls_total`/`totals`/
|
||
`open_items`/`dimensions[]`.
|
||
|
||
**Source faisant autorité** : `qa/audit_5d/out/MANIFEST.json` clé `audited_artifacts`
|
||
(byte-gaté par `check_artifacts` ⇒ reproduit à chaque build via
|
||
`sorted(ARTIFACT_PATHS.values())` dans `audit_5d_gen.py:61` — le registre des hand-off
|
||
que `qalib/artifacts.py::load_artifacts()` charge). Le README énumère les 5 chemins
|
||
dans un **ORDRE DIFFÉRENT** du MANIFEST (workflow 2e ici, 3e au MANIFEST trié) ⇒
|
||
comparaison par **ENSEMBLE**.
|
||
|
||
**Dérive silencieuse fermée** : brancher un nouveau livrable amont sur l'audit
|
||
(nouvelle entrée `ARTIFACT_PATHS` → nouveau chemin dans `audited_artifacts`) ou en
|
||
retirer un laisse la section README **périmée en silence** pendant que l'audit lit un
|
||
autre jeu de fichiers ⇒ le lecteur/banquier croirait l'audit couvrir un **périmètre
|
||
qu'il ne couvre plus** (l'invention #6 interdit), qu'aucune suite `tests/` (FONCTIONS
|
||
de contrôle, pas la prose) n'attrape. **État courant** : les 5 puces == registre
|
||
exactement (rien à réécrire · anti-invention #6), le défaut est la **surface ungated**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Audit 5D (4e surface) ·
|
||
IDENTITÉ des LIVRABLES AUDITÉS » entre le bloc des 5 dimensions et le bloc DevOps
|
||
run-book) : on RECOMPUTE l'ensemble depuis `MANIFEST.audited_artifacts` (zéro
|
||
duplication du registre) et on parse les puces `` - `<chemin>` `` de la section
|
||
« ## Livrables audités » → égalité par ENSEMBLE exigée (absent ET fantôme mordus, via
|
||
set-diff `absents`/`en trop`). **Cohérences croisées bonus** : **(a)** chaque chemin
|
||
audité RÉSOUT un fichier commité sur disque (`os.path.exists` — le `_load` de l'auditeur
|
||
lève `FileNotFoundError` sinon, audit à vide impossible) ; **(b)** |livrables audités|
|
||
== |alias distincts d'artefacts référencés par les `controls[].artifacts` de
|
||
`audit_spec.json`| (un artefact chargé mais jamais contrôlé, ou un alias contrôlé sans
|
||
chemin de chargement → `KeyError` runtime, désynchronise). Section absente = échec
|
||
(traçabilité #6). `import os` ajouté au bloc (non importé globalement).
|
||
|
||
**6 morsures vérifiées** (4 côté README · 2 côté source) :
|
||
1. README puce `workflow.json` retirée → ✗ « absents=[…workflow.json] » ;
|
||
2. README puce FANTÔME `demo/scenarios/out/run_sheet.json` ajoutée → ✗ « en trop
|
||
(fantôme)=[…run_sheet.json] » ;
|
||
3. README typo `commission_plan.json`→`commissions_plan.json` → ✗ absents ET fantôme ;
|
||
4. README header de section renommé → ✗ « section « ## Livrables audités »
|
||
INTROUVABLE/vide » ;
|
||
5. `audit_spec.json` : alias `phantom_alias` ajouté à un contrôle → ✗ « désynchro
|
||
registre/spec : 5 livrables MAIS 6 alias distincts contrôlés » (cross-anchor b) ;
|
||
6. `MANIFEST.audited_artifacts` : un chemin pointé vers un fichier inexistant → ✗
|
||
« INTROUVABLES sur disque » (cross-anchor a) + ✗ README périmé.
|
||
Restauré = green : 5 puces == registre · 5 == 5 alias · 5 fichiers résolus · exit 0.
|
||
Working tree byte-restauré via `git checkout -- <fichier précis>` (**JAMAIS**
|
||
`git checkout .` / `git clean`, interdits absolus). **7 gates re-verts** :
|
||
`validate_json` / `guard_constraints` / `check_docs` / `check_artifacts` /
|
||
`check_regression` / `check_ci_integrity` / `check_readme_claims` (tous rc=0).
|
||
|
||
- `ci/README.md` mis à jour : clause de la row récap `check-readme-claims` (surface
|
||
audit 5D étendue) + paragraphe détaillé « 4ᵉ surface du même README de l'audit 5D ».
|
||
- **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'exécution
|
||
réelle de l'audit `bench` reste côté VPS).
|
||
- **Auto-score 4Big** : 96/100.
|
||
|
||
## Session `20260801_213444` · Buffer S8 · Fiche ONAPI/Legal : 2ᵉ SURFACE PROSE des ENTITÉS PORTEUSES
|
||
|
||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA — anti-dérive doc). Roadmap
|
||
plancher atteinte ; on continue de fermer les surfaces prose data-derived encore
|
||
ungatées. Cible de cette session : `03_agents/onapi_legal/AGENT.md:54`.
|
||
|
||
**Surface trouvée (ungatée)** : la fiche ONAPI/Legal décrit le champ Select
|
||
`entite_porteuse` du DocType CONFOTUR par « **les 7 entités de CLAUDE.md #Entités
|
||
(WAF · WA SRL · AC Arias Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060
|
||
QC)** ». C'est un **COMPTE littéral** (« 7 ») **+** l'**énumération complète** — une
|
||
**SECONDE surface prose** du même menu que le champ `entite_porteuse` offrira.
|
||
|
||
Le bloc « Confotur entités » déjà en place ancre le champ à CLAUDE.md §Entités et
|
||
gate la ligne du README `legal/confotur` (surface **(e)**), mais ce motif est ancré
|
||
sur `05_deliverables_mvp/legal/confotur/README.md` — **il ne vise pas `03_agents/`**.
|
||
La fiche restait donc **hors de tout gate** : recompter la §Entités (aujourd'hui 7)
|
||
n'atteignait jamais cette phrase.
|
||
|
||
**Dérive silencieuse fermée** : AJOUTER / RETIRER / RENOMMER une entité dans
|
||
CLAUDE.md §Entités (source ancre) → régénérer propage le menu de l'artefact **et** la
|
||
ligne du README confotur, MAIS la fiche onapi_legal se **périme en silence** — elle
|
||
annoncerait « 7 entités » quand il y en a 8, ou nommerait `Ploutos` là où le menu ne
|
||
l'offre plus. L'agent ERPNext Backend qui seede le DocType croirait le déroulant
|
||
couvrir un périmètre d'entités qu'il ne couvre plus (l'**invention #6** interdit).
|
||
Aucune suite `tests/` (FONCTIONS de build du DocType, pas la prose d'une fiche) ne
|
||
l'attrape. **État courant** : la fiche == §Entités == menu artefact exactement
|
||
(rien à réécrire · #6) ; le défaut était la surface **ungatée**.
|
||
|
||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Fiche ONAPI/Legal ·
|
||
2ᵉ SURFACE PROSE des ENTITÉS PORTEUSES », inséré juste après le bloc « Confotur
|
||
entités » et avant le bloc Chat OTOIA) : on **re-dérive** la liste depuis les tokens
|
||
en gras de la section « ## Entités » de CLAUDE.md (source ancre · zéro duplication)
|
||
et on exige de la fiche — **(a)** le COMPTE littéral (« les N entités ») ==
|
||
|§Entités| ; **(b)** l'énumération == §Entités **ORDRE EXACT** (absent ET fantôme
|
||
mordus par set-diff + comparaison ordonnée) ; **(c)** l'ancre « CLAUDE.md #Entités »
|
||
citée sur la ligne ; **(d)** cross-check bonus — l'énumération == options
|
||
`entite_porteuse` de l'artefact CONFOTUR byte-gaté (la fiche décrit **exactement** le
|
||
menu que le DocType offrira). Ligne absente = échec (traçabilité #6).
|
||
|
||
**6 morsures vérifiées** (5 côté fiche · 1 côté artefact) :
|
||
1. compte `7`→`8` → ✗ (a) « fiche dit 8 entités MAIS §Entités en porte 7 » ;
|
||
2. `Ploutos` retiré de l'énumération → ✗ (b) « absent(s)=['Ploutos'] » ;
|
||
3. entité FANTÔME `Fantom SA` ajoutée → ✗ (b) « fantôme(s)=['Fantom SA'] » ;
|
||
4. réordre `WAF`↔`WA SRL` → ✗ (b) « ordre : fiche […] ≠ §Entités […] » ;
|
||
5. ancre `#Entités` retirée de la ligne → ✗ (c) « ne cite pas CLAUDE.md #Entités » ;
|
||
6. option `Ploutos`→`Ploutos SRL` dans l'artefact CONFOTUR → ✗ (d) « fiche […] ≠
|
||
menu artefact […] → la fiche décrit un menu que le DocType n'offre pas ».
|
||
Restauré = green : (a)(b)(c)(d) tous ✓ · exit 0. Working tree byte-restauré via
|
||
`git checkout -- <fichier précis>` (**JAMAIS** `git checkout .` / `git clean`,
|
||
interdits absolus). **7 gates re-verts** : `validate_json` / `guard_constraints` /
|
||
`check_docs` / `check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||
`check_readme_claims` (tous rc=0).
|
||
|
||
- `ci/README.md` mis à jour : paragraphe « Entités porteuses du DocType CONFOTUR »
|
||
étendu d'une clause « **2ᵉ surface prose (fiche ONAPI/Legal)** » (compte + liste +
|
||
cross-check menu artefact).
|
||
- **Note anti-stale** : la mémoire `agent-fiche-role-attrs-ungated` est désormais
|
||
**périmée** — les attributs des fiches mobile / rendu / ifc_speckle (niveau, scope,
|
||
modules, permissions, entité) SONT déjà gatés (blocs « Fiche Mobile » et « Fiches
|
||
Faisabilité »). La classe résiduelle réelle est celle des LISTES data-derived
|
||
transcrites en prose de fiche, dont cette session ferme l'occurrence entités.
|
||
- **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'application
|
||
réelle du DocType par `bench` reste côté agent ERPNext Backend).
|
||
- **Auto-score 4Big** : 96/100.
|