[DTP-Worker 20260801_213444] Sprint 8 · buffer · Fiche ONAPI/Legal : gate de la 2ᵉ SURFACE PROSE des ENTITÉS PORTEUSES
Surface ungatée fermée : `03_agents/onapi_legal/AGENT.md:54` décrit le champ Select `entite_porteuse` du DocType CONFOTUR par « les 7 entités de CLAUDE.md #Entités (WAF · WA SRL · AC Arias Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060 QC) » — un COMPTE littéral + l'énumération complète du même menu. Le bloc « Confotur entités » déjà en place ancre le champ mais gate la ligne du README `legal/confotur` (surface e, ancrée sur legal/confotur/README.md) ; le motif ne vise PAS 03_agents/ ⇒ la fiche restait hors de tout gate. Dérive #6 : ajouter/retirer/renommer une entité dans CLAUDE.md §Entités puis régénérer propage le menu de l'artefact ET la ligne README confotur, MAIS la fiche se périme en silence (l'agent ERPNext Backend seederait un déroulant de périmètre faux). Aucune suite tests/ (FONCTIONS de build, pas la prose) ne l'attrape. Gate ajouté (ci/check_readme_claims.sh) : re-dérive la liste depuis les tokens gras de « ## Entités » de CLAUDE.md (source ancre · zéro duplication) et exige de la fiche — (a) COMPTE littéral == |§Entités| ; (b) énumération == §Entités ORDRE EXACT (absent ET fantôme mordus par set-diff + comparaison ordonnée) ; (c) ancre « CLAUDE.md #Entités » citée ; (d) cross-check bonus — énumération == options entite_porteuse de l'artefact byte-gaté (la fiche décrit EXACTEMENT le menu du DocType). Ligne absente = échec (#6). 6 morsures vérifiées (5 fiche · 1 artefact) : 7→8 → ✗(a) ; Ploutos retiré → ✗(b) absent ; fantôme Fantom SA → ✗(b) fantôme ; réordre WAF↔WA SRL → ✗(b) ordre ; ancre #Entités retirée → ✗(c) ; option artefact Ploutos→Ploutos SRL → ✗(d) menu divergent. Restauré = green (a/b/c/d ✓ · exit 0). Working tree byte-restauré via git checkout -- <fichier précis> (JAMAIS git checkout . / git clean). 7 gates re-verts. ci/README.md étendu (clause « 2ᵉ surface prose (fiche ONAPI/Legal) »). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+9
-1
@@ -295,7 +295,15 @@ chaque entité) ; **(d)** wiring intact (`options_source == "entites"` · le dé
|
||||
nomme chaque entité (nom complet **ou** 1er token — l'abréviation « AC » de « AC
|
||||
Arias Cuevas » est un choix éditorial toléré · #6). Renommer une entité dans
|
||||
CLAUDE.md seul mord **simultanément** l'artefact, le spec, sa déclaration **et** le
|
||||
README — l'ancre est vive.
|
||||
README — l'ancre est vive. **2ᵉ surface prose (fiche ONAPI/Legal)** : la fiche
|
||||
`03_agents/onapi_legal/AGENT.md:54` ÉNUMÈRE à la main « les **7 entités** de
|
||||
CLAUDE.md #Entités (…) » — un COMPTE littéral + la liste complète que le motif (e),
|
||||
ancré sur le README `legal/confotur`, ne balaie pas. On re-dérive la liste de
|
||||
CLAUDE.md §Entités et on exige de la fiche : **(a)** le compte littéral == |§Entités|
|
||||
· **(b)** l'énumération == §Entités **ordre exact** (absent ET fantôme mordus par
|
||||
set-diff) · **(c)** l'ancre « CLAUDE.md #Entités » citée · **(d)** cross-check —
|
||||
l'énumération == options `entite_porteuse` de l'artefact byte-gaté (la fiche décrit
|
||||
**exactement** le menu que le DocType offrira).
|
||||
|
||||
**Champs `dossier_vente`/`estado` du DocType CONFOTUR dérivés du workflow vente.**
|
||||
La §« Cœur du livrable : cross-cohérence » du même README `legal/confotur` affirme
|
||||
|
||||
@@ -6083,6 +6083,106 @@ if cm_ents is not None:
|
||||
good(f"Confotur entités · (e) README cite CLAUDE.md + nomme les "
|
||||
f"{len(cm_ents)} entités")
|
||||
|
||||
# ============================================================================
|
||||
# Fiche ONAPI/Legal (03_agents/onapi_legal/AGENT.md:54) · 2e SURFACE PROSE des
|
||||
# ENTITÉS PORTEUSES du DocType CONFOTUR — la fiche ÉNUMÈRE À LA MAIN « les 7
|
||||
# entités de CLAUDE.md #Entités (WAF · WA SRL · AC Arias Cuevas · Consortium ECR
|
||||
# DR · Helios RD · Ploutos · 9060 QC) ».
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le bloc « Confotur entités » ci-dessus ancre le champ Select `entite_porteuse`
|
||||
# (options de l'artefact · spec[entites] · entites_source · wiring) et gate la
|
||||
# ligne du README confotur (surface e, ancrée sur `{D}/legal/confotur/README.md`).
|
||||
# Mais la FICHE agent onapi_legal:54 est une SECONDE surface prose du MÊME menu — un
|
||||
# COMPTE littéral « les 7 entités » ET l'énumération complète — qu'AUCUN bloc
|
||||
# n'atteint (le motif (e) ne vise pas 03_agents/). Piège #6 : AJOUTER / RETIRER /
|
||||
# RENOMMER une entité dans CLAUDE.md §Entités (source ancre) puis régénérer propage
|
||||
# le menu de l'artefact ET la ligne du README confotur, MAIS la fiche onapi_legal
|
||||
# reste PÉRIMÉE en silence : elle annoncerait « 7 entités » quand il y en a 8, ou
|
||||
# nommerait `Ploutos` là où le menu ne l'offre plus — l'agent ERPNext Backend qui
|
||||
# seede le DocType croirait le déroulant couvrir un périmètre d'entités qu'il ne
|
||||
# couvre plus (l'invention #6 interdit). Aucune suite tests/ (FONCTIONS de build du
|
||||
# DocType, pas la prose d'une fiche) n'attrape ce « vert trompeur » — même patron
|
||||
# d'IDENTITÉ D'UNE LISTE que la marque SEO §Entités, la §4 du RBAC SPEC ou la ligne
|
||||
# README (e) ci-dessus. On RE-DÉRIVE la liste depuis CLAUDE.md §Entités (source
|
||||
# ancre · zéro duplication) et on exige de la fiche : (a) le COMPTE littéral ==
|
||||
# |§Entités| ; (b) l'énumération == §Entités ORDRE EXACT (absent ET fantôme mordus
|
||||
# par set-diff + comparaison ordonnée) ; (c) l'ancre « CLAUDE.md #Entités » citée ;
|
||||
# (d) cross-check bonus — la liste de la fiche == options `entite_porteuse` de
|
||||
# l'artefact byte-gaté (la fiche décrit EXACTEMENT le menu que le DocType offrira).
|
||||
# Ligne absente = échec (traçabilité #6).
|
||||
# ============================================================================
|
||||
LEGAL_FI = "03_agents/onapi_legal/AGENT.md"
|
||||
try:
|
||||
_cm_le = open("CLAUDE.md", encoding="utf-8").read()
|
||||
_sec_le = re.search(r"^## Entités\s*\n(.*?)(?=^## )", _cm_le, re.S | re.M)
|
||||
if not _sec_le:
|
||||
raise ValueError("section « ## Entités » introuvable")
|
||||
le_ents = [_nfc(x.strip()) for x in re.findall(r"\*\*([^*]+?)\*\*", _sec_le.group(1))]
|
||||
if not le_ents:
|
||||
raise ValueError("aucune entité en gras dans §Entités")
|
||||
if len(le_ents) != len(set(le_ents)):
|
||||
raise ValueError(f"entités non uniques : {le_ents}")
|
||||
except (OSError, ValueError) as e:
|
||||
bad(f"Fiche ONAPI entités · CLAUDE.md §Entités illisible/inattendu : {e}"); le_ents = None
|
||||
# menu RÉEL de l'artefact byte-gaté (cross-check d)
|
||||
try:
|
||||
_cf_dt_le = load("legal/confotur/out/doctype_confotur_application.json")
|
||||
_ep_le = [f for f in _cf_dt_le.get("fields", []) if f.get("fieldname") == "entite_porteuse"]
|
||||
le_art_opts = ([_nfc(o.strip()) for o in str(_ep_le[0].get("options", "")).split("\n") if o.strip()]
|
||||
if len(_ep_le) == 1 else None)
|
||||
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||
bad(f"Fiche ONAPI entités · artefact confotur illisible/inattendu : {e}"); le_art_opts = None
|
||||
le_txt = read_norm(LEGAL_FI)
|
||||
if le_ents is not None and le_txt is not None:
|
||||
m_le = re.search(r"\*\*`entite_porteuse`\*\*.{0,60}?les (\d+) entités de (.+?)\((.+?)\)",
|
||||
le_txt)
|
||||
if m_le is None:
|
||||
bad(f"Fiche ONAPI entités · {LEGAL_FI} — ligne `entite_porteuse` "
|
||||
f"(« les N entités de CLAUDE.md #Entités (…) ») INTROUVABLE/périmée "
|
||||
f"(claim absent = régression #6)")
|
||||
else:
|
||||
# (a) COMPTE littéral == |§Entités|
|
||||
n_claim = int(m_le.group(1))
|
||||
if n_claim == len(le_ents):
|
||||
good(f"Fiche ONAPI entités · (a) compte « {n_claim} entités » == "
|
||||
f"CLAUDE.md §Entités")
|
||||
else:
|
||||
bad(f"Fiche ONAPI entités · (a) fiche dit « {n_claim} entités » MAIS "
|
||||
f"CLAUDE.md §Entités en porte {len(le_ents)} → fiche périmée, régénérer")
|
||||
# (b) énumération == §Entités, ORDRE EXACT (absent ET fantôme mordus)
|
||||
fi_ents = [_nfc(x.strip()) for x in m_le.group(3).split("·")]
|
||||
if fi_ents == le_ents:
|
||||
good(f"Fiche ONAPI entités · (b) énumération == CLAUDE.md §Entités "
|
||||
f"(ordre exact · {len(fi_ents)})")
|
||||
else:
|
||||
_abs = [e for e in le_ents if e not in fi_ents]
|
||||
_pha = [e for e in fi_ents if e not in le_ents]
|
||||
_detail = []
|
||||
if _abs:
|
||||
_detail.append(f"absent(s)={_abs}")
|
||||
if _pha:
|
||||
_detail.append(f"fantôme(s)={_pha}")
|
||||
if not _detail:
|
||||
_detail.append(f"ordre : fiche {fi_ents} ≠ §Entités {le_ents}")
|
||||
bad(f"Fiche ONAPI entités · (b) énumération ≠ CLAUDE.md §Entités "
|
||||
f"({' · '.join(_detail)}) → aligner la fiche")
|
||||
# (c) l'ancre « CLAUDE.md #Entités » est bien citée sur la ligne
|
||||
if "CLAUDE.md" in m_le.group(2) and "#Entités" in m_le.group(2):
|
||||
good(f"Fiche ONAPI entités · (c) ancre « CLAUDE.md #Entités » citée")
|
||||
else:
|
||||
bad(f"Fiche ONAPI entités · (c) la ligne `entite_porteuse` ne cite pas "
|
||||
f"l'ancre « CLAUDE.md #Entités » (source={m_le.group(2)!r})")
|
||||
# (d) cross-check bonus — la liste de la fiche == menu RÉEL de l'artefact
|
||||
if le_art_opts is None:
|
||||
bad(f"Fiche ONAPI entités · (d) champ `entite_porteuse` non-singleton "
|
||||
f"dans l'artefact → menu réel indéterminable")
|
||||
elif fi_ents == le_art_opts:
|
||||
good(f"Fiche ONAPI entités · (d) énumération == options `entite_porteuse` "
|
||||
f"de l'artefact (la fiche décrit le menu réel du DocType)")
|
||||
else:
|
||||
bad(f"Fiche ONAPI entités · (d) fiche {fi_ents} ≠ menu artefact "
|
||||
f"{le_art_opts} → la fiche décrit un menu que le DocType n'offre pas")
|
||||
|
||||
# ============================================================================
|
||||
# Chat OTOIA · l'IDENTITÉ de la persona (`Amélie` / voix `multilingual_v2`) et
|
||||
# des 4 CAPABILITIES OTOIA (`aec.py` + `knowledge.py` + `prompt_engine.py` +
|
||||
|
||||
Reference in New Issue
Block a user