[DTP-Worker 20260802_133549] Sprint 8 · buffer · roles_couverts (« 44 ») : enquête anti-dérive → NON-surface prouvée (3 manifestes importent la même fonction roles_by_portail sur l'unique contrat rbac_50_roles.json → transitivement mono-sourcé, un cross-gate serait redondant #5, contra le cross-check RBAC-50 qui re-dérive) + documentation du garde-fou dans ci/README.md pour prévenir un gate N+1 redondant
This commit is contained in:
@@ -1371,3 +1371,41 @@ figés à 13 ⇒ les **5 surfaces head-docs+GAP mordent** « dit 13 MAIS 03_agen
|
||||
(preuve que l'autorité est le git-index, pas la cohérence interne). Arbre restauré. **7 gates
|
||||
re-joués → exit 0** : check_ci_integrity · check_artifacts · check_docs · check_readme_claims ·
|
||||
check_regression · guard_constraints · validate_json. Aucune commande touchant au VPS.
|
||||
|
||||
## Sprint 8 · buffer · `roles_couverts` (« 44 ») — enquête anti-dérive → **non-surface prouvée** + documentation du garde-fou mono-source (évite un gate N+1 redondant #5)
|
||||
|
||||
**Contexte** — Série anti-dérive Sprint 8. Un balayage des comptes numériques a
|
||||
exhumé un candidat de **cohérence croisée** : le total « **44 rôles couverts par les
|
||||
5 portails** » apparaît, identique, dans **trois** manifestes byte-gatés
|
||||
(`frontend/portails`, `frontend/chat_otoia`, `mobile/app_config` ·
|
||||
`counts.roles_couverts=44`). Chaque « 44 » vif n'est ancré qu'à SON propre manifeste
|
||||
(mobile README · `demo/scenarios/out/run_sheet.md`). Aucun `ci/*.sh` ne compare les
|
||||
trois entre eux. Hypothèse initiale : surface non couverte, analogue au cross-check
|
||||
RBAC « 50 » (`rbac/apply_plan/rbac_apply_plan.py:149` exige
|
||||
`fixtures==userperm==roleprofile`).
|
||||
|
||||
**Enquête — l'analogie RBAC-50 ne tient PAS** (mémoire *fix-vs-gate-transitively-
|
||||
protected-constant*). Le « 50 » EST cross-gaté car ses trois rendus **re-dérivent**
|
||||
chacun leur décompte avec leur **propre** logique. Ici, au contraire, les trois
|
||||
modules **importent la même** fonction de partition : `mobilelib/deps.py:77` et
|
||||
`chatlib/deps.py:84` font tous deux `roles_by_portail = portails_builder.roles_by_portail`
|
||||
(unique définition `frontend/portails/wslib/builder.py:36`), appliquée à l'**unique**
|
||||
contrat `rbac/rbac_50_roles.json` (une seule copie de chaque dans `git ls-files`).
|
||||
`roles_couverts` est donc **transitivement mono-sourcé** (code partagé + donnée
|
||||
partagée) : les trois totaux **ne peuvent diverger** que si cette fonction ou ce
|
||||
contrat change — auquel cas les trois changent ensemble et `check_artifacts`
|
||||
(reproductibilité byte-à-byte) vérifie chaque rebuild. Un gate « 44==44==44 » serait
|
||||
**redondant (#5)** et masquerait la vraie garantie (le partage de code), pas une
|
||||
surface à protéger.
|
||||
|
||||
**Livraison — DOCUMENTATION du garde-fou, pas un gate.** Ajout d'un bloc sourcé
|
||||
« **Non-surface documentée — `roles_couverts` N'EST PAS cross-gaté, à dessein** » dans
|
||||
`ci/README.md` (entre le bloc mobile Expo et le bloc CONFOTUR) : cite les 3 imports
|
||||
partagés + le contrat unique + contraste explicite avec le cross-check RBAC-50, pour
|
||||
qu'une session future ne rajoute PAS le gate redondant. Chemins en backticks (non
|
||||
link-checkés, cf. mémoire *backtick-path-escapes-check-docs*).
|
||||
|
||||
**Vérif** — 4 citations de lignes vérifiées exactes (`deps.py:77`, `deps.py:84`,
|
||||
`wslib/builder.py:36`, `rbac_apply_plan.py:149`). **7 gates re-joués → exit 0** :
|
||||
guard_constraints · validate_json · check_docs · check_artifacts · check_regression ·
|
||||
check_ci_integrity · check_readme_claims. Aucune commande touchant au VPS.
|
||||
|
||||
@@ -491,6 +491,26 @@ Marketing), un **retrait** (Compta absent — l'énumération tombe à 4 tandis
|
||||
est aveugle. Cohérence croisée : `len(role_navigation) == counts.onglets ==
|
||||
counts.portails` — mord un compteur du manifeste désynchronisé de sa navigation.
|
||||
|
||||
**Non-surface documentée — `roles_couverts` (« 44 ») N'EST PAS cross-gaté, à dessein.**
|
||||
Le total « 44 rôles couverts par les 5 portails » apparaît, identique, dans **trois**
|
||||
manifestes (`frontend/portails`, `frontend/chat_otoia`, `mobile/app_config` ·
|
||||
`counts.roles_couverts=44`). On pourrait croire à trois rendus indépendants réclamant
|
||||
un cross-check façon RBAC « 50 » (où `rbac/apply_plan/rbac_apply_plan.py:149` exige
|
||||
`fixtures==userperm==roleprofile`, car chacun **re-dérive** son décompte avec sa propre
|
||||
logique). Ce n'est **pas** le cas ici : les trois modules **importent la même** fonction
|
||||
de partition — `mobilelib/deps.py:77` et `chatlib/deps.py:84` font tous deux
|
||||
`roles_by_portail = portails_builder.roles_by_portail` (l'unique définition,
|
||||
`frontend/portails/wslib/builder.py:36`) — appliquée à l'**unique** contrat
|
||||
`rbac/rbac_50_roles.json`. `roles_couverts` est donc **transitivement mono-sourcé**
|
||||
(code partagé + donnée partagée) : les trois totaux ne peuvent diverger que si cette
|
||||
fonction ou ce contrat change, auquel cas les trois changent ensemble et
|
||||
`check_artifacts` (reproductibilité byte-à-byte) vérifie chaque rebuild. Un gate
|
||||
« 44==44==44 » serait **redondant** (#5) — cf. mémoire *fix-vs-gate-transitively-
|
||||
protected-constant*. Chaque « 44 » vif reste néanmoins ancré à SON manifeste
|
||||
(mobile README ci-dessus · `demo/scenarios/out/run_sheet.md` sourcé à
|
||||
`portails/…/roles_couverts`), ce qui suffit : la valeur ne peut mentir que si son
|
||||
manifeste ment, et le manifeste est byte-gaté.
|
||||
|
||||
Même classe enfin sur le **DocType CONFOTUR Application** (livrable `legal/confotur`) :
|
||||
la ligne de synthèse du README du module (« **18 champs** (14 de donnée) · **4
|
||||
sections** · **3 rôles** · … · **2 évènements de dépôt** ») **et** la cellule de la
|
||||
|
||||
Reference in New Issue
Block a user