diff --git a/05_activity_log/2026-08-06.md b/05_activity_log/2026-08-06.md index 32772bc..aa86b0e 100644 --- a/05_activity_log/2026-08-06.md +++ b/05_activity_log/2026-08-06.md @@ -1,5 +1,50 @@ # Activity Log · 2026-08-06 · Claude Code DTP Worker +## Session `20260806_031432` — FIX générateur (NOUVELLE sous-classe : liste per-slot vs ensemble distinct) · `crm/financement_bancaire` : `MANIFEST.roles_rbac_utilises` répétait `ventes-conseiller` (dup ungaté) + +**Choix de tâche.** `./run_ci.sh` au démarrage = **33 PASS · 0 FAIL · 0 SKIP**, arbre propre, +roadmap intégralement livrée/gatée. Les 5 derniers commits étant FIX-help / currency / vérif-only, +chasse **adversariale à un vrai défaut ungaté** sur un **axe frais** (anti-churn) : la +**cohérence sémantique interne des artefacts commités** (un champ « ensemble » contenant un +doublon) — axe non balayé par les 7 axes de `024430`. + +**Défaut trouvé (réel, haute confiance).** +`05_deliverables_mvp/crm/financement_bancaire/out/MANIFEST.json` · `roles_rbac_utilises` portait +**4 entrées pour 3 rôles distincts** : `ventes-conseiller` / `OTO Ventes Conseiller` **répété** +(positions 1 et 4). Reproductible depuis le générateur (donc **pas** un artefact stale — byte-repro +vert) : `finlib/builder.py:89` faisait `[roles_resolved[k] for k in sorted(roles_resolved)]`, +itérant les **4 slots logiques** de `spec["roles"]` — or **deux** slots (`conseiller_wag` ET +`validation_dossier`) pointent le même rôle `ventes-conseiller` → doublon. + +**Preuve que c'est un bug et non un per-slot voulu.** +1. La sortie **drope la clé de slot** (`cle`) : chaque entrée ne porte que `role_id` + + `erpnext_role_name`. Un doublon ne transporte donc **aucune** information distinctive — si le + per-slot était voulu, la clé de slot serait sérialisée. Smoking gun. +2. Sémantique documentée : README `MANIFEST.json → … rôles RBAC **utilisés** » (README.md:54) + + `ci/README.md:1100` « l'**ensemble distinct** `(role_id, nom)` réellement payé ». +3. **Convention codebase** : les 3 modules frères produisent tous un ensemble **distinct** + (`confotur` 3/3 · `commissions` 4/4 · `workflow_vente` 7/7, `n == distinct`). `financement` + était **le seul outlier** (4/3). + +**Fix (`finlib/builder.py:89`, aligné idiome `commissions`).** Ensemble **distinct** trié par +`role_id` : `[{"role_id": rid, "erpnext_role_name": resolver.erpnext_name(rid)} for rid in +sorted({rr["role_id"] for rr in roles_resolved.values()})]` + commentaire expliquant le +dédoublonnage multi-slots. Artefact régénéré (`build`) → `roles_rbac_utilises` = **3/3 distinct** +(`compta-tresorier`, `ventes-conseiller`, `ventes-directeur`). + +**Pourquoi 0 gate ajouté (#5).** Le champ `roles_rbac_utilises` de `financement` n'est lu par +**aucun** gate (les blocs `check_readme_claims` qui le lisent visent confotur/commissions/ +workflow_vente, en **SET** — donc dedup) ni aucun consommateur externe (`grep` = 0). Le champ +`counts` n'inclut pas de compte de rôles pour ce module (contrairement aux frères) → **aucune** +prose/oracle à réaligner. Le fix corrige la **source** ; un gate distinctness serait redondant +avec la convention déjà tenue par les frères et non-régressante ici (verify-before-gate). + +**Non-régression.** `./run_ci.sh` = **33 PASS · 0 FAIL · 0 SKIP** après (byte-repro +`check_artifacts` **vert avec le nouvel artefact** ; les **35** tests `crm-financement-bancaire` +verts — aucun ne figeait `roles_rbac_utilises`, l.204 teste `role_validation`, non affecté). +**2 fichiers édités** (`finlib/builder.py` + `out/MANIFEST.json` régénéré), **0 chiffre inventé** +(#6 — 4/3 recomputés), **aucune commande VPS** (#8). + ## Session `20260806_024430` — VÉRIF indépendante multi-axes (7 axes) → **CLEAN · 0 édition de production** **Choix de tâche.** `./run_ci.sh` au démarrage = **33 PASS · 0 FAIL · 0 SKIP**, arbre propre, diff --git a/05_deliverables_mvp/crm/financement_bancaire/finlib/builder.py b/05_deliverables_mvp/crm/financement_bancaire/finlib/builder.py index 461df53..60fae48 100644 --- a/05_deliverables_mvp/crm/financement_bancaire/finlib/builder.py +++ b/05_deliverables_mvp/crm/financement_bancaire/finlib/builder.py @@ -86,7 +86,16 @@ def build_bundle(spec: dict, resolver: RoleResolver) -> dict[str, Any]: "banniere_lignes": len(gate_spec["banniere"]["lignes"]), "workflow_suivi_etapes": len(gate_spec["workflow_suivi_banque"]), }, - "roles_rbac_utilises": [roles_resolved[k] for k in sorted(roles_resolved)], + # Ensemble DISTINCT des rôles RBAC réellement utilisés. Plusieurs slots + # logiques peuvent pointer le même rôle (ex. conseiller_wag ET + # validation_dossier == ventes-conseiller) : on dédoublonne par role_id + # et on trie par role_id, comme les modules frères (commissions, + # confotur, workflow_vente). Sans ce dédoublonnage, la liste répétait le + # rôle et contredisait sa sémantique « rôles utilisés » (ensemble). + "roles_rbac_utilises": [ + {"role_id": rid, "erpnext_role_name": resolver.erpnext_name(rid)} + for rid in sorted({rr["role_id"] for rr in roles_resolved.values()}) + ], } return { diff --git a/05_deliverables_mvp/crm/financement_bancaire/out/MANIFEST.json b/05_deliverables_mvp/crm/financement_bancaire/out/MANIFEST.json index 1ee742f..59a7a94 100644 --- a/05_deliverables_mvp/crm/financement_bancaire/out/MANIFEST.json +++ b/05_deliverables_mvp/crm/financement_bancaire/out/MANIFEST.json @@ -17,14 +17,6 @@ "workflow_suivi_etapes": 6 }, "roles_rbac_utilises": [ - { - "role_id": "ventes-conseiller", - "erpnext_role_name": "OTO Ventes Conseiller" - }, - { - "role_id": "ventes-directeur", - "erpnext_role_name": "OTO Ventes Directeur" - }, { "role_id": "compta-tresorier", "erpnext_role_name": "OTO Compta Trésorier" @@ -32,6 +24,10 @@ { "role_id": "ventes-conseiller", "erpnext_role_name": "OTO Ventes Conseiller" + }, + { + "role_id": "ventes-directeur", + "erpnext_role_name": "OTO Ventes Directeur" } ] }