[DTP-Worker 20260802_040511] Sprint 8 · buffer · RBAC SPEC §3 : ancrage de la colonne « Familles rattachées » PAR portail sur rbac_50_roles.json
Nouvelle surface anti-dérive (#6) : la table §3 « Cartographie portails ↔ familles » porte deux colonnes data-derived du contrat ; « Nb rôles » était gatée, « Familles rattachées » (SET des `famille` distinctes par portail) ne l'était pas — le count-gate l'avale via `[^|]*`. Gate « 1quater-bis » : recompute le SET de familles par portail depuis rbac_50_roles.json[roles][].famille, égalité par ENSEMBLE (absent + fantôme) avec les jetons bruts de la cellule (parenthèses éditoriales exclues, ordre non gaté). Silent-green prouvé : reclasser les 2 rôles `legal` de `direction` en `finance` garde le compte 9==9 VERT mais fait mordre FANTÔME {legal}. 6 verts arbre propre · 5 morsures adversariales · 6 gates re-verts exit 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1242,6 +1242,54 @@ if src_roles is not None and spec_rd is not None:
|
||||
bad(f"RBAC SPEC §3 · total — {SPEC_RD} dit {mt.group(1)} MAIS "
|
||||
f"rbac_50_roles.json compte {exp_tot} → corriger la SPEC")
|
||||
|
||||
# 1quater-bis) RBAC_50_ROLES_SPEC.md §3 — colonne « Familles rattachées » PAR portail
|
||||
# La MÊME table §3 porte, à GAUCHE de la colonne « Nb rôles » (gatée ci-dessus), la
|
||||
# colonne « Familles rattachées » : pour chaque portail, l'ENSEMBLE des `famille`
|
||||
# distinctes de ses rôles (ex. `direction` → {direction, finance, faisabilite, legal}).
|
||||
# C'est un SET data-derived du contrat `rbac_50_roles.json[roles][].famille` — mais le
|
||||
# bloc §3 ci-dessus l'AVALE par `[^|]*` (il ne capture QUE le compte), donc AUCUN gate
|
||||
# ne le touche. Silent-green réel : reclasser la `famille` d'un rôle À L'INTÉRIEUR d'un
|
||||
# portail (ex. l'unique rôle `legal` de `direction` repassé en `finance`) change le SET
|
||||
# de familles SANS changer le « Nb rôles » du portail → la cellule §3 ment en silence
|
||||
# pendant que le compte-gate reste VERT ; ajouter/retirer une famille d'un portail
|
||||
# (nouveau rôle d'une famille inédite) laisse la cellule PÉRIMÉE. Ni check_artifacts
|
||||
# (SPEC n'est pas un out/*.json) ni le §3 count-gate ni le §5 (regroupements ÉDITORIAUX,
|
||||
# volontairement NON mappés famille↔groupe) ne mordent. On RECOMPUTE le SET par portail
|
||||
# et on exige, par ENSEMBLE (absent ET fantôme), l'égalité avec les jetons `famille` de
|
||||
# la cellule. On ne gate QUE les jetons `famille` bruts (identifiant de tête de chaque
|
||||
# item séparé par `,`), PAS les parenthèses ÉDITORIALES (« finance (CFO) », « faisabilite
|
||||
# (analyste) » — paraphrase, pas contrat, #6). Un portail sans cellule échoue AUSSI
|
||||
# (INTROUVABLE = régression de traçabilité #6).
|
||||
if src_roles is not None and spec_rd is not None:
|
||||
fam_by_portail = {}
|
||||
for r in src_roles:
|
||||
p = r.get("portail"); f = r.get("famille")
|
||||
fam_by_portail.setdefault(p, [])
|
||||
if f not in fam_by_portail[p]:
|
||||
fam_by_portail[p].append(f)
|
||||
for portail in sorted(fam_by_portail):
|
||||
exp_fam = fam_by_portail[portail]
|
||||
# cellule « Familles rattachées » = 2ᵉ colonne (entre le portail et « Nb rôles »)
|
||||
pat = rf"\| \*\*{re.escape(portail)}\*\*[^|]*\| ([^|]*)\| \d+ \|"
|
||||
m = re.search(pat, spec_rd)
|
||||
if m is None:
|
||||
bad(f"RBAC SPEC §3 familles · portail `{portail}` — cellule INTROUVABLE "
|
||||
f"dans {SPEC_RD} (attendu familles {{{', '.join(exp_fam)}}})")
|
||||
continue
|
||||
# jeton `famille` de tête de chaque item séparé par « , » (hors parenthèses éditoriales)
|
||||
got_fam = re.findall(r"(?:^|,)\s*([a-z]+)", m.group(1).strip())
|
||||
absent = [f for f in exp_fam if f not in got_fam]
|
||||
phantom = [f for f in got_fam if f not in exp_fam]
|
||||
if not absent and not phantom:
|
||||
good(f"RBAC SPEC §3 familles · portail `{portail}` — {{{', '.join(sorted(got_fam))}}} "
|
||||
f"== familles distinctes du contrat")
|
||||
else:
|
||||
det = []
|
||||
if absent: det.append(f"MANQUE {{{', '.join(absent)}}}")
|
||||
if phantom: det.append(f"FANTÔME {{{', '.join(phantom)}}}")
|
||||
bad(f"RBAC SPEC §3 familles · portail `{portail}` — la cellule diverge du "
|
||||
f"contrat : {' · '.join(det)} (attendu {{{', '.join(exp_fam)}}}) → corriger la SPEC")
|
||||
|
||||
# 1quinquies) RBAC_50_ROLES_SPEC.md §7 — comptes du run-book d'application --------
|
||||
# La NOTE §7 (« ✅ … livré en-repo ») restitue, sur une SURFACE DISTINCTE des READMEs
|
||||
# userperm_gen / roleprofile_gen (déjà gatés), TROIS comptes data-derived du run-book
|
||||
|
||||
Reference in New Issue
Block a user