[DTP-Worker] Sprint 8 · buffer · Frontend Console/AGENT.md : gate d'IDENTITÉ des configs runtime Chat OTOIA (persona · langues · endpoint:null #6/#8) ancré sur chat_mount.json ⨯ MANIFEST.json

Bloc anti-dérive #6 dans ci/check_readme_claims.sh : la cellule « Métrique
vérifiée » de 03_agents/frontend_console/AGENT.md:29 restituait 3 attributs
data-derived du montage OTOIA (persona Amélie · langues FR/EN/ES ·
`endpoint: null`) ; le bloc chat_otoia amont ne gate que le COMPTE
blocks/mounts/portails, et le gate persona/capabilities ancré sur CLAUDE.md
vise spec/mounts/MANIFEST/README/oracle, jamais cette fiche. Le nouveau bloc
recompute les 3 depuis out/chat_mount.json (5 configs) + out/MANIFEST.json
byte-gatés : persona==MANIFEST.persona.nom, langues==MANIFEST.langues majuscule,
endpoint:null == affirmation d'honnêteté exigeant all(mount.endpoint is None)
— un endpoint fabriqué mord. Cohérences croisées MANIFEST⇔chaque mount +
endpoint_statut=='a_confirmer'⇔endpoints tous null. 6 morsures vérifiées ·
7 gates verts · aucune écriture out/ (0 dérive artefact).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-01 10:40:20 +00:00
parent 7e8bb9a0de
commit 71999e04c4
3 changed files with 157 additions and 1 deletions
+60
View File
@@ -1106,3 +1106,63 @@ interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integr
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; l'application `bench` réelle
reste côté agent ERPNext Backend / VPS).
- **Auto-score 4Big** : 96/100.
## Session `20260801_103304` · Buffer S8 · Chat OTOIA — IDENTITÉ des configs runtime (persona · langues · endpoint) dans la fiche Frontend Console
**Contexte** : Sprint 8 · buffer (roadmap fonctionnellement close ; poursuite de la
série anti-dérive CLAUDE.md #6, classe « fiche agent qui restitue des attributs
data-derived, gatée uniquement sur des COMPTES agrégés » — mémoire
[[agent-fiche-role-attrs-ungated]]).
**Dérive silencieuse fermée** :
- `03_agents/frontend_console/AGENT.md:29` — la cellule « Métrique vérifiée » du
livrable `chat_otoia` restitue TROIS attributs data-derived du montage OTOIA :
« persona **Amélie** … · langues **FR/EN/ES** · `` `endpoint: null` `` ». Le bloc
chat_otoia amont (`ci/check_readme_claims.sh`) ne recompute que le **COMPTE**
blocks/mounts/portails (tous = 5) — AVEUGLE à CE QUE dit chaque config runtime.
- Le gate persona/capabilities « ancré sur CLAUDE.md §Architecture cible » vise le
spec, les 5 mounts, le MANIFEST, le README et l'oracle du test — **JAMAIS** cette
cellule de fiche, et il ignore langues comme endpoint. La cellule était donc une
surface data-derived ungated de plus.
- Sources faisant autorité (byte-gatées par `check_artifacts`) :
`frontend/chat_otoia/out/chat_mount.json` (une config par portail · 5) +
`out/MANIFEST.json` (persona/langues/endpoint_statut consolidés).
- **`endpoint: null` = AFFIRMATION D'HONNÊTETÉ #6/#8** : l'endpoint OTOIA n'est PAS
fabriqué (renseigné côté VPS · agent Frontend). Qu'une config gagne un endpoint réel
dans l'artefact et la fiche « endpoint: null » devient un MENSONGE en silence.
- **État courant** : aucun attribut périmé — persona `Amélie` · langues `fr/en/es` ·
`endpoint == null` sur les 5 mounts ET le MANIFEST (anti-invention #6, rien à
réécrire). Le défaut est la **surface ungated**.
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Chat OTOIA · IDENTITÉ des configs
runtime (persona · langues · endpoint) » après le bloc de COMPTE chat_otoia) : charge
`MANIFEST.json` + `chat_mount.json` (5 configs) et exige, sur la cellule de la fiche
(regex `persona (\S+) QC · langues ([A-Z/]+) · \`endpoint: ([^\`]+)\``, ne matche QUE
la ligne :29, pas la prose Scope :12) : (a) persona == `MANIFEST.persona.nom` (le
« QC » est le qualificatif de marque `Voix Amélie QC` de CLAUDE.md, gardé en littéral
NON gaté) ; (b) langues `FR/EN/ES` == `MANIFEST.langues` en majuscule ; (c) `endpoint:
null` avec `all(m.endpoint is None)` sur les 5 mounts (sinon `exp_endpoint` devient
`NON-null(...)` ⇒ morsure d'honnêteté). Cohérences croisées : `MANIFEST.persona.nom`
et `MANIFEST.langues` == CHAQUE mount (montage désynchronisé mordu) ·
`endpoint_statut == 'a_confirmer'` ⇔ endpoints TOUS null (incohérence interne
artefact sinon). Un claim absent échoue AUSSI (INTROUVABLE = régression #6). Aucune
suite `tests/` (FONCTIONS du builder, jamais la prose de la fiche) n'attrape ce
« vert trompeur ».
**6 morsures vérifiées** (restauré vert après chacune) : fiche persona `Amélie→Amelia`
(mismatch) · fiche langues `FR/EN/ES→FR/EN` · fiche `endpoint: null→endpoint: fixé` ·
**artefact** un mount `endpoint null→URL réelle` (bascule d'honnêteté ET incohérence
`endpoint_statut='a_confirmer'` — le vrai *silent green* : l'endpoint fabriqué pendant
que la fiche promet `null`) · fiche retire le bloc attributs (claim absent =
INTROUVABLE) · **artefact** un mount `persona Amélie→Nadia` (montage désynchronisé du
MANIFEST). Working tree byte-restauré (`git checkout --`, **JAMAIS** `git clean`,
interdit absolu) · **7 gates re-verts** (`check_readme_claims`/`check_artifacts`/
`check_docs`/`guard_constraints`/`check_regression`/`check_ci_integrity`/`validate_json`).
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé sous le
bloc de COMPTE chat_otoia, avec renvoi au gate persona/capabilities distinct) mis à
jour.
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
aucune écriture dans un `out/` ⇒ 0 dérive d'artefact ; le câblage réel de l'endpoint
OTOIA + web-component reste côté agent Frontend / VPS).
- **Auto-score 4Big** : 96/100.
+24 -1
View File
File diff suppressed because one or more lines are too long
+73
View File
@@ -2234,6 +2234,79 @@ if co_cb is not None:
bad(f"Chat OTOIA · {CO_RD} — dit {m.group(1)} configs runtime MAIS artefact "
f"dit {co_mo} → régénérer le README")
# ============================================================================
# Chat OTOIA · IDENTITÉ des configs runtime (persona · langues · endpoint) —
# ATTRIBUTS transcrits À LA MAIN dans la cellule « Métrique vérifiée » de la
# fiche agent, AVEUGLES au gate de COMPTE ci-dessus.
# ----------------------------------------------------------------------------
# Le bloc précédent gate le NOMBRE de blocks/mounts/portails ; il est indifférent
# à CE QUE chaque config runtime dit. Or la même cellule (03_agents/
# frontend_console/AGENT.md:29) restitue TROIS attributs data-derived du montage :
# « persona Amélie … · langues FR/EN/ES · `endpoint: null` ». Ils sortent des
# artefacts byte-gatés out/chat_mount.json (une config par portail) + out/
# MANIFEST.json (persona/langues/endpoint_statut consolidés) — jamais de la spec.
# • persona.nom : le prénom de l'assistant (le « QC » est le qualificatif de
# marque CLAUDE.md « Voix Amélie QC », gardé en littéral — non gaté ici).
# • langues : la surface trilingue FR/EN/ES lue par le générateur dans
# seo_spec.json (source unique des langues).
# • endpoint : `null` est une AFFIRMATION D'HONNÊTETÉ #6/#8 — l'endpoint OTOIA
# n'est PAS fabriqué (renseigné côté VPS). Si une config gagnait un endpoint
# réel, la fiche « endpoint: null » deviendrait un MENSONGE en silence.
# Cohérence croisée (bijection du générateur) : MANIFEST.persona.nom ET
# MANIFEST.langues doivent valoir EXACTEMENT ce que porte CHAQUE mount (un mount
# désynchronisé de son propre manifeste mord ici) ; endpoint_statut « a_confirmer »
# doit correspondre à des endpoints TOUS `null` (sinon incohérence interne de
# l'artefact). Un claim absent échoue AUSSI (INTROUVABLE = régression #6). Aucune
# suite tests/ (FONCTIONS du builder, jamais la prose de la fiche) n'attrape ce
# « vert trompeur ».
# ============================================================================
try:
ci_man = load("frontend/chat_otoia/out/MANIFEST.json")
ci_mounts = load("frontend/chat_otoia/out/chat_mount.json")
ci_persona = ci_man["persona"]["nom"]
ci_langs = list(ci_man["langues"])
ci_statut = ci_man["endpoint_statut"]
if not ci_mounts:
bad("Chat OTOIA identité · out/chat_mount.json vide"); ci_persona = None
except (OSError, KeyError, ValueError, TypeError) as e:
bad(f"Chat OTOIA identité · artefact illisible/inattendu : {e}"); ci_persona = None
if ci_persona is not None:
# Cohérence croisée MANIFEST ⇔ chaque config runtime (bijection du générateur)
bad_persona = sorted({m["persona"]["nom"] for m in ci_mounts if m["persona"]["nom"] != ci_persona})
bad_langs = sorted({"/".join(m["langues"]) for m in ci_mounts if list(m["langues"]) != ci_langs})
all_null = all(m["endpoint"] is None for m in ci_mounts)
if bad_persona:
bad(f"Chat OTOIA identité · persona MANIFEST={ci_persona!r} MAIS mounts portent "
f"aussi {bad_persona} (montage désynchronisé)")
if bad_langs:
bad(f"Chat OTOIA identité · langues MANIFEST={ci_langs} MAIS mounts portent "
f"aussi {bad_langs} (montage désynchronisé)")
if all_null and ci_statut != "a_confirmer":
bad(f"Chat OTOIA identité · endpoints TOUS null MAIS endpoint_statut={ci_statut!r} "
f"(attendu 'a_confirmer' — incohérence interne artefact)")
if (not all_null) and ci_statut == "a_confirmer":
bad("Chat OTOIA identité · endpoint_statut='a_confirmer' MAIS ≥1 endpoint fabriqué "
"(incohérence interne artefact)")
exp_langs = "/".join(l.upper() for l in ci_langs)
exp_endpoint = "null" if all_null else "NON-null(" + ",".join(
sorted({str(m["endpoint"]) for m in ci_mounts if m["endpoint"] is not None})) + ")"
co_fi2 = read_norm(CO_FI)
if co_fi2 is not None:
m = re.search(r"persona (\S+) QC · langues ([A-Z/]+) · `endpoint: ([^`]+)`", co_fi2)
if m is None:
bad(f"Chat OTOIA identité · {CO_FI} — claim « persona <nom> QC · langues "
f"<L> · `endpoint: <e>` » INTROUVABLE (attendu {ci_persona}/{exp_langs}/{exp_endpoint})")
else:
got = m.groups()
want = (ci_persona, exp_langs, exp_endpoint)
if got == want:
good(f"Chat OTOIA identité · {CO_FI} — persona {got[0]} · langues {got[1]} · "
f"endpoint {got[2]} == artefact (chat_mount ×{len(ci_mounts)} ⇔ MANIFEST)")
else:
bad(f"Chat OTOIA identité · {CO_FI} — dit persona {got[0]}/langues {got[1]}/"
f"endpoint {got[2]} MAIS artefact dit {want[0]}/{want[1]}/{want[2]} "
f"→ régénérer la fiche")
# ============================================================================
# Recette (module) · couple « N livrables de sprint + M métriques succès MVP »
# transcrit À LA MAIN dans DEUX docs — même classe de « vert trompeur ».