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:
- Fix each bug independently (done — immediate impact)
- Wait for full unified system before fixing (rejected — bugs are live)
- 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
libs/libs-ui/auth-ui/src/lib/guards/admin.guard.tsapps/gograb-admin/src/app/core/guards/admin-role.guard.tslibs/libs-api/auth-core/src/lib/guards/roles.guard.tsAPIs/backend-vitto-api/src/app/users/user-dossier.service.tsAPIs/backend-vitto-api/src/app/engine/vitto.controller.tsAPIs/backend-api/src/app/spaces/space-invitation.service.tslibs/libs-foundational/core-models/src/lib/types/space.types.ts
🔗 Related
- Decision ID:
dev_1773511030762_shhrrd2 - Session: 220
- Workspace: gspace1
Auto-generated by MCP Smart Consolidation