[DTP-Worker] Sprint 8 · buffer L75 · Domaine SEO : le total ET la ventilation par langue des mots-clés (« 258 (fr=87·en=87·es=84) ») étaient transcrits À LA MAIN dans DEUX docs (table du README module seo + ligne de la fiche agent seo) sans AUCUN gate — ajouter un projet/vocabulaire ferait dériver les deux docs en silence pendant que seo/out/MANIFEST.json (byte-gaté par check_artifacts, counts recomptés de projets_master.json) dit autre chose → nouveau bloc dans check_readme_claims recomputant le quadruplet (total + fr/en/es) depuis MANIFEST.counts et exigeant l'égalité avec les deux docs (3 morsures : dérive total · compensation entre langues captée là où le total seul est aveugle · claim disparu)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,10 @@
|
||||
# DEUX docs (table du README + prose « OTO Ventes 4 cartes/11 liens/12
|
||||
# rôles ») + total « N Workspace natifs » → portails MANIFEST
|
||||
# (tableau `workspaces`, byte-gaté par check_artifacts)
|
||||
# seo/README.md + 03_agents/seo/AGENT.md (comptes de mots-clés) :
|
||||
# • total + ventilation « 258 mots-clés (fr=87 · en=87 · es=84) » transcrits À
|
||||
# LA MAIN dans DEUX docs → seo MANIFEST.counts
|
||||
# (keywords_total + keywords_per_lang, recomptés de projets_master, byte-gatés)
|
||||
# rbac/{roleprofile_gen,apply_plan,userperm_gen}/README.md (comptes 3 volets) :
|
||||
# • table « Nb rôles » PAR profil + total bijectif → roleprofile MANIFEST
|
||||
# • ligne agrégée « 6 étapes · 50 rôles / 116 DocPerm / 28 UP / 6 Role
|
||||
@@ -584,6 +588,49 @@ if up_bm is not None and up_rd is not None:
|
||||
bad(f"RBAC userperm · {UP_RD} dit {'/'.join(mu.groups())} MAIS MANIFEST "
|
||||
f"dit {'/'.join(up_exp)} ({up_src}) → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# SEO · comptes de mots-clés (total + ventilation par langue) —
|
||||
# même classe de « vert trompeur », transcrits À LA MAIN dans DEUX docs.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur SEO émet out/MANIFEST.json dont le bloc `counts` porte
|
||||
# keywords_total et keywords_per_lang{fr,en,es}, RECOMPTÉS à chaque build depuis
|
||||
# `projets_master.json` (byte-gaté par check_artifacts ⇒ source faisant autorité).
|
||||
# Ce quadruplet est recopié À LA MAIN à DEUX endroits : la table « Livrables » du
|
||||
# README du module (05_deliverables_mvp/seo/README.md — « **258** mots-clés
|
||||
# (fr=87 · en=87 · es=84) ») ET la même ligne de la fiche agent
|
||||
# (03_agents/seo/AGENT.md). Aucun gate ne les couvrait : ajouter un projet ou du
|
||||
# vocabulaire éditorial ferait dériver LES DEUX docs en silence pendant que
|
||||
# l'artefact dit autre chose — même piège que les triplets par workspace des
|
||||
# portails. On RECOMPUTE ici (total + 3 langues) depuis MANIFEST.counts (déjà
|
||||
# byte-gaté · zéro duplication du compteur du générateur) et on exige l'égalité
|
||||
# avec les DEUX docs. Un claim absent échoue AUSSI (traçabilité).
|
||||
# ============================================================================
|
||||
SEO_RD = f"{D}/seo/README.md"
|
||||
SEO_FI = "03_agents/seo/AGENT.md"
|
||||
try:
|
||||
seo_c = load("seo/out/MANIFEST.json")["counts"]
|
||||
seo_exp = (str(seo_c["keywords_total"]),
|
||||
str(seo_c["keywords_per_lang"]["fr"]),
|
||||
str(seo_c["keywords_per_lang"]["en"]),
|
||||
str(seo_c["keywords_per_lang"]["es"]))
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"SEO · MANIFEST illisible/inattendu : {e}"); seo_exp = None
|
||||
if seo_exp is not None:
|
||||
seo_src = (f"total={seo_exp[0]} fr={seo_exp[1]} en={seo_exp[2]} es={seo_exp[3]}")
|
||||
seo_pat = r"\*\*(\d+)\*\* mots-clés \(fr=(\d+) · en=(\d+) · es=(\d+)\)"
|
||||
for path_f in (SEO_RD, SEO_FI):
|
||||
txt = read_norm(path_f)
|
||||
if txt is None:
|
||||
continue
|
||||
m = re.search(seo_pat, txt)
|
||||
if m is None:
|
||||
bad(f"SEO · {path_f} — claim mots-clés INTROUVABLE (attendu {seo_src})")
|
||||
elif m.groups() == seo_exp:
|
||||
good(f"SEO · {path_f} — {'/'.join(m.groups())} == MANIFEST ({seo_src})")
|
||||
else:
|
||||
bad(f"SEO · {path_f} — dit {'/'.join(m.groups())} MAIS MANIFEST dit "
|
||||
f"{'/'.join(seo_exp)} ({seo_src}) → régénérer le doc")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user