From 1441693e25a03b27c9ca0730f47c6da652b927f3 Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Wed, 5 Aug 2026 17:53:52 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker=2020260805=5F174324]=20GATE=20NEUF?= =?UTF-8?q?=20classe=20claude-md-constant-anchor=20:=20prose=20#9=20des=20?= =?UTF-8?q?modules=20bancable=20+=20commissions=20ancr=C3=A9e=20sur=20CLAU?= =?UTF-8?q?DE.md.=20Mutation=20#9=20(8.5%=E2=86=929%)=20mordait=20D=C3=89J?= =?UTF-8?q?=C3=80=20les=208=20surfaces=20generator/template=20mais=204=20c?= =?UTF-8?q?opies=20restaient=20p=C3=A9rim=C3=A9es=20EN=20SILENCE=20dans=20?= =?UTF-8?q?DEUX=20modules=20distincts,=20chacune=20se=20r=C3=A9clamant=20?= =?UTF-8?q?=C2=AB=20(#9)=20=C2=BB/=C2=AB=20CLAUDE.md=20#9/#10=20=C2=BB=20(?= =?UTF-8?q?corriger=20le=20generator=20ne=20les=20touche=20pas=20=E2=86=92?= =?UTF-8?q?=20invention=20#6=20latente)=20:=20(a)=20bancable/README.md=20+?= =?UTF-8?q?=20(b)=20banclib/finance.py=20docstring=20=C2=AB=203%=20=C3=A9d?= =?UTF-8?q?ition/8.5%=20marketing=20(#9)=20=C2=BB=20=C2=B7=20(c)=20banclib?= =?UTF-8?q?/deps.py=20=C2=AB=20CLAUDE.md=20#9/#10=20(3%/8.5%/52%=C2=B7USD+?= =?UTF-8?q?DOP=C2=B7Cardnet=C2=B7Letter=20US)=20=C2=BB=206=20marqueurs=20?= =?UTF-8?q?=C2=B7=20(d)=20crm/commissions/README.md=20=C2=AB=20pourcentage?= =?UTF-8?q?s=20canoniques=20(3%=20=C3=A9dition=C2=B78.5%=20marketing=C2=B7?= =?UTF-8?q?52%=20=C3=A9quilibre)=20=C2=BB.=20Extension=20du=20bloc=20d'anc?= =?UTF-8?q?rage=20existant=20(check=5Freadme=5Fclaims.sh,=20apr=C3=A8s=20T?= =?UTF-8?q?emplate=20canonique)=20R=C3=89UTILISANT=20exp=20(z=C3=A9ro=20re?= =?UTF-8?q?-parse).=20Teeth=20mutation-v=C3=A9rifi=C3=A9s=20:=208.5%?= =?UTF-8?q?=E2=86=929%=20mord=20les=204=20=C2=B7=2052%=E2=86=9255%=20mord?= =?UTF-8?q?=20(c)+(d)=20SEULS=20(a/b=20ne=20citent=20qu'=C3=A9dition+marke?= =?UTF-8?q?ting=20=3D=20ciblage=20pr=C3=A9cis)=20=C2=B7=20#10=20Cardnet?= =?UTF-8?q?=E2=86=92Azul=20mord=20l'=C3=A9num=20(c)=20;=20arbre=20restaur?= =?UTF-8?q?=C3=A9=20=3D=20vert.=20Doc=20ci/README=20=C2=A72.=200=20prod,?= =?UTF-8?q?=200=20artefact=20rebuild=20(aucun=20out/=20ni=20doc=20scor?= =?UTF-8?q?=C3=A9=20audit=5F4big),=200=20chiffre=20saisi=20(#6,=20recomput?= =?UTF-8?q?=C3=A9s=20de=20CLAUDE.md),=200=20VPS=20(#8).=20run=5Fci=2033=20?= =?UTF-8?q?PASS=C2=B70=20FAIL=C2=B70=20SKIP.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- 05_activity_log/2026-08-05.md | 44 +++++++++++++++++ ci/README.md | 12 +++++ ci/check_readme_claims.sh | 93 +++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/05_activity_log/2026-08-05.md b/05_activity_log/2026-08-05.md index 0e77f36..819bd7f 100644 --- a/05_activity_log/2026-08-05.md +++ b/05_activity_log/2026-08-05.md @@ -1520,3 +1520,47 @@ la main** (#6 — les 20/30 sont lus du spec, non retapés), **aucune commande V journal. **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**. diff --git a/ci/README.md b/ci/README.md index 0a42505..0f575d8 100644 --- a/ci/README.md +++ b/ci/README.md @@ -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 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 `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 diff --git a/ci/check_readme_claims.sh b/ci/check_readme_claims.sh index 445e4de..a696c9a 100755 --- a/ci/check_readme_claims.sh +++ b/ci/check_readme_claims.sh @@ -5864,6 +5864,99 @@ if exp is not None: + (f" · absents={miss}" if miss else "") + (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 # #10 — même classe d'ANCRAGE que la CITATION #10 des fiches ci-dessus, mais sur