[DTP-Worker] Sprint 8 · buffer L60 · Domaine SEO (3e surface) : la CARTE hreflang (« carte alternate FR/EN/ES + x-default par page ») était décrite EN PROSE dans le README du module seo sans AUCUN gate d'IDENTITÉ. Les deux blocs SEO existants gatent le COMPTE de mots-clés (artefact seo_keywords) et les @type du graphe schema.org (artefact seo_schema_org) — jamais le jeu de langues hreflang, qui vit dans un TROISIÈME artefact (seo_hreflang) au contenu distinct. Ce jeu est DATA-DERIVED : langues de contenu = {a.hreflang} − {x-default} de seo/out/seo_hreflang.json (byte-gaté par check_artifacts) = {en,es,fr} · x_default_lang = fr. Aucun gate ne comparait ces CODES à l'artefact : AJOUTER une langue au bundle (pt → 4 langues de contenu) · RETIRER/ÉCHANGER es ferait dériver la prose (README:17) en silence pendant que la carte byte-gatée dit autre chose — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de génération, pas la prose du README) n'attrape → nouveau bloc recomputant l'ENSEMBLE des langues de contenu depuis seo_hreflang.json (zéro duplication de la carte du générateur #6) et exigeant que la cellule les nomme EXACTEMENT (absent ET en trop via set-diff · casse normalisée) + mentionne x-default. Cohérences croisées en bonus (mordent un artefact INTERNEMENT incohérent) : carte UNIFORME (toutes les pages portent le même jeu d'alternate) · x-default présent sur CHAQUE page · langue par défaut (x_default_lang) ∈ langues de contenu (ni vacante ni étrangère) · pour chaque page x-default.href == canonical == href de la langue par défaut (l'invariant README:61). Un claim absent échoue AUSSI. 7 morsures vérifiées : prose échange ES→PT captée (absents=[es] en trop=[pt]) · prose retrait ES (sous-ensemble) capté · prose x-default supprimé capté · prose reformulée (carte INTROUVABLE) captée · artefact +langue pt sur 1 page (non uniforme) capté (2 jeux distincts + prose absents=[pt]) · artefact x_default_lang→de (défaut étranger + href incohérent) capté · artefact x-default.href≠canonical sur 1 page capté ; restauré = green : [en,es,fr] + x-default == seo_hreflang · uniforme · défaut fr · href cohérent (10 pages). État courant : aucune langue périmée (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail « 3e surface SEO ») mis à jour · 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-07-31 18:07:08 +00:00
parent e52519dab1
commit 607b22282b
3 changed files with 171 additions and 1 deletions
+62
View File
@@ -1,5 +1,67 @@
# Activity Log · 2026-07-31 · Claude Code DTP
## Session `20260731_180119` · Buffer S8 · Domaine SEO (3e surface) : la **carte hreflang** (« carte `alternate` **FR/EN/ES** + `x-default` par page ») était décrite EN PROSE dans le README du module `seo` sans AUCUN gate d'IDENTITÉ — les deux blocs SEO existants gatent le COMPTE de mots-clés (artefact `seo_keywords`) et les `@type` du graphe schema.org (artefact `seo_schema_org`), jamais le jeu de langues hreflang qui vit dans un **troisième** artefact.
**Tâche** : **Sprint 8 · buffer L75** (DevOps CI/CD · QA). Roadmap fonctionnellement
close ; poursuite de la série anti-dérive (CLAUDE.md #6). Cette session cible la
**3ᵉ surface data-derived du même README SEO** — la carte hreflang, dont le jeu de
langues cité dans la table « Ce que ça fait » pointe l'artefact généré sans être
recomputé par aucun gate.
**Dérive silencieuse fermée** :
- `05_deliverables_mvp/seo/README.md:17` : « | hreflang | … carte `alternate`
**FR/EN/ES** + `x-default` par page | » — l'ENSEMBLE des langues de contenu +
le `x-default`.
- Source faisant autorité (byte-gatée par `check_artifacts`) :
`seo/out/seo_hreflang.json` — chaque page porte un ensemble d'`alternate` (une
langue de contenu par entrée) + un `x-default` ; langues de contenu =
`{a.hreflang} {x-default}` = `{en, es, fr}` · `x_default_lang = fr`.
- Les deux blocs SEO existants (mots-clés · schema.org) sont **aveugles** à ces
codes : **AJOUTER** une langue au bundle (`pt` → 4 langues), **RETIRER/ÉCHANGER**
`es` ferait dériver la prose en silence pendant que la carte byte-gatée dit
autre chose — « vert trompeur » qu'aucune suite `tests/` (qui teste des
FONCTIONS de génération, pas la prose) n'attrape.
- **État courant** : **aucune langue périmée**`FR/EN/ES` + `x-default` recoupe
l'artefact exactement (anti-invention #6, rien à réécrire). Le défaut est la
**surface ungated**.
**Nouveau bloc dans `ci/check_readme_claims.sh`** : recompute l'ENSEMBLE des
langues de contenu depuis `seo_hreflang.json` (zéro duplication de la carte du
générateur · #6) et exige que la cellule les nomme **exactement** (absent ET en
trop via set-diff · casse normalisée) + mentionne `x-default`. Cohérences croisées
en bonus (mordent un artefact **internement incohérent**) : carte **uniforme**
(toutes les pages portent le même jeu d'`alternate`) · `x-default` présent sur
**chaque** page · langue par défaut (`x_default_lang`) ∈ langues de contenu (ni
vacante ni étrangère) · pour chaque page `x-default`.href == `canonical` == href de
la langue par défaut (l'invariant README:61). Un claim absent échoue AUSSI.
### Preuve (7 morsures vérifiées + restauration verte)
| Injection | Résultat |
|---|---|
| README échange langue (`ES → PT`) | ✗ absents=`[es]` · en trop=`[pt]` · exit 1 |
| README retrait `ES` (sous-ensemble) | ✗ absents=`[es]` · exit 1 |
| README `x-default` supprimé | ✗ `x-default` non mentionné · exit 1 |
| README claim reformulé | ✗ carte « `alternate` … par page » INTROUVABLE · exit 1 |
| artefact +langue `pt` sur 1 page (non uniforme) | ✗ carte NON uniforme (2 jeux) + prose absents=`[pt]` · exit 1 |
| artefact `x_default_lang → de` (défaut étranger) | ✗ `de` ∉ langues de contenu + href incohérent · exit 1 |
| artefact `x-default`.href ≠ canonical (1 page) | ✗ href incohérent sur `[home]` · exit 1 |
| restauré | ✓ `[en,es,fr]` + `x-default` == `seo_hreflang` · uniforme · défaut `fr` · href cohérent (10 pages) · exit 0 |
- **`ci/README.md`** — surface ajoutée à la table récap du pipeline + paragraphe
descriptif (« 3ᵉ surface du même README SEO »).
Suite CI complète re-verte (7 gates) : `guard_constraints` · `validate_json` ·
`check_docs` · `check_artifacts` · `check_regression` · `check_ci_integrity` ·
`check_readme_claims`.
**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).
**Auto-score 4Big** : 96/100.
---
## Session `20260731_173114` · Buffer S8 · Domaine SEO (2e surface) : la **composition du graphe schema.org** (« graphe JSON-LD (`Organization` + une `Residence` par projet) ») était décrite EN PROSE dans le README du module `seo` sans AUCUN gate d'IDENTITÉ — le bloc SEO existant ne gate que le COMPTE de mots-clés (total + fr/en/es).
- **Constat** : les `@type` du `@graph` de `seo/out/seo_schema_org.json` (byte-gaté)