Le gate valide la bonne-formation JSON SEULEMENT (parse strict), mais l.27 portait un
commentaire orphelin annonçant un contrôle de conformité $schema/draft que le code
n'implemente jamais (branche then imprime juste le check). Nouvelle sous-classe
comment-vs-code : les scripts de GATE eux-memes, jamais couverts par les sweeps
docstring-vs-code (scopes aux generateurs de prod + helpers *lib/).
Isolement verifie : sweep des 8 scripts ci/*.sh + lib.sh = 0 autre derive.
Fix 2 volets : (1) suppression de la ligne fantome ; (2) en-tete PERIMETRE explicite
(bonne-formation seule ; conformite $schema = oracle jsonschema optionnel de
check_regression.sh, 17 skips par design) -> le commentaire retire devient une
affirmation positive et vraie du perimetre.
0 changement de logique executable, 0 artefact rebuild, 0 gate ajoute (#5, FIX pas
controle neuf), 0 chiffre saisi (#6), 0 VPS (#8). run_ci 33 PASS / 0 FAIL / 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La table §1 « Ce que fait le pipeline » de ci/README.md est LA doc canonique des jobs
statiques (une ligne par gate ci/*.sh). Sa complétude était le jumeau exact de la fiche QA
fermée par afa6165, mais NON gaté : check_ci_integrity verrouille le câblage (ci/*.sh ↔
gate.needs), le bloc fiche-QA ne lit que 03_agents/qa/AGENT.md — rien n'exigeait que chaque
gate figure dans la table §1. Un 9ᵉ gate y serait omis EN SILENCE. Prouvé ungate par mutation
(retrait de la ligne de table check_mobile_workflow → run_ci --static 8 PASS, aucun gate ne mord).
Fix = extension du gate existant (PAS un nouveau job · #5) : bloc Python dans check_readme_claims.sh
(avant sys.exit) réutilisant _gate_names re-dérivé de git ls-files 'ci/*.sh' (hors lib.sh · #6).
Exige chaque basename cité dans une LIGNE DE TABLE (|…) de la section §1 — délibérément PAS la
prose §1 (qui ne cite que certains gates pour l'explication mobile-build.yml : un contrôle
whole-section serait édenté sur un retrait de ligne de table). 0 nouveau ci/*.sh, 33 jobs inchangés.
Teeth 2 axes : MUT1 suppression de la vraie ligne de table (l.24) → RED nommant check_mobile_workflow.sh ;
MUT2 9ᵉ ci/*.sh factice tracké → RED sur les DEUX surfaces (fiche QA + table §1 : forward-protection)
puis git rm --cached + rm, arbre byte-restauré (JAMAIS git clean). Piège inerte écarté : sed 15d
visait l'en-tête de table (grep -n renumérotait relatif au pipe), re-ciblé sur la ligne 24 réelle.
Doc sous-section « COMPLÉTUDE de l'énumération dans la TABLE §1 » ajoutée en §2 de ci/README
(discipline ci-readme-table-detail-in-section2). Sweep préalable repo-wide 7-gates/32-jobs : 0
dérive réelle (toutes occurrences historiques datées ou pédagogiques, classées KEEP).
0 édition de production, 0 artefact rebuild, 0 chiffre saisi (#6 — 8/9 recomputés), 0 VPS (#8).
run_ci 33 PASS · 0 FAIL · 0 SKIP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Régression neuve depuis commit 9c062ef : OTO_DESIGN_SYSTEM_v1.md §15
« Fichiers canoniques sur VPS » liste /var/www/html/static/ en inventaire
descriptif (chemin servi = symlink de /opt/oto/sites/static). Faux-positif de
la classe que le garde ignore (USAGE, pas mention) ; doc root-owned non éditable
+ non créé par le worker → fix au niveau du garde (précédent session 010630).
- ci/guard_constraints.sh : OTO_DESIGN_SYSTEM_*.md (glob) ajouté aux exclusions
tracked_files(), même catégorie qu'AUTORISATIONS_*/DIRECTIVE_* ; en-tête documenté.
- ci/README.md : §exclusions + NB inconsistance chemin-servi-vs-source mis à jour.
- Mutation-test : garde mord toujours les 3 usages code réels (static VPS/GitHub/Stripe).
- Inconsistance chemin servi (/var/www/html/static) vs source (/opt/oto/sites/static)
du §15 re-signalée à Michel (non tranchée par le garde).
run_ci.sh : 30 PASS · 0 FAIL · 0 SKIP (rétabli). Zéro nouveau module, zéro gate ajouté (#5).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Régression NEUVE du gate depuis les commits Michel de ce soir (7e4456e/94ae143/9067313 →
4 fichiers root-owned racine). constraints-guard mordait AUTORISATIONS_MICHEL_20260803.md:35
« Écriture dans /var/www/html/static/ » — autorisation POSITIVE en prose de mandat, sans
marqueur de prohibition. Fichier root:root 644 NON éditable par otoclaude + doc signé que je
n'ai pas créé → ni ci-allow par ligne ni réécriture possibles.
Correctif au niveau du garde (ci/, que je possède) : AUTORISATIONS_*.md + DIRECTIVE_*.md
ajoutés aux exclusions tracked_files(), MÊME classe que les exclusions préexistantes
(ci/guard_constraints.sh + .gitea/workflows/*.yml) — docs contenant NÉCESSAIREMENT les
termes en texte de politique. Détection vraie-positive PRÉSERVÉE (mutation-test : un .sh
commité avec les 3 usages interdits → garde mord 3/3). CLAUDE.md RESTE scanné.
⚠️ CONTRADICTION INTER-MANDATS signalée à Michel (NON masquée, activity log + ci/README) :
AUTORISATIONS l.35 contredit l'interdit absolu CLAUDE.md — le chemin correct est le SYMLINK
source /opt/oto/sites/static/. Recommandation : corriger l.35. Décision → Michel.
ci/README §guard mis en cohérence. Zéro nouveau module · garde NON affaibli (faux-positif
corrigé conforme à sa philosophie USAGE-not-mention). run_ci.sh 30 PASS 0 FAIL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Audit doc-vs-réalité (fan-out exploration) sur les *.md de tête, 03_agents/*/AGENT.md,
05_deliverables_mvp/*/README.md, ci/README.md, roadmap → UNE candidate : CLAUDE.md#2
« michel/otov7-platform » vs section Git « oto-enterprise-os-dtp ». FAUX POSITIF connu
(mémoire otov7-platform-not-drift) : deux dépôts Gitea distincts, tous deux corrects —
otov7-platform = dépôt PRODUIT (plateforme OTOV7 cible du refactoring), oto-enterprise-os-dtp
= dépôt MANDAT (ce worker). L'agent d'exploration (sans accès mémoire) l'a re-remonté →
preuve que le garde-fou méritait d'être in-repo, pas seulement en mémoire privée.
Action : paragraphe « Non-dérive documentée » ajouté à la section guard_constraints.sh de
ci/README.md (propriétaire de #2), calqué sur la note roles_couverts « 44 » — explicite que
produit ≠ mandat, qu'il ne faut PAS « aligner » CLAUDE.md#2, et qu'il n'y a rien à gater
(le garde ne vérifie que l'ABSENCE de github/gitlab/bitbucket, pas l'identité d'un repo
Gitea autorisé).
Discipline : zéro module · zéro gate ajouté (#5) · CLAUDE.md intact (on ne « corrige » pas
la constitution · #6). Recompute README concordant (22/22 scores={100} · 564/564 · 15/15
in_repo · 13 agents · gate.needs=30) = zéro dérive numérique. run_ci.sh --static 7 PASS ·
guard_constraints/check_docs/check_readme_claims verts (nouveau texte cite les plateformes
interdites mais chaque ligne porte « interdites » → ignorée par le garde). Aucune commande
touchant au VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Même fix que dcb463e, un cran plus haut. dcb463e avait dérivé le décompte 30/23/7
du COMMENTAIRE de run_ci.sh (il se périme à chaque module ajouté/retiré de ci.yml) ;
mais la DOC du lanceur (ci/README.md §« Rejouer le gate EN LOCAL ») re-transcrivait
encore les mêmes nombres à la main : bloc d'usage L34-35 (« 7 gates statiques + 23
suites de module » / « 7 gates ci/*.sh ») + checklist L1601 (« 7 gates statiques »).
Vérif d'exposition (verify-uncovered-before-gating) : mutation 23→24 / 7→8 →
check_readme_claims ET check_docs restent VERTS → surface réellement NON gatée.
Décision FIXER pas gater (fix-vs-gate + local-ci-runner) : ci/README.md:51-54 déclare
lui-même que run_ci.sh « n'a pas à être re-gaté (#5) » (exactitude structurelle) —
gater la prose qui le décrit trahirait cette posture. On retire donc les nombres
figés et on laisse run_ci.sh seul propriétaire du décompte (dérivé de gate.needs,
imprimé à l'exécution + --list). Ajout d'un paragraphe l'explicitant (même raison #6).
Intactes : les « 7 gates re-verts » du CHANGELOG (narratif historique d'états passés
VRAIS, pas une composition vive). Zéro module · zéro gate (#5) · zéro chiffre inventé
(#6) · run_ci.sh 30 PASS · guards verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Balayage de complétude après cb8d931 (qui a ancré « 13 agents » aux 2 docs de
mandat de tête) : 3ᵉ surface HORS gate = le livrable Sprint 1 GAP_ANALYSIS_SPRINT1.md
(Definition of Done). Retranscrit le compte à 3 endroits vifs — périmètre d'audit
(l.12) · constat global total (l.53, le « 12 » analytique EXCLU) · coche de
couverture DoD (l.214). Prouvé ungate (grep ci/=0 ; mutation 13→14 laissait exit 0)
et à dérive prouvée (publiciste 12→13). Extension de la boucle head-docs existante
(3 tuples réutilisant n_agents = git ls-files 03_agents/*/AGENT.md · zéro nouvelle
machinerie · #5) ; on n'ancre que le total ; INTROUVABLE = échec (#6). ci/README.md
documente désormais 7 surfaces vives. 6 morsures (M5 no-false-positive sur le « 12 » ·
M6 SILENT-GREEN via git rm --cached prouvant l'autorité git-index). 7 gates exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Classe « seuil data-derived recopié dans une garde de validation + sa prose,
jamais ancré » (déjà couverte pour min_doc_bytes/min_test_methods de l'auditeur
4Big). Livrable Sprint 7 demo/scenarios : la garantie #3 du README énonce deux
planchers RÉELLEMENT imposés par check_invariants bloc (c) — len(sc["beats"])<3,
len(mods)<2 — mais recopiés à la main à 3 surfaces (comparaison `<`, message
d'erreur « (min N) », prose README), aucune gatée. Muter « ≥ 3 beats »→« ≥ 4 »
laissait check_readme_claims exit 0 (prouvé ungate).
Gate re-dérive les 2 minima depuis la SEULE comparaison `<` (source unique #5) et
exige message + prose == plancher effectif ; surface INTROUVABLE échoue (#6).
7 morsures adversariales (dont M3 SILENT-GREEN : code resserré `<3`→`<4` ⇒ message
ET README mordent, preuve autorité=CODE). 39 tests OK (générateur inchangé) ; suite
CI complète re-verte.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le générateur workflow_vente_gen.py (Livrable Sprint 4 l.50) porte un ledger de
9 invariants métier de graphe dans `_validate_bundle` (marqueurs `# Invariant N ·`,
phrasé « schéma + 9 invariants »), avec le nombre « 9 » recopié à la main à 4
surfaces vives (gen l.223 + README l.78/114/125), aucune gatée. Prouvé ungate
avant ajout (README 9→10 laissait check_readme_claims exit 0). Gate ajouté
(a)(b)(d) sur le modèle Mobile : recompute le ledger depuis le SEUL registre-source
`# Invariant N ·`, exige contiguïté 1..N + toute mention « N invariants » du .py et
du README == |ledger|. Pas de gate (e) enum : la liste « ## Invariants vérifiés par
le CLI » compte le schéma en item 1 et fusionne les invariants 8&9 → n'est pas le
ledger (faux positif fragile évité). « 25 tests » exclu nativement par l'ancre
« invariants » (aucun faux positif). 3 checks verts arbre propre · 7 morsures
adversariales (dont M3 SILENT-GREEN `# Invariant 10 ·` ⇒ autorité=CODE, M7
no-false-positive) · unittest 25 OK · suite CI complète re-verte.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
row_re du gate check_readme_claims §comptes-par-suite exigeait un lien …/README.md ;
la fiche erpnext_backend pointe rbac/ via RBAC_50_ROLES_SPEC.md (son point d'entrée
contrat), donc sa cellule « Tests | 10 | » échappait au recompute depuis
regression_plan.json. Mutation-test 10→99 : gate restait VERT (vrai angle mort,
classe « vert trompeur »). Extension : accepte tout *.md d'entrée du dossier module
(/[\w.-]+.md) ; le garde path-not-in-auth protège l'élargissement. rbac désormais
vue+mordue ; 7 gates verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Recompute le compte « 12 invariants » depuis le SEUL registre-source
(`# Invariant N ·` de `_validate_bundle`) — 4 surfaces prose hand-transcrites
(CLI .py, 2× README, docstring test) ancrées, aucune n'était gatée. Style de
marqueur `# Invariant N ·` + fonction `_validate_bundle` = deux différences
structurelles vs les 7 blocs `# N ·`/`_validate` précédents ; ajoute la surface
fichier-de-tests (b'). 4 verts arbre propre · 8 morsures adversariales · 6 gates
CI exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extension du bloc « RBAC fixtures » (points 4 & 5) : la 3e surface prose du fait
de sécurité set_user_permissions (SPEC §2 encadré + §6 row) était NON gatée. Le
test test_rbac impose scope/famille à tout détenteur mais jamais le NOM du rôle ni
la prose §2. Réutilise fx_sup (singleton déjà byte-gaté · pas de doublon d'unicité,
#5) comme nom-autorité + src_roles pour scope/famille.
Prouvé M6 SILENT-GREEN : rename détenteur dans le contrat + régen artefacts =>
check_artifacts VERT mais §2 name-gate RED (autorité = artefact, pas cohérence SPEC).
6 morsures adversariales, 6 gates re-verts exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nouvelle surface anti-dérive (#6) : la table §3 « Cartographie portails ↔
familles » porte deux colonnes data-derived du contrat ; « Nb rôles » était
gatée, « Familles rattachées » (SET des `famille` distinctes par portail) ne
l'était pas — le count-gate l'avale via `[^|]*`.
Gate « 1quater-bis » : recompute le SET de familles par portail depuis
rbac_50_roles.json[roles][].famille, égalité par ENSEMBLE (absent + fantôme)
avec les jetons bruts de la cellule (parenthèses éditoriales exclues, ordre
non gaté). Silent-green prouvé : reclasser les 2 rôles `legal` de `direction`
en `finance` garde le compte 9==9 VERT mais fait mordre FANTÔME {legal}.
6 verts arbre propre · 5 morsures adversariales · 6 gates re-verts exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le document-modèle CANONIQUE que toute faisabilité doit reproduire recopiait à la
main les 6 valeurs #9/#10 à 5 surfaces structurées, aucune gatée. Nouveau bloc
« TEMPLATE FAISABILITÉ CANONIQUE v1.0 » (réutilise exp/exp_excl déjà recomputés de
CLAUDE.md · zéro dup) : intro#9, 3 lignes table #9, intro#10, 3 lignes table #10
(+ exclusion ❌), checklist 6 marqueurs. 5 verts sur arbre propre · 11 morsures
adversariales dont M10/M11 (mutation CLAUDE.md #9/#10 SEULE ⇒ cascade sur 3 régions =
anchor-is-live). 6 gates exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le bloc « Fiscal · CONTRAT DE FORMAT » ancrait le format DGII
(E + tipoeCF(2) + secuencia(10) = 13 · Ley 32-23) sur ecf_plan.json[e_ncf]
byte-gaté, mais UNIQUEMENT sur 4 surfaces de PROSE (README x3 + fiche
erpnext_backend). Le composeur d'exécution ecflib/ncf.py — qui VALIDE et
COMPOSE réellement l'e-NCF cote VPS — portait 3 copies INDÉPENDANTES du
format (ENCF_RE regex de validation · FORMULE publiée par compose_encf ·
docstring/commentaire), + un oracle de test hardcodé, tous NON gatés.
Silent-green : un rango DGII a 12 chiffres régénère ecf_spec->ecf_plan (les
4 proses suivent) mais laisse ENCF_RE a {2}{10} => is_valid_encf REJETTE un
e-NCF valide (bug runtime) pendant que tests/ reste VERT (oracle == FORMULE
périmée). check_artifacts (pas un out/*.json) et tests/ (teste les fonctions,
pas leur ancrage) sont aveugles.
Gate : extension du bloc e-NCF (surfaces 5->9) réutilisant prefix/tipo/seq/
total + ecf_check déja dérivés (zéro re-dérivation du format · #6). 7 morsures
adversariales dont M6 SILENT-GREEN (artefact seq 10->12, ncf.py inchangé =>
les 5 surfaces mordent, autorité = artefact). 39 tests unittest verts. 6 gates
CI re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
RECOMPUTE le ledger d'invariants depuis le SEUL registre-source (les `# N ·` de
`_validate` de audit_5d_gen.py) et gate les 6 transcriptions manuelles de « 15
invariants » (4 dans le .py, 2 dans le README), toutes invisibles à
check_artifacts. Ledger PROPRE 1..15 (schéma compté à part). Exige : (a) ledger
contigu 1..N (lacune/doublon nu mordu) ; (b) toute mention « N invariants » du
.py == |ledger| ; (d) toute mention README == |ledger|. Le distinct « 17
contrôles » est exclu nativement par l'ancre sur le mot « invariants » (aucun
faux positif). 6 morsures adversariales dont M3 (ajout `# 16 ·` mord .py+README,
preuve que l'autorité est le CODE) et M6 (« 17 contrôles » reste invisible).
6 gates re-verts exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5ᵉ instance de la classe « ledger d'invariants » (après Chat OTOIA · SEO ·
Fiscal e-CF · Legal CONFOTUR). Le compte « 12 invariants » de
crm/dossier_vente/doctype_dossier_vente_gen.py était transcrit à la main à
7 endroits (4 chaînes du .py + 3 du README : commande, titre « ## Les 12
invariants », prose de score), aucun gaté — invisibles à check_artifacts
(le .py n'est pas un out/*.json) et aux suites tests/ (qui testent des
fonctions, pas la prose). Ajouter un contrôle # 13 · sans toucher les 7
chaînes ⇒ CI applique 13 contrôles pendant que docs+self-reports disent 12
en silence (vert trompeur · #6).
Ledger PROPRE 1..12 (≈ CONFOTUR) : schéma compté à part (« schéma + N
invariants »), pas de schéma-#1 non marqué, pas de split a/b ; détection de
doublon nu conservée en filet. Le gate RECOMPUTE le ledger depuis le seul
registre-source (# N · de _validate) et exige (a) ledger contigu 1..N ;
(b) toute mention « N invariants » du .py == |ledger| ; (c) annonce du titre
README == |ledger| ; (d) toute mention README == |ledger| ; (e) énumération
numérotée de la section contiguë 1..N.
5 checks verts sur l'arbre propre. 7 morsures adversariales (M1 self-report
.py · M2 titre README · M3 prose README · M4 ajout # 13 · = ledger 13 vs
prose 12, mord .py+README+énumération = autorité au CODE · M5 gap # 7 · ·
M6 doublon nu # 5 · · M7 énumération 7→8). 6 gates re-verts exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
4ᵉ application du pattern « ledger d'invariants » (après Chat OTOIA · SEO ·
Fiscal e-CF) à legal/confotur/confotur_application_gen.py. Le compte « 14
invariants » y est transcrit à la main à SIX endroits non gatés, tous
invisibles à check_artifacts (le .py n'est pas un out/*.json) : 4 chaînes du
.py (docstrings module + _validate, succès CLI, aide du sous-parseur) + 2 du
README (bloc de commande, commentaire d'arborescence). Ajouter un contrôle
# 15 · à _validate sans toucher les 6 chaînes ⇒ README + self-reports mentent
en silence pendant que la CI applique 15 contrôles — « vert trompeur » que ni
tests/ (FONCTIONS, pas la prose) ni le byte-gate d'artefact n'attrapent.
Particularité CONFOTUR (≠ Fiscal) : ledger PROPRE 1..14 (pas de schéma-#1 non
marqué, pas de split a/b) MAIS le README porte AUSSI un compte de SOUS-ENSEMBLE
éditorial (« 2 invariants refusent tout champ monétaire ») à ne pas confondre
avec le total — un \d+ invariants naïf mordrait l'arbre propre. Le gate exclut
le sous-ensemble par lookahead négatif (\d+)\s+invariants(?!\s+refusent),
appliqué au .py comme au README.
Nouveau bloc (ci/check_readme_claims.sh) : RECOMPUTE le ledger depuis le SEUL
registre-source (# N · de _validate) et exige (a) ledger CONTIGU 1..N (lacune
OU doublon nu = vrai défaut) ; (b) toute mention-total du .py == |ledger| ;
(c) toute mention-total du README (hors « refusent ») == |ledger|. 3 checks
verts sur l'arbre propre. 6 morsures vérifiées (M1 self-report .py 14→15 · M2
README commande 14→15 · M3 README arborescence 14→13 · M4 ajout # 15 · ⇒
ledger→15 vs prose 14, mord .py ET README · M5 gap # 7 · · M6 doublon nu # 5 ·)
+ M7 no-false-positive (sous-ensemble 2→3 reste vert). 6 gates re-verts exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3ᵉ application du pattern « ledger d'invariants » (après Chat OTOIA + SEO) : le
nombre magique « 12 invariants » du générateur fiscal ecf_dgii_gen.py est
transcrit à la main à 7 endroits (4 chaînes du .py : docstrings module/_validate
+ succès CLI + aide sous-parseur ; 3 du README : bloc commande + titre « ## Les
12 invariants » + prose de score), aucun gaté, tous invisibles à check_artifacts
(le .py source n'est pas un out/*.json). Ajouter un contrôle # 13 · à _validate
sans toucher les 7 chaînes = 13 contrôles appliqués pendant que README et
self-reports mentent en silence — vert trompeur qu'aucune suite tests/ (fonctions,
pas la prose) n'attrape.
Gate (bloc « Fiscal · e-CF DGII · IDENTITÉ du COMPTE D'INVARIANTS ») : RECOMPUTE
le ledger depuis le SEUL registre-source (# N · de _validate) et exige (a) ledger
CONTIGU 1..N ; (b) toute mention « N invariants » du .py == |ledger| ; (c) annonce
du titre README == |ledger| ; (d) toute mention README == |ledger| ; (e)
énumération numérotée prose du README contiguë 1..N. Particularité fiscale (≠
SEO/Chat OTOIA propres 1..N) : invariant 1 = validation de SCHÉMA non marquée
# 1 · (marqueurs 2..N), invariant 12 SPLITTÉ en # 12a ·/# 12b · (2 volets d'un
même invariant). Le ledger = {1:schéma} ∪ marqueurs-top-level, collapse 12a/12b
mais MORD un vrai doublon nu.
5 checks verts (ledger 1..12). 8 morsures : M1 self-report .py 12→13 (b) · M2
titre 12→13 (c+d) · M3 mention README 12→13 (d) · M4 ajout # 13 · ⇒ ledger→13
pendant que prose reste 12 (b+c+d, preuve que l'autorité est le CODE) · M5 drop
# 7 · = gap non contigu (a) · M6 doublon nu # 5 · · M7 énumération 7.→8. (e) ·
M8 drop validate(bundle, schema) = invariant 1 introuvable. 6 gates re-verts
(check_artifacts · check_docs · guard_constraints · check_ci_integrity ·
check_readme_claims · check_regression) exit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le bloc Publiciste/branding existant ancre les 4 tokens DESIGN (#4 : couleurs +
typographies). Le MÊME module porte une 2e constante constitutionnelle NON gatée :
les devises CLAUDE.md #10 (« **USD + DOP** »), recopiées à 4 endroits data-derived,
tous invisibles à check_artifacts (pas un out/*.json) : (a) branding.py
DEVISE_PRIMAIRE/SECONDAIRE (auto-étiquetées « #10 · USD + DOP » sans gate) ; (b)
generator.py _fmt_usd/_fmt_dop — les formateurs qui IMPRIMENT le code devise sur
la grille de prix du site public vente.otov7.com (sortie face-public) ; (c) footer
HTML « Prix … en USD + DOP (Cardnet) » ; (d) l'oracle hardcodé
assertIn("USD 150 000") du test — une copie jamais comparée à CLAUDE.md. Aucune
suite tests/ (FONCTIONS de rendu, pas l'ancre à CLAUDE.md) n'attrape la dérive.
Nouveau bloc : RE-PARSE les 2 devises depuis la ligne #10 de CLAUDE.md
(indépendamment de exp amont · aucun skip hérité), exige (a) constantes branding ==
#10 ordre inclus ; (b) ensemble des codes émis par les formateurs == #10 ; (c)
footer cite les 2 devises dans l'ordre + (Cardnet) ; (d) oracle test == devise
primaire. Claim absent échoue AUSSI (#6). 6 morsures vérifiées (M5 : rename #10
CLAUDE.md-only cascade sur les 4 copies = preuve ancre live), 4 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
La SPEC RBAC a déjà 3 gates (§3 ventilation par portail · §4 colonne Entité · §7
run-book) mais son §5 « Les N rôles (résumé) » restait AVEUGLE. Ce §5 restitue le
total de rôles sur 3 surfaces prose : le compte-titre « ## 5. Les 50 rôles », NEUF
comptes parenthétiques de regroupement (`**Ventes (8)**` …) et une ligne
d'auto-contrôle arithmétique `_(6+8+4+7+5+8+4+2+6 = 50.)_`. AJOUTER un rôle au
contrat (|rôles| 50→51) laisse titre/somme/`= 50` périmés en silence ; ÉDITER
`Ventes (8)→(7)` sans toucher la ligne casse la cohérence titre↔somme — ni les
suites tests/ (FONCTIONS RBAC, jamais la prose) ni le byte-gate d'artefact ne
l'attrapent.
Subtilité (memory rbac-spec-portail-count-gate : « §5 by-family is editorial ») :
les 9 regroupements sont ÉDITORIAUX (« Direction / Gouvernance » agrège des rôles
de familles direction+finance ≠ colonne `famille`) ⇒ AUCUN mapping groupe↔famille
(dérive fausse). On gate UNIQUEMENT ce qui est data-derived sans ce mapping.
Nouveau bloc « 1septies) §5 » : on recompute N = |rôles| du contrat
(rbac_50_roles.json, byte-gaté) et on exige (a) compte-titre == N ; (b) les 9
comptes de regroupement == EXACTEMENT dans l'ordre les termes de la ligne
(comparaison de LISTES ⇒ mord valeur ET position) ; (c) Σ termes == membre droit ;
(d) membre droit == N. Section/titre/ligne/comptes absents = échec (#6).
5 morsures vérifiées (working tree byte-restauré via git checkout -- <fichier>,
gate rc=1 sous mutation · rc=0 restauré) : titre 50→51 (a) · Ventes (8)→(9) (b) ·
= 50.→= 49. (c+d double) · terme 6+→7+ (b+c double) · suppression ligne (absence).
ci/README.md : row check-readme-claims étendue de la clause §5. 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
Surface ungated distincte des fiches : chaque `05_deliverables_mvp/<suite>/README.md`
se re-déclare le compte de SA suite (commentaire `# N tests` de la commande unittest ·
bullet « → **N/N verts** » · prose d'auto-score « en-repo (N tests verts + …) ») — 27
claims sur 16 modules. Tous les blocs de comptes de tests existants visent 03_agents/*
(row_re, agrégats prose, per-suite hors table) ; row_re ne lit le README de module QUE
comme cible de lien. Un test ajouté/retiré met à jour regression_plan.json (auth =
plan.suites[path].test_methods, byte-gaté) tandis que la prose du README rote en silence.
Nouveau bloc « READMEs de MODULE · comptes de tests self-reportés » (table config
MODULE_README_TESTS · motifs ancrés) : chaque motif DOIT matcher (absent = régression #6)
ET tous ses groupes == auth ; `**N/N verts**` capture 2 groupes → un 25/24 incohérent mord.
5 modules sans self-report (chat_otoia/mobile/publiciste/acceptance/audit_4big) hors table.
4 morsures vérifiées (drift commentaire · incohérence N/N · disparition de claim · drift
auto-score prose) ; restauré = 440 checks de base intacts + 27 nouveaux ; check_ci_integrity
+ check_docs re-verts. Restauration par backup ciblé (jamais git checkout ./git clean).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>