[DTP-Worker 20260805_174324] GATE NEUF classe claude-md-constant-anchor : prose #9 des modules bancable + commissions ancrée sur CLAUDE.md. Mutation #9 (8.5%→9%) mordait DÉJÀ les 8 surfaces generator/template mais 4 copies restaient périmées EN SILENCE dans DEUX modules distincts, chacune se réclamant « (#9) »/« CLAUDE.md #9/#10 » (corriger le generator ne les touche pas → invention #6 latente) : (a) bancable/README.md + (b) banclib/finance.py docstring « 3% édition/8.5% marketing (#9) » · (c) banclib/deps.py « CLAUDE.md #9/#10 (3%/8.5%/52%·USD+DOP·Cardnet·Letter US) » 6 marqueurs · (d) crm/commissions/README.md « pourcentages canoniques (3% édition·8.5% marketing·52% équilibre) ». Extension du bloc d'ancrage existant (check_readme_claims.sh, après Template canonique) RÉUTILISANT exp (zéro re-parse). Teeth mutation-vérifiés : 8.5%→9% mord les 4 · 52%→55% mord (c)+(d) SEULS (a/b ne citent qu'édition+marketing = ciblage précis) · #10 Cardnet→Azul mord l'énum (c) ; arbre restauré = vert. Doc ci/README §2. 0 prod, 0 artefact rebuild (aucun out/ ni doc scoré audit_4big), 0 chiffre saisi (#6, recomputés de CLAUDE.md), 0 VPS (#8). run_ci 33 PASS·0 FAIL·0 SKIP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-05 17:53:52 +00:00
parent db91a6bb5b
commit 1441693e25
3 changed files with 149 additions and 0 deletions
+44
View File
@@ -1520,3 +1520,47 @@ la main** (#6 — les 20/30 sont lus du spec, non retapés), **aucune commande V
journal. journal.
**Vérif.** `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (aucun fichier gaté touché). **Vérif.** `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP** (aucun fichier gaté touché).
---
## Session 20260805_174324 · GATE NEUF — prose #9 des modules bancable + commissions ancrée sur CLAUDE.md
**Contexte.** Repo vert au démarrage (33 PASS · 0 FAIL · 0 SKIP), tous modules livrés,
roadmap 8-sem sans tâche-feature ouverte. Sonde ciblée sur la classe **claude-md-constant-anchor-gate** :
les constantes canoniques #9 (3 % édition · 8.5 % marketing · 52 % point d'équilibre)
recopiées hors du module generator.
**Constat (mutation-prouvé).** `sed` #9 `8.5 %→9 %` sur `CLAUDE.md` → le gate
`check_readme_claims.sh` fait rougir **8 surfaces generator/template** (model.py CANONICAL,
README, renderer `_CANONICAL_MARKERS`, oracle test, 2 docstrings scorer, template intro/§5.2/§7)
— l'ancre est vivante. **MAIS 4 copies restaient périmées EN SILENCE**, dans DEUX modules
DISTINCTS, chacune se réclamant explicitement « (#9) » / « CLAUDE.md #9/#10 » :
- (a) `faisabilite/bancable/README.md` — « 3 % édition » et « 8.5 % marketing » (#9)
- (b) `faisabilite/bancable/banclib/finance.py` — MÊME phrase, en docstring
- (c) `faisabilite/bancable/banclib/deps.py` — « CLAUDE.md #9/#10 (3 %/8.5 %/52 % · USD+DOP · Cardnet · Letter US) » (6 marqueurs)
- (d) `crm/commissions/README.md` — « pourcentages canoniques (3 % édition · 8.5 % marketing · 52 % point d'équilibre) »
Corriger le generator ne TOUCHE pas ces modules → invention #6 latente, de la classe déjà
fermée 10× (publiciste #10 · fiscal moneda · fiches #10 · template canonique).
**Fix.** Extension du bloc d'ancrage existant dans `ci/check_readme_claims.sh` (juste après
« Template canonique »), **réutilisant `exp`** déjà recomputé des lignes #9/#10 de `CLAUDE.md`
(zéro re-parse, zéro duplication). Un claim absent échoue AUSSI (traçabilité #6). Documenté
en `ci/README.md` §2 (paragraphe « paramètres canoniques »), pas de nouvelle ligne au
tableau §1 (cf. [[ci-readme-table-detail-in-section2]]).
**Teeth (mutation-vérifié, arbre restauré à chaque fois).**
- `#9 8.5 %→9 %` → mord les **4** surfaces.
- `#9 52 %→55 %` → mord **(c)+(d) SEULEMENT** ; (a)/(b) ne citent qu'édition+marketing ⇒
correctement épargnées = **ciblage précis** (pas de faux-rouge).
- `#10 Cardnet→Azul` → mord l'énumération 6-marqueurs de (c).
- Arbre restauré → gate exit=0, les 4 surfaces re-vertes.
**Portée / anti-churn.** **0 fichier de production édité** (seuls `ci/check_readme_claims.sh`
+ `ci/README.md`), **0 artefact reconstruit** (aucun `out/*.json` ni module doc scoré par
audit_4big → pas de rebuild `quality_report`), **0 chiffre saisi à la main** (#6 — les 6
valeurs sont recomputées de `CLAUDE.md`, jamais retapées), **aucune commande VPS** (#8 —
100 % local). Classe RÉCURRENTE (chaque module distinct qui recopie une constante #9/#10
citée est une surface à ancrer) : nouvelle sous-surface (bancable + commissions) close.
**Vérif.** `./run_ci.sh` → **33 PASS · 0 FAIL · 0 SKIP**.
+12
View File
@@ -1196,6 +1196,18 @@ vérifiées : renderer `Cardnet→Azul` (absent/en-trop) · test oracle retire `
mord SIMULTANÉMENT model.py + renderer + test + les DEUX docstrings** (la valeur mord SIMULTANÉMENT model.py + renderer + test + les DEUX docstrings** (la valeur
même de l'ancrage) ; restauré = vert. même de l'ancrage) ; restauré = vert.
Même classe enfin sur QUATRE copies **hors du module generator** — la prose #9 de
DEUX modules distincts qui se réclame explicitement « (#9) » / « CLAUDE.md #9/#10 »
mais qu'aucun gate ne liait à la contrainte (corriger le generator ne les touche pas) :
(a) `faisabilite/bancable/README.md` et (b) sa docstring `banclib/finance.py`
(« 3 % édition » et « 8.5 % marketing » (#9)), (c) `banclib/deps.py`
(« CLAUDE.md #9/#10 (3 %/8.5 %/52 % · USD+DOP · Cardnet · Letter US) », 6 marqueurs),
(d) `crm/commissions/README.md` (« pourcentages canoniques (3 % édition · 8.5 %
marketing · 52 % point d'équilibre) »). On RÉUTILISE `exp` (zéro re-parse). Morsures
vérifiées : `#9 8.5 %→9 %` mord les 4 · `#9 52 %→55 %` mord (c)+(d) SEULS ((a)/(b) ne
citent qu'édition+marketing ⇒ correctement épargnées, ciblage précis) · `#10
Cardnet→Azul` mord l'énumération (c). Un claim absent échoue AUSSI (traçabilité #6).
Même classe enfin sur la **fiche d'identité du rôle RBAC mobile** — la fiche agent Même classe enfin sur la **fiche d'identité du rôle RBAC mobile** — la fiche agent
`03_agents/mobile/AGENT.md`. Les builds/soumissions stores étant **hors-repo** (#8), `03_agents/mobile/AGENT.md`. Les builds/soumissions stores étant **hors-repo** (#8),
l'agent mobile le reconnaît et déclare que son **seul ancrage in-repo vérifiable** est l'agent mobile le reconnaît et déclare que son **seul ancrage in-repo vérifiable** est
+93
View File
@@ -5864,6 +5864,99 @@ if exp is not None:
+ (f" · absents={miss}" if miss else "") + (f" · absents={miss}" if miss else "")
+ (f" · en trop={extra}" if extra else "") + " → régénérer le template") + (f" · en trop={extra}" if extra else "") + " → régénérer le template")
# ============================================================================
# Bancable + Commissions · PROSE #9 (« pourcentages canoniques ») ANCRÉE sur
# CLAUDE.md — même classe d'ANCRAGE que « paramètres canoniques » (generator) et
# « Template canonique » ci-dessus, mais sur des MODULES DISTINCTS
# (faisabilite/bancable, crm/commissions) dont la doc RECOPIE à la main les
# pourcentages #9 en se réclamant EXPLICITEMENT « (#9) » / « CLAUDE.md #9/#10 »,
# sans qu'aucun gate ne les liât à la contrainte.
# ----------------------------------------------------------------------------
# Le bloc « paramètres canoniques » ancre le SEUL module generator (model.py /
# README / renderer / scorer / test) + le TEMPLATE. Restent QUATRE copies
# data-derived dans DEUX autres modules, toutes invisibles à check_artifacts
# (prose/docstrings hors out/) et non attrapées par leurs tests/ (FONCTIONS) :
# (a) faisabilite/bancable/README.md — « 3 % édition » et « 8.5 % marketing » (#9)
# (b) faisabilite/bancable/banclib/finance.py — MÊME phrase, en docstring
# (c) faisabilite/bancable/banclib/deps.py — « CLAUDE.md #9/#10 (3 %/8.5 %/52 %·…) »
# (d) crm/commissions/README.md — « (3 % édition · 8.5 % marketing · 52 % …) »
# La mutation #9 (ex. 8.5 %→9 %) fait DÉJÀ rougir les 8 surfaces generator/template,
# MAIS ces 4 copies-là restent périmées EN SILENCE : corriger le generator ne les
# TOUCHE pas (modules distincts) — invention #6 latente, de la classe déjà fermée
# 10× pour publiciste #10 / fiscal moneda / fiches #10. On RÉUTILISE `exp`
# (recompute #9 depuis CLAUDE.md · zéro duplication). Un claim absent échoue AUSSI.
# ============================================================================
if exp is not None:
_p_edt = _pnorm(exp["frais_edition_pct"]); _p_mkt = _pnorm(exp["marketing_pct"])
_p_eql = _pnorm(exp["point_equilibre_pct"])
_want6b = {_pnorm(exp[k]) for k in _num_keys} | {_ai(exp[k]) for k in _txt_keys}
# (a)+(b) même phrase « « E % édition » et « M % marketing » (#9) »
_duo_re = re.compile(r"«\s*([\d.]+)\s*%\s*[ée]dition\s*»\s*et\s*"
r"«\s*([\d.]+)\s*%\s*marketing\s*»\s*\(#9\)")
for _lbl, _rel in (("bancable/README", "faisabilite/bancable/README.md"),
("bancable/finance.py", "faisabilite/bancable/banclib/finance.py")):
_txt = read_norm(f"{D}/{_rel}")
if _txt is None:
bad(f"Canoniques prose #9 · {_lbl} illisible"); continue
_mm = _duo_re.search(_txt)
if _mm is None:
bad(f"Canoniques prose #9 · {_lbl} — phrase « « N % édition » et "
f"« N % marketing » (#9) » INTROUVABLE (traçabilité #6)")
else:
_got = {_pnorm(float(_mm.group(1))), _pnorm(float(_mm.group(2)))}
_want = {_p_edt, _p_mkt}
if _got == _want:
good(f"Canoniques prose #9 · {_lbl} — {_p_edt} édition · {_p_mkt} "
f"marketing == CLAUDE.md #9")
else:
bad(f"Canoniques prose #9 · {_lbl} — cite {sorted(_got)} MAIS CLAUDE.md "
f"{sorted(_want)} → aligner (ou CLAUDE.md)")
# (c) deps.py « CLAUDE.md #9/#10 (3 % / 8.5 % / 52 % · USD+DOP · Cardnet · Letter US) »
_dep = read_norm(f"{D}/faisabilite/bancable/banclib/deps.py")
if _dep is None:
bad("Canoniques prose #9 · bancable/deps.py illisible")
else:
_md = re.search(r"CLAUDE\.md #9/#10\s*\(([^)]+)\)", _dep)
if _md is None:
bad("Canoniques prose #9 · bancable/deps.py — « CLAUDE.md #9/#10 (…) » "
"INTROUVABLE (traçabilité #6)")
else:
_got = set()
for _tok in re.split(r"[/·]", _md.group(1)):
_p = _pct(_tok)
_got.add(_pnorm(_p) if _p is not None else _ai(_tok))
_got.discard("")
if _got == _want6b:
good("Canoniques prose #9 · bancable/deps.py — 6 marqueurs == "
"CLAUDE.md #9/#10")
else:
_miss = sorted(_want6b - _got); _extra = sorted(_got - _want6b)
bad(f"Canoniques prose #9 · bancable/deps.py — énumère {sorted(_got)} MAIS "
f"CLAUDE.md {sorted(_want6b)}"
+ (f" · absents={_miss}" if _miss else "")
+ (f" · en trop={_extra}" if _extra else "") + " → aligner (ou CLAUDE.md)")
# (d) commissions/README « pourcentages canoniques (E % édition · M % marketing · Q % …) »
_com = read_norm(f"{D}/crm/commissions/README.md")
if _com is None:
bad("Canoniques prose #9 · commissions/README illisible")
else:
_mc = re.search(r"pourcentages canoniques\s*\(([^)]*%[^)]*)\)", _com)
if _mc is None:
bad("Canoniques prose #9 · commissions/README — « pourcentages canoniques "
"(… %) » INTROUVABLE (traçabilité #6)")
else:
_got = {_pnorm(float(_x)) for _x in re.findall(r"([\d.]+)\s*%", _mc.group(1))}
_want = {_p_edt, _p_mkt, _p_eql}
if _got == _want:
good(f"Canoniques prose #9 · commissions/README — {sorted(_want)} == "
f"CLAUDE.md #9")
else:
_miss = sorted(_want - _got); _extra = sorted(_got - _want)
bad(f"Canoniques prose #9 · commissions/README — cite {sorted(_got)} MAIS "
f"CLAUDE.md {sorted(_want)}"
+ (f" · absents={_miss}" if _miss else "")
+ (f" · en trop={_extra}" if _extra else "") + " → aligner (ou CLAUDE.md)")
# ============================================================================ # ============================================================================
# Fiscal · ecf_dgii — le JEU DE DEVISES `moneda` (`USD`/`DOP`) ANCRÉ sur CLAUDE.md # Fiscal · ecf_dgii — le JEU DE DEVISES `moneda` (`USD`/`DOP`) ANCRÉ sur CLAUDE.md
# #10 — même classe d'ANCRAGE que la CITATION #10 des fiches ci-dessus, mais sur # #10 — même classe d'ANCRAGE que la CITATION #10 des fiches ci-dessus, mais sur