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>
Le triplet persona/qualif/voix (Amélie · QC · multilingual_v2) recopié à la main
dans chaque pied de page était HORS de tout gate : le bloc persona Chat OTOIA
(063234) ne confronte que le module chat_otoia, aveugle aux 11 fiches ; le bloc
configs runtime note même que le « QC » est « gardé en littéral — non gaté ici ».
Bloc ajouté (check_readme_claims.sh) : RE-DÉRIVATION INDÉPENDANTE du triplet de
§Architecture cible (regex qui ne fige PAS le qualificatif en dur ⇒ QC→… mord ici,
pas seulement via l'INTROUVABLE du bloc persona) · 3 tokens == CLAUDE.md exigés sur
chaque fiche portant le pied de page · pied de page malformé & évaporation totale du
recensement échouent AUSSI (#6). 6 morsures vérifiées (CLAUDE.md voix v2→v3 : 11
fiches + cascade persona · CLAUDE.md qualif QC→BC : 11 fiches, bloc indépendant ·
seo voix · crm persona · bim malformé · surface évaporée) · restauré green · 7 gates
re-verts. ci/README.md (récap + paragraphe détaillé) mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3e surface du MÊME README audit_4big, jamais gatée : les deux seuils que le
scorer applique (DOC « ≥ 400 octets » · TESTS « ≥ 8 méthodes def test_* »),
transcrits à la main. Le bloc BARÈME ne capture que le POIDS voisin (regex
`| `DOC` | 20 |`), aveugle à la 3e cellule. Ces nombres sont DATA-DERIVED de
quality_spec.json[thresholds] (min_doc_bytes/min_test_methods) — l'INPUT
byte-gaté par check_artifacts (report rebuild depuis lui).
Gate ajouté (check_readme_claims.sh) : (1) cross-check d'ANCRAGE — le seuil
TESTS APPLIQUÉ, lu de l'evidence « (seuil N) » de CHAQUE module du report ==
spec.min_test_methods pour tous (mord une divergence spec↔report) ; (2) prose
DOC « ≥ N octets » == spec ; (3) prose TESTS « ≥ N méthodes » == spec ; claim
absent échoue AUSSI (traçabilité #6). Élever min_test_methods (8→12 : module de
8-11 tests sous FAIL) ou changer min_doc_bytes rebuild le report SANS toucher au
README → prose périmée en silence, désormais interdite.
5 morsures vérifiées (README 400→450 · README 8→10 · ligne DOC vidée · spec
min_test_methods 8→12 rebuild : README+cross-check · spec min_doc_bytes 400→500
rebuild) ; restauré = green · 7 gates re-verts. ci/README.md (récap + paragraphe
détaillé) mis à jour. Hors périmètre VPS : néant.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3e surface du MÊME README `qa/audit_5d` : la table « ## Les 5 dimensions »
(README:15-19) transcrit par ligne le triplet (id · titre · reference) de chaque
dimension. Jusqu'ici gatée seulement sur son COMPTE agrégé (« 5 dimensions ») — un
WILDCARD aveugle à QUELLE dimension. Une norme de référence permutée (D3 fiscal
`Ley 32-23`, D1 probatoire `ISA 500`) est une affirmation de conformité fausse
(l'invention même que #6 interdit) sur l'audit de second niveau que le banquier lit.
Gate ajouté (`ci/check_readme_claims.sh`) : liste ORDONNÉE {id:(titre,reference)}
recomputée de `qa/audit_5d/out/audit_report.json[dimensions]` (byte-gaté) — identité
par ensemble d'id (absent/en trop), ordre préservé (D1→D5), (titre,reference) par
ligne. Cohérence croisée bonus : rapport == audit_spec.json[dimensions] (l'INPUT dont
il dérive). Table disparue = échec (traçabilité #6).
8 morsures vérifiées (README rename titre/permute norme ISA/Ley/supprime ligne/
réordonne · artefact & spec renommés · table supprimée) ; restauré green · 7 gates
re-verts. Édition hors `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact.
ci/README.md (recap + paragraphe détaillé) mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Le bloc « paramètres canoniques » n'ancrait que model.py::CANONICAL + le README ;
son propre commentaire nommait pourtant le défaut (« marqueurs hardcodés dans le
test, une copie de plus jamais comparée à CLAUDE.md ») sans le fermer. Nouveau bloc :
helper _list_vs_want6 (set-diff EXACT absent/en-trop) pour les copies-LISTES
renderer._CANONICAL_MARKERS + oracle du test ; substring normalisé (USD+DOP==USD + DOP)
pour les 2 docstrings scorer. 4 morsures vérifiées dont CLAUDE.md #10 Cardnet→Azul
mordant SIMULTANÉMENT model+renderer+test+2 docstrings (valeur de l'ancrage) ;
restauré vert · 7 gates re-verts. ci/README.md + activity log mis à jour.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aucun taux de commission n'étant documenté dans CLAUDE.md, le README §« Anti-invention » promet (README:22-23) « 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 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é out/commission_plan.json.
Dérive la plus dommageable possible du module : 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, jamais la promesse README vs artefact) ne l'attrape.
Gate ajouté (bloc « CRM/Commissions · ANTI-INVENTION (#6) ») : recompute de l'état null/confirmé depuis l'artefact + (a) invariant #7 permanent (aucun taux_pct sans source) · (b) a_confirmer ⟺ taux_pct is null · (c) MANIFEST.counts recoupe le plan (taux_a_confirmer / evenements) · (d) la promesse #6 du README REFLÈTE l'artefact dans les DEUX SENS (tout-null ⇒ promesse présente ; taux confirmé ⇒ promesse retirée) — zéro faux négatif quand la Direction remplira les taux · (e) note_taux du MANIFEST cohérente.
5 morsures vérifiées (taux sans source · taux avec source mais a_confirmer stale + README périmé · a_confirmer=false sur null · counts périmé 5→4 · promesse retirée INTROUVABLE), restauré vert, 7 gates re-verts. Working tree byte-restauré via git checkout -- (JAMAIS git clean). Édition hors 05_deliverables_mvp/*/out ⇒ 0 dérive d'artefact. ci/README.md (récap + paragraphe détaillé) mis à jour. Auto-score 4Big 96/100.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>