[DTP-Worker 20260802_043512] Sprint 8 · buffer · Faisabilité : ancrage du DOMAINE DES CODES PROJET (garde _validate_brief + 2 schémas JSON) sur CLAUDE.md §Projets
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5343,6 +5343,120 @@ if exp is not None:
|
||||
(f" · (pas {exp_excl})" if cites_excl and exp_excl else "")
|
||||
good(f"Fiches #10 · {label} — cite {_cited} == CLAUDE.md #10")
|
||||
|
||||
# ============================================================================
|
||||
# Faisabilité/generator · DOMAINE DES CODES PROJET (P01..P09) ancré sur §Projets
|
||||
# — même classe d'ANCRAGE que le CONTRAT DE FORMAT e-NCF (`ncf.py`) : une GARDE
|
||||
# DE VALIDATION en CODE qui encode un domaine constitutionnel SANS l'ancrer.
|
||||
# ----------------------------------------------------------------------------
|
||||
# Le générateur 4 volets (Livrable Sprint 3 · « P07 Aqua Terra <1h ») REFUSE tout
|
||||
# brief dont le `projet` n'est pas un code canonique. Le DOMAINE des codes valides
|
||||
# EST exactement l'ensemble des projets de CLAUDE.md §Projets (P01..P09). Il est
|
||||
# recopié À LA MAIN à QUATRE surfaces, AUCUNE ancrée sur §Projets, toutes
|
||||
# invisibles à `check_artifacts` (aucune n'est un `out/*.json`) :
|
||||
# (a) `faisabilite/generator/faisabilite_gen.py::_validate_brief` — la GARDE
|
||||
# runtime `code[:2] == "P0" and code[2] in "123456789"` (le domaine effectif)
|
||||
# + le message `attendu P01..P09` (les bornes) ;
|
||||
# (b) `faisabilite/version.schema.json` — `properties.projet.pattern "^P0[1-9]$"`
|
||||
# (validation JSON du `version.json` par projet) + sa `description` ;
|
||||
# (c) `faisabilite/generator/brief.schema.json` — même `pattern "^P0[1-9]$"`
|
||||
# (validation JSON du brief d'entrée) + sa `description`.
|
||||
# « Vert trompeur » : si CLAUDE.md §Projets AJOUTE un 10ᵉ projet (`P10 …`, évènement
|
||||
# de portefeuille réel), la GARDE et les DEUX patterns REJETTENT `P10` comme
|
||||
# « invalide (attendu P01..P09) » → le générateur REFUSE de scaffolder un projet
|
||||
# LÉGITIMEMENT mandaté (bug d'exécution) pendant que la suite `tests/` reste VERTE
|
||||
# (ses oracles P01/P02 sont self-consistants, jamais comparés à §Projets). Ni
|
||||
# `check_artifacts` (schémas/`.py` ne sont pas des `out/*.json`) ni `tests/` (teste
|
||||
# la FONCTION `_validate_brief`, pas son ANCRAGE) ne mordent. Symétriquement,
|
||||
# RETIRER un projet de §Projets laisse la garde trop PERMISSIVE (accepte un code
|
||||
# démobilisé). On RE-DÉRIVE le domaine de §Projets et on exige que chaque surface
|
||||
# accepte EXACTEMENT cet ensemble (test COMPORTEMENTAL du pattern, robuste à la
|
||||
# forme de la classe de caractères), + la déclaration de l'ancrage « §Projets ».
|
||||
# ----------------------------------------------------------------------------
|
||||
try:
|
||||
_fcm = open("CLAUDE.md", encoding="utf-8").read()
|
||||
_fmp = re.search(r"^## Projets\s*\n(.+)$", _fcm, re.M)
|
||||
if _fmp is None:
|
||||
raise ValueError("section « ## Projets » INTROUVABLE")
|
||||
fpj_codes = sorted(set(re.findall(r"\bP\d{2,}\b", _fmp.group(1))))
|
||||
if not fpj_codes:
|
||||
raise ValueError("aucun code projet PNN parsé")
|
||||
except (OSError, ValueError) as e:
|
||||
bad(f"Faisabilité domaine · CLAUDE.md §Projets illisible/inattendu : {e}")
|
||||
fpj_codes = None
|
||||
|
||||
if fpj_codes is not None:
|
||||
fpj_set = set(fpj_codes); fpj_mn, fpj_mx = fpj_codes[0], fpj_codes[-1]
|
||||
# (a) la garde runtime _validate_brief : préfixe + ensemble de chiffres + message
|
||||
FG = f"{D}/faisabilite/generator/faisabilite_gen.py"
|
||||
try:
|
||||
_fg = open(FG, encoding="utf-8").read()
|
||||
except OSError as e:
|
||||
_fg = None; bad(f"Faisabilité domaine · {FG} illisible : {e}")
|
||||
if _fg is not None:
|
||||
_mpre = re.search(r'code\[:2\]\s*==\s*"([^"]+)"', _fg)
|
||||
_mdig = re.search(r'code\[2\]\s*in\s*"([^"]+)"', _fg)
|
||||
if not (_mpre and _mdig):
|
||||
bad("Faisabilité domaine · _validate_brief : préfixe/ensemble-chiffres du "
|
||||
"code projet INTROUVABLE (ancre morte) → la garde a changé de forme")
|
||||
else:
|
||||
_accept = {f"{_mpre.group(1)}{d}" for d in _mdig.group(1)}
|
||||
_miss = sorted(fpj_set - _accept); _extra = sorted(_accept - fpj_set)
|
||||
if _miss or _extra:
|
||||
bad(f"Faisabilité domaine · _validate_brief accepte {sorted(_accept)} ≠ "
|
||||
f"CLAUDE.md §Projets{' · manquants=' + str(_miss) if _miss else ''}"
|
||||
f"{' · en trop=' + str(_extra) if _extra else ''} → aligner la garde "
|
||||
f"(ou CLAUDE.md §Projets)")
|
||||
else:
|
||||
good(f"Faisabilité domaine · _validate_brief accepte exactement les "
|
||||
f"{len(_accept)} codes {fpj_mn}..{fpj_mx} de CLAUDE.md §Projets")
|
||||
_mmsg = re.search(r'brief\.projet invalide \(attendu ([^)]+)\)', _fg)
|
||||
if not _mmsg:
|
||||
bad("Faisabilité domaine · message « brief.projet invalide (attendu …) » "
|
||||
"INTROUVABLE (ancre morte)")
|
||||
elif fpj_mn not in _mmsg.group(1) or fpj_mx not in _mmsg.group(1):
|
||||
bad(f"Faisabilité domaine · message « attendu {_mmsg.group(1)} » ne cite pas "
|
||||
f"les bornes {fpj_mn}..{fpj_mx} de CLAUDE.md §Projets")
|
||||
else:
|
||||
good(f"Faisabilité domaine · message d'erreur cite les bornes "
|
||||
f"{fpj_mn}..{fpj_mx} == CLAUDE.md §Projets")
|
||||
# (b)+(c) les 2 schémas JSON : le pattern accepte EXACTEMENT §Projets (comportemental)
|
||||
_probe = fpj_set | {"P00", "P10", "P99", "P0", "PXX", "P1", "P010", "Q01"}
|
||||
for _rel in ("version.schema.json", "generator/brief.schema.json"):
|
||||
SP = f"{D}/faisabilite/{_rel}"
|
||||
try:
|
||||
_sj = json.load(open(SP, encoding="utf-8"))
|
||||
except (OSError, ValueError) as e:
|
||||
bad(f"Faisabilité domaine · {_rel} illisible/inattendu : {e}"); continue
|
||||
_prop = (_sj.get("properties") or {}).get("projet") or {}
|
||||
_pat = _prop.get("pattern")
|
||||
if not _pat:
|
||||
bad(f"Faisabilité domaine · {_rel} : properties.projet.pattern INTROUVABLE")
|
||||
else:
|
||||
try:
|
||||
_rx = re.compile(_pat)
|
||||
except re.error as e:
|
||||
bad(f"Faisabilité domaine · {_rel} pattern {_pat!r} illégal : {e}"); _rx = None
|
||||
if _rx is not None:
|
||||
_acc = {c for c in _probe if _rx.fullmatch(c)}
|
||||
_miss = sorted(fpj_set - _acc); _extra = sorted(_acc - fpj_set)
|
||||
if _miss or _extra:
|
||||
bad(f"Faisabilité domaine · {_rel} pattern {_pat!r} accepte {sorted(_acc)}"
|
||||
f" ≠ CLAUDE.md §Projets{' · manquants=' + str(_miss) if _miss else ''}"
|
||||
f"{' · en trop=' + str(_extra) if _extra else ''}")
|
||||
else:
|
||||
good(f"Faisabilité domaine · {_rel} pattern accepte exactement les "
|
||||
f"{len(fpj_set)} codes de §Projets")
|
||||
_desc = _prop.get("description", "") or ""
|
||||
if not re.search(r"CLAUDE\.md\s*§?\s*Projets", _desc):
|
||||
bad(f"Faisabilité domaine · {_rel} : description projet ne DÉCLARE pas "
|
||||
f"l'ancrage « CLAUDE.md §Projets » : {_desc!r}")
|
||||
elif fpj_mn not in _desc or fpj_mx not in _desc:
|
||||
bad(f"Faisabilité domaine · {_rel} : description ne cite pas les bornes "
|
||||
f"{fpj_mn}..{fpj_mx} : {_desc!r}")
|
||||
else:
|
||||
good(f"Faisabilité domaine · {_rel} description ancre {fpj_mn}..{fpj_mx} "
|
||||
f"sur CLAUDE.md §Projets")
|
||||
|
||||
# ============================================================================
|
||||
# TEMPLATE FAISABILITÉ CANONIQUE v1.0 · PARAMÈTRES #9/#10 — même classe d'ANCRAGE
|
||||
# que « paramètres canoniques » (generator) et « Fiches #10 » ci-dessus, sur une
|
||||
|
||||
Reference in New Issue
Block a user