[DTP-Worker 20260806_031432] FIX générateur — crm/financement_bancaire MANIFEST.roles_rbac_utilises répétait ventes-conseiller (dup ungaté, liste per-slot vs ensemble distinct)

Défaut réel/reproductible (pas 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"] — 2 slots (conseiller_wag ET validation_dossier) pointent
le même rôle ventes-conseiller → 4 entrées pour 3 rôles distincts. Preuve bug (pas
per-slot voulu) : la sortie drope la clé de slot (cle), donc le doublon ne porte
aucune info distinctive ; sémantique documentée README.md:54 « rôles RBAC utilisés »
+ ci/README.md:1100 « ensemble distinct » ; les 3 modules frères produisent tous un
ensemble distinct (confotur 3/3, commissions 4/4, workflow_vente 7/7) — financement
seul outlier 4/3.

Fix (aligné idiome commissions) : ensemble distinct trié par role_id via
sorted({rr["role_id"] for rr in roles_resolved.values()}). Artefact régénéré → 3/3
distinct. 0 gate ajouté (#5 — champ lu par AUCUN gate financement ni consommateur
externe ; convention distinctness déjà tenue par les frères). 0 chiffre inventé (#6).
run_ci 33 PASS · 0 FAIL · 0 SKIP (byte-repro vert avec nouvel artefact, 35 tests verts).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-08-06 03:22:44 +00:00
parent 243523c6c2
commit 48276ee916
3 changed files with 59 additions and 9 deletions
@@ -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 {