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>
12 KiB
Activity log · 2026-08-02 · Claude Code DTP Worker
Sprint 8 · buffer · CRM Dossier Vente — gate d'IDENTITÉ du COMPTE D'INVARIANTS de _validate (5ᵉ instance du ledger)
Contexte — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » (recompute le nombre de contrôles
CI depuis le registre-source # N · de _validate, jamais une liste à la main)
a déjà couvert Chat OTOIA, SEO, Fiscal e-CF et Legal CONFOTUR. Le
5ᵉ générateur portant le même nombre magique restait NON gaté :
crm/dossier_vente/doctype_dossier_vente_gen.py (candidats restants recensés :
qa/audit_5d ·15, crm/commissions ·10, tous ledgers propres non gatés).
Le compte « 12 invariants » y est transcrit à la main à SEPT endroits,
aucun gaté, tous invisibles à check_artifacts (le .py source n'est pas un
out/*.json) :
- docstring module (l.14 « schéma + 12 invariants de ») ;
- docstring
_validate(l.77 « 12 invariants de cross-cohérence ») ; - message de succès CLI
validate« … schéma + 12 invariants verts. » (l.218) ; - aide du sous-parseur
validate(l.230) ; - README bloc de commande « schéma + 12 invariants » (l.56) ;
- README titre de section « ## Les 12 invariants » (l.60) ;
- README prose de score « 12 invariants de cross-cohérence » (l.83).
Ajouter un contrôle # 13 · à _validate sans toucher les 7 chaînes ⇒ le README
ET les self-reports du .py mentent en silence pendant que la CI applique 13
contrôles. Aucune suite tests/ (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
Particularité du registre Dossier Vente (≈ CONFOTUR, ≠ Fiscal) : le ledger est PROPRE 1..12 — le schéma est compté À PART (phrasé « schéma + N invariants »), donc pas de schéma-#1 non marqué et pas de split a/b. On garde néanmoins la détection de doublon nu comme filet. Le README porte AUSSI une énumération numérotée sous le titre de section (item 1 = conformité au schéma, puis les contrôles), gatée en contiguïté 1..N.
Gate ajouté (ci/check_readme_claims.sh, bloc « CRM · Dossier Vente · IDENTITÉ
du COMPTE D'INVARIANTS ») — 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 de registre) ;
- (b) toute mention « N invariants » du
.py== |ledger| ; - (c) l'annonce du titre README « ## Les N invariants » == |ledger| ;
- (d) toute mention « N invariants » du README == |ledger| ;
- (e) l'ÉNUMÉRATION numérotée de la section (« 1. … 2. … N. ») contiguë 1..N. Une mention ou le registre absent échoue AUSSI (traçabilité #6).
Vérif — 5 checks verts sur l'arbre propre (ledger 1..12 = 12 marqueurs # N ·,
schéma compté à part). 7 morsures adversariales : M1 self-report .py 12→13
(b) · M2 titre README 12→13 (c+d) · M3 prose README 12→13 (d) · M4 ajout marqueur
# 13 · ⇒ ledger→13 pendant que la prose reste 12 (mord .py ET README ET
l'énumération, preuve que l'autorité est le CODE) · M5 suppression # 7 · ⇒ gap
non-contigu (a) · M6 doublon nu # 5 · ⇒ détection de vrai doublon (a) · M7
énumération README 7.→8. ⇒ deux 8/pas de 7 (e). Gates re-verts : check_artifacts
· check_docs · guard_constraints · check_ci_integrity · check_regression ·
check_readme_claims tous exit 0.
Sprint 8 · buffer · Legal CONFOTUR — gate d'IDENTITÉ du COMPTE D'INVARIANTS de _validate (4ᵉ instance du ledger)
Contexte — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » (recompute le nombre de contrôles
CI depuis le registre-source # N · de _validate, jamais une liste à la main)
a déjà couvert Chat OTOIA, SEO et Fiscal e-CF. Le 4ᵉ générateur
portant le même nombre magique restait NON gaté :
legal/confotur/confotur_application_gen.py.
Le compte « 14 invariants » y est transcrit à la main à SIX endroits,
aucun gaté, tous invisibles à check_artifacts (le .py source n'est pas un
out/*.json) :
- docstring module (l.24 « schéma + 14 invariants de ») ;
- docstring
_validate(l.87 « 14 invariants de cross-coherence ») ; - message de succès CLI
validate« … schéma + 14 invariants verts. » (l.283) ; - aide du sous-parseur
validate(l.295) ; - README bloc de commande « schéma + 14 invariants » (l.56) ;
- README commentaire d'arborescence « CLI build/validate · 14 invariants » (l.82).
Ajouter un contrôle # 15 · à _validate sans toucher les 6 chaînes ⇒ le README
ET les self-reports du .py mentent en silence pendant que la CI applique 15
contrôles. Aucune suite tests/ (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
Particularité du registre CONFOTUR (≠ Fiscal) : le ledger est 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 » (l.92) — à NE PAS confondre avec le total. Un \d+ invariants naïf
mordrait donc l'arbre PROPRE (il verrait {2, 14}). Le gate exclut le
sous-ensemble par lookahead négatif (\d+)\s+invariants(?!\s+refusent),
appliqué au .py comme au README.
Gate ajouté (ci/check_readme_claims.sh, bloc « Legal · CONFOTUR · IDENTITÉ
du COMPTE D'INVARIANTS ») — 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 de registre) ;
- (b) toute mention-total « N invariants » du
.py(hors « refusent ») == |ledger| ; - (c) toute mention-total du README (hors « refusent ») == |ledger|. Une mention ou le registre absent échoue AUSSI (disparition d'un chiffre = régression de traçabilité #6).
Vérif — 3 checks verts sur l'arbre propre (ledger 1..14 = 14 marqueurs # N ·).
6 morsures adversariales : M1 self-report .py 14→15 (b) · M2 README commande
14→15 (c) · M3 README arborescence 14→13 (c) · M4 ajout marqueur # 15 · ⇒
ledger→15 pendant que la prose reste 14 (mord .py ET README, preuve que
l'autorité est le CODE) · M5 suppression # 7 · ⇒ gap non-contigu (a) · M6
doublon nu # 5 · ⇒ détection de vrai doublon (a). M7 no-false-positive :
sous-ensemble « 2 → 3 invariants refusent » reste VERT (le lookahead exclut bien
le sous-ensemble). Gates re-verts : check_artifacts · check_docs ·
guard_constraints · check_ci_integrity · check_regression ·
check_readme_claims tous exit 0.
Sprint 8 · buffer · Publiciste — gate d'ANCRAGE des DEVISES du site public sur CLAUDE.md #10
Contexte — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le bloc Publiciste/branding existant ancre les 4 tokens DESIGN
de CLAUDE.md #4 (2 couleurs + 2 typographies) sur leurs 4 copies. Mais le MÊME
module publiciste porte une 2ᵉ constante constitutionnelle — les devises
CLAUDE.md #10 (« USD + DOP ») — recopiée à 4 endroits data-derived, aucun
gaté, tous invisibles à check_artifacts (pas un out/*.json) :
lib/branding.pyDEVISE_PRIMAIRE/DEVISE_SECONDAIRE— constantes auto- étiquetées « contrainte #10 · USD + DOP », sans gate ;lib/generator.py_fmt_usd/_fmt_dop— les formateurs qui IMPRIMENT le code devise sur la grille de prix du site publicvente.otov7.com(sortie face-public : une devise hors #10 = mandat trahi en silence) ;lib/generator.pyfooter HTML « Prix … en USD + DOP (Cardnet) » ;tests/test_publiciste.py— l'oracle hardcodéassertIn("USD 150 000", …), une copie de plus jamais comparée à CLAUDE.md.
Aucune suite tests/ (qui teste des fonctions de rendu, pas l'ancre à
CLAUDE.md) n'attrape la dérive : renommer la devise #10 et aligner le module
reste vert alors que le site émettrait la mauvaise devise ; ne rien bouger reste
vert alors que branding.py se dit « #10 » en mentant.
Gate ajouté (ci/check_readme_claims.sh, bloc « Publiciste/generator+branding
· DEVISES CANONIQUES ») — RE-PARSE les 2 devises depuis la ligne #10 de CLAUDE.md
(indépendamment de exp amont · aucun skip hérité) puis exige :
- (a)
branding.pyDEVISE_PRIMAIRE/SECONDAIRE == #10 (ordre inclus) ; - (b) l'ensemble des codes émis par les formateurs
generator.py== #10 ; - (c) le footer HTML cite les 2 devises dans l'ordre +
(Cardnet); - (d) l'oracle du test == devise primaire #10. Un claim absent échoue AUSSI (traçabilité #6 · anti-évaporation).
Vérif — 5 checks verts sur l'arbre propre. 6 morsures adversariales :
M1 branding primaire USD→EUR · M2 formateur _fmt_usd→EUR (hors #10) · M3 footer
USD+DOP→USD+EUR · M4 oracle test → EUR · M5 CLAUDE.md #10 USD→EUR = cascade sur
les 4 copies simultanément (preuve que l'ancre est CLAUDE.md, pas la cohérence
interne) · M6 footer supprimé → INTROUVABLE. Gates re-verts :
check_readme_claims · check_docs · guard_constraints · check_ci_integrity
tous exit 0.
Sprint 8 · buffer · Fiscal e-CF DGII : gate d'IDENTITÉ du COMPTE D'INVARIANTS de _validate
Contexte — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « ledger d'invariants » a déjà été appliqué à Chat
OTOIA et SEO (recompute le nombre d'invariants CI depuis le registre-source
# N · de _validate, jamais une liste à la main). Le 3ᵉ générateur portant
le même nombre magique restait NON couvert : fiscal/ecf_dgii/ecf_dgii_gen.py.
Le compte « 12 invariants » y est transcrit à la main à SEPT endroits,
aucun gaté, tous invisibles à check_artifacts (le .py source n'est pas un
out/*.json) :
ecf_dgii_gen.pydocstring module (l.24) ;- docstring
_validate(l.110) ; - message de succès CLI
validate« … schéma + 12 invariants verts. » (l.277) ; - aide du sous-parseur
validate(l.289) ; - README bloc de commande « schéma + 12 invariants » (l.65) ;
- README titre de section « ## Les 12 invariants » (l.69) ;
- README prose de score « 12 invariants de cross-cohérence » (l.105).
Ajouter un contrôle # 13 · à _validate sans toucher les 7 chaînes ⇒ le README
ET les self-reports du .py mentent en silence pendant que la CI applique 13
contrôles. Aucune suite tests/ (qui teste des FONCTIONS de validation, pas la
prose) n'attrape ce « vert trompeur ».
Particularité du registre fiscal (≠ SEO/Chat OTOIA au ledger propre 1..N) :
l'invariant 1 est la validation de SCHÉMA (validate(bundle, schema), non
marquée # 1 ·), les marqueurs couvrent 2..N, et l'invariant 12 est
splitté en # 12a · (unicité évènements) / # 12b · (comptes du manifeste) —
deux volets d'un même invariant. Le gate reconstruit donc le ledger = {1:schéma}
∪ marqueurs-top-level, en collapsant 12a/12b, tout en mordant un vrai doublon
d'un numéro NON suffixé.
Gate ajouté (ci/check_readme_claims.sh, 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 (schéma #1 présent + marqueurs 2..N sans lacune ; doublon nu = défaut mordu ; 12a/12b comptés 1×) ;
- (b) toute mention « N invariants » du
.py== |ledger| ; - (c) l'annonce du titre README == |ledger| ;
- (d) toute mention « N invariants » du README == |ledger| ;
- (e) l'ÉNUMÉRATION numérotée du README (« 1. … 2. … N. ») elle-même contiguë 1..N (item ni sauté ni dupliqué).
Vérif — 5 checks verts sur l'arbre propre (ledger 1..12 = schéma #1 + 11
marqueurs). 8 morsures adversariales : M1 self-report .py 12→13 (b) · M2
titre README 12→13 (c+d) · M3 mention README 12→13 (d) · M4 ajout marqueur # 13 ·
⇒ ledger→13 pendant que la prose reste 12 (b+c+d, preuve que l'autorité est le
CODE, pas la prose) · M5 suppression # 7 · ⇒ gap non-contigu (a) · M6 doublon nu
# 5 · ⇒ détection de vrai doublon · M7 énumération README 7.→8. ⇒ deux 8/pas de
7 (e) · M8 suppression validate(bundle, schema) ⇒ invariant 1 introuvable. Gates
re-verts : check_artifacts · check_docs · guard_constraints ·
check_ci_integrity · check_readme_claims · check_regression tous exit 0.