[DTP-Worker 20260802_010501] Sprint 8 · buffer · Legal CONFOTUR : gate d'IDENTITÉ du COMPTE D'INVARIANTS de _validate (4ᵉ instance du ledger)
4ᵉ application du pattern « ledger d'invariants » (après Chat OTOIA · SEO · Fiscal e-CF) à legal/confotur/confotur_application_gen.py. Le compte « 14 invariants » y est transcrit à la main à SIX endroits non gatés, tous invisibles à check_artifacts (le .py n'est pas un out/*.json) : 4 chaînes du .py (docstrings module + _validate, succès CLI, aide du sous-parseur) + 2 du README (bloc de commande, commentaire d'arborescence). Ajouter un contrôle # 15 · à _validate sans toucher les 6 chaînes ⇒ README + self-reports mentent en silence pendant que la CI applique 15 contrôles — « vert trompeur » que ni tests/ (FONCTIONS, pas la prose) ni le byte-gate d'artefact n'attrapent. Particularité CONFOTUR (≠ Fiscal) : ledger PROPRE 1..14 (pas de schéma-#1 non marqué, pas de split a/b) MAIS le README porte AUSSI un compte de SOUS-ENSEMBLE éditorial (« 2 invariants refusent tout champ monétaire ») à ne pas confondre avec le total — un \d+ invariants naïf mordrait l'arbre propre. Le gate exclut le sous-ensemble par lookahead négatif (\d+)\s+invariants(?!\s+refusent), appliqué au .py comme au README. Nouveau bloc (ci/check_readme_claims.sh) : RECOMPUTE le ledger depuis le SEUL registre-source (# N · de _validate) et exige (a) ledger CONTIGU 1..N (lacune OU doublon nu = vrai défaut) ; (b) toute mention-total du .py == |ledger| ; (c) toute mention-total du README (hors « refusent ») == |ledger|. 3 checks verts sur l'arbre propre. 6 morsures vérifiées (M1 self-report .py 14→15 · M2 README commande 14→15 · M3 README arborescence 14→13 · M4 ajout # 15 · ⇒ ledger→15 vs prose 14, mord .py ET README · M5 gap # 7 · · M6 doublon nu # 5 ·) + M7 no-false-positive (sous-ensemble 2→3 reste vert). 6 gates re-verts exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,59 @@
|
|||||||
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
||||||
|
|
||||||
|
## Sprint 8 · buffer · Legal CONFOTUR — gate d'IDENTITÉ du COMPTE D'INVARIANTS de `_validate` (4ᵉ instance du ledger)
|
||||||
|
|
||||||
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
|
||||||
|
chiffres »). Le pattern « ledger d'invariants » (recompute le nombre de contrôles
|
||||||
|
CI depuis le registre-source `# N ·` de `_validate`, jamais une liste à la main)
|
||||||
|
a déjà couvert **Chat OTOIA**, **SEO** et **Fiscal e-CF**. Le **4ᵉ générateur**
|
||||||
|
portant le même nombre magique restait NON gaté :
|
||||||
|
`legal/confotur/confotur_application_gen.py`.
|
||||||
|
|
||||||
|
Le compte **« 14 invariants »** y est transcrit **à la main à SIX endroits**,
|
||||||
|
aucun gaté, tous invisibles à `check_artifacts` (le `.py` source n'est pas un
|
||||||
|
`out/*.json`) :
|
||||||
|
1. docstring module (l.24 « schéma + 14 invariants de ») ;
|
||||||
|
2. docstring `_validate` (l.87 « 14 invariants de cross-coherence ») ;
|
||||||
|
3. message de succès CLI `validate` « … schéma + 14 invariants verts. » (l.283) ;
|
||||||
|
4. aide du sous-parseur `validate` (l.295) ;
|
||||||
|
5. README bloc de commande « schéma + 14 invariants » (l.56) ;
|
||||||
|
6. README commentaire d'arborescence « CLI build/validate · 14 invariants » (l.82).
|
||||||
|
|
||||||
|
Ajouter un contrôle `# 15 ·` à `_validate` sans toucher les 6 chaînes ⇒ le README
|
||||||
|
ET les self-reports du `.py` mentent en silence pendant que la CI applique 15
|
||||||
|
contrôles. Aucune suite `tests/` (qui teste des FONCTIONS de validation, pas la
|
||||||
|
prose) n'attrape ce « vert trompeur ».
|
||||||
|
|
||||||
|
**Particularité du registre CONFOTUR** (≠ Fiscal) : le ledger est **PROPRE 1..14**
|
||||||
|
(pas de schéma-#1 non marqué, pas de split a/b). MAIS le README porte AUSSI un
|
||||||
|
compte de **SOUS-ENSEMBLE éditorial** — « **2 invariants** refusent tout champ
|
||||||
|
monétaire » (l.92) — à NE PAS confondre avec le total. Un `\d+ invariants` naïf
|
||||||
|
mordrait donc l'arbre PROPRE (il verrait `{2, 14}`). Le gate exclut le
|
||||||
|
sous-ensemble par **lookahead négatif** `(\d+)\s+invariants(?!\s+refusent)`,
|
||||||
|
appliqué au `.py` comme au README.
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « Legal · CONFOTUR · IDENTITÉ
|
||||||
|
du COMPTE D'INVARIANTS ») — RECOMPUTE le ledger depuis le SEUL registre-source
|
||||||
|
(`# N ·` de `_validate`) et exige :
|
||||||
|
- **(a)** ledger CONTIGU 1..N (lacune OU doublon nu = vrai défaut de registre) ;
|
||||||
|
- **(b)** toute mention-total « N invariants » du `.py` (hors « refusent ») == |ledger| ;
|
||||||
|
- **(c)** toute mention-total du README (hors « refusent ») == |ledger|.
|
||||||
|
Une mention ou le registre absent échoue AUSSI (disparition d'un chiffre =
|
||||||
|
régression de traçabilité #6).
|
||||||
|
|
||||||
|
**Vérif** — 3 checks verts sur l'arbre propre (ledger 1..14 = 14 marqueurs `# N ·`).
|
||||||
|
**6 morsures** adversariales : M1 self-report `.py` 14→15 (b) · M2 README commande
|
||||||
|
14→15 (c) · M3 README arborescence 14→13 (c) · **M4 ajout marqueur `# 15 ·` ⇒
|
||||||
|
ledger→15 pendant que la prose reste 14 (mord `.py` ET README, preuve que
|
||||||
|
l'autorité est le CODE)** · M5 suppression `# 7 ·` ⇒ gap non-contigu (a) · M6
|
||||||
|
doublon nu `# 5 ·` ⇒ détection de vrai doublon (a). **M7 no-false-positive** :
|
||||||
|
sous-ensemble « 2 → 3 invariants refusent » reste VERT (le lookahead exclut bien
|
||||||
|
le sous-ensemble). Gates re-verts : `check_artifacts` · `check_docs` ·
|
||||||
|
`guard_constraints` · `check_ci_integrity` · `check_regression` ·
|
||||||
|
`check_readme_claims` tous exit 0.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Sprint 8 · buffer · Publiciste — gate d'ANCRAGE des DEVISES du site public sur CLAUDE.md #10
|
## Sprint 8 · buffer · Publiciste — gate d'ANCRAGE des DEVISES du site public sur CLAUDE.md #10
|
||||||
|
|
||||||
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
|
||||||
|
|||||||
@@ -1844,6 +1844,103 @@ if ecf_src is not None:
|
|||||||
bad(f"Fiscal invariants · {ECF_RD_INV} — énumération prose {ecf_enum} "
|
bad(f"Fiscal invariants · {ECF_RD_INV} — énumération prose {ecf_enum} "
|
||||||
f"≠ 1..{ecf_ninv} (item sauté/dupliqué) → régénérer le README")
|
f"≠ 1..{ecf_ninv} (item sauté/dupliqué) → régénérer le README")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Legal · CONFOTUR · IDENTITÉ du COMPTE D'INVARIANTS de `_validate` — 4ᵉ instance
|
||||||
|
# de la classe « ledger d'invariants » (après Chat OTOIA · SEO · Fiscal e-CF).
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# Le générateur confotur_application_gen.py applique un COMPTE d'invariants de
|
||||||
|
# cross-cohérence dont la source d'autorité n'est PAS un artefact JSON (invisible
|
||||||
|
# à check_artifacts qui byte-gate les out/*.json) mais le LEDGER NUMÉROTÉ de
|
||||||
|
# `_validate` : les marqueurs `# N ·` (1..14) qui ouvrent chaque contrôle appliqué.
|
||||||
|
# Le nombre « 14 » est transcrit À LA MAIN à SIX endroits qu'AUCUN gate ne
|
||||||
|
# couvrait : QUATRE chaînes du .py (docstring module, docstring `_validate`,
|
||||||
|
# message de succès CLI « … 14 invariants verts. », aide du sous-parseur
|
||||||
|
# `validate`) + DEUX du README (bloc de commande « schéma + 14 invariants »,
|
||||||
|
# commentaire d'arborescence « CLI build/validate · 14 invariants »). Ajouter un
|
||||||
|
# contrôle `# 15 ·` à `_validate` sans toucher les chaînes ⇒ le README ET les
|
||||||
|
# self-reports du .py mentent en silence pendant que la CI applique 15 contrôles —
|
||||||
|
# « vert trompeur » (#6) que ni les suites tests/ (FONCTIONS de validation, jamais
|
||||||
|
# la prose) ni le byte-gate d'artefact (aveugle au .py source) n'attrapent.
|
||||||
|
# PARTICULARITÉ vs Fiscal : ledger PROPRE 1..N (pas de schéma-#1 non marqué, pas de
|
||||||
|
# split a/b) MAIS le README porte AUSSI un compte de SOUS-ENSEMBLE éditorial
|
||||||
|
# (« 2 invariants refusent tout champ monétaire ») À NE PAS confondre avec le total
|
||||||
|
# — on l'exclut par lookahead négatif `(?!\s+refusent)`, faute de quoi le gate
|
||||||
|
# mordrait l'arbre propre (le « 2 » n'est pas le compte du ledger). On RECOMPUTE le
|
||||||
|
# ledger depuis le SEUL registre-source (les `# N ·` de `_validate`) et on exige :
|
||||||
|
# (a) ledger CONTIGU 1..N (lacune OU doublon nu = vrai défaut de registre, mordu) ;
|
||||||
|
# (b) TOUTE mention-total « N invariants » du .py == |ledger| ; (c) TOUTE
|
||||||
|
# mention-total du README (hors sous-ensemble « refusent ») == |ledger|. Mention ou
|
||||||
|
# registre absent = échec (disparition d'un chiffre = régression de traçabilité #6).
|
||||||
|
# ============================================================================
|
||||||
|
CF_GEN = f"{D}/legal/confotur/confotur_application_gen.py"
|
||||||
|
CF_RD = f"{D}/legal/confotur/README.md"
|
||||||
|
# mention-total = « N invariants » NON suivi de « refusent » (le sous-ensemble
|
||||||
|
# éditorial anti-invention du README, ≠ compte total du ledger).
|
||||||
|
_CF_RX_TOT = r"(\d+)\s+invariants(?!\s+refusent)"
|
||||||
|
try:
|
||||||
|
cf_src = open(CF_GEN, encoding="utf-8").read()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"CONFOTUR invariants · générateur {CF_GEN} illisible : {e}"); cf_src = None
|
||||||
|
if cf_src is not None:
|
||||||
|
_mfn = re.search(r"def _validate\b", cf_src)
|
||||||
|
if _mfn is None:
|
||||||
|
bad(f"CONFOTUR invariants · fonction `_validate` INTROUVABLE dans {CF_GEN} "
|
||||||
|
"(registre-source du ledger absent → impossible de re-dériver)")
|
||||||
|
else:
|
||||||
|
_bs = _mfn.end()
|
||||||
|
_mn = re.search(r"\ndef ", cf_src[_bs:])
|
||||||
|
_body = cf_src[_bs: _bs + _mn.start()] if _mn else cf_src[_bs:]
|
||||||
|
# marqueurs `# N ·` (le ledger confotur est propre : pas de suffixe a/b,
|
||||||
|
# mais on garde la détection de doublon nu comme pour Fiscal).
|
||||||
|
_pairs = re.findall(r"#\s*(\d+)([a-z]?)\s*·", _body)
|
||||||
|
_dup_bare = sorted({n for n in {p[0] for p in _pairs}
|
||||||
|
if [s for num, s in _pairs if num == n and s == ""]
|
||||||
|
and sum(1 for num, _ in _pairs if num == n) > 1})
|
||||||
|
_top = sorted({int(n) for n, _ in _pairs})
|
||||||
|
if not _top:
|
||||||
|
bad(f"CONFOTUR invariants · aucun marqueur `# N ·` dans `_validate` de "
|
||||||
|
f"{CF_GEN} (ledger vide → impossible de re-dériver)")
|
||||||
|
elif _dup_bare:
|
||||||
|
bad(f"CONFOTUR invariants · marqueur(s) `# N ·` dupliqué(s) sans suffixe "
|
||||||
|
f"a/b dans `_validate` : {_dup_bare} — vrai doublon de registre")
|
||||||
|
else:
|
||||||
|
cf_ninv = len(_top)
|
||||||
|
if _top != list(range(1, cf_ninv + 1)):
|
||||||
|
bad(f"CONFOTUR invariants · ledger `_validate` NON contigu : {_top} "
|
||||||
|
f"(attendu 1..{cf_ninv}) — lacune/doublon dans les marqueurs `# N ·`")
|
||||||
|
else:
|
||||||
|
good(f"CONFOTUR invariants · ledger `_validate` contigu 1..{cf_ninv} "
|
||||||
|
f"({cf_ninv} marqueurs `# N ·`)")
|
||||||
|
# (b) self-reports du .py « N invariants » (hors sous-ensemble « refusent »).
|
||||||
|
cf_py_rep = sorted({int(x) for x in re.findall(_CF_RX_TOT, cf_src)})
|
||||||
|
if not cf_py_rep:
|
||||||
|
bad(f"CONFOTUR invariants · aucune mention-total « N invariants » dans "
|
||||||
|
f"{CF_GEN} (self-report absent → attendu {cf_ninv})")
|
||||||
|
elif cf_py_rep == [cf_ninv]:
|
||||||
|
good(f"CONFOTUR invariants · {CF_GEN} — self-report(s) {cf_py_rep} "
|
||||||
|
f"== ledger ({cf_ninv})")
|
||||||
|
else:
|
||||||
|
bad(f"CONFOTUR invariants · {CF_GEN} — self-report(s) « N invariants » "
|
||||||
|
f"{cf_py_rep} MAIS ledger en compte {cf_ninv} "
|
||||||
|
"(une chaîne du générateur désynchronisée du registre)")
|
||||||
|
# (c) README : mentions-total (le sous-ensemble « N invariants refusent »
|
||||||
|
# est exclu par le lookahead ⇒ ne fausse pas le compte).
|
||||||
|
try:
|
||||||
|
cf_rd_raw = open(CF_RD, encoding="utf-8").read()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"CONFOTUR invariants · {CF_RD} illisible : {e}"); cf_rd_raw = None
|
||||||
|
if cf_rd_raw is not None:
|
||||||
|
cf_rd_rep = sorted({int(x) for x in re.findall(_CF_RX_TOT, cf_rd_raw)})
|
||||||
|
if not cf_rd_rep:
|
||||||
|
bad(f"CONFOTUR invariants · {CF_RD} — aucune mention-total « N "
|
||||||
|
f"invariants » (attendu {cf_ninv} · disparition = régression #6)")
|
||||||
|
elif cf_rd_rep == [cf_ninv]:
|
||||||
|
good(f"CONFOTUR invariants · {CF_RD} — mention(s)-total {cf_rd_rep} "
|
||||||
|
"== ledger (aucune dérive · sous-ensemble « refusent » exclu)")
|
||||||
|
else:
|
||||||
|
bad(f"CONFOTUR invariants · {CF_RD} — mention(s)-total « N invariants » "
|
||||||
|
f"{cf_rd_rep} MAIS ledger en compte {cf_ninv} → régénérer le README")
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# CRM · pipeline vente (états / transitions) — même classe de « vert trompeur »,
|
# CRM · pipeline vente (états / transitions) — même classe de « vert trompeur »,
|
||||||
# transcrit À LA MAIN dans DEUX README de module.
|
# transcrit À LA MAIN dans DEUX README de module.
|
||||||
|
|||||||
Reference in New Issue
Block a user