Bugfix: Why did executives get /unauthorized and escalation alerts n...

Documentation for Sessions

🐛 Bugfix: Why did executives get /unauthorized and escalation alerts n...

Date: 2026-03-14
Time: 17:57:10 UTC
Session: gspace1-220.3
Agent: angular
Confidence: 97%
Status: ✅ Documented


📋 Decision Context

Question:

Why did executives get /unauthorized and escalation alerts never reach anyone?

Task: S220: Fix 4 silent role bugs


🎯 Decision Made

Chosen:

Fixed 4 silent bugs + 2 gaps: (1) executive added to frontend adminGuard + app-level adminRoleGuard, (2) editor:30 added to ROLE_HIERARCHY, (3) dossier reads 'type'/'level' not phantom 'role'/'roleLevel' and derives numeric level via derivePermissions(), (4) resolveUserType() validates against JWT roles ignoring frontend claims, (D) removed 'contributor' from SpaceRole enum, (E) space_builder mapped to manager(40) not user(20).

Options Considered:

  1. Fix each bug independently (done — immediate impact)
  2. Wait for full unified system before fixing (rejected — bugs are live)
  3. Add executive to some guards but not all (what initially happened — caused infinite loop)

💭 Reasoning

Root causes traced to code: (1) ADMIN_ALLOWED_ROLES hardcoded as ['admin','developer','system'] without 'executive' in 4 independent locations — admin.guard.ts, adminRoleGuard, space-invitation.service.ts, and docs-admin.guard.ts. Only docs-admin had executive. The app-level adminRoleGuard ALSO read raw localStorage instead of AuthService, causing infinite redirect loops when auth_backup was null. (2) ROLE_HIERARCHY in roles.guard.ts had no entry for 'editor' — unknown roles default to 0 via ?? operator, making editors anonymous. (3) UserDossierService read 'userEntry.roleLevel' and 'userEntry.role' but UserHierarchy schema has fields named 'level' (numeric 1-10) and 'type' (string enum). The phantom field always returned undefined, defaulting roleLevel to 20. Even fixing the field name was insufficient — hierarchy 'level' is 1-10 (depth) not 20-100 (SystemRole scale). Fixed by deriving numeric level from hierarchy type via platformRoleFromHierarchyType() → derivePermissions().level. (4) POST /chat trusted body.userType from frontend — a viewer could claim executive and get executive persona/tools.


📁 Files Involved


🔗 Related


Auto-generated by MCP Smart Consolidation