[DTP-Worker] Sprint 8 · buffer · Publiciste/branding : les 4 TOKENS DESIGN CANONIQUES de la marque luxury — fond dark #0a0a12 + accent doré #f0b429, titres Fraunces + corps Cormorant Garamond (contrainte NON-NÉGOCIABLE CLAUDE.md #4) — étaient RECOPIÉS à QUATRE endroits tous NON gatés : (a) les CONSTANTES lib/branding.py (COLOR_BG/COLOR_ACCENT/FONT_DISPLAY/FONT_BODY), source unique importée par le générateur & substituée dans le gabarit {{COLOR_BG}}…, hors out/ donc INVISIBLE à check_artifacts ; (b) le docstring du fichier ; (c) le README ; (d) le tuple d'oracle HARDCODÉ de tests/test_publiciste.py. Le seul contrôle existant (test_marque_luxury) assert que le RENDU contient ces marqueurs mais ils sont une copie de plus JAMAIS comparée à CLAUDE.md — même patron EXACT que les paramètres canoniques faisabilite/generator (CANONICAL↔CLAUDE.md #9/#10). Gate ajouté : les 4 tokens recomputés de la ligne #4 de CLAUDE.md (zéro duplication) ; (a) branding.py CONSTANTES == #4 (hex insensible casse, fontes exact), (b) docstring cite les 4, (c) README cite les 2 fontes, (d) oracle du test == #4 (set-diff). 6 morsures vérifiées (constante accent/display · CLAUDE.md #4 accent → mord SIMULTANÉMENT les 3 copies aval · docstring · README · oracle), restauré vert, 7 gates re-verts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-01 02:41:10 +00:00
parent 3a91c9d52f
commit 68004265d6
3 changed files with 199 additions and 1 deletions
+27 -1
View File
File diff suppressed because one or more lines are too long
+117
View File
@@ -3513,6 +3513,123 @@ if _ws_json is not None and _ws_roles is not None:
f"MAIS workspace.json met « {rname} » dans son Has Role → "
f"SUR-EXPOSITION console, assertion #6 VIOLÉE")
# ============================================================================
# Publiciste/branding · TOKENS DESIGN CANONIQUES « ancrés sur CLAUDE.md #4 »
# — les 4 valeurs de la marque luxury (2 couleurs + 2 typographies), jamais gatées.
# ----------------------------------------------------------------------------
# La contrainte NON-NÉGOCIABLE #4 de CLAUDE.md fixe l'identité visuelle : fond
# dark `#0a0a12` + accent doré `#f0b429`, titres Fraunces + corps Cormorant
# Garamond. C'est la SOURCE FAISANT AUTORITÉ. Ces 4 tokens sont RECOPIÉS à
# QUATRE endroits, tous NON gatés :
# (a) lib/branding.py CONSTANTES (COLOR_BG/COLOR_ACCENT/FONT_DISPLAY/FONT_BODY)
# — la source unique importée par le générateur ET substituée dans le
# gabarit ({{COLOR_BG}}…) ; ce n'est PAS un out/*.json → invisible à
# check_artifacts ;
# (b) le docstring de branding.py (« `#0a0a12` fond · `#f0b429` … Fraunces
# (titres) + Cormorant Garamond ») — la prose du module ;
# (c) README:43 (« Gabarit dark+doré (Fraunces + Cormorant Garamond) ») ;
# (d) tests/test_publiciste.py — le tuple d'oracle HARDCODÉ
# ("#0a0a12","#f0b429","Fraunces","Cormorant Garamond") : le SEUL contrôle
# existant assert que le RENDU contient ces marqueurs, mais ils sont une
# COPIE de plus, JAMAIS comparée à CLAUDE.md. Si #4 change (ex. accent
# `#f0b429`→`#e0a420`) et qu'on aligne branding.py, l'oracle du test reste
# périmé (rouge trompeur) ; si RIEN ne bouge, tout reste vert alors que le
# site public émettrait la mauvaise couleur — invention silencieuse (#6) que
# nulle suite tests/ (qui teste des FONCTIONS, pas l'ancrage à CLAUDE.md)
# n'attrape. Même patron EXACT que les paramètres canoniques
# faisabilite/generator (ancrage CANONICAL↔CLAUDE.md #9/#10).
# On RECOMPUTE les 4 tokens depuis la ligne #4 de CLAUDE.md (zéro duplication) et
# on exige : (a) branding.py CONSTANTES == #4 ; (b) docstring cite les 4 EXACTS ;
# (c) README cite les 2 fontes ; (d) l'oracle du test == #4. Hex insensible à la
# casse, fontes comparées à l'exact (strip). Un claim absent échoue AUSSI.
# ============================================================================
PUB = f"{D}/publiciste"
try:
cm_raw4 = open("CLAUDE.md", encoding="utf-8").read()
l4 = re.search(r"^4\.\s+(.+)$", cm_raw4, re.M)
if not l4:
raise ValueError("contrainte #4 INTROUVABLE")
hexes = [h.lower() for h in re.findall(r"`(#[0-9a-fA-F]{6})`", l4.group(1))]
mfp = re.search(r"\(([^)]+)\)", l4.group(1))
fonts = [f.strip() for f in mfp.group(1).split("+")] if mfp else []
if len(hexes) != 2 or len(fonts) != 2:
raise ValueError(f"attendu 2 couleurs + 2 fontes, lu {hexes} / {fonts}")
b4 = {"bg": hexes[0], "accent": hexes[1], "display": fonts[0], "body": fonts[1]}
except (OSError, ValueError) as e:
bad(f"Branding canoniques · CLAUDE.md #4 illisible/inattendu : {e}"); b4 = None
if b4 is not None:
good(f"Branding canoniques · CLAUDE.md #4 sain : bg={b4['bg']} accent={b4['accent']} "
f"display={b4['display']!r} body={b4['body']!r}")
# (a) ANCRAGE : lib/branding.py CONSTANTES == CLAUDE.md #4 -------------------
BR = f"{PUB}/lib/branding.py"
try:
br_src = open(BR, encoding="utf-8").read()
except OSError as e:
bad(f"Branding canoniques · {BR} illisible : {e}"); br_src = None
if br_src is not None:
const_pat = {
"bg": r'COLOR_BG\s*=\s*"([^"]+)"',
"accent": r'COLOR_ACCENT\s*=\s*"([^"]+)"',
"display": r'FONT_DISPLAY\s*=\s*"([^"]+)"',
"body": r'FONT_BODY\s*=\s*"([^"]+)"',
}
drift = []
for k, pat in const_pat.items():
m = re.search(pat, br_src)
got = m.group(1) if m else None
want = b4[k]
ok = (got is not None and
(got.lower() == want if k in ("bg", "accent") else got.strip() == want))
if not ok:
drift.append(f"{k}={got!r} (attendu {want!r})")
if drift:
bad(f"Branding canoniques · branding.py CONSTANTES DÉRIVENT de CLAUDE.md #4 : "
f"{' · '.join(drift)} → aligner branding.py (ou CLAUDE.md)")
else:
good("Branding canoniques · branding.py CONSTANTES == CLAUDE.md #4 (4 tokens)")
# (b) PROSE docstring : les 4 tokens cités AVANT les CONSTANTES -----------
doc = br_src.split("COLOR_BG", 1)[0]
doc_hex = {h.lower() for h in re.findall(r"`(#[0-9a-fA-F]{6})`", doc)}
miss = [b4[k] for k in ("bg", "accent") if b4[k] not in doc_hex]
miss += [b4[k] for k in ("display", "body") if b4[k] not in doc]
if miss:
bad(f"Branding canoniques · docstring branding.py — tokens ABSENTS de la "
f"prose : {miss} (claim absent = régression · #6)")
else:
good("Branding canoniques · docstring branding.py cite les 4 tokens == CLAUDE.md #4")
# (c) README : la ligne du gabarit cite les 2 fontes -----------------------
PBR_RD = f"{PUB}/README.md"
pbr_rd = read_norm(PBR_RD)
if pbr_rd is not None:
rd_miss = [b4[k] for k in ("display", "body") if b4[k] not in pbr_rd]
if rd_miss:
bad(f"Branding canoniques · {PBR_RD} — fontes ABSENTES de la prose : "
f"{rd_miss} (attendu {b4['display']} + {b4['body']} == CLAUDE.md #4)")
else:
good(f"Branding canoniques · {PBR_RD} cite les 2 fontes == CLAUDE.md #4")
# (d) ORACLE du test : le tuple hardcodé == les 4 tokens de CLAUDE.md #4 ----
TBR = f"{PUB}/tests/test_publiciste.py"
try:
tbr_src = open(TBR, encoding="utf-8").read()
except OSError as e:
bad(f"Branding canoniques · {TBR} illisible : {e}"); tbr_src = None
if tbr_src is not None:
mt = re.search(r"for token in \(([^)]+)\)", tbr_src)
if mt is None:
bad(f"Branding canoniques · {TBR} — tuple d'oracle « for token in (...) » "
f"INTROUVABLE (le contrôle #4 du test a disparu · régression)")
else:
toks = [t.strip().strip('"\'') for t in mt.group(1).split(",") if t.strip()]
toks_n = {t.lower() if t.startswith("#") else t for t in toks}
want_n = {b4["bg"], b4["accent"], b4["display"], b4["body"]}
if toks_n == want_n:
good(f"Branding canoniques · {TBR} oracle == CLAUDE.md #4 (4 tokens)")
else:
miss = sorted(want_n - toks_n); extra = sorted(toks_n - want_n)
bad(f"Branding canoniques · {TBR} oracle DÉRIVE de CLAUDE.md #4"
+ (f" · absents={miss}" if miss else "")
+ (f" · en trop={extra}" if extra else "") + " → aligner le test")
sys.exit(1 if FAIL else 0)
PY
rc=$?