From 0752e3598824340acb49e1c4cf76e0bc12caaf38 Mon Sep 17 00:00:00 2001 From: Claude Code DTP Worker Date: Sun, 2 Aug 2026 10:11:34 +0000 Subject: [PATCH] =?UTF-8?q?[DTP-Worker=2020260802=5F100534]=20Sprint=208?= =?UTF-8?q?=20=C2=B7=20buffer=20=C2=B7=20Ancrage=20des=20MINIMA=20D'ORCHES?= =?UTF-8?q?TRATION=20de=20demo/scenarios=20(=C2=AB=20=E2=89=A5=202=20modul?= =?UTF-8?q?es=20distincts=20=C2=B7=20=E2=89=A5=203=20beats=20=C2=BB)=20sur?= =?UTF-8?q?=20la=20garde=20check=5Finvariants=20(CODE-autorit=C3=A9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- 05_activity_log/2026-08-02.md | 47 ++++++++++++++++++++++++ ci/check_readme_claims.sh | 67 +++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/05_activity_log/2026-08-02.md b/05_activity_log/2026-08-02.md index 27899f7..59ec2fb 100644 --- a/05_activity_log/2026-08-02.md +++ b/05_activity_log/2026-08-02.md @@ -1,5 +1,52 @@ # Activity log · 2026-08-02 · Claude Code DTP Worker +## Sprint 8 · buffer · Démo/scenarios — ancrage des MINIMA D'ORCHESTRATION (« ≥ 2 modules distincts · ≥ 3 beats ») sur la garde `check_invariants` (CODE-autorité) + +**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de +chiffres »). Classe « seuil data-derived recopié dans une garde de validation + +sa prose, jamais ancré » (déjà couverte pour les planchers `min_doc_bytes` / +`min_test_methods` de l'auditeur 4Big). Un candidat restait NON gaté (grep : +absent de tous les `ci/*.sh`) au **Livrable Sprint 7** (`demo/scenarios`, run-sheet +de pitch P07/P05) : la **garantie #3** du README (« chaque scénario tisse **≥ 2 +modules distincts** et **≥ 3 beats** ») énonce deux planchers structurels +RÉELLEMENT imposés par la garde `check_invariants` bloc (c) de +`demo_scenario_gen.py` — la SEULE autorité d'exécution : `len(sc["beats"]) < 3` +refuse un scénario sous 3 beats, `len(mods) < 2` sous 2 modules distincts. Les +deux nombres sont recopiés À LA MAIN à **3 surfaces**, aucune gatée : (1) la +comparaison `< N`/`< M` (le plancher EFFECTIF) · (2) le message d'erreur +« (min 3) »/« (min 2 · orchestration) » (bornes annoncées au caller) · (3) la +prose README. + +**Le « vert trompeur » — PROUVÉ ungate avant ajout** (mémoire +`verify-uncovered-before-gating`) : muter « ≥ 3 beats »→« ≥ 4 »/« ≥ 2 modules »→ +« ≥ 5 » dans le README laissait `check_readme_claims` **exit 0**. Resserrer la +règle (démo plus riche : `< 2`→`< 3` modules) sans toucher la prose ⇒ README +PÉRIMÉ en silence, documentant un plancher que le code n'applique plus — dérive +qu'aucune suite `tests/` (exerce la FONCTION `check_invariants`, jamais la prose) +n'attrape, invisible à `check_artifacts` (`.py` ≠ `out/*.json`). + +**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Démo · run-sheet · MINIMA +D'ORCHESTRATION », juste après le bloc « modules cités ») — RE-DÉRIVE les 2 minima +depuis la SEULE comparaison `<` de la garde (source unique · zéro duplication #5) +et exige : (1) autorité = `<` de `check_invariants` ; (2) le message d'erreur +« (min N) »/« (min M · orchestration) » == plancher effectif ; (3) la prose #3 du +README == plancher effectif. Une surface INTROUVABLE échoue AUSSI (ancre morte · +anti-évaporation #6). + +**Vérif** — 3 checks verts sur l'arbre propre (≥ 2 modules · ≥ 3 beats). **7 +morsures** adversariales, gate lancé SEUL, reverts par `cp` ciblé (jamais +`git checkout` large — cf. incident consigné) : **M1** README `≥3 beats`→`≥4` (3) · +**M2** README `≥2 modules`→`≥5` (3) · **M3 SILENT-GREEN** garde `<3`→`<4` beats +(code resserré, prose+message figés) ⇒ **message ET README mordent** (preuve que +l'autorité est le CODE, pas la cohérence interne de la prose) · **M4** message +`(min 3)`→`(min 4)` désync de `<` ⇒ message mord, README reste OK · **M5** garde +`<2`→`<3` modules ⇒ message ET README mordent · **M6** prose #3 supprimée ⇒ +INTROUVABLE · **M7** comparaison `<` de la garde retirée ⇒ autorité INTROUVABLE. +Arbre restauré (`git status` propre, seule l'addition au gate subsiste). Suite +unittest re-verte : **39 tests OK** (générateur inchangé). Suite CI complète +re-verte : `check_artifacts` · `check_docs` · `guard_constraints` · +`check_ci_integrity` · `check_regression` · `check_readme_claims` tous exit 0. + ## Sprint 8 · buffer · CRM/workflow_vente — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate_bundle` (9ᵉ instance du ledger · dialecte `# Invariant N ·`) **Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de diff --git a/ci/check_readme_claims.sh b/ci/check_readme_claims.sh index 4229db5..e7cf204 100755 --- a/ci/check_readme_claims.sh +++ b/ci/check_readme_claims.sh @@ -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(...)