[DTP-Worker 20260802_100534] Sprint 8 · buffer · Ancrage des MINIMA D'ORCHESTRATION de demo/scenarios (« ≥ 2 modules distincts · ≥ 3 beats ») sur la garde check_invariants (CODE-autorité)
Classe « seuil data-derived recopié dans une garde de validation + sa prose, jamais ancré » (déjà couverte pour min_doc_bytes/min_test_methods de l'auditeur 4Big). Livrable Sprint 7 demo/scenarios : la garantie #3 du README énonce deux planchers RÉELLEMENT imposés par check_invariants bloc (c) — len(sc["beats"])<3, len(mods)<2 — mais recopiés à la main à 3 surfaces (comparaison `<`, message d'erreur « (min N) », prose README), aucune gatée. Muter « ≥ 3 beats »→« ≥ 4 » laissait check_readme_claims exit 0 (prouvé ungate). Gate re-dérive les 2 minima depuis la SEULE comparaison `<` (source unique #5) et exige message + prose == plancher effectif ; surface INTROUVABLE échoue (#6). 7 morsures adversariales (dont M3 SILENT-GREEN : code resserré `<3`→`<4` ⇒ message ET README mordent, preuve autorité=CODE). 39 tests OK (générateur inchangé) ; suite CI complète re-verte. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -3369,6 +3369,73 @@ if demo_n is not None:
|
||||
bad(f"Démo · {DEMO_RD} — dit {m.group(1)} modules cités MAIS artefact dit "
|
||||
f"{demo_n} → régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# Démo · run-sheet · MINIMA D'ORCHESTRATION (≥ M modules distincts · ≥ N beats)
|
||||
# — même classe de « vert trompeur », au grain des SEUILS de la garde d'invariant.
|
||||
# ----------------------------------------------------------------------------
|
||||
# La garantie #3 du README du module (« chaque scénario tisse ≥ 2 modules
|
||||
# distincts et ≥ 3 beats ») ÉNONCE deux planchers structurels qui sont EN RÉALITÉ
|
||||
# imposés par la garde `check_invariants` (bloc (c)) de demo_scenario_gen.py — la
|
||||
# SEULE autorité d'exécution : `len(sc["beats"]) < N` refuse un scénario sous N
|
||||
# beats, `len(mods) < M` sous M modules distincts. Ces deux nombres sont recopiés
|
||||
# À LA MAIN à TROIS surfaces, aucune gatée : (1) la comparaison `< N`/`< M` (le
|
||||
# plancher EFFECTIF), (2) le message d'erreur « (min N) »/« (min M · orchestration) »
|
||||
# (les bornes annoncées au caller), (3) la prose « ≥ M modules distincts … ≥ N
|
||||
# beats » du README. Resserrer la règle (p.ex. exiger ≥ 3 modules pour une démo
|
||||
# plus riche : `< 2`→`< 3`) sans toucher la prose laisse le README PÉRIMÉ en
|
||||
# silence, documentant un plancher que le code n'applique plus — dérive qu'aucune
|
||||
# suite tests/ (qui exerce la FONCTION `check_invariants`, jamais la prose du
|
||||
# README) n'attrape, et que `check_artifacts` ne voit pas (`.py` ≠ `out/*.json`).
|
||||
# Même patron que les seuils min_doc_bytes/min_test_methods de l'auditeur 4Big.
|
||||
# On RE-DÉRIVE les deux minima depuis la comparaison `<` de la garde (source
|
||||
# unique · zéro duplication #5) et on exige que le message d'erreur ET la prose
|
||||
# du README les répètent À L'IDENTIQUE. Une surface INTROUVABLE échoue AUSSI
|
||||
# (ancre morte · anti-évaporation #6).
|
||||
# ============================================================================
|
||||
DEMO_GEN = f"{D}/demo/scenarios/demo_scenario_gen.py"
|
||||
try:
|
||||
demo_src = open(DEMO_GEN, encoding="utf-8").read()
|
||||
except OSError as e:
|
||||
bad(f"Démo minima · {DEMO_GEN} illisible : {e}"); demo_src = None
|
||||
if demo_src is not None:
|
||||
# (1) plancher EFFECTIF = comparaison `<` de la garde d'orchestration (autorité)
|
||||
mb = re.search(r'len\(sc\["beats"\]\)\s*<\s*(\d+)', demo_src)
|
||||
mm = re.search(r'len\(mods\)\s*<\s*(\d+)', demo_src)
|
||||
if mb is None or mm is None:
|
||||
bad(f"Démo minima · garde `check_invariants` — comparaison `len(...)<N` "
|
||||
f"INTROUVABLE dans {DEMO_GEN} (beats={mb is not None} modules={mm is not None})")
|
||||
else:
|
||||
min_beats, min_mods = mb.group(1), mm.group(1)
|
||||
good(f"Démo minima · garde d'orchestration — ≥ {min_mods} modules · "
|
||||
f"≥ {min_beats} beats (source unique = comparaison `<` de check_invariants)")
|
||||
# (2) message d'erreur de la garde == plancher effectif
|
||||
gm_b = re.search(r"beat\(s\) \(min (\d+)\)", demo_src)
|
||||
gm_m = re.search(r"\(min (\d+) · orchestration\)", demo_src)
|
||||
if gm_b is None or gm_m is None:
|
||||
bad(f"Démo minima · message d'erreur « (min N) » INTROUVABLE dans "
|
||||
f"{DEMO_GEN} (beats={gm_b is not None} modules={gm_m is not None})")
|
||||
elif gm_b.group(1) != min_beats or gm_m.group(1) != min_mods:
|
||||
bad(f"Démo minima · message garde dit (min {gm_m.group(1)} modules · "
|
||||
f"min {gm_b.group(1)} beats) MAIS la comparaison `<` impose "
|
||||
f"(≥ {min_mods} · ≥ {min_beats}) → aligner le message sur la garde")
|
||||
else:
|
||||
good(f"Démo minima · message garde « (min {min_mods} · orchestration) » / "
|
||||
f"« (min {min_beats}) » == comparaison `<`")
|
||||
# (3) prose #3 du README == plancher effectif
|
||||
demo_rd3 = read_norm(DEMO_RD)
|
||||
if demo_rd3 is not None:
|
||||
mr = re.search(r"≥ (\d+) modules distincts\*\* et \*\*≥ (\d+) beats", demo_rd3)
|
||||
if mr is None:
|
||||
bad(f"Démo minima · prose « ≥ M modules distincts … ≥ N beats » "
|
||||
f"INTROUVABLE dans {DEMO_RD} (attendu ≥ {min_mods} · ≥ {min_beats})")
|
||||
elif mr.groups() == (min_mods, min_beats):
|
||||
good(f"Démo minima · README — ≥ {mr.group(1)} modules · ≥ {mr.group(2)} "
|
||||
f"beats == garde ({min_mods} · {min_beats})")
|
||||
else:
|
||||
bad(f"Démo minima · README dit ≥ {mr.group(1)} modules · ≥ {mr.group(2)} "
|
||||
f"beats MAIS la garde impose ≥ {min_mods} · ≥ {min_beats} → "
|
||||
f"régénérer le README")
|
||||
|
||||
# ============================================================================
|
||||
# Chat OTOIA · montage de l'assistant conversationnel par portail (nombre de
|
||||
# Custom Block / configs runtime / portails) — même classe de « vert trompeur »,
|
||||
|
||||
Reference in New Issue
Block a user