[DTP-Worker 20260802_073526] Sprint 8 · buffer · Ledger d'invariants 2ᵉ FAMILLE : ancrage du COMPTE # INVn ·/validate_bundle de deploy_runbook (11) + acceptance (11) — dialecte « N familles d'invariants » qui avait glissé la clôture
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,68 @@
|
|||||||
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
# Activity log · 2026-08-02 · Claude Code DTP Worker
|
||||||
|
|
||||||
|
## Sprint 8 · buffer · Ledger d'invariants — 2ᵉ FAMILLE (`# INVn ·` / `validate_bundle` / « N familles d'invariants ») : ancrage du COMPTE de `deploy_runbook` (11) + `acceptance` (11)
|
||||||
|
|
||||||
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention de
|
||||||
|
chiffres »). La classe « ledger d'invariants » (recompute le nombre de contrôles CI
|
||||||
|
depuis le registre-source des marqueurs numérotés de la fonction `_validate`, jamais
|
||||||
|
une liste à la main) avait été **déclarée close à 8 générateurs** — mais sur le SEUL
|
||||||
|
dialecte `# N ·` / « N invariants » / `_validate`(`_validate_bundle`). La mémoire
|
||||||
|
`invariant-ledger-count-gate` consigne précisément le risque : « un prior *CLOSED
|
||||||
|
après 7* était FAUX — un style de marqueur différent avait glissé ; re-scanner LES
|
||||||
|
DEUX styles avant de croire la clôture ». Un **re-scan systématique** a exhumé une
|
||||||
|
**DEUXIÈME famille** entièrement HORS gate : marqueurs `# INVn ·` (préfixe `INV`)
|
||||||
|
dans `validate_bundle`, phrasé « N **familles d'**invariants ». DEUX générateurs la
|
||||||
|
portent :
|
||||||
|
- `devops/deploy_runbook/deploy_runbook_gen.py` — ledger `# INV1..INV11` dans
|
||||||
|
`validate_bundle`, compte **« 11 familles d'invariants »** recopié à **3 surfaces
|
||||||
|
vives** : générateur l.272 (message CLI de succès) · README l.73 (bloc de commande)
|
||||||
|
· suite tests l.4 (docstring) ;
|
||||||
|
- `qa/acceptance/acceptance_gen.py` — ledger `# INV1..INV11` dans `validate_bundle`,
|
||||||
|
compte à **2 surfaces vives** : README l.46 « 11 invariants » · suite tests l.4
|
||||||
|
« 11 familles d'invariants ». (Le `.py` acceptance ne porte AUCUN compte numéroté
|
||||||
|
→ surface non exigée.)
|
||||||
|
|
||||||
|
**Le « vert trompeur »** — ajouter un contrôle `# INV12 ·` à `validate_bundle` sans
|
||||||
|
toucher ces chaînes ⇒ README + self-reports + docstrings de test mentent en silence
|
||||||
|
pendant que la CI applique 12 contrôles. Ni `check_artifacts` (le `.py` source n'est
|
||||||
|
pas un `out/*.json`) ni les suites `tests/` (FONCTIONS de validation, jamais la prose)
|
||||||
|
n'attrapent la dérive. **Prouvé (M4 SILENT-GREEN)** : injecter `# INV12 ·` dans
|
||||||
|
`validate_bundle` (ledger→12, toute la prose reste 11) ⇒ les **3 surfaces
|
||||||
|
deploy_runbook mordent** « [11] MAIS ledger en compte 12 » — preuve que l'autorité
|
||||||
|
est le **CODE-registre**, pas la cohérence interne de la prose.
|
||||||
|
|
||||||
|
**Particularités** — Ledger PROPRE 1..N compté À PART du schéma (« schéma + N
|
||||||
|
invariants »). Les mentions NON numérotées de « invariants » (docstrings « invariants
|
||||||
|
de déploiement/recette », README « Un invariant refuse … ») ne sont pas ancrées par
|
||||||
|
un chiffre → **aucun faux positif**. Le compte-regex accepte les DEUX formes
|
||||||
|
(« N invariants » ET « N familles d'invariants ») via un préfixe optionnel
|
||||||
|
`(?:familles d')?`. Les `daily_reports`/`activity_log` (snapshots datés — ex.
|
||||||
|
acceptance « 10 » d'avant la croissance 10→11) ne sont PAS des surfaces vives et ne
|
||||||
|
sont volontairement pas ancrés (aucune dérive à surveiller sur un log figé).
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « DevOps deploy_runbook + QA
|
||||||
|
acceptance · IDENTITÉ du COMPTE d'INVARIANTS de `validate_bundle` », juste après le
|
||||||
|
bloc Mobile) — **paramétré sur les 2 modules** (zéro duplication). RECOMPUTE le
|
||||||
|
ledger depuis le SEUL registre-source (`# INVn ·` de `validate_bundle`, corps extrait
|
||||||
|
jusqu'au `def` suivant) et exige : **(a)** ledger CONTIGU 1..N (lacune OU doublon nu
|
||||||
|
= vrai défaut de registre) ; **(b)** CHAQUE surface déclarée porte ≥1 mention
|
||||||
|
« N [familles d']invariants » toutes == |ledger|. Une surface sans mention = self-report
|
||||||
|
ÉVAPORÉ (échec · anti-évaporation #6).
|
||||||
|
|
||||||
|
**Vérif** — 7 checks verts sur l'arbre propre (2 ledgers 1..11 + 5 surfaces).
|
||||||
|
**8 morsures** adversariales, gate lancé SEUL, reverts par `cp` ciblé (jamais
|
||||||
|
`git checkout` large — cf. incident consigné) : **M1** deploy `.py` 11→12 (b générateur)
|
||||||
|
· **M2** deploy README 11→12 (b) · **M3** deploy test 11→12 (b) · **M4 SILENT-GREEN**
|
||||||
|
`# INV12 ·` injecté ⇒ 3 surfaces deploy mordent (autorité = CODE) · **M5** `# INV7 ·`
|
||||||
|
supprimé ⇒ ledger non contigu (a) + 3 surfaces désync · **M6** acceptance README 11→12
|
||||||
|
(b) · **M7** acceptance test 11→12 (b) · **M8** compte retiré du README acceptance ⇒
|
||||||
|
self-report ÉVAPORÉ. Arbre restauré (`git status` propre). Suites unittest re-vertes :
|
||||||
|
deploy_runbook **29 tests OK** · acceptance **37 tests OK** (générateurs inchangés).
|
||||||
|
Suite complète re-verte : `check_artifacts` · `check_docs` · `guard_constraints` ·
|
||||||
|
`check_ci_integrity` · `check_regression` · `check_readme_claims` tous exit 0.
|
||||||
|
**Les DEUX familles de ledger sont désormais gatées ; re-scanner tout NOUVEAU
|
||||||
|
dialecte de marqueur (préfixe/phrasé) avant de re-déclarer la classe close.**
|
||||||
|
|
||||||
## Sprint 8 · buffer · RBAC SPEC §2 — ancrage de l'encadré « Défense en profondeur » (NOM du rôle détenteur de `set_user_permissions` · scope · famille) sur l'artefact byte-gaté
|
## Sprint 8 · buffer · RBAC SPEC §2 — ancrage de l'encadré « Défense en profondeur » (NOM du rôle détenteur de `set_user_permissions` · scope · famille) sur l'artefact byte-gaté
|
||||||
|
|
||||||
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention »). Le §2
|
**Contexte** — Série anti-dérive Sprint 8 (CLAUDE.md #6 « zéro invention »). Le §2
|
||||||
|
|||||||
@@ -8646,6 +8646,94 @@ if mbi_src is not None:
|
|||||||
bad(f"Mobile invariants · {MBI_RD} — mention(s) « N invariants » "
|
bad(f"Mobile invariants · {MBI_RD} — mention(s) « N invariants » "
|
||||||
f"{mbi_rd_rep} MAIS ledger en compte {mbi_ninv} → régénérer le README")
|
f"{mbi_rd_rep} MAIS ledger en compte {mbi_ninv} → régénérer le README")
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# DevOps deploy_runbook + QA acceptance · IDENTITÉ du COMPTE d'INVARIANTS de
|
||||||
|
# `validate_bundle` — DEUXIÈME famille de « ledger d'invariants », distincte des
|
||||||
|
# 8 générateurs déjà gatés (Chat OTOIA · SEO · Fiscal · CONFOTUR · Dossier Vente ·
|
||||||
|
# Audit 5D · Commissions · Mobile).
|
||||||
|
# ----------------------------------------------------------------------------
|
||||||
|
# La série « ledger » précédente a été déclarée close à 8 générateurs — MAIS sur
|
||||||
|
# le SEUL patron `# N ·` / « N invariants » / `_validate`(`_validate_bundle`).
|
||||||
|
# DEUX générateurs portent le MÊME nombre magique dans un DIALECTE différent, resté
|
||||||
|
# HORS de tout gate : marqueurs `# INVn ·` (préfixe `INV`) dans `validate_bundle`,
|
||||||
|
# et phrasé « N **familles d'**invariants ». C'est exactement le piège consigné
|
||||||
|
# (« CLOSED après N était FAUX — un style de marqueur différent avait glissé ») :
|
||||||
|
# • devops/deploy_runbook — ledger `# INV1..INV11` dans `validate_bundle`, compte
|
||||||
|
# « 11 familles d'invariants » recopié à TROIS surfaces (générateur l.272 · README
|
||||||
|
# l.73 · suite tests l.4) ;
|
||||||
|
# • qa/acceptance — ledger `# INV1..INV11` dans `validate_bundle`, compte à DEUX
|
||||||
|
# surfaces (README l.46 « 11 invariants » · suite tests l.4 « 11 familles
|
||||||
|
# d'invariants »). Le .py acceptance ne porte PAS de compte numéroté → non exigé.
|
||||||
|
# Ajouter un contrôle `# INV12 ·` à `validate_bundle` sans toucher ces chaînes ⇒
|
||||||
|
# README + self-reports mentent en silence pendant que la CI applique 12 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. Ledger
|
||||||
|
# PROPRE 1..N compté À PART du schéma (phrasé « schéma + N invariants »). Les
|
||||||
|
# mentions NON numérotées de « invariants » (docstrings « invariants de … », « Un
|
||||||
|
# invariant refuse … ») ne sont pas ancrées par un chiffre → aucun faux positif. On
|
||||||
|
# RECOMPUTE le ledger depuis le SEUL registre-source (les `# INVn ·` de
|
||||||
|
# `validate_bundle`) et on exige : (a) ledger CONTIGU 1..N (lacune/doublon = défaut
|
||||||
|
# de registre) ; (b) CHAQUE surface déclarée porte ≥1 mention « N [familles d']
|
||||||
|
# invariants » toutes == |ledger|. Surface sans mention = self-report évaporé (échec
|
||||||
|
# · régression de traçabilité #6). Les daily_reports/activity_log (snapshots datés,
|
||||||
|
# ex. acceptance « 10 » d'avant la croissance 10→11) NE sont PAS des surfaces vives
|
||||||
|
# et ne sont volontairement pas ancrés.
|
||||||
|
# ============================================================================
|
||||||
|
DRA_INV_RE = re.compile(r"(\d+)\s+(?:familles\s+d['’ʼ]\s*)?invariants")
|
||||||
|
DRA_MODS = [
|
||||||
|
("DevOps · deploy_runbook", f"{D}/devops/deploy_runbook/deploy_runbook_gen.py",
|
||||||
|
[("générateur", f"{D}/devops/deploy_runbook/deploy_runbook_gen.py"),
|
||||||
|
("README", f"{D}/devops/deploy_runbook/README.md"),
|
||||||
|
("suite tests", f"{D}/devops/deploy_runbook/tests/test_deploy_runbook.py")]),
|
||||||
|
("QA · acceptance", f"{D}/qa/acceptance/acceptance_gen.py",
|
||||||
|
[("README", f"{D}/qa/acceptance/README.md"),
|
||||||
|
("suite tests", f"{D}/qa/acceptance/tests/test_acceptance.py")]),
|
||||||
|
]
|
||||||
|
for _lbl, _gen, _surfaces in DRA_MODS:
|
||||||
|
try:
|
||||||
|
_src = open(_gen, encoding="utf-8").read()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"{_lbl} invariants · générateur {_gen} illisible : {e}"); continue
|
||||||
|
_mfn = re.search(r"def validate_bundle\b", _src)
|
||||||
|
if _mfn is None:
|
||||||
|
bad(f"{_lbl} invariants · fonction `validate_bundle` INTROUVABLE dans {_gen} "
|
||||||
|
"(registre-source du ledger absent → impossible de re-dériver)"); continue
|
||||||
|
_bs = _mfn.end()
|
||||||
|
_mn = re.search(r"\ndef ", _src[_bs:])
|
||||||
|
_body = _src[_bs: _bs + _mn.start()] if _mn else _src[_bs:]
|
||||||
|
_pairs = re.findall(r"#\s*INV\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"{_lbl} invariants · aucun marqueur `# INVn ·` dans `validate_bundle` de "
|
||||||
|
f"{_gen} (ledger vide → impossible de re-dériver)"); continue
|
||||||
|
if _dup_bare:
|
||||||
|
bad(f"{_lbl} invariants · marqueur(s) `# INVn ·` dupliqué(s) dans "
|
||||||
|
f"`validate_bundle` : {_dup_bare} — vrai doublon de registre"); continue
|
||||||
|
_ninv = len(_top)
|
||||||
|
if _top != list(range(1, _ninv + 1)):
|
||||||
|
bad(f"{_lbl} invariants · ledger `validate_bundle` NON contigu : {_top} "
|
||||||
|
f"(attendu 1..{_ninv}) — lacune/doublon dans les marqueurs `# INVn ·`")
|
||||||
|
else:
|
||||||
|
good(f"{_lbl} invariants · ledger `validate_bundle` contigu 1..{_ninv} "
|
||||||
|
f"({_ninv} marqueurs `# INVn ·` · schéma compté à part)")
|
||||||
|
for _sname, _spath in _surfaces:
|
||||||
|
try:
|
||||||
|
_sraw = open(_spath, encoding="utf-8").read()
|
||||||
|
except OSError as e:
|
||||||
|
bad(f"{_lbl} invariants · {_sname} {_spath} illisible : {e}"); continue
|
||||||
|
_rep = sorted({int(x) for x in DRA_INV_RE.findall(_sraw)})
|
||||||
|
if not _rep:
|
||||||
|
bad(f"{_lbl} invariants · aucune mention « N (familles d')invariants » dans "
|
||||||
|
f"{_spath} ({_sname}) — self-report évaporé (attendu {_ninv} · régression #6)")
|
||||||
|
elif _rep == [_ninv]:
|
||||||
|
good(f"{_lbl} invariants · {_sname} — mention(s) {_rep} == ledger ({_ninv})")
|
||||||
|
else:
|
||||||
|
bad(f"{_lbl} invariants · {_sname} ({_spath}) — mention(s) « N invariants » "
|
||||||
|
f"{_rep} MAIS ledger `validate_bundle` en compte {_ninv} → resynchroniser")
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Traçabilité roadmap · le `roadmap_ref` VERBATIM des artefacts — la CITATION
|
# Traçabilité roadmap · le `roadmap_ref` VERBATIM des artefacts — la CITATION
|
||||||
# (n° de ligne + « libellé bullet ») ANCRÉE sur la ligne RÉELLE de la roadmap,
|
# (n° de ligne + « libellé bullet ») ANCRÉE sur la ligne RÉELLE de la roadmap,
|
||||||
|
|||||||
Reference in New Issue
Block a user