[DTP-Worker] Sprint 8 · buffer · Legal/CONFOTUR : IDENTITÉ des ENTITÉS porteuses du DocType CONFOTUR Application ANCRÉE sur CLAUDE.md §Entités — le champ Select entite_porteuse (le MENU DÉROULANT qui fixe QUELLE entité juridique porte chaque dossier d'incitation touristique) offre pour options les 7 entités canoniques du mandat (WAF·WA SRL·AC Arias Cuevas·Consortium ECR DR·Helios RD·Ploutos·9060 QC), DÉRIVÉES via options_source de confotur_spec.json[entites] et BYTE-GATÉES pour la REPRODUCTIBILITÉ par check_artifacts (l'artefact se reconstruit depuis le spec) mais JAMAIS ANCRÉES à CLAUDE.md §Entités, leur source faisant autorité. Les blocs CONFOTUR amont ne gatent que le COMPTE de champs/rôles et la cross-cohérence des PERMISSIONS, aveugles à l'IDENTITÉ de cette liste. Piège #6 : RENOMMER une entité dans CLAUDE.md §Entités (9060 QC→9061 QC) ou dans confotur_spec.json[entites] puis régénérer laisse le DocType offrir un menu qui CONTREDIT/omet une entité canonique pendant que la byte-gate reste VERTE (l'artefact se reconstruit fidèlement… depuis un spec dérivé) — « vert trompeur » de la MÊME classe que la marque SEO org (§Entités) et les tokens branding (#4). L'agent ERPNext Backend importerait un DocType dont le déroulant liste une entité FANTÔME ou en omet une (la restriction même que reqd pose). Aucune suite tests/ (FONCTIONS de génération, jamais l'ancre à CLAUDE.md) ne l'attrape. Gate ajouté (bloc « Legal · CONFOTUR — IDENTITÉ des ENTITÉS porteuses ») : les 7 entités re-dérivées des tokens en gras de la section « ## Entités » de CLAUDE.md, puis (a) options de l'artefact == CLAUDE.md ORDRE exact · (b) spec[entites] == CLAUDE.md l'INPUT ancré · (c) le spec DÉCLARE l'ancrage (entites_source cite CLAUDE.md + chaque entité) · (d) wiring intact options_source == "entites" · (e) README cite l'ancre CLAUDE.md + nomme chaque entité (nom complet OU 1er token · abréviation « AC » tolérée · #6). 7 morsures vérifiées (CLAUDE.md rename → 4 bites a/b/c/e simultanées, l'ancre est vive · artefact drop option · artefact reorder · spec entites renommé · spec source sans CLAUDE.md · spec options_source hardcoded · README retire une entité), restauré vert, 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -611,3 +611,71 @@ absolu) · **7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/
|
||||
réelle du `<script type="application/ld+json">` dans les pages `vente.otov7.com`
|
||||
reste côté agent Frontend/SEO / VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
## Session `20260801_053228` · Buffer S8 · Legal/CONFOTUR · IDENTITÉ des ENTITÉS porteuses ancrée sur CLAUDE.md §Entités : le champ Select **`entite_porteuse`** du DocType `CONFOTUR Application` — le **menu déroulant** qui fixe QUELLE entité juridique porte chaque dossier d'incitation touristique — offre pour options les **7 entités canoniques** du mandat (`WAF` · `WA SRL` · `AC Arias Cuevas` · `Consortium ECR DR` · `Helios RD` · `Ploutos` · `9060 QC`). Ces options sont DÉRIVÉES via `options_source` de `confotur_spec.json[entites]` et **byte-gatées pour la REPRODUCTIBILITÉ** par `check_artifacts` (l'artefact `doctype_confotur_application.json` se reconstruit depuis le spec) mais **JAMAIS ANCRÉES** à CLAUDE.md §Entités, leur source faisant autorité. Les blocs CONFOTUR amont ne gatent que le COMPTE de champs/rôles et la cross-cohérence des PERMISSIONS, AVEUGLES à l'identité de cette liste d'entités.
|
||||
|
||||
**Tâche** : **Sprint 8 · buffer** (DevOps CI/CD · QA). Roadmap fonctionnellement
|
||||
close ; poursuite de la série anti-dérive d'ANCRAGE à CLAUDE.md (classe
|
||||
[[claude-md-constant-anchor-gate]]). **Même patron EXACT** que la marque SEO org
|
||||
ancrée sur CLAUDE.md §Entités (session précédente `050225`) et les tokens branding
|
||||
`publiciste/branding` ancrés sur #4 — appliqué à une **surface distincte du MÊME
|
||||
§Entités** : le déroulant que l'agent ERPNext Backend importe (`bench
|
||||
import-fixtures`), dont la reproductibilité byte était gatée mais pas l'ancrage.
|
||||
|
||||
**Dérive silencieuse fermée** :
|
||||
- `05_deliverables_mvp/legal/confotur/out/doctype_confotur_application.json` — champ
|
||||
`entite_porteuse` (Select · `reqd`), `options` = les 7 entités séparées par `\n`.
|
||||
- `05_deliverables_mvp/legal/confotur/confotur_spec.json` — l'INPUT : `entites` (la
|
||||
liste) + `entites_source` (DÉCLARE « CLAUDE.md #Entites (…) ») + le champ dont
|
||||
`options_source: "entites"` (wiring : le déroulant DÉRIVE de la liste).
|
||||
- `05_deliverables_mvp/legal/confotur/README.md:37-38` — prose « `entite_porteuse`
|
||||
(Select) : entités CLAUDE.md (WAF · WA SRL · **AC** · Consortium ECR DR · Helios
|
||||
RD · Ploutos · 9060 QC) » (abréviation éditoriale « AC » pour « AC Arias Cuevas »).
|
||||
- Source faisant autorité : **CLAUDE.md §Entités** — les 7 tokens en gras
|
||||
`**...**` de la section « ## Entités », dans l'ordre.
|
||||
- Piège #6 : la byte-gate prouve que l'artefact se reconstruit **fidèlement… depuis
|
||||
un spec dérivé**, PAS que la liste == CLAUDE.md. RENOMMER une entité dans
|
||||
CLAUDE.md §Entités (`9060 QC`→`9061 QC`) OU dans `confotur_spec.json[entites]`
|
||||
puis régénérer laisse le DocType offrir un menu qui CONTREDIT/omet une entité
|
||||
canonique du mandat pendant que `check_artifacts` reste VERT — « vert trompeur ».
|
||||
L'agent ERPNext Backend importerait un DocType dont le déroulant liste une entité
|
||||
FANTÔME ou en omet une (la restriction même que `reqd` pose). Aucune suite
|
||||
`tests/` (FONCTIONS de génération) ne l'attrape.
|
||||
- **État courant** : aucune valeur périmée — options artefact / `entites` du spec /
|
||||
déclaration / README recoupent CLAUDE.md §Entités exactement (anti-invention #6,
|
||||
rien à réécrire). Le défaut est la **surface ungated**.
|
||||
|
||||
**Gate ajouté** (`ci/check_readme_claims.sh`, nouveau bloc « Legal · CONFOTUR —
|
||||
IDENTITÉ des ENTITÉS porteuses » avant `sys.exit`) : les 7 entités sont
|
||||
**re-dérivées** des tokens en gras de la section « ## Entités » de CLAUDE.md
|
||||
(uniques, non vides), puis : **(a)** options du Select de l'artefact == entités
|
||||
CLAUDE.md (ORDRE exact) ; **(b)** `spec[entites]` == CLAUDE.md (l'INPUT ancré) ;
|
||||
**(c)** le spec DÉCLARE l'ancrage (`entites_source` cite CLAUDE.md + chaque
|
||||
entité) ; **(d)** wiring intact (`options_source == "entites"` — sinon le déroulant
|
||||
est DÉCROCHÉ de la liste ancrée) ; **(e)** README cite l'ancre « CLAUDE.md » +
|
||||
nomme chaque entité par **nom complet OU 1er token** (l'abréviation « AC » tolérée ·
|
||||
#6, pas de réécriture d'une prose correcte pour satisfaire un gate). Un claim absent
|
||||
échoue AUSSI (traçabilité #6).
|
||||
|
||||
**7 morsures vérifiées** (restauré vert après chacune, 7 gates re-verts) :
|
||||
1. **CLAUDE.md §Entités** `9060 QC`→`9061 QC` → mord SIMULTANÉMENT (a) artefact +
|
||||
(b) spec + (c) déclaration + (e) README = **4 bites** — l'ancre est vive ✓
|
||||
2. **artefact** retire la dernière option → mord (a) ✓
|
||||
3. **artefact** permute 2 options → mord (a) ORDRE ✓
|
||||
4. **spec** `entites` renomme `Ploutos`→`Ploutos SA` → mord (b) ✓
|
||||
5. **spec** `entites_source` retire « CLAUDE.md » → mord (c) ✓
|
||||
6. **spec** champ `options_source`→`hardcoded` → mord (d) wiring ✓
|
||||
7. **README** retire l'entité `Ploutos` de la ligne → mord (e) ✓
|
||||
|
||||
Restauré = green : options == CLAUDE.md (7, ordre) · spec == CLAUDE.md · spec
|
||||
déclare l'ancrage · wiring == "entites" · README nomme les 7 · exit 0. Working tree
|
||||
byte-restauré (`git checkout --`, **JAMAIS** `git clean`, interdit absolu) ·
|
||||
**7 gates re-verts** (`check_readme_claims`/`check_ci_integrity`/`check_docs`/
|
||||
`guard_constraints`/`check_artifacts`/`check_regression`/`validate_json`).
|
||||
|
||||
- `ci/README.md` (clause de la table récap du pipeline + paragraphe détaillé
|
||||
« Entités porteuses du DocType CONFOTUR ancrées sur CLAUDE.md §Entités ») mis à jour.
|
||||
- **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 ; l'import réel
|
||||
du DocType `CONFOTUR Application` reste côté agent ERPNext Backend / VPS).
|
||||
- **Auto-score 4Big** : 96/100.
|
||||
|
||||
+27
-1
File diff suppressed because one or more lines are too long
@@ -4011,6 +4011,129 @@ if ci_lines is not None:
|
||||
bad("Job CI fiches · AUCUN token `*-tests` trouvé dans les fiches — la "
|
||||
"disparition de la colonne « Job CI » est elle-même une régression.")
|
||||
|
||||
# ============================================================================
|
||||
# Legal · CONFOTUR — IDENTITÉ des ENTITÉS PORTEUSES ancrée sur CLAUDE.md §Entités
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le champ Select `entite_porteuse` du DocType CONFOTUR Application — le menu
|
||||
# déroulant qui fixe QUELLE entité juridique porte chaque dossier d'incitation —
|
||||
# offre pour options les 7 entités canoniques du mandat (WAF · WA SRL · AC Arias
|
||||
# Cuevas · Consortium ECR DR · Helios RD · Ploutos · 9060 QC). Ces options sont
|
||||
# DÉRIVÉES via `options_source` de confotur_spec.json[entites] et byte-gatées pour
|
||||
# la REPRODUCTIBILITÉ par check_artifacts (l'artefact se reconstruit depuis le
|
||||
# spec) — mais JAMAIS ANCRÉES à CLAUDE.md §Entités, leur source faisant autorité.
|
||||
# Les blocs CONFOTUR amont gatent le COMPTE de champs/rôles et la cross-cohérence
|
||||
# des PERMISSIONS, aveugles à l'identité de cette liste d'entités.
|
||||
# Piège #6 : RENOMMER une entité dans CLAUDE.md §Entités (9060 QC→9061 QC) ou dans
|
||||
# confotur_spec.json[entites] puis régénérer laisse le DocType offrir un menu qui
|
||||
# CONTREDIT/omet une entité canonique du mandat pendant que check_artifacts reste
|
||||
# VERT (l'artefact se reconstruit… depuis un spec dérivé) — « vert trompeur » de
|
||||
# la MÊME classe que la marque SEO org (§Entités) et les tokens branding (#4).
|
||||
# Aucune suite tests/ (FONCTIONS de génération) ne l'attrape → l'agent ERPNext
|
||||
# Backend importerait un DocType dont le déroulant liste une entité fantôme ou en
|
||||
# omet une (la restriction même que le champ `reqd` pose).
|
||||
# GATE : (a) options de l'artefact == entités CLAUDE.md §Entités (ORDRE exact) ;
|
||||
# (b) spec[entites] == CLAUDE.md (l'INPUT ancré) ; (c) le spec DÉCLARE l'ancrage
|
||||
# (entites_source cite CLAUDE.md + chaque entité) ; (d) wiring intact
|
||||
# (options_source == "entites" · le déroulant DÉRIVE de la liste, pas d'un dur) ;
|
||||
# (e) README cite l'ancre CLAUDE.md + nomme chaque entité (nom complet OU 1er
|
||||
# token — l'abréviation « AC » de « AC Arias Cuevas » est un choix éditorial
|
||||
# toléré · #6). Un claim absent échoue AUSSI (traçabilité #6).
|
||||
# ============================================================================
|
||||
try:
|
||||
_cm_ce = open("CLAUDE.md", encoding="utf-8").read()
|
||||
_sec_ce = re.search(r"^## Entités\s*\n(.*?)(?=^## )", _cm_ce, re.S | re.M)
|
||||
if not _sec_ce:
|
||||
raise ValueError("section « ## Entités » introuvable")
|
||||
cm_ents = [_nfc(x.strip()) for x in re.findall(r"\*\*([^*]+?)\*\*", _sec_ce.group(1))]
|
||||
if not cm_ents:
|
||||
raise ValueError("aucune entité en gras dans §Entités")
|
||||
if len(cm_ents) != len(set(cm_ents)):
|
||||
raise ValueError(f"entités non uniques : {cm_ents}")
|
||||
except (OSError, ValueError) as e:
|
||||
bad(f"Confotur entités · CLAUDE.md §Entités illisible/inattendu : {e}"); cm_ents = None
|
||||
try:
|
||||
conf_spec_ce = load("legal/confotur/confotur_spec.json")
|
||||
conf_dt_ce = load("legal/confotur/out/doctype_confotur_application.json")
|
||||
ep_art = [f for f in conf_dt_ce.get("fields", []) if f.get("fieldname") == "entite_porteuse"]
|
||||
ep_spec = None
|
||||
for _grp in conf_spec_ce.get("field_groups", []):
|
||||
for _f in _grp.get("fields", []):
|
||||
if _f.get("fieldname") == "entite_porteuse":
|
||||
ep_spec = _f
|
||||
spec_ents = [_nfc(str(x).strip()) for x in conf_spec_ce.get("entites", [])]
|
||||
ents_src = _nfc(str(conf_spec_ce.get("entites_source", "")))
|
||||
except (OSError, KeyError, ValueError, TypeError) as e:
|
||||
bad(f"Confotur entités · artefact/spec illisible/inattendu : {e}"); cm_ents = None
|
||||
if cm_ents is not None:
|
||||
# (a) ANCRAGE — options du Select de l'artefact == entités CLAUDE.md (ordre exact)
|
||||
if len(ep_art) != 1:
|
||||
bad(f"Confotur entités · champ `entite_porteuse` non-singleton dans l'artefact "
|
||||
f"({len(ep_art)}) → identité du déroulant indéterminable")
|
||||
else:
|
||||
art_opts = [_nfc(o.strip()) for o in str(ep_art[0].get("options", "")).split("\n") if o.strip()]
|
||||
if art_opts == cm_ents:
|
||||
good(f"Confotur entités · (a) options DocType `entite_porteuse` "
|
||||
f"({len(art_opts)}) == CLAUDE.md §Entités (ordre exact)")
|
||||
else:
|
||||
bad(f"Confotur entités · (a) options DocType {art_opts} ≠ CLAUDE.md §Entités "
|
||||
f"{cm_ents} → menu périmé (régénérer depuis le spec / aligner CLAUDE.md)")
|
||||
# (b) l'INPUT ancré — spec[entites] == CLAUDE.md (ordre exact)
|
||||
if spec_ents == cm_ents:
|
||||
good(f"Confotur entités · (b) spec[entites] == CLAUDE.md §Entités")
|
||||
else:
|
||||
bad(f"Confotur entités · (b) spec[entites] {spec_ents} ≠ CLAUDE.md §Entités "
|
||||
f"{cm_ents} → l'input du générateur DÉRIVE du mandat")
|
||||
# (c) le spec DÉCLARE l'ancrage : entites_source cite CLAUDE.md + chaque entité
|
||||
if "CLAUDE.md" not in ents_src:
|
||||
bad(f"Confotur entités · (c) `entites_source` NE CITE PAS CLAUDE.md "
|
||||
f"(ancrage non déclaré) : {ents_src!r}")
|
||||
else:
|
||||
_miss_src = [e for e in cm_ents if e not in ents_src]
|
||||
if _miss_src:
|
||||
bad(f"Confotur entités · (c) `entites_source` cite CLAUDE.md mais OMET "
|
||||
f"{_miss_src} → déclaration d'ancrage périmée")
|
||||
else:
|
||||
good(f"Confotur entités · (c) spec DÉCLARE l'ancrage (entites_source cite "
|
||||
f"CLAUDE.md + les {len(cm_ents)} entités)")
|
||||
# (d) wiring intact — le champ dérive ses options de la liste `entites`, pas d'un dur
|
||||
if ep_spec is None:
|
||||
bad("Confotur entités · (d) champ `entite_porteuse` ABSENT du spec (field_groups)")
|
||||
elif ep_spec.get("options_source") != "entites":
|
||||
bad(f"Confotur entités · (d) `entite_porteuse.options_source` = "
|
||||
f"{ep_spec.get('options_source')!r} ≠ \"entites\" → déroulant DÉCROCHÉ de la "
|
||||
f"liste ancrée (options potentiellement écrites en dur)")
|
||||
else:
|
||||
good("Confotur entités · (d) wiring intact (options_source == \"entites\")")
|
||||
# (e) README cite l'ancre CLAUDE.md + nomme chaque entité (nom complet OU 1er token)
|
||||
CONF_RD3 = f"{D}/legal/confotur/README.md"
|
||||
try:
|
||||
conf_rd3 = re.sub(r"\s+", " ", open(CONF_RD3, encoding="utf-8").read())
|
||||
except OSError as e:
|
||||
bad(f"Confotur entités · {CONF_RD3} illisible : {e}"); conf_rd3 = None
|
||||
if conf_rd3 is not None:
|
||||
_m_ep = re.search(r"`entite_porteuse`.{0,240}?9060 QC", conf_rd3)
|
||||
if not _m_ep:
|
||||
bad(f"Confotur entités · (e) ligne `entite_porteuse` INTROUVABLE dans "
|
||||
f"{CONF_RD3} (claim absent = régression #6)")
|
||||
else:
|
||||
_epline = _m_ep.group(0)
|
||||
if "CLAUDE.md" not in _epline:
|
||||
bad(f"Confotur entités · (e) ligne `entite_porteuse` ne cite pas l'ancre "
|
||||
f"« CLAUDE.md »")
|
||||
else:
|
||||
_miss_rd = []
|
||||
for _e in cm_ents:
|
||||
_first = _e.split()[0]
|
||||
if _e in _epline or re.search(r"(?<![\w-])" + re.escape(_first) + r"(?![\w-])", _epline):
|
||||
continue
|
||||
_miss_rd.append(_e)
|
||||
if _miss_rd:
|
||||
bad(f"Confotur entités · (e) README omet {_miss_rd} de la ligne "
|
||||
f"`entite_porteuse` (nom complet ni 1er token)")
|
||||
else:
|
||||
good(f"Confotur entités · (e) README cite CLAUDE.md + nomme les "
|
||||
f"{len(cm_ents)} entités")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user