[DTP-Worker] Sprint 8 · buffer L75 · Domaine Frontend/Chat OTOIA : le montage de l'assistant conversationnel par portail (frontend/chat_otoia) affichait « 5 Custom Block + 5 configs runtime » (fiche agent frontend_console) et « 5 portails · 5 fixtures · 5 configs runtime » (README du module) — trois nombres data-derived, TOUS = 5 (piège aveugle), transcrits À LA MAIN dans DEUX docs sans AUCUN gate, alors que frontend/chat_otoia/out/MANIFEST.json (byte-gaté par check_artifacts, counts.custom_blocks/mounts/portails recomptés du contrat RBAC à chaque build via la bijection 1 block ⇔ 1 mount ⇔ 1 portail métier, plateforme exclu) fait autorité. Piège aveugle caractéristique : les trois valent 5 aujourd'hui — un gate qui n'en recompterait qu'UN serait aveugle à la dérive des deux autres (ajouter un portail au contrat RBAC → chat_otoia rebâtit 6 blocks/6 mounts/6 portails pendant que les docs restent à 5 en silence) → nouveau bloc dans check_readme_claims recomputant CHAQUE nombre depuis SON PROPRE champ du MANIFEST et exigeant l'égalité avec les deux docs. Cohérence croisée : custom_blocks == mounts == portails == |MANIFEST.portails| (la bijection du générateur) — mord un compteur désynchronisé de sa propre liste. Un claim absent échoue AUSSI (5 morsures vérifiées : dérive custom_block fiche captée là où mounts reste 5 · dérive configs runtime fiche captée là où blocks reste 5 · dérive portails README · dérive fixtures README · claim configs runtime disparu = red ; restauré = green). ci/README.md (table + détail) mis à jour · 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+17
-1
@@ -20,7 +20,7 @@ et manuellement (`workflow_dispatch`). Jobs statiques (+ une suite `unittest` pa
|
||||
| `check-artifacts` | `ci/check_artifacts.sh` | Reproductibilité : chaque `out/*.json` versionné == build frais | ✅ oui |
|
||||
| `check-regression` | `ci/check_regression.sh` | Fraîcheur : `qa/regression/out/regression_run.json` (`run`) == run frais + verdict PASS | ✅ oui |
|
||||
| `check-ci-integrity` | `ci/check_ci_integrity.sh` | Intégrité du câblage : `gate.needs` == tous les jobs non-manuels · chaque `ci/*.sh` câblé au gate | ✅ oui |
|
||||
| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) == artefact cité (#6) | ✅ oui |
|
||||
| `check-readme-claims` | `ci/check_readme_claims.sh` | Intégrité des chiffres des docs d'entrée : chaque nombre de `README.md` « État courant », de la fiche QA « Verdict agrégé » **et** de la colonne « Tests » par suite des tables de fiches **et** des agrégats en prose (Total CRM / RBAC / e-CF) **et** des comptes par workspace des portails (cartes/liens/rôles, ×2 docs) **et** des comptes RBAC des 3 volets (table Nb rôles/profil, ligne agrégée apply_plan, ventilation userperm) **et** des comptes de mots-clés SEO (total + fr/en/es, ×2 docs) **et** du pipeline vente CRM (états/transitions, ×2 docs) **et** de l'app mobile Expo (onglets/rôles/langues/identifiants a_confirmer) **et** du DocType CONFOTUR (champs/données/sections/rôles/évènements de dépôt, ×2 docs) **et** de l'audit 5D (contrôles/dimensions ×2 docs + ventilation verdict pass/fail/à-confirmer) **et** du run-book de déploiement VPS (phases ×2 dans la fiche devops + confirmations préalables count & énumération dans le README) **et** du run-sheet de démo (nombre de modules cités dans le diagramme du README) **et** du montage Chat OTOIA par portail (`Custom Block`/configs runtime/portails, tous = 5 aujourd'hui, ×2 docs) == artefact cité (#6) | ✅ oui |
|
||||
| `gate` | — | Agrégat vert = gate qualité 4Big franchi | ✅ oui |
|
||||
|
||||
Aucune dépendance réseau/marketplace hors `actions/checkout`. Tout tourne avec
|
||||
@@ -258,6 +258,22 @@ dernière citation d'un module (9), ferait dériver le diagramme en silence. Coh
|
||||
croisée en bonus : `counts.modules_cites_uniques` == |`modules_cites`| (liste
|
||||
dédupliquée du manifeste) — mord un compteur désynchronisé de sa propre liste.
|
||||
|
||||
Même classe enfin sur le **montage Chat OTOIA par portail** (livrable
|
||||
`frontend/chat_otoia`) : le nombre de **`Custom Block`**, de **configs runtime** et
|
||||
de **portails** couverts, transcrits **à la main** dans DEUX docs (fiche agent
|
||||
`frontend_console` — « **N `Custom Block` + M configs runtime** » · README du
|
||||
module — « Portails (P, `plateforme` exclu) », « N fixtures `Custom Block` », « M
|
||||
configs runtime »), pointaient l'artefact sans qu'aucun gate ne les recompute. Ces
|
||||
trois nombres valent **tous 5 aujourd'hui** — un gate qui n'en recompterait qu'un
|
||||
serait **aveugle** à la dérive des autres (ajouter un portail au contrat RBAC →
|
||||
chat_otoia rebâtit 6 blocks ⁄ 6 mounts ⁄ 6 portails pendant que les docs restent à
|
||||
5). Chacun est recomputé depuis **son propre** champ de
|
||||
`frontend/chat_otoia/out/MANIFEST.json` (`counts.custom_blocks` · `counts.mounts` ·
|
||||
`counts.portails`, byte-gaté par `check_artifacts`) et comparé aux docs. Cohérence
|
||||
croisée : `custom_blocks` == `mounts` == `portails` == |`MANIFEST.portails`| (la
|
||||
bijection 1 block ⇔ 1 mount ⇔ 1 portail du générateur) — mord un compteur
|
||||
désynchronisé de sa propre liste.
|
||||
|
||||
Un claim **absent** échoue aussi (la dérive de formulation qui ferait
|
||||
disparaître un chiffre est elle-même une régression de traçabilité). stdlib pur
|
||||
(bash/git/python3), zéro réseau.
|
||||
|
||||
@@ -72,6 +72,13 @@
|
||||
# de dépôt » transcrit À LA MAIN dans DEUX docs → confotur
|
||||
# MANIFEST.counts (fields/data_fields/sections/roles/depot_events, recomptés
|
||||
# de confotur_spec.json, byte-gatés)
|
||||
# frontend/chat_otoia/README.md + 03_agents/frontend_console/AGENT.md (montage
|
||||
# du Chat OTOIA par portail) :
|
||||
# • triplet « N `Custom Block` · M configs runtime · P portails » (tous = 5
|
||||
# aujourd'hui — piège aveugle) transcrit À LA MAIN dans DEUX docs → chat_otoia
|
||||
# MANIFEST.counts (custom_blocks/mounts/portails, recomptés du contrat RBAC,
|
||||
# byte-gatés) + cohérence croisée == |MANIFEST.portails| (bijection 1 block ⇔
|
||||
# 1 mount ⇔ 1 portail)
|
||||
# Un claim absent échoue AUSSI (la dérive de formulation qui ferait disparaître
|
||||
# un chiffre est elle-même une régression de traçabilité).
|
||||
#
|
||||
@@ -1028,6 +1035,96 @@ if demo_n is not None:
|
||||
bad(f"Démo · {DEMO_RD} — dit {m.group(1)} modules cités MAIS artefact dit "
|
||||
f"{demo_n} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# Chat OTOIA · montage de l'assistant conversationnel par portail (nombre de
|
||||
# Custom Block / configs runtime / portails) — même classe de « vert trompeur »,
|
||||
# transcrit À LA MAIN dans DEUX docs, sans AUCUN gate.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur chat_otoia_gen émet out/MANIFEST.json (byte-gaté par
|
||||
# check_artifacts ⇒ faisant autorité) dont `counts.custom_blocks`, `counts.mounts`
|
||||
# et `counts.portails` sont RECOMPTÉS à chaque build depuis le contrat RBAC (un
|
||||
# `Custom Block` ⇔ une config runtime ⇔ un portail métier, `plateforme` exclu —
|
||||
# invariant 2 du générateur : bijection 1 block ⇔ 1 mount ⇔ 1 portail). Ces
|
||||
# nombres sont recopiés À LA MAIN : la fiche agent Frontend Console
|
||||
# (03_agents/frontend_console/AGENT.md — « **N `Custom Block` + M configs
|
||||
# runtime** ») ET le README du module (05_deliverables_mvp/frontend/chat_otoia/
|
||||
# README.md — « Portails (N, `plateforme` exclu) », « N fixtures `Custom Block` »,
|
||||
# « M configs runtime »). Piège « aveugle » caractéristique (cf. DevOps phases ⁄
|
||||
# confirmations, bascule verdict audit_5d) : custom_blocks, mounts ET portails
|
||||
# valent TOUS TROIS 5 AUJOURD'HUI — un gate qui n'en recompterait qu'un serait
|
||||
# AVEUGLE à la dérive des autres (ajouter un portail au contrat RBAC → chat_otoia
|
||||
# rebâtit 6 blocks ⁄ 6 mounts ⁄ 6 portails pendant que les docs restent à 5). On
|
||||
# RECOMPUTE donc CHAQUE nombre depuis SON PROPRE champ du MANIFEST (jamais figé
|
||||
# ici · zéro duplication du compteur du générateur #5) et on exige l'égalité avec
|
||||
# les docs. Cohérence croisée : counts.custom_blocks == counts.mounts ==
|
||||
# counts.portails == |MANIFEST.portails| (la bijection du générateur) — mord un
|
||||
# compteur désynchronisé de sa propre liste. Un claim absent échoue AUSSI (la
|
||||
# disparition d'un chiffre est une régression · traçabilité).
|
||||
# ============================================================================
|
||||
CO_RD = f"{D}/frontend/chat_otoia/README.md"
|
||||
CO_FI = "03_agents/frontend_console/AGENT.md"
|
||||
try:
|
||||
co_man = load("frontend/chat_otoia/out/MANIFEST.json")
|
||||
co_cb = str(co_man["counts"]["custom_blocks"])
|
||||
co_mo = str(co_man["counts"]["mounts"])
|
||||
co_po = str(co_man["counts"]["portails"])
|
||||
co_nlist = len(co_man["portails"])
|
||||
if not (co_cb == co_mo == co_po == str(co_nlist)):
|
||||
bad(f"Chat OTOIA · incohérence artefact : custom_blocks={co_cb} · "
|
||||
f"mounts={co_mo} · portails={co_po} · |portails|={co_nlist} "
|
||||
f"(bijection 1 block ⇔ 1 mount ⇔ 1 portail attendue)")
|
||||
except (OSError, KeyError, ValueError) as e:
|
||||
bad(f"Chat OTOIA · artefact chat_otoia illisible/inattendu : {e}"); co_cb = None
|
||||
if co_cb is not None:
|
||||
# 1) Fiche agent Frontend Console — « N `Custom Block` + M configs runtime »
|
||||
co_fi = read_norm(CO_FI)
|
||||
if co_fi is not None:
|
||||
m = re.search(r"\*\*(\d+) `Custom Block` \+ (\d+) configs runtime\*\*", co_fi)
|
||||
if m is None:
|
||||
bad(f"Chat OTOIA · {CO_FI} — claim « N `Custom Block` + M configs runtime » "
|
||||
f"INTROUVABLE (attendu {co_cb}/{co_mo})")
|
||||
elif m.groups() == (co_cb, co_mo):
|
||||
good(f"Chat OTOIA · {CO_FI} — {'/'.join(m.groups())} == artefact "
|
||||
f"(custom_blocks={co_cb} · mounts={co_mo})")
|
||||
else:
|
||||
bad(f"Chat OTOIA · {CO_FI} — dit {'/'.join(m.groups())} MAIS artefact dit "
|
||||
f"{co_cb}/{co_mo} → régénérer la fiche")
|
||||
# 2) README module — « Portails (N, `plateforme` exclu) »
|
||||
co_rd = read_norm(CO_RD)
|
||||
if co_rd is not None:
|
||||
m = re.search(r"Portails \((\d+), `plateforme` exclu\)", co_rd)
|
||||
if m is None:
|
||||
bad(f"Chat OTOIA · {CO_RD} — claim « Portails (N, `plateforme` exclu) » "
|
||||
f"INTROUVABLE (attendu portails={co_po})")
|
||||
elif m.group(1) == co_po:
|
||||
good(f"Chat OTOIA · {CO_RD} — {m.group(1)} portails == artefact "
|
||||
f"(portails={co_po})")
|
||||
else:
|
||||
bad(f"Chat OTOIA · {CO_RD} — dit {m.group(1)} portails MAIS artefact dit "
|
||||
f"{co_po} → régénérer le README")
|
||||
# 3) README module — « N fixtures `Custom Block` »
|
||||
m = re.search(r"(\d+) fixtures `Custom Block`", co_rd)
|
||||
if m is None:
|
||||
bad(f"Chat OTOIA · {CO_RD} — claim « N fixtures `Custom Block` » INTROUVABLE "
|
||||
f"(attendu custom_blocks={co_cb})")
|
||||
elif m.group(1) == co_cb:
|
||||
good(f"Chat OTOIA · {CO_RD} — {m.group(1)} fixtures == artefact "
|
||||
f"(custom_blocks={co_cb})")
|
||||
else:
|
||||
bad(f"Chat OTOIA · {CO_RD} — dit {m.group(1)} fixtures MAIS artefact dit "
|
||||
f"{co_cb} → régénérer le README")
|
||||
# 4) README module — « M configs runtime » (2e transcription des mounts)
|
||||
m = re.search(r"(\d+) configs runtime", co_rd)
|
||||
if m is None:
|
||||
bad(f"Chat OTOIA · {CO_RD} — claim « M configs runtime » INTROUVABLE "
|
||||
f"(attendu mounts={co_mo})")
|
||||
elif m.group(1) == co_mo:
|
||||
good(f"Chat OTOIA · {CO_RD} — {m.group(1)} configs runtime == artefact "
|
||||
f"(mounts={co_mo})")
|
||||
else:
|
||||
bad(f"Chat OTOIA · {CO_RD} — dit {m.group(1)} configs runtime MAIS artefact "
|
||||
f"dit {co_mo} → régénérer le README")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user