[DTP-Worker 20260802_000501] Sprint 8 · buffer · Publiciste : gate d'ANCRAGE des DEVISES du site public sur CLAUDE.md #10
Le bloc Publiciste/branding existant ancre les 4 tokens DESIGN (#4 : couleurs + typographies). Le MÊME module porte une 2e constante constitutionnelle NON gatée : les devises CLAUDE.md #10 (« **USD + DOP** »), recopiées à 4 endroits data-derived, tous invisibles à check_artifacts (pas un out/*.json) : (a) branding.py DEVISE_PRIMAIRE/SECONDAIRE (auto-étiquetées « #10 · USD + DOP » sans gate) ; (b) generator.py _fmt_usd/_fmt_dop — les formateurs qui IMPRIMENT le code devise sur la grille de prix du site public vente.otov7.com (sortie face-public) ; (c) footer HTML « Prix … en USD + DOP (Cardnet) » ; (d) l'oracle hardcodé assertIn("USD 150 000") du test — une copie jamais comparée à CLAUDE.md. Aucune suite tests/ (FONCTIONS de rendu, pas l'ancre à CLAUDE.md) n'attrape la dérive. Nouveau bloc : RE-PARSE les 2 devises depuis la ligne #10 de CLAUDE.md (indépendamment de exp amont · aucun skip hérité), exige (a) constantes branding == #10 ordre inclus ; (b) ensemble des codes émis par les formateurs == #10 ; (c) footer cite les 2 devises dans l'ordre + (Cardnet) ; (d) oracle test == devise primaire. Claim absent échoue AUSSI (#6). 6 morsures vérifiées (M5 : rename #10 CLAUDE.md-only cascade sur les 4 copies = preuve ancre live), 4 gates re-verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -6131,6 +6131,124 @@ if b4 is not None:
|
||||
+ (f" · absents={miss}" if miss else "")
|
||||
+ (f" · en trop={extra}" if extra else "") + " → aligner le test")
|
||||
|
||||
# ============================================================================
|
||||
# Publiciste/generator+branding · DEVISES CANONIQUES du site public « ancrées
|
||||
# sur CLAUDE.md #10 » (USD + DOP) — les libellés monétaires RÉELLEMENT ÉMIS sur
|
||||
# vente.otov7.com, jamais gatés.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le bloc branding #4 ci-dessus ancre les 4 tokens DESIGN. Mais le MÊME module
|
||||
# porte une 2ᵉ constante constitutionnelle NON gatée : les DEUX devises de
|
||||
# CLAUDE.md #10 (« **USD + DOP** devises »), recopiées à QUATRE endroits data-
|
||||
# derived, tous invisibles à check_artifacts (pas un out/*.json) et jamais
|
||||
# confrontés à #10 :
|
||||
# (a) lib/branding.py DEVISE_PRIMAIRE/DEVISE_SECONDAIRE — constantes AUTO-
|
||||
# étiquetées « contrainte #10 · USD + DOP », sans aucun gate ;
|
||||
# (b) lib/generator.py `_fmt_usd`/`_fmt_dop` — les DEUX formateurs qui
|
||||
# IMPRIMENT le code devise sur la grille de prix du site public
|
||||
# (`f"USD {value:,.0f}"` / `f"DOP {value:,.0f}"`) ; c'est la SORTIE
|
||||
# FACE-PUBLIC : une devise HORS #10 ici = mandat trahi en silence (#6) ;
|
||||
# (c) lib/generator.py footer (émis dans le HTML) « Prix … en USD + DOP
|
||||
# (Cardnet) » — la prose du pied de page du site ;
|
||||
# (d) tests/test_publiciste.py — l'oracle HARDCODÉ « assertIn("USD 150 000",
|
||||
# …) » : une COPIE de plus de la devise primaire, JAMAIS comparée à #10.
|
||||
# Aucune suite tests/ (qui teste des FONCTIONS de rendu, pas l'ancre à
|
||||
# CLAUDE.md) n'attrape la dérive : renommer la devise #10 (USD→EUR) et aligner
|
||||
# le module reste vert alors que le site émettrait la mauvaise devise ; ne RIEN
|
||||
# bouger reste vert alors que branding se dit « #10 » en mentant. Même patron
|
||||
# EXACT que le bloc branding/#4 et faisabilite/#9-#10. On RE-PARSE les 2 devises
|
||||
# depuis la ligne #10 de CLAUDE.md (indépendamment de `exp` amont · aucun skip
|
||||
# hérité) et on exige : (a) les 2 constantes == #10 (ordre inclus) ; (b)
|
||||
# l'ensemble des codes émis par les formateurs == #10 ; (c) le footer cite les 2
|
||||
# devises dans l'ordre ; (d) l'oracle du test == devise primaire. Un claim
|
||||
# absent échoue AUSSI (traçabilité #6).
|
||||
# ============================================================================
|
||||
try:
|
||||
cm_raw10p = open("CLAUDE.md", encoding="utf-8").read()
|
||||
l10p = re.search(r"^10\.\s+(.+)$", cm_raw10p, re.M)
|
||||
if not l10p:
|
||||
raise ValueError("contrainte #10 INTROUVABLE")
|
||||
seg10p = [s for s in re.split(r"·", l10p.group(1)) if "devise" in _ai(s)]
|
||||
mdev = re.search(r"\*\*(.+?)\*\*", seg10p[0]) if seg10p else None
|
||||
if not mdev:
|
||||
raise ValueError("segment devises #10 (« **… devises** ») illisible")
|
||||
pub_cur = re.findall(r"[A-Z]{3}", mdev.group(1))
|
||||
if len(pub_cur) != 2:
|
||||
raise ValueError(f"attendu 2 devises en gras, lu {pub_cur}")
|
||||
except (OSError, ValueError) as e:
|
||||
bad(f"Publiciste devises · CLAUDE.md #10 illisible/inattendu : {e}"); pub_cur = None
|
||||
if pub_cur is not None:
|
||||
good(f"Publiciste devises · CLAUDE.md #10 sain : primaire={pub_cur[0]} "
|
||||
f"secondaire={pub_cur[1]}")
|
||||
PUB = f"{D}/publiciste"
|
||||
# (a) ANCRAGE : branding.py DEVISE_PRIMAIRE/SECONDAIRE == #10 (ordre inclus) ---
|
||||
BRD = f"{PUB}/lib/branding.py"
|
||||
try:
|
||||
brd_src = open(BRD, encoding="utf-8").read()
|
||||
except OSError as e:
|
||||
bad(f"Publiciste devises · {BRD} illisible : {e}"); brd_src = None
|
||||
if brd_src is not None:
|
||||
dev_pat = {
|
||||
"primaire": (r'DEVISE_PRIMAIRE\s*=\s*"([^"]+)"', pub_cur[0]),
|
||||
"secondaire": (r'DEVISE_SECONDAIRE\s*=\s*"([^"]+)"', pub_cur[1]),
|
||||
}
|
||||
ddrift = []
|
||||
for k, (pat, want) in dev_pat.items():
|
||||
m = re.search(pat, brd_src)
|
||||
got = m.group(1) if m else None
|
||||
if got != want:
|
||||
ddrift.append(f"{k}={got!r} (attendu {want!r})")
|
||||
if ddrift:
|
||||
bad(f"Publiciste devises · branding.py CONSTANTES DÉRIVENT de CLAUDE.md #10 : "
|
||||
f"{' · '.join(ddrift)} → aligner branding.py (ou CLAUDE.md)")
|
||||
else:
|
||||
good(f"Publiciste devises · branding.py DEVISE_PRIMAIRE/SECONDAIRE == "
|
||||
f"CLAUDE.md #10 ({pub_cur[0]}/{pub_cur[1]})")
|
||||
# (b) SORTIE : les formateurs generator.py émettent EXACTEMENT les 2 devises #10
|
||||
GEN = f"{PUB}/lib/generator.py"
|
||||
try:
|
||||
gen_src = open(GEN, encoding="utf-8").read()
|
||||
except OSError as e:
|
||||
bad(f"Publiciste devises · {GEN} illisible : {e}"); gen_src = None
|
||||
if gen_src is not None:
|
||||
emis = re.findall(r'return f"([A-Z]{3}) \{value:[^}]+\}"', gen_src)
|
||||
if set(emis) != set(pub_cur):
|
||||
miss = sorted(set(pub_cur) - set(emis)); extra = sorted(set(emis) - set(pub_cur))
|
||||
bad(f"Publiciste devises · formateurs generator.py émettent {sorted(set(emis))} "
|
||||
f"MAIS CLAUDE.md #10 = {sorted(set(pub_cur))}"
|
||||
+ (f" · absents={miss}" if miss else "")
|
||||
+ (f" · HORS #10={extra}" if extra else "")
|
||||
+ " → le site public émettrait une devise non conforme (#6)")
|
||||
else:
|
||||
good(f"Publiciste devises · formateurs generator.py émettent {sorted(set(emis))} "
|
||||
f"== CLAUDE.md #10")
|
||||
# (c) FOOTER émis dans le HTML : « en <D1> + <D2> (Cardnet) » ordre inclus ---
|
||||
mft = re.search(r"en ([A-Z]{3}) \+ ([A-Z]{3}) \(Cardnet\)", gen_src)
|
||||
if mft is None:
|
||||
bad(f"Publiciste devises · {GEN} — pied de page « en <D1> + <D2> (Cardnet) » "
|
||||
f"INTROUVABLE (claim absent = régression · #6)")
|
||||
elif [mft.group(1), mft.group(2)] == pub_cur:
|
||||
good(f"Publiciste devises · footer generator.py cite {pub_cur[0]} + {pub_cur[1]} "
|
||||
f"== CLAUDE.md #10")
|
||||
else:
|
||||
bad(f"Publiciste devises · footer generator.py cite {mft.group(1)} + {mft.group(2)} "
|
||||
f"MAIS CLAUDE.md #10 = {pub_cur[0]} + {pub_cur[1]} → aligner le footer")
|
||||
# (d) ORACLE du test : « assertIn("<D1> 150 000", self.html) » == devise primaire
|
||||
TP = f"{PUB}/tests/test_publiciste.py"
|
||||
try:
|
||||
tp_src = open(TP, encoding="utf-8").read()
|
||||
except OSError as e:
|
||||
bad(f"Publiciste devises · {TP} illisible : {e}"); tp_src = None
|
||||
if tp_src is not None:
|
||||
mto = re.search(r'assertIn\("([A-Z]{3}) [\d ]+", self\.html\)', tp_src)
|
||||
if mto is None:
|
||||
bad(f"Publiciste devises · {TP} — oracle « assertIn(\"<devise> …\", self.html) » "
|
||||
f"INTROUVABLE (le contrôle prix du test a disparu · régression)")
|
||||
elif mto.group(1) == pub_cur[0]:
|
||||
good(f"Publiciste devises · {TP} oracle prix == devise primaire #10 ({pub_cur[0]})")
|
||||
else:
|
||||
bad(f"Publiciste devises · {TP} oracle prix cite {mto.group(1)!r} MAIS devise "
|
||||
f"primaire #10 = {pub_cur[0]!r} → aligner le test")
|
||||
|
||||
# ============================================================================
|
||||
# Fiches agents · colonne « Job CI » — chaque nom de job cité DOIT exister dans
|
||||
# .gitea/workflows/ci.yml (même classe de « vert trompeur », côté câblage CI).
|
||||
|
||||
Reference in New Issue
Block a user