[DTP-Worker 20260801_233454] Sprint 8 · buffer · RBAC SPEC §5 : gate de la LIGNE D'AUTO-CONTRÔLE du « résumé »
La SPEC RBAC a déjà 3 gates (§3 ventilation par portail · §4 colonne Entité · §7 run-book) mais son §5 « Les N rôles (résumé) » restait AVEUGLE. Ce §5 restitue le total de rôles sur 3 surfaces prose : le compte-titre « ## 5. Les 50 rôles », NEUF comptes parenthétiques de regroupement (`**Ventes (8)**` …) et une ligne d'auto-contrôle arithmétique `_(6+8+4+7+5+8+4+2+6 = 50.)_`. AJOUTER un rôle au contrat (|rôles| 50→51) laisse titre/somme/`= 50` périmés en silence ; ÉDITER `Ventes (8)→(7)` sans toucher la ligne casse la cohérence titre↔somme — ni les suites tests/ (FONCTIONS RBAC, jamais la prose) ni le byte-gate d'artefact ne l'attrapent. Subtilité (memory rbac-spec-portail-count-gate : « §5 by-family is editorial ») : les 9 regroupements sont ÉDITORIAUX (« Direction / Gouvernance » agrège des rôles de familles direction+finance ≠ colonne `famille`) ⇒ AUCUN mapping groupe↔famille (dérive fausse). On gate UNIQUEMENT ce qui est data-derived sans ce mapping. Nouveau bloc « 1septies) §5 » : on recompute N = |rôles| du contrat (rbac_50_roles.json, byte-gaté) et on exige (a) compte-titre == N ; (b) les 9 comptes de regroupement == EXACTEMENT dans l'ordre les termes de la ligne (comparaison de LISTES ⇒ mord valeur ET position) ; (c) Σ termes == membre droit ; (d) membre droit == N. Section/titre/ligne/comptes absents = échec (#6). 5 morsures vérifiées (working tree byte-restauré via git checkout -- <fichier>, gate rc=1 sous mutation · rc=0 restauré) : titre 50→51 (a) · Ventes (8)→(9) (b) · = 50.→= 49. (c+d double) · terme 6+→7+ (b+c double) · suppression ligne (absence). ci/README.md : row check-readme-claims étendue de la clause §5. 7 gates re-verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2553,3 +2553,61 @@ Restauré = green : (a)(b)(c)(d) tous ✓ (ledger contigu 1..15 · 15 marqueurs)
|
|||||||
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||||
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||||
- **Auto-score 4Big** : 96/100.
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sprint 8 · buffer · RBAC SPEC §5 : gate de la LIGNE D'AUTO-CONTRÔLE du « résumé »
|
||||||
|
|
||||||
|
**Contexte** : suite de la campagne anti-dérive documentaire (Sprint 8 · QA
|
||||||
|
« regression tests exhaustifs »). Baseline des 7 gates verte avant intervention.
|
||||||
|
Recherche (sous-agent Explore) de la prochaine surface data-derived transcrite en
|
||||||
|
prose mais NON gatée — la plupart des COMPTES d'artefact sont déjà fermés. Le
|
||||||
|
candidat retenu est une surface interne de `rbac/RBAC_50_ROLES_SPEC.md` : le §5.
|
||||||
|
|
||||||
|
**Défaut** : la SPEC RBAC a DÉJÀ trois gates (§3 ventilation par portail · §4
|
||||||
|
colonne Entité · §7 run-book), mais son §5 « Les N rôles (résumé) » restait
|
||||||
|
AVEUGLE. Ce §5 restitue le total de rôles sur TROIS surfaces prose : (i) le
|
||||||
|
compte-titre « ## 5. Les 50 rôles (résumé) », (ii) NEUF comptes parenthétiques de
|
||||||
|
regroupement (`**Ventes (8)**` …) et (iii) une LIGNE d'auto-contrôle arithmétique
|
||||||
|
`_(6+8+4+7+5+8+4+2+6 = 50.)_`. AJOUTER un rôle au contrat (|rôles| 50→51) laisse le
|
||||||
|
titre, la somme et le « = 50 » PÉRIMÉS en silence ; ÉDITER `Ventes (8)→(7)` sans
|
||||||
|
toucher la ligne casse la cohérence titre↔somme — aucune suite `tests/` (FONCTIONS
|
||||||
|
RBAC, jamais la prose de la SPEC) ni le byte-gate d'artefact ne l'attrape.
|
||||||
|
|
||||||
|
**Subtilité (memory `rbac-spec-portail-count-gate` : « §5 by-family is
|
||||||
|
editorial »)** : les 9 regroupements sont ÉDITORIAUX — « Direction / Gouvernance »
|
||||||
|
agrège des rôles de familles direction+finance, ≠ la colonne `famille` du contrat.
|
||||||
|
On NE mappe donc PAS groupe↔famille (ce serait une dérive fausse). On gate
|
||||||
|
UNIQUEMENT ce qui est data-derived et vérifiable SANS ce mapping.
|
||||||
|
|
||||||
|
**Gate ajouté** (`ci/check_readme_claims.sh`, bloc « 1septies) §5 », inséré après
|
||||||
|
le bloc §4 et avant le bloc apply_plan) : on RECOMPUTE N = |rôles| du contrat
|
||||||
|
(`rbac_50_roles.json`, byte-gaté par check_artifacts) et on exige — **(a)** le
|
||||||
|
compte-titre « ## 5. Les N rôles » == N ; **(b)** les 9 comptes de regroupement ==
|
||||||
|
EXACTEMENT, dans l'ordre, les termes de la ligne arithmétique (cohérence interne
|
||||||
|
prose↔somme, comparaison de LISTES ordonnées) ; **(c)** l'arithmétique est VRAIE
|
||||||
|
(Σ termes == membre droit) ; **(d)** le membre droit == N. Section/titre/ligne/
|
||||||
|
comptes absents = échec (#6).
|
||||||
|
|
||||||
|
**5 morsures vérifiées** (working tree byte-restauré après chacune via
|
||||||
|
`git checkout -- <fichier précis>`, JAMAIS `git checkout .` / `git clean` ;
|
||||||
|
gate rc=1 sous mutation, rc=0 restauré) :
|
||||||
|
1. titre `50`→`51` → ✗ (a) « titre dit 51 rôles MAIS le contrat en compte 50 » ;
|
||||||
|
2. regroupement `Ventes (8)`→`(9)` → ✗ (b) « [6, 9, 4…] ≠ termes [6, 8, 4…] » ;
|
||||||
|
3. ligne `= 50.`→`= 49.` → ✗ (c) « écrit = 49 MAIS Σ = 50 » + ✗ (d) « totalise
|
||||||
|
49 MAIS le contrat compte 50 » (double morsure) ;
|
||||||
|
4. terme `6+8+…`→`7+8+…` → ✗ (b) « termes [7, 8…] ≠ [6, 8…] » + ✗ (c) « = 50
|
||||||
|
MAIS Σ = 51 » (double morsure) ;
|
||||||
|
5. suppression de la ligne d'auto-contrôle → ✗ « ligne … INTROUVABLE » (absence).
|
||||||
|
Restauré = green : (a)(b)(c)(d) tous ✓ (titre 50 · 9 comptes == 6+8+4+7+5+8+4+2+6
|
||||||
|
· Σ=50 · membre droit 50 == |rôles|).
|
||||||
|
|
||||||
|
- `ci/README.md` : la row `check-readme-claims` étendue de la clause §5 (compte-
|
||||||
|
titre + 9 comptes de regroupement éditoriaux + ligne d'auto-contrôle, sans
|
||||||
|
mapping groupe↔famille).
|
||||||
|
- **7 gates re-verts** : `guard_constraints` / `validate_json` / `check_docs` /
|
||||||
|
`check_artifacts` / `check_regression` / `check_ci_integrity` /
|
||||||
|
`check_readme_claims` (tous rc=0).
|
||||||
|
- **Hors périmètre worker (VPS · #8)** : néant (gate bash/python3 stdlib en-repo ;
|
||||||
|
édition **hors** `05_deliverables_mvp/*/out` ⇒ 0 dérive d'artefact).
|
||||||
|
- **Auto-score 4Big** : 96/100.
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -1377,6 +1377,78 @@ if src_roles is not None and spec_rd is not None:
|
|||||||
good(f"RBAC SPEC §4 · (c) les {len(cm4)} entités nommées du mandat sont "
|
good(f"RBAC SPEC §4 · (c) les {len(cm4)} entités nommées du mandat sont "
|
||||||
f"portées ≥1× par le contrat")
|
f"portées ≥1× par le contrat")
|
||||||
|
|
||||||
|
# 1septies) RBAC_50_ROLES_SPEC.md §5 — « Les N rôles (résumé) » : compte-titre,
|
||||||
|
# comptes de regroupement éditoriaux et LIGNE d'auto-contrôle arithmétique -------
|
||||||
|
# Le §5 « résumé » restitue le total de rôles sur TROIS surfaces prose qu'aucun
|
||||||
|
# gate ne touchait — (i) le TITRE « ## 5. Les N rôles (résumé) », (ii) NEUF comptes
|
||||||
|
# parenthétiques de regroupement (« **Ventes (8)** » …) et (iii) une LIGNE
|
||||||
|
# d'auto-contrôle arithmétique « _(6+8+…+6 = 50.)_ ». Le §3 gate la ventilation par
|
||||||
|
# PORTAIL, le §7 le run-book, le §4 les entités — TOUS aveugles à ce §5. NB : les 9
|
||||||
|
# regroupements sont ÉDITORIAUX (« Direction / Gouvernance » agrège des rôles de
|
||||||
|
# familles direction+finance ; ≠ la colonne `famille` du contrat, cf. memory
|
||||||
|
# rbac-spec-portail-count-gate « §5 by-family is editorial ») → on NE mappe PAS
|
||||||
|
# groupe↔famille (ce serait une dérive fausse). On gate ce qui EST data-derived et
|
||||||
|
# vérifiable SANS ce mapping : (a) le compte-titre N == |rôles| du contrat (byte-
|
||||||
|
# gaté par check_artifacts) ; (b) les 9 comptes de regroupement == EXACTEMENT, dans
|
||||||
|
# l'ordre, les termes de la ligne arithmétique (cohérence interne prose↔somme) ;
|
||||||
|
# (c) l'arithmétique est VRAIE (Σ termes == membre droit) ; (d) le membre droit ==
|
||||||
|
# |rôles|. AJOUTER un rôle au contrat (|rôles| 50→51) laisse le titre, la somme et
|
||||||
|
# le « = 50 » PÉRIMÉS en silence ; ÉDITER « Ventes (8) »→« (7) » sans toucher la
|
||||||
|
# ligne casse (b) puis (c). Section/titre/ligne/comptes absents = échec (#6).
|
||||||
|
if src_roles is not None and spec_rd is not None:
|
||||||
|
N5 = len(src_roles)
|
||||||
|
_m5 = re.search(r"## 5\..*?(?=## 6\.)", spec_rd)
|
||||||
|
if _m5 is None:
|
||||||
|
bad(f"RBAC SPEC §5 · section « ## 5. » INTROUVABLE dans {SPEC_RD} "
|
||||||
|
f"(claim absent = régression #6)")
|
||||||
|
else:
|
||||||
|
sec5 = _m5.group(0)
|
||||||
|
# (a) compte-titre « ## 5. Les N rôles »
|
||||||
|
mt5 = re.search(r"## 5\. Les (\d+) rôles", sec5)
|
||||||
|
if mt5 is None:
|
||||||
|
bad(f"RBAC SPEC §5 · titre « ## 5. Les N rôles » INTROUVABLE dans {SPEC_RD}")
|
||||||
|
elif mt5.group(1) == str(N5):
|
||||||
|
good(f"RBAC SPEC §5 · (a) compte-titre {mt5.group(1)} == |rôles| "
|
||||||
|
f"rbac_50_roles.json ({N5})")
|
||||||
|
else:
|
||||||
|
bad(f"RBAC SPEC §5 · (a) titre dit {mt5.group(1)} rôles MAIS le contrat "
|
||||||
|
f"en compte {N5} → corriger la SPEC")
|
||||||
|
# 9 comptes de regroupement (gras · « (N) » collant au **fermant)
|
||||||
|
heads = [int(m.group(1)) for m in
|
||||||
|
re.finditer(r"\*\*[^*]+?\((\d+)\)\*\*", sec5)]
|
||||||
|
# ligne d'auto-contrôle « _(a+b+… = T.)_ »
|
||||||
|
ma5 = re.search(r"_\(((?:\d+\+)+\d+) = (\d+)\.\)_", sec5)
|
||||||
|
if ma5 is None:
|
||||||
|
bad(f"RBAC SPEC §5 · ligne d'auto-contrôle « _(a+b+… = T.)_ » "
|
||||||
|
f"INTROUVABLE dans {SPEC_RD} (claim absent = régression #6)")
|
||||||
|
elif not heads:
|
||||||
|
bad(f"RBAC SPEC §5 · aucun compte de regroupement « **… (N)** » trouvé "
|
||||||
|
f"dans {SPEC_RD} (claim absent = régression #6)")
|
||||||
|
else:
|
||||||
|
addends = [int(x) for x in ma5.group(1).split("+")]
|
||||||
|
rhs = int(ma5.group(2))
|
||||||
|
# (b) comptes de regroupement == termes de la ligne, EN ORDRE
|
||||||
|
if heads == addends:
|
||||||
|
good(f"RBAC SPEC §5 · (b) {len(heads)} comptes de regroupement == "
|
||||||
|
f"termes de la ligne d'auto-contrôle ({'+'.join(map(str, addends))})")
|
||||||
|
else:
|
||||||
|
bad(f"RBAC SPEC §5 · (b) comptes de regroupement {heads} ≠ termes de "
|
||||||
|
f"la ligne {addends} (ordre/valeur) → aligner titres et somme")
|
||||||
|
# (c) arithmétique vraie
|
||||||
|
if sum(addends) == rhs:
|
||||||
|
good(f"RBAC SPEC §5 · (c) Σ termes {'+'.join(map(str, addends))} = "
|
||||||
|
f"{rhs} (arithmétique exacte)")
|
||||||
|
else:
|
||||||
|
bad(f"RBAC SPEC §5 · (c) la ligne écrit « = {rhs} » MAIS Σ termes = "
|
||||||
|
f"{sum(addends)} → corriger la somme")
|
||||||
|
# (d) membre droit == |rôles| du contrat
|
||||||
|
if rhs == N5:
|
||||||
|
good(f"RBAC SPEC §5 · (d) membre droit {rhs} == |rôles| "
|
||||||
|
f"rbac_50_roles.json ({N5})")
|
||||||
|
else:
|
||||||
|
bad(f"RBAC SPEC §5 · (d) la ligne totalise {rhs} MAIS le contrat "
|
||||||
|
f"compte {N5} rôles → SPEC périmée")
|
||||||
|
|
||||||
# 2) apply_plan — ligne « Génération réelle » agrégeant les 3 volets ------------
|
# 2) apply_plan — ligne « Génération réelle » agrégeant les 3 volets ------------
|
||||||
AP_RD = f"{D}/rbac/apply_plan/README.md"
|
AP_RD = f"{D}/rbac/apply_plan/README.md"
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user