[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:
@@ -303,3 +303,58 @@ mobile∉`OTO Ventes` · exit 0. Working tree byte-restauré (`git checkout --`,
|
|||||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; l'attachement
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; l'attachement
|
||||||
réel des rôles aux Workspaces `bench` reste côté VPS).
|
réel des rôles aux Workspaces `bench` reste côté VPS).
|
||||||
- **Auto-score 4Big** : 96/100.
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|
||||||
|
## Session `20260801_023211` · Buffer S8 · Domaine 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`), la 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 même fichier ; (c) le README (ligne du gabarit) ; (d) le **tuple d'oracle HARDCODÉ** de `tests/test_publiciste.py`.
|
||||||
|
|
||||||
|
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||||
|
close ; poursuite de la série anti-dérive (CLAUDE.md #6). **Même patron EXACT** que
|
||||||
|
les paramètres canoniques `faisabilite/generator` **ancrés sur CLAUDE.md #9/#10**
|
||||||
|
(`CANONICAL` ↔ contrainte) — appliqué à la **contrainte #4** (identité visuelle) et
|
||||||
|
à son consommateur `publiciste/branding`, module **entièrement hors CI** jusqu'ici
|
||||||
|
(grep `branding|0a0a12|f0b429|Fraunces` dans `ci/` = 0 avant cette session).
|
||||||
|
|
||||||
|
**Dérive silencieuse fermée** :
|
||||||
|
- `05_deliverables_mvp/publiciste/lib/branding.py:13-20` — les 4 CONSTANTES ·
|
||||||
|
`05_deliverables_mvp/publiciste/lib/branding.py:3-4` — le docstring qui les cite ·
|
||||||
|
`05_deliverables_mvp/publiciste/README.md:43` — « Gabarit dark+doré (Fraunces +
|
||||||
|
Cormorant Garamond) » · `05_deliverables_mvp/publiciste/tests/test_publiciste.py:193`
|
||||||
|
— `for token in ("#0a0a12", "#f0b429", "Fraunces", "Cormorant Garamond")`.
|
||||||
|
- Source faisant autorité : **CLAUDE.md #4** (ligne 18) — la contrainte
|
||||||
|
constitutionnelle, comme #9/#10 le sont pour le générateur de faisabilité.
|
||||||
|
- Piège : le SEUL contrôle existant (`test_marque_luxury`) assert que le RENDU
|
||||||
|
HTML CONTIENT ces 4 marqueurs — mais ils sont **HARDCODÉS dans le test**, une
|
||||||
|
copie de plus **jamais comparée à CLAUDE.md**. Si #4 change (accent
|
||||||
|
`#f0b429`→`#c9a227`) 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
|
||||||
|
`vente.otov7.com` émettrait la mauvaise couleur — invention silencieuse de la
|
||||||
|
classe même que #6 interdit, qu'aucune suite `tests/` (qui teste des FONCTIONS,
|
||||||
|
pas l'ancrage à CLAUDE.md) n'attrape.
|
||||||
|
- **État courant** : **aucun token périmé** — les 4 constantes + docstring + README
|
||||||
|
+ oracle du test recoupent CLAUDE.md #4 exactement (anti-invention #6, rien à
|
||||||
|
réécrire). Le défaut est la **surface ungated** (module hors CI).
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Publiciste/branding »
|
||||||
|
avant `sys.exit`) : (0) **ancrage** — les 4 tokens recomputés de la ligne #4 de
|
||||||
|
CLAUDE.md (2 couleurs backtickées + 2 fontes de la parenthèse `(… + …)`) ; (a)
|
||||||
|
`branding.py` CONSTANTES == #4 (hex **insensible à la casse**, fontes à l'exact
|
||||||
|
strip) ; (b) **docstring** (texte AVANT les constantes) cite les 4 EXACTS ; (c)
|
||||||
|
README cite les 2 fontes ; (d) **oracle du test** — le tuple `for token in (...)`
|
||||||
|
== les 4 tokens de #4 (set-diff : absent ET en trop). Un claim absent échoue AUSSI
|
||||||
|
(traçabilité #6).
|
||||||
|
|
||||||
|
**6 morsures vérifiées** : `branding.py` accent `#f0b429→#e0a420` (constante
|
||||||
|
périmée) · `branding.py` display `Fraunces→Playfair Display` · **CLAUDE.md #4**
|
||||||
|
accent `→#c9a227` (mord **SIMULTANÉMENT** les 3 copies aval : constante + docstring
|
||||||
|
+ oracle du test — prouve la valeur de l'ANCRAGE) · docstring retire l'accent de la
|
||||||
|
prose (claim absent) · README échange une fonte (`Cormorant Garamond→Georgia`) ·
|
||||||
|
oracle du test retire `Fraunces` ; restauré = green : 4 tokens sains · constantes ==
|
||||||
|
#4 · docstring 4 tokens · README 2 fontes · oracle == #4 · exit 0. Working tree
|
||||||
|
byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) ·
|
||||||
|
**7 gates re-verts**.
|
||||||
|
|
||||||
|
- `ci/README.md` (table récap du pipeline + paragraphe détaillé « Tokens design
|
||||||
|
canoniques `publiciste/branding` ancrés sur CLAUDE.md #4 ») mis à jour.
|
||||||
|
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||||
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact ; le déploiement
|
||||||
|
réel du site `vente.otov7.com` reste côté VPS).
|
||||||
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|||||||
+27
-1
File diff suppressed because one or more lines are too long
@@ -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"MAIS workspace.json met « {rname} » dans son Has Role → "
|
||||||
f"SUR-EXPOSITION console, assertion #6 VIOLÉE")
|
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)
|
sys.exit(1 if FAIL else 0)
|
||||||
PY
|
PY
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|||||||
Reference in New Issue
Block a user