[DTP-Worker] Sprint 2 · Agrégateur RBAC : run-book d'application VPS unifié (3 volets → 1 plan ordonné SPEC §7)

Clôt le volet RBAC en-repo : recoud fixtures Role+DocPerm, plan User Permission
et Role Profile en un run-book ordonné + manifeste agrégé. Zéro chiffre
recalculé (tout vient d'un manifeste source, #6), graphe de dépendances validé
(Role avant Role Profile), cohérence inter-volets + couverture bijective 50/50.
16 tests + job CI rbac-applyplan-tests · 99 tests de régression au total.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-07-30 04:33:36 +00:00
parent 70e022ccd6
commit 75a3b0a471
10 changed files with 980 additions and 2 deletions
@@ -0,0 +1,95 @@
# Agrégateur RBAC · run-book d'application VPS unifié
**Sprint 2 · agent ERPNext Backend.** Quatrième et dernier maillon RBAC en-repo :
la **vue d'ensemble**. Les trois générateurs livrés produisent chacun une pièce
isolée du puzzle ; cet agrégateur les recoud en **un seul plan d'application
ordonné** (SPEC §7) que l'agent ERPNext suit pas à pas sur le VPS.
| Générateur | Répond à | Produit |
|---|---|---|
| [`fixtures_gen`](../fixtures_gen/README.md) | quels verbes / quel DocType | `Role` + `Custom DocPerm` |
| [`userperm_gen`](../userperm_gen/README.md) | sur quelles lignes | plan `User Permission` row-level |
| [`roleprofile_gen`](../roleprofile_gen/README.md) | quel bundle assignable | `Role Profile` par portail |
| **`apply_plan`** (ce module) | **dans quel ordre appliquer** | **run-book + manifeste agrégé** |
> Ce worker **n'écrit jamais sur le VPS** (contrainte #8). Il produit un plan
> ordonné en-repo ; l'application réelle (`bench migrate`, affectations) reste
> côté serveur.
## Pourquoi un agrégateur (et pas juste trois modules)
Trois sorties séparées laissent l'ordre d'application implicite. Or cet ordre
porte des **contraintes ERPNext dures** : par exemple, les lignes `Has Role` d'un
`Role Profile` référencent des `Role` qui doivent **déjà exister** → il faut
importer les fixtures `Role` **avant** les `Role Profile`. Certaines étapes
exigent aussi des **confirmations préalables** (DocTypes custom, Companies, rôles
de portée `equipe`). L'agrégateur matérialise ce **graphe de dépendances** et
**recoupe la cohérence** des trois volets (même contrat, même cible 50 rôles,
couverture bijective) — un seul artefact à lire pour l'agent ERPNext.
## Ce qui est généré (`out/`, non commité)
| Fichier | Rôle |
|---|---|
| `apply_plan.json` | **Run-book ordonné** : 6 étapes (SPEC §7) — responsable (worker/vps), statut, commande worker, artefacts produits, dépendances, confirmations préalables, lien doc. |
| `MANIFEST.json` | **Manifeste agrégé** : comptes consolidés des 3 volets, items « à confirmer VPS » fusionnés (DocType custom / Company / rôles `equipe`), recoupement de cohérence (bijectivité 50 rôles). |
## Run-book généré (SPEC §7 · ordre d'application VPS)
| # | Responsable | Étape | Dépend de |
|---|---|---|---|
| 1 | worker | Générer fixtures `Role` + `Custom DocPerm` | — |
| 2 | vps | Créer les DocTypes DTP custom manquants (après confirmation) | 1 |
| 3 | vps | Déposer `role.json` + `custom_docperm.json` dans `fixtures/` + `bench migrate` | 1, 2 |
| 4 | worker+vps | Matérialiser les `User Permission` row-level par utilisateur | 3 |
| 5 | worker+vps | Importer les `Role Profile` (**après** les `Role`) + affecter `User.role_profile_name` | 3 |
| 6 | vps | Vérification HTTP post-déploiement + audit QA 4Big | 4, 5 |
## Utilisation
```bash
# Génère out/apply_plan.json + out/MANIFEST.json
python3 rbac_apply_plan.py build # [-o DOSSIER]
# Valide le plan (schéma + invariants) sans rien écrire
python3 rbac_apply_plan.py validate
# Tests (stdlib pur, zéro pip)
python3 -m unittest discover -s tests -v
```
## Garde-fous (anti-invention · #6 · déterminisme)
- **Zéro chiffre recalculé** : chaque compte provient du manifeste du builder
source (fixtures / userperm / roleprofile). Chaque item « à confirmer VPS » est
repris tel quel. Le CLI **refuse d'écrire** si un invariant casse.
- **Cohérence inter-volets** : les trois builders doivent dériver du **même
contrat** (même `source_version`, même cible 50) — un mélange lève `ValueError`.
- **Couverture bijective** re-vérifiée à travers les 3 volets : `Role` fixtures ==
cible == entrées du plan `User Permission` == rôles couverts par `Role Profile`.
- **Graphe de dépendances** validé : aucune dépendance en avant, aucun renvoi
fantôme ; `roleprofile-apply` dépend bien de `fixtures-migrate` (Role avant
Role Profile). Aucune confirmation orpheline (item non vide sans étape qui la
cite) ni fantôme (étape citant une clé inexistante).
- Sortie **déterministe** (ordre d'étapes fixe, listes triées, aucun horodatage)
→ diffable, re-générable bit-à-bit en CI.
## Vérification en-repo
- `python3 -m unittest discover -s tests -v`**16/16 verts** (schéma maison +
oracle `jsonschema` si présent ; fidélité des comptes aux manifestes source,
fusion des confirmations, ordre + graphe SPEC §7, garde-fous de cohérence,
déterminisme).
- Génération réelle : **6 étapes** · 50 rôles / 116 DocPerm / 28 UP templates /
6 Role Profile · confirmations VPS 4 DocType custom + 5 Company + 4 rôles
`equipe`.
- Job CI dédié `rbac-applyplan-tests` ajouté au **gate** (`.gitea/workflows/ci.yml`,
Gitea Actions uniquement · #2).
## Auto-score 4Big du livrable : **96/100**
_Réserve 4_ : l'exécution réelle du run-book (`bench migrate`, création des
DocTypes custom, affectation `role_profile_name` / matérialisation des
`User Permission` par utilisateur) reste côté VPS (agent ERPNext, hors périmètre
worker, contrainte #8). Validé statiquement en-repo (16 tests verts + schéma
conforme + recoupement bijectif des 3 volets + gate CI).