"""Portée de connaissance + rôles du Chat OTOIA, dérivés du contrat RBAC. Principe de sécurité + anti-invention (#6) : l'assistant embarqué dans un portail ne peut « connaître » que les DocTypes que les rôles de CE portail sont autorisés à voir. On borne donc la portée de connaissance à la surface RBAC exacte du portail (les `permissions_cibles`) — la même que celle des Workspaces. Résultat : le chat ne peut ni prétendre, ni exposer un DocType hors de la portée du portail, et aucun périmètre n'est inventé. Tout est dérivé du CONTRAT (jamais de la spec de présentation) : - `roles_allowed` = rôles du portail (roles_by_portail du builder Workspaces) ; - `knowledge_scope` = DocTypes autorisés du portail (doctypes_by_portail). Ordre trié → sortie déterministe (diffable, re-générable). """ from __future__ import annotations from . import deps def roles_for(contract: dict, portail_key: str) -> list[str]: """Rôles ERPNext du portail (triés), depuis le contrat RBAC.""" return sorted(deps.roles_by_portail(contract).get(portail_key, [])) def knowledge_scope_for(contract: dict, portail_key: str) -> list[str]: """DocTypes que le portail est autorisé à voir (triés), depuis le contrat RBAC.""" return sorted(deps.doctypes_by_portail(contract).get(portail_key, set()))