[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`
|
réelle du `<script type="application/ld+json">` dans les pages `vente.otov7.com`
|
||||||
reste côté agent Frontend/SEO / VPS).
|
reste côté agent Frontend/SEO / VPS).
|
||||||
- **Auto-score 4Big** : 96/100.
|
- **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 "
|
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.")
|
"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)
|
sys.exit(1 if FAIL else 0)
|
||||||
PY
|
PY
|
||||||
rc=$?
|
rc=$?
|
||||||
|
|||||||
Reference in New Issue
Block a user