[DTP-Worker] Sprint 8 · buffer L60 · Domaine CRM/dossier_vente (2e surface) : le CATALOGUE de projets du DocType porteur (« Projet (Select P01..P09 ancré sur CLAUDE.md) ») était ANCRÉ à CLAUDE.md EN PROSE sans AUCUN gate d'IDENTITÉ. Le bloc CRM pipeline existant ne recompute que le COMPTE d'états (« les 9 états du pipeline ») du MÊME README — jamais la liste des projets. Ce catalogue est DATA-DERIVED : le champ Select projet de crm/dossier_vente/out/doctype_oto_dossier_vente.json (byte-gaté par check_artifacts) porte l'ensemble ORDONNÉ des 9 options (P01 Structure … P09 1069 Crisfer), transcription de la section « ## Projets » de CLAUDE.md (source faisant autorité · contraintes #6/#7). PIÈGE : check_artifacts ne prouve QUE DocType==spec (byte-for-byte), et la spec RECOPIE elle-même le catalogue — donc TOUTE la chaîne (spec → DocType) peut DÉRIVER de CLAUDE.md en restant BYTE-VERTE. RENOMMER un projet (P03 Nakua → P03 Nakua Bay) · en AJOUTER un (P10) · en RETIRER un laisse le Select périmé, contredisant silencieusement CLAUDE.md pendant que la prose « ancré sur CLAUDE.md » devient FAUSSE — « vert trompeur » qu'aucune suite tests/ (qui teste des FONCTIONS de builder, pas l'ancrage à CLAUDE.md) n'attrape → nouveau bloc recomputant le catalogue depuis « ## Projets » de CLAUDE.md (zéro duplication · source unique · même esprit que le roadmap-anchor INV11 qui ancre les roadmap_line au fichier roadmap) et exigeant que les options du Select l'égalent EXACTEMENT (set-diff absent ET en trop, PUIS ordre · NFC) + que la prose porte la plage P01..P<dernier> + le mot d'ancrage. Cohérences croisées en bonus (mordent un catalogue CLAUDE.md internement incohérent) : catalogue NON VIDE, codes SANS DOUBLON et CONTIGUS depuis P01. Un claim absent échoue AUSSI. 6 morsures vérifiées : CLAUDE.md rename P03 Nakua→P03 Nakua Bay (Select DÉRIVE : absents=[P03 Nakua Bay] en trop=[P03 Nakua]) · CLAUDE.md +P10 (Select absents=[P10 …] + README dit P01..P09 MAIS catalogue P01..P10) · DocType réordonné (bon ENSEMBLE mais ORDRE ≠) · DocType renomme 1 libellé (P07 Aqua Terra Las Terrenas→P07 Aqua Terra) · README plage P01..P09→P01..P08 · README ancrage supprimé (claim INTROUVABLE) ; restauré = green : Select projet == CLAUDE.md (9 projets, ordre inclus) · plage P01..P09 + ancrage · catalogue contigu · exit 0. État courant : aucun projet périmé (anti-invention #6, rien à réécrire) — le défaut est la surface ungated. ci/README.md (table + détail « catalogue de projets ancré sur CLAUDE.md ») mis à jour · 7 gates re-verts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1991,6 +1991,95 @@ if hl_pages:
|
||||
f"{'+x-default' if has_xdef else ''} MAIS carte "
|
||||
f"{sorted(content_langs)}+x-default{detail} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# CRM/dossier_vente (2e surface) · CATALOGUE DE PROJETS « P01..P09 ancré sur
|
||||
# CLAUDE.md » — le Select `projet` du DocType porteur.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le bloc CRM pipeline ci-dessus recompute le COMPTE d'états du même README
|
||||
# (« les 9 états du pipeline »). Restait, dans le MÊME README, une surface
|
||||
# data-derived distincte et jamais gatée : la liste des PROJETS. Le champ Select
|
||||
# `projet` du DocType (out/doctype_oto_dossier_vente.json, byte-gaté par
|
||||
# check_artifacts) porte l'ENSEMBLE ORDONNÉ des 9 projets OTO
|
||||
# (« P01 Structure », « P02 Coral del Sur », …). Le README:46 le résume
|
||||
# « Projet (`Select` **P01..P09** ancré sur CLAUDE.md) » et le `_comment` du
|
||||
# doctype_spec.json le déclare « ancré sur CLAUDE.md … pas inventé ». Or ce
|
||||
# catalogue est une TRANSCRIPTION MANUELLE : la section « ## Projets » de
|
||||
# CLAUDE.md est la SOURCE FAISANT AUTORITÉ (contraintes #6/#7 · liste des
|
||||
# projets), mais AUCUN gate ne compare les options du DocType à CLAUDE.md.
|
||||
# check_artifacts ne prouve que DocType == spec (byte-for-byte) ; la spec
|
||||
# elle-même recopie la liste — donc TOUTE la chaîne (spec → DocType) peut
|
||||
# DÉRIVER de CLAUDE.md en restant byte-verte : RENOMMER un projet dans CLAUDE.md
|
||||
# (« P03 Nakua » → « P03 Nakua Bay »), en AJOUTER un (P10) ou en RETIRER un
|
||||
# laisse le Select périmé, contredisant silencieusement CLAUDE.md pendant que la
|
||||
# prose « ancré sur CLAUDE.md » devient FAUSSE — « vert trompeur » qu'aucune
|
||||
# suite tests/ (qui teste des FONCTIONS de builder, pas l'ancrage à CLAUDE.md)
|
||||
# n'attrape. Même esprit que le roadmap-anchor (INV11) qui ancre les
|
||||
# `roadmap_line` de l'artefact au fichier roadmap : ici on ANCRE le catalogue
|
||||
# projet du DocType à CLAUDE.md. On RECOMPUTE le catalogue depuis « ## Projets »
|
||||
# de CLAUDE.md (zéro duplication · source unique) et on exige que les options du
|
||||
# Select l'égalent EXACTEMENT (absent ET en trop via set-diff, puis ORDRE), et
|
||||
# que la prose porte la bonne plage P01..P<dernier> + le mot d'ancrage. Un claim
|
||||
# absent échoue AUSSI. Cohérences croisées en bonus (mordent un catalogue
|
||||
# CLAUDE.md internement incohérent) : catalogue NON VIDE, codes SANS DOUBLON et
|
||||
# CONTIGUS depuis P01 (P01,P02,…,P0N — byte-déterminisme du contrat).
|
||||
# ============================================================================
|
||||
def _nfc(s):
|
||||
return unicodedata.normalize("NFC", s)
|
||||
try:
|
||||
cm_raw = open("CLAUDE.md", encoding="utf-8").read()
|
||||
mcm = re.search(r"^## Projets\s*\n(.+)$", cm_raw, re.M)
|
||||
if mcm is None:
|
||||
raise ValueError("section « ## Projets » INTROUVABLE")
|
||||
# catalogue faisant autorité = tokens « PNN Label » séparés par « · »
|
||||
cat = [_nfc(t.strip()) for t in mcm.group(1).split("·") if t.strip()]
|
||||
cat_codes = [re.match(r"(P\d{2})\b", p).group(1) for p in cat]
|
||||
except (OSError, ValueError, AttributeError) as e:
|
||||
bad(f"CRM projets · CLAUDE.md « ## Projets » illisible/inattendu : {e}"); cat = None
|
||||
if cat is not None:
|
||||
# bonus : catalogue non vide · codes sans doublon · contigus depuis P01
|
||||
contig = cat_codes == [f"P{i:02d}" for i in range(1, len(cat_codes) + 1)]
|
||||
if not cat or len(set(cat_codes)) != len(cat_codes) or not contig:
|
||||
bad(f"CRM projets · catalogue CLAUDE.md dégénéré : codes={cat_codes} "
|
||||
f"(attendu P01..P{len(cat_codes):02d} contigus, sans doublon, non vide)")
|
||||
else:
|
||||
good(f"CRM projets · catalogue CLAUDE.md sain : {len(cat)} projets "
|
||||
f"P01..{cat_codes[-1]} contigus")
|
||||
# 1) ANCRAGE : options du Select `projet` du DocType == catalogue CLAUDE.md
|
||||
try:
|
||||
dv_dt = load("crm/dossier_vente/out/doctype_oto_dossier_vente.json")
|
||||
pf = next(f for f in dv_dt["fields"] if f.get("fieldname") == "projet")
|
||||
dt_opts = [_nfc(o.strip()) for o in pf["options"].split("\n") if o.strip()]
|
||||
except (OSError, KeyError, ValueError, StopIteration) as e:
|
||||
bad(f"CRM projets · DocType Select `projet` illisible/inattendu : {e}"); dt_opts = None
|
||||
if dt_opts is not None:
|
||||
if dt_opts == cat:
|
||||
good(f"CRM projets · Select `projet` du DocType == CLAUDE.md "
|
||||
f"({len(cat)} projets, ordre inclus)")
|
||||
elif set(dt_opts) == set(cat):
|
||||
bad(f"CRM projets · Select `projet` porte le bon ENSEMBLE mais un ORDRE "
|
||||
f"≠ CLAUDE.md : DocType={dt_opts} vs {cat} → régénérer le DocType")
|
||||
else:
|
||||
miss = [p for p in cat if p not in dt_opts]
|
||||
extra = [p for p in dt_opts if p not in cat]
|
||||
detail = (f" · absents={miss}" if miss else "") + \
|
||||
(f" · en trop={extra}" if extra else "")
|
||||
bad(f"CRM projets · Select `projet` du DocType DÉRIVE de CLAUDE.md"
|
||||
f"{detail} → régénérer le DocType (ou aligner CLAUDE.md)")
|
||||
# 2) PROSE : README résume la plage P01..P<dernier> + ancrage CLAUDE.md
|
||||
dv_rd2 = read_norm(f"{D}/crm/dossier_vente/README.md")
|
||||
if dv_rd2 is not None:
|
||||
mp = re.search(r"Projet \(`Select` \*\*(P\d{2})\.\.(P\d{2})\*\* "
|
||||
r"ancré sur CLAUDE\.md\)", dv_rd2)
|
||||
if mp is None:
|
||||
bad(f"CRM projets · {D}/crm/dossier_vente/README.md — claim « Projet "
|
||||
f"(`Select` P01..P{cat_codes[-1][1:]} ancré sur CLAUDE.md) » INTROUVABLE")
|
||||
elif (mp.group(1), mp.group(2)) == (cat_codes[0], cat_codes[-1]):
|
||||
good(f"CRM projets · README plage {mp.group(1)}..{mp.group(2)} "
|
||||
f"+ ancrage CLAUDE.md == catalogue")
|
||||
else:
|
||||
bad(f"CRM projets · README dit {mp.group(1)}..{mp.group(2)} MAIS catalogue "
|
||||
f"CLAUDE.md va de {cat_codes[0]} à {cat_codes[-1]} → régénérer le README")
|
||||
|
||||
sys.exit(1 if FAIL else 0)
|
||||
PY
|
||||
rc=$?
|
||||
|
||||
Reference in New Issue
Block a user