40ee6f6a46
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>