[DTP-Worker 20260802_034704] Sprint 8 · buffer · Faisabilité : ancrage du TEMPLATE CANONIQUE v1.0 (5 surfaces #9/#10) sur CLAUDE.md

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>
This commit is contained in:
Claude Code DTP Worker
2026-08-02 03:47:04 +00:00
parent d429fccf9a
commit ab73cf9384
2 changed files with 190 additions and 0 deletions
+56
View File
@@ -1,5 +1,61 @@
# Activity log · 2026-08-02 · Claude Code DTP Worker
## Sprint 8 · buffer · Faisabilité — ancrage du TEMPLATE CANONIQUE v1.0 (5 surfaces #9/#10) sur CLAUDE.md
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
chiffres »). Le pattern « constante canonique CLAUDE.md recopiée à la main dans
une surface data-derived » (re-dérive la valeur depuis la contrainte, jamais la
cohérence interne) couvre déjà le générateur (`model.py`/README/renderer/scorer/
oracle-test), les fiches ERPNext/CRM (« Fiches #10 »), le module fiscal (`moneda`),
la marque SEO §Entités, la persona Chat OTOIA, les tokens branding #4, etc. Un
fichier restait NON gaté (grep : absent de tous les `ci/*.sh`) et c'est
paradoxalement **le plus normatif** : `05_deliverables_mvp/faisabilite/
TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md`, le DOCUMENT-MODÈLE « CANONIQUE » (Livrable
Sprint 1) que **toute faisabilité en production DOIT reproduire**, et que le
générateur 4 volets + le Publiciste + la régénération batch S4 sont censés suivre.
Ce template recopie **à la main les 6 valeurs de CLAUDE.md #9/#10 à CINQ surfaces
structurées**, toutes se réclamant de « contrainte #9 »/« #10 », **aucune gatée** :
1. **l.28** intro §0 « frais **3 %** · marketing **8.5 %** · point d'équilibre
**52 %** » (3 pourcentages #9, associés par mot-clé) ;
2. **l.144-146** §5.2 — 3 lignes de table « **N %** (fixe · contrainte #9) » ;
3. **l.29** intro §0 « **USD + DOP** · format **Letter US** · paiements **Cardnet** » ;
4. **l.149-151** §5.2 — 3 lignes « **valeur** (… contrainte #10) » (la ligne
paiement citant l'exclusion « ❌ pas-X ») ;
5. **l.196** §7 checklist « 3 % / 8.5 % / 52 % · USD+DOP · Letter US · Cardnet
présents » (énumération des 6 marqueurs).
**Le « vert trompeur »** — si CLAUDE.md #9 passe **52 %→55 %** (ou #10 renomme le
prestataire) et que les modules s'alignent, ce TEMPLATE — la RÉFÉRENCE de toutes
les faisabilités — reste PÉRIMÉ en silence, imposant à chaque projet un paramètre
qui CONTREDIT le mandat pendant qu'il se réclame « contrainte #9/#10 ». Ni
`check_artifacts` (ce n'est pas un `out/*.json`) ni `check_docs`/`guard_constraints`
ni aucune suite `tests/` (FONCTIONS, jamais l'ancre à CLAUDE.md) ne mordent.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « TEMPLATE FAISABILITÉ CANONIQUE
v1.0 · PARAMÈTRES #9/#10 », juste après « Fiches #10 ») — RÉUTILISE `exp` (les 6
valeurs déjà recomputées des lignes #9/#10 de CLAUDE.md · zéro re-dérivation) +
`exp_excl` (prestataire exclu du `(pas X)`). Exige que chacune des 5 surfaces ==
CLAUDE.md : (1) 3 pcts associés par mot-clé ; (2) SET des 3 lignes « (fixe ·
contrainte #9) » == {3 %,8.5 %,52 %} (mord aussi ligne ajoutée/retirée) ; (3)/(4)
chaque valeur #10 présente en gras dans sa région ancrée + l'exclusion ❌ ; (5)
énumération des 6 marqueurs == ensemble EXACT (set-diff absent ET en trop). Une
surface INTROUVABLE échoue AUSSI (recensement évaporé = régression #6).
**Vérif** — 5 checks verts sur l'arbre propre. **11 morsures** adversariales :
M1 intro#9 52→55 · M2 ligne#9 8.5→9 · M3 intro#10 Cardnet→Azul · M4 ligne#10
Letter US→A4 · M5 exclusion ❌ Stripe→PayPal · M6 checklist perd Cardnet · M7
checklist 52→60 · M8 intro#9 supprimée (INTROUVABLE) · M9 checklist « présents »→
« présent » (INTROUVABLE) · **M10 CLAUDE.md #9 52→55 SEUL ⇒ cascade sur 3 régions
(1)(2)(5)** · **M11 CLAUDE.md #10 Cardnet→Azul SEUL ⇒ cascade sur 3 régions
(3)(4)(5)** — les deux preuves que l'AUTORITÉ est CLAUDE.md, pas la cohérence
interne du template. Un piège corrigé en route : le groupe capturé est le NOMBRE nu
(sans `%`), donc `_pct()` (qui exige un `%`) renvoyait `None``float()` direct.
Gates re-verts : `check_artifacts` · `check_docs` · `guard_constraints` ·
`check_ci_integrity` · `check_regression` · `check_readme_claims` tous exit 0.
---
## Sprint 8 · buffer · Fiscal e-CF — ancrage du CONTRAT DE FORMAT e-NCF dans le COMPOSEUR `ncf.py` (CODE) + son ORACLE de test
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
+134
View File
@@ -5295,6 +5295,140 @@ if exp is not None:
(f" · (pas {exp_excl})" if cites_excl and exp_excl else "")
good(f"Fiches #10 · {label} — cite {_cited} == CLAUDE.md #10")
# ============================================================================
# TEMPLATE FAISABILITÉ CANONIQUE v1.0 · PARAMÈTRES #9/#10 — même classe d'ANCRAGE
# que « paramètres canoniques » (generator) et « Fiches #10 » ci-dessus, sur une
# SURFACE encore distincte : le DOCUMENT-MODÈLE « CANONIQUE » que TOUTE faisabilité
# en production DOIT reproduire — `05_deliverables_mvp/faisabilite/
# TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md` (Livrable Sprint 1 · statut « CANONIQUE :
# toute faisabilité en production DOIT s'y conformer »).
# ----------------------------------------------------------------------------
# Ce template recopie À LA MAIN les 6 valeurs de CLAUDE.md #9/#10 à CINQ surfaces
# structurées, TOUTES se réclamant de « contrainte #9 »/« #10 » :
# (1) l.28 intro §0 « frais édition **3 %** · marketing **8.5 %** · point
# d'équilibre **52 %** pré-vente » (les 3 pourcentages #9, associés par mot-clé) ;
# (2) l.144-146 §5.2 — 3 lignes de table « **N %** (fixe · contrainte #9) »
# (frais/marketing/équilibre) ;
# (3) l.29 intro §0 « **USD + DOP** · format **Letter US** · paiements **Cardnet** »
# (les 3 valeurs #10) ;
# (4) l.149-151 §5.2 — 3 lignes de table « **valeur** (… contrainte #10) » (devises ·
# format · paiement, la ligne paiement citant l'exclusion « ❌ pas-X ») ;
# (5) l.196 §7 checklist « 3 % / 8.5 % / 52 % · USD+DOP · Letter US · Cardnet présents »
# (l'énumération des 6 marqueurs, comme la prose README:28 du generator).
# AUCUN gate ne liait ce fichier à CLAUDE.md (grep : absent de tous les `ci/*.sh`) :
# check_artifacts est aveugle (ce n'est pas un `out/*.json`), check_docs/guard aussi.
# Piège #6 « vert trompeur » : si CLAUDE.md #9 passe 52 %→55 % (ou #10 renomme le
# prestataire) et que les modules s'alignent, ce TEMPLATE — la référence que le
# générateur 4 volets, le Publiciste et la régénération batch S4 (§8) sont censés
# suivre — reste PÉRIMÉ en silence, imposant à TOUTES les faisabilités un paramètre
# qui CONTREDIT le mandat, pendant qu'il se réclame « contrainte #9/#10 ». Aucune
# suite tests/ (FONCTIONS, jamais l'ancre à CLAUDE.md) ne l'attrape. On RÉUTILISE
# `exp` (6 valeurs recomputées de #9/#10 · zéro duplication) + `exp_excl` (prestataire
# exclu) et on exige que CHACUNE des 5 surfaces == CLAUDE.md. Une surface INTROUVABLE
# échoue AUSSI (le recensement qui s'évapore est lui-même une régression #6).
# ============================================================================
if exp is not None:
TPL = f"{D}/faisabilite/TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md"
tpl = read_norm(TPL)
if tpl is None:
bad(f"Template canonique · {TPL} illisible")
else:
_pct_kw_map = (("frais_edition_pct", r"frais", "frais édition"),
("marketing_pct", r"marketing", "marketing"),
("point_equilibre_pct", r"[ée]quilibre", "point d'équilibre"))
# (1) intro §0 (l.28) · les 3 pourcentages #9 associés par mot-clé
m1 = re.search(r"#9 Param[^→]*→(.+?)pr[ée]-vente", tpl)
if m1 is None:
bad("Template canonique · (1) intro #9 (l.28) INTROUVABLE "
"(attendu frais/marketing/équilibre en gras)")
else:
seg1 = m1.group(1); drift = []
for key, kw, lab in _pct_kw_map:
mm = re.search(kw + r"[^*]*?\*\*\s*(\d+(?:\.\d+)?)\s*%", seg1)
got = float(mm.group(1)) if mm else None
if got != exp[key]:
drift.append(f"{lab}={_pnorm(got) if got is not None else '∅'} "
f"(attendu {_pnorm(exp[key])})")
if drift:
bad("Template canonique · (1) intro #9 (l.28) DÉRIVE de CLAUDE.md #9 : "
f"{' · '.join(drift)} → aligner le template (ou CLAUDE.md)")
else:
good("Template canonique · (1) intro #9 (l.28) — 3 pourcentages == "
"CLAUDE.md #9")
# (2) §5.2 (l.144-146) · les 3 lignes de table « **N %** (fixe · contrainte #9) »
rows9 = re.findall(r"\*\*\s*(\d+(?:\.\d+)?)\s*%\s*\*\*\s*\(fixe · contrainte #9\)",
tpl)
want9 = {exp[k] for k in _num_keys}
got9 = {float(x) for x in rows9}
if len(rows9) != 3:
bad(f"Template canonique · (2) §5.2 — attendu 3 lignes « **N %** (fixe · "
f"contrainte #9) », trouvé {len(rows9)} ({rows9}) → régénérer le template")
elif got9 == want9:
good("Template canonique · (2) §5.2 — 3 lignes « (fixe · contrainte #9) » == "
"CLAUDE.md #9 (3 %/8.5 %/52 %)")
else:
miss = sorted(_pnorm(v) for v in want9 - got9)
extra = sorted(_pnorm(v) for v in got9 - want9)
bad(f"Template canonique · (2) §5.2 — lignes #9 {sorted(map(_pnorm, got9))} "
f"MAIS CLAUDE.md {sorted(map(_pnorm, want9))}"
+ (f" · absents={miss}" if miss else "")
+ (f" · en trop={extra}" if extra else "") + " → régénérer le template")
# (3) intro §0 (l.29) · les 3 valeurs #10 en gras
m3 = re.search(r"#10 Devises\*\* → (.+?)\.", tpl)
if m3 is None:
bad("Template canonique · (3) intro #10 (l.29) INTROUVABLE "
"(attendu devises/format/paiement en gras)")
else:
seg3 = m3.group(1); drift = []
for k in _txt_keys:
if not re.search(r"\*\*\s*" + re.escape(exp[k]) + r"\s*\*\*", seg3):
drift.append(f"{_lab10[k]} attendu **{exp[k]}**")
if drift:
bad("Template canonique · (3) intro #10 (l.29) DÉRIVE de CLAUDE.md #10 : "
f"{' · '.join(drift)} → aligner le template (ou CLAUDE.md)")
else:
good("Template canonique · (3) intro #10 (l.29) — devises/format/paiement "
"== CLAUDE.md #10")
# (4) §5.2 (l.149-151) · les 3 lignes de table « **valeur** (… contrainte #10) »
drift = []
# devises + format : « **valeur** (contrainte #10) »
for k in ("devises", "format_doc"):
if not re.search(r"\*\*\s*" + re.escape(exp[k]) + r"\s*\*\*\s*\(contrainte #10\)",
tpl):
drift.append(f"ligne {_lab10[k]} attendue « **{exp[k]}** (contrainte #10) »")
# paiement : « **valeur** (❌ <exclu> · contrainte #10) » — cite l'exclusion #10
pay_re = (r"\*\*\s*" + re.escape(exp["paiement"]) + r"\s*\*\*\s*\(❌\s*"
+ (re.escape(exp_excl) if exp_excl else r"\S+") + r"\s*·\s*contrainte #10\)")
if not re.search(pay_re, tpl):
drift.append(f"ligne paiement attendue « **{exp['paiement']}** (❌ "
f"{exp_excl or '?'} · contrainte #10) »")
if drift:
bad("Template canonique · (4) §5.2 lignes #10 DÉRIVENT de CLAUDE.md #10 : "
f"{' · '.join(drift)} → aligner le template (ou CLAUDE.md)")
else:
good("Template canonique · (4) §5.2 — 3 lignes « (… contrainte #10) » (devises · "
f"format · paiement ❌ {exp_excl}) == CLAUDE.md #10")
# (5) §7 checklist (l.196) · énumération des 6 marqueurs canoniques
_want6_tpl = {_pnorm(exp[k]) for k in _num_keys} | {_ai(exp[k]) for k in _txt_keys}
m5 = re.search(r"Param[èe]tres canoniques\*\* \| (.+?) pr[ée]sents", tpl)
if m5 is None:
bad("Template canonique · (5) §7 checklist — énumération « 3 %/…/Cardnet "
"présents » INTROUVABLE")
else:
got5 = set()
for tok in re.split(r"[/·]", m5.group(1)):
p = _pct(tok)
got5.add(_pnorm(p) if p is not None else _ai(tok))
if got5 == _want6_tpl:
good("Template canonique · (5) §7 checklist — énumère les 6 marqueurs == "
"CLAUDE.md #9/#10")
else:
miss = sorted(_want6_tpl - got5); extra = sorted(got5 - _want6_tpl)
bad(f"Template canonique · (5) §7 checklist — énumère {sorted(got5)} MAIS "
f"CLAUDE.md {sorted(_want6_tpl)}"
+ (f" · absents={miss}" if miss else "")
+ (f" · en trop={extra}" if extra else "") + " → régénérer le template")
# ============================================================================
# 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