10a48657c7
Original task (#101): When an admin saves the role editor, role holders need their permission-driven UI (admin nav items, permission-gated action buttons, etc.) to refresh without waiting for a page reload. The server already emitted `apps_changed`, but that event is semantically about visible apps, not the broader cached permission state, and the client only invalidated the apps list and `/api/auth/me`. Changes: - artifacts/api-server/src/lib/realtime.ts - Extracted role-holder resolution (direct user_roles + indirect via group_roles -> user_groups) into a private helper. - Added `emitRolePermissionsChangedToHolders(roleId)` that emits a new `role_permissions_changed` socket event with `{ roleId }` to every holder of the role. - artifacts/api-server/src/routes/roles.ts - After `PUT /api/roles/:id/permissions` succeeds, call the new emitter alongside the existing `emitAppsChangedToRoleHolders`. - artifacts/tx-os/src/hooks/use-notifications-socket.ts - Subscribed to `role_permissions_changed`. Invalidates `getMe`, `listRoles`, `listPermissions`, and—when the payload includes the role id—`getRolePermissions`, the role permission audit, and role usage queries so admin-only UI re-evaluates without a refresh. Scope notes / deviations: - The task spec called out `PUT /api/roles/:id/permissions` only, so the matching POST/DELETE single-permission endpoints still emit only `apps_changed`. Filed as follow-up #150 to keep them consistent. - No new automated tests added (filed as follow-up #151). Pre-existing typecheck errors in artifacts/api-server/src/routes/executive-meetings.ts are unrelated and untouched. - `replit.md` not updated; this is a behavioral refinement of an existing socket flow, not an architectural change. Replit-Task-Id: bd31a9a9-dbf1-497a-8505-96672f92bc79