2026 03 19 Role System Cleanup Handoff
Documentation for Plans
Role System Cleanup — Agent Handoff
Session: S241 Date: 2026-03-19 Status: Ready for execution Priority: P0 — This causes active bugs and agent confusion Estimated scope: ~40 files across 4 backends + 5 frontend libs
Why This Exists
The codebase has 6+ parallel role/tier vocabularies that grew organically across sessions S52→S93→S124→S175→S209→S220. S220 introduced PlatformRole and derivePermissions() as the canonical unification — but the migration was never completed. The result:
- AI agents reading this codebase get confused about what L1/L2/L3 means, what role strings are valid, and which hierarchy is current
- Active bugs: executive users fall to wrong hierarchy level, space builders get inflated to admin, chat persona breaks for manager-role users
- Dead code: deprecated types, unreachable branches, stale comments that mislead both humans and agents
The Canonical Source of Truth
File: libs/libs-foundational/core-models/src/lib/utils/role-derivation.ts
Two Axes
PlatformRole (global, on User.platformRole):
executive (90) → developer (80) → admin (60) → builder (40) → user (20) → guest (5)
SpaceRole (per-space, on SpaceMember):
owner (40) → admin (30) → editor (20) → viewer (10)
Tier Hierarchy (L0–L4)
From libs/libs-foundational/auth-core/src/lib/models/auth.types.ts lines 13-21:
L0: executive — founders/C-suite
L1: developer, admin — GoGrab internal engineering & platform ops
L2: space_builder (founder), space_admin (CEO) — create & manage spaces
L3: space_user — team members within a space
L4: platform_user — end customers of generated platforms (separate DB collection)
Backend System Roles (JWT roles[] array)
From libs/libs-api/auth-core/src/lib/auth-core.constants.ts:
system (100) > executive (90) > developer (80) > admin (60) > manager (40) > editor (30) > user (20) > viewer (10)
The Derivation Function
derivePermissions(platformRole, spaceRole?) outputs:
level— numeric privilegefeatures— feature flags for Vitto UIconfigAccess—'developer' | 'platform_builder' | 'end_user'toolAccess—'developer' | 'space_builder' | 'platform_user'backendRoles— JWT roles array valueslegacyUserType— for backward compatisAdmin,isExecutive— convenience booleans
Task List — Ordered by Priority
P0 — Active Bugs (fix immediately)
Bug 1: executive falls to hierarchy level 2
File: APIs/backend-api/src/app/backend-auth/backend-auth.service.ts lines 274-284
getHierarchyLevel() has no case 'executive' — falls through to default: return 2, placing executives at the same level as space_user.
Fix: Add case 'executive': return 0; before the default case.
Bug 2: space_builder role check in chat controller is dead code
File: APIs/backend-ai-api/src/app/chat/chat.controller.ts line 184
} else if (roles.includes('space_builder')) {
JWT roles[] never contains 'space_builder' — space builders have roles: ['manager']. This branch never executes. All manager-role users fall through to 'platform_user', getting the wrong Vitto persona.
Fix: Change to roles.includes('manager') OR use derivePermissions(platformRole).toolAccess.
Bug 3: ROLE_PRIORITY maps manager → admin (role inflation)
File: libs/libs-foundational/core-models/src/lib/utils/role-derivation.ts line 255
['admin', 'manager'], // manager maps to admin PlatformRole
mapUserTypeToRoles('space_builder') → ['manager']. Then platformRoleFromLegacyRoles(['manager']) → 'admin' via this mapping. Space builders get silently promoted to admin-level permissions.
Fix: Change to ['builder', 'manager'] — managers should map to builder, not admin.
Bug 4: buildRoleContext() uses wrong keys for builder users
File: APIs/backend-vitto-api/src/app/engine/context-assembly/context-assembly-helpers.ts lines 52-65
roleDescriptions uses key 'platform_builder', but users have PlatformRole: 'builder'. A builder user matches no key and falls through to 'end_user' description. Every chat request for builders gets the wrong role description in the system prompt.
Fix: Change the key from 'platform_builder' to 'builder', or add both as aliases.
P1 — Deprecated Types to Replace
Task 1: Replace VittoUserType with PlatformRole + derivePermissions()
What: VittoUserType = 'executive' | 'developer' | 'admin' | 'space_builder' | 'platform_user'
Where it's used (8 files):
libs/libs-ai/vitto-chat/src/lib/types/chat.types.ts— type definition +FEATURES_BY_USER_TYPElibs/libs-ai/vitto-chat/src/lib/services/user-context.service.ts—defaultRoleLevel(),resolveUserType()libs/libs-ai/vitto-chat/src/lib/components/chat-shell/chat-shell.component.ts— consumes user typelibs/libs-ai/vitto-chat/src/lib/plugins/plugin-presets.ts— plugin config by user typeapps/gograb-ai/src/app/pages/vitto-chat-panel/vitto-chat-panel.component.ts—ROLE_TO_USER_TYPEmaplibs/libs-ai/vitto-chat/src/lib/components/welcome-message/welcome-message.component.tslibs/libs-ai/vitto-chat/src/lib/components/command-bar/command-bar.component.ts
How to fix:
- Delete
VittoUserTypeandFEATURES_BY_USER_TYPEfromchat.types.ts - Replace all imports with
PlatformRolefrom@libs-foundational/core-models - Replace
FEATURES_BY_USER_TYPE[userType]withderivePermissions(platformRole).features - Replace
defaultRoleLevel(userType)withderivePermissions(platformRole).level - Delete
ROLE_TO_USER_TYPEinvitto-chat-panel.component.ts— useplatformRoledirectly - Update
plugin-presets.tsto key onPlatformRoleinstead ofVittoUserType
Task 2: Replace VittoLayer with VittoTaskTarget or remove entirely
What: VittoLayer = 'developer' | 'platform_builder' | 'end_user' (marked @deprecated in own file)
Where it's used (~30 files):
APIs/backend-vitto-api/src/app/types/vitto.types.ts— definitionAPIs/backend-vitto-api/src/app/tools/plugins/tool-plugin.types.ts—ToolPlugin.layersAPIs/backend-vitto-api/src/app/tools/tool-registry.service.ts— filters plugins by layer- All ~20 tool plugin files under
APIs/backend-vitto-api/src/app/tools/plugins/
How to fix:
- In
vitto.types.ts: deleteVittoLayer, keepVittoTaskTarget - In
tool-plugin.types.ts: changelayers: VittoLayer[]to useconfigAccessvalues fromDerivedPermissionsorVittoTaskTarget - Update each tool plugin's
layersdeclaration - Fix
whistle.plugin.tswhich uses invalid values'space_user'and'space_admin' - Update
tool-registry.service.tsfilter logic
Task 3: Replace mapUserTypeToRoles() with derivePermissions()
File: APIs/backend-api/src/app/backend-auth/backend-auth.service.ts lines 259-268
How to fix:
- In the registration flow (line 73), convert
RegistrationUserType→PlatformRoleusingplatformRoleFromHierarchyType() - Store
platformRoleon the User document - Use
derivePermissions(platformRole).backendRolesto get the JWT roles - Delete
mapUserTypeToRoles()
Task 4: Add executive to UserHierarchyType
File: libs/libs-api/backend-core/src/lib/schemas/user-hierarchy.schema.ts
How to fix:
- Add
'executive'to theUserHierarchyTypeunion at line 8 - Add
'executive'to the@Prop enumat line 89 - Update the comment block (lines 5-12) to match the current L0-L4 hierarchy
- Fix the
level min: 1validator —getHierarchyLevel()assigns level 0, which violates the schema minimum
P2 — Stale Types and Dead Code to Remove
Task 5: Remove SystemRoles enum from shared-models
File: libs/core/shared-models/src/lib/rbac/role.ts lines 50-55
4-value enum (missing executive, developer, system). The canonical backend SystemRoles is in libs/libs-api/auth-core/src/lib/auth-core.constants.ts. Check if libs/core/security/ guards actually import this — if not, delete the enum. If they do, migrate them to the auth-core import.
Task 6: Fix TenantContext.userType in duplicated files
Files:
libs/libs-ai/space-agents/src/lib/models/vitto-hub.types.tsline 118libs/libs-ai/ai-panel-core/src/lib/models/vitto-hub.types.tsline 118
Both have userType?: 'developer' | 'admin' | 'space_builder' | 'platform_user' — missing executive. Either add executive or change the type to PlatformRole.
Task 7: Fix ChatRequest.userType in backend-ai-api
File: APIs/backend-ai-api/src/app/chat/chat.controller.ts line 51
Same 4-value type, missing executive. Change to PlatformRole or at minimum add 'executive'.
Task 8: Fix ai-infrastructure.schema.ts enum
File: APIs/backend-ai-api/src/app/schemas/ai-infrastructure.schema.ts line 395
MongoDB enum only allows ['developer', 'space_builder', 'platform_user']. Add 'executive', 'admin', 'builder', 'user', 'guest' — or change to accept any string.
Task 9: Fix RecallOptions.userType in vitto-memory
File: APIs/backend-vitto-api/src/app/mind/memory/vitto-memory.types.ts line 65
3-value type. Change to PlatformRole.
Task 10: Fix memory-persistence.service.ts layer value
File: APIs/backend-vitto-api/src/app/engine/memory-persistence.service.ts lines 224-225
Stores 'space_builder' as layer value, which is not a valid VittoLayer member. Change to derivePermissions(platformRole).configAccess or the canonical PlatformRole string.
Task 11: Delete deprecated vitto-chat.service.ts
File: libs/libs-ai/gograb-ai-lib/src/lib/services/vitto-chat.service.ts
Marked @deprecated since S133. Has its own local VittoUserLayer type. Verify no imports reference it, then delete.
Task 12: Fix ROLE_HIERARCHY in roles.guard.ts
File: libs/libs-api/auth-core/src/lib/guards/roles.guard.ts lines 41-50
Missing builder (40) and guest (5) from PlatformRole. If a user's JWT roles[] contains 'builder' (which derivePermissions('builder').backendRoles returns ['manager'], so this may never occur), the guard assigns level 0. Add builder: 40, guest: 5 for safety — or confirm no JWT ever contains these values.
Task 13: Remove local ROLE_HIERARCHY copy in admin-users.service.ts
File: APIs/backend-api/src/app/admin/admin-users.service.ts lines 31-42
Local copy that diverges from the shared guard. Import from roles.guard.ts or role-derivation.ts instead.
Task 14: Fix RegisterDto vocabulary
File: libs/libs-api/api-contracts/src/lib/auth/auth.dto.ts lines 50-51
Uses UserHierarchyType strings (space_builder, space_admin, space_user, platform_user). Consider whether the registration API should accept PlatformRole values instead, with a migration path for existing clients.
P3 — Comment and Documentation Fixes
Task 15: Update user-hierarchy.schema.ts comment block
File: libs/libs-api/backend-core/src/lib/schemas/user-hierarchy.schema.ts lines 1-12
Currently says L0: developer, admin. Should say L0: executive, L1: developer/admin, L2: space_builder/space_admin, L3: space_user, L4: platform_user.
Task 16: Update builder-profile.schema.ts comments
File: APIs/backend-ai-api/src/app/agents/schemas/builder-profile.schema.ts lines 14-19
References T1/T2/T3. Update to L0-L4.
Task 17: Update space-ai-preferences.schema.ts comments
File: APIs/backend-ai-api/src/app/agents/schemas/space-ai-preferences.schema.ts lines 51-59
References T3. Update to L4.
Task 18: Update memory file
File: /Users/fguijarro/.claude/projects/-Users-fguijarro-developer-repos-gspace-gspace1/memory/s209-tier-hierarchy-governance.md
States space_admin = L2 at level 40. But role-derivation.ts maps space_admin → admin at level 60. Correct the memory to match the canonical source.
Task 19: Update MCP/mcp-gograb-ai if it has role references
Check MCP/mcp-gograb-ai/src/ for any hardcoded tier or role strings. If found, align with canonical source.
Verification Checklist
After all changes, verify:
-
derivePermissions('executive')returns level 90, isExecutive true -
derivePermissions('builder')returns level 40, configAccess 'platform_builder', isAdmin false -
platformRoleFromLegacyRoles(['manager'])returns'builder'(NOT'admin') -
getHierarchyLevel('executive')returns 0 -
UserHierarchyTypeincludes'executive' - No file imports
VittoUserType(deleted) - No file imports
VittoLayer(deleted) -
FEATURES_BY_USER_TYPEdeleted — all consumers usederivePermissions().features -
mapUserTypeToRoles()deleted — registration usesderivePermissions().backendRoles -
ROLE_TO_USER_TYPEinvitto-chat-panel.component.tsdeleted -
chat.controller.tsin backend-ai-api correctly identifies manager-role users -
buildRoleContext()keys matchPlatformRolevalues - No
grep -r "space_builder" --include="*.ts"results outside of schema enum definitions, registration DTOs, and test fixtures - Build passes:
yarn build(ornx run-many --target=build) - Existing tests pass
Files Summary (all files that need changes)
# P0 — Active bugs
APIs/backend-api/src/app/backend-auth/backend-auth.service.ts
APIs/backend-ai-api/src/app/chat/chat.controller.ts
libs/libs-foundational/core-models/src/lib/utils/role-derivation.ts
APIs/backend-vitto-api/src/app/engine/context-assembly/context-assembly-helpers.ts
# P1 — Deprecated types
libs/libs-ai/vitto-chat/src/lib/types/chat.types.ts
libs/libs-ai/vitto-chat/src/lib/services/user-context.service.ts
libs/libs-ai/vitto-chat/src/lib/components/chat-shell/chat-shell.component.ts
libs/libs-ai/vitto-chat/src/lib/plugins/plugin-presets.ts
libs/libs-ai/vitto-chat/src/lib/components/welcome-message/welcome-message.component.ts
libs/libs-ai/vitto-chat/src/lib/components/command-bar/command-bar.component.ts
apps/gograb-ai/src/app/pages/vitto-chat-panel/vitto-chat-panel.component.ts
APIs/backend-vitto-api/src/app/types/vitto.types.ts
APIs/backend-vitto-api/src/app/tools/plugins/tool-plugin.types.ts
APIs/backend-vitto-api/src/app/tools/tool-registry.service.ts
APIs/backend-vitto-api/src/app/tools/plugins/*.ts (~20 files)
libs/libs-api/backend-core/src/lib/schemas/user-hierarchy.schema.ts
# P2 — Stale types and dead code
libs/core/shared-models/src/lib/rbac/role.ts
libs/libs-ai/space-agents/src/lib/models/vitto-hub.types.ts
libs/libs-ai/ai-panel-core/src/lib/models/vitto-hub.types.ts
APIs/backend-ai-api/src/app/schemas/ai-infrastructure.schema.ts
APIs/backend-vitto-api/src/app/mind/memory/vitto-memory.types.ts
APIs/backend-vitto-api/src/app/engine/memory-persistence.service.ts
libs/libs-ai/gograb-ai-lib/src/lib/services/vitto-chat.service.ts
libs/libs-api/auth-core/src/lib/guards/roles.guard.ts
APIs/backend-api/src/app/admin/admin-users.service.ts
libs/libs-api/api-contracts/src/lib/auth/auth.dto.ts
# P3 — Comments and docs
libs/libs-api/backend-core/src/lib/schemas/user-hierarchy.schema.ts (comments)
APIs/backend-ai-api/src/app/agents/schemas/builder-profile.schema.ts (comments)
APIs/backend-ai-api/src/app/agents/schemas/space-ai-preferences.schema.ts (comments)
.claude/projects/.../memory/s209-tier-hierarchy-governance.md
Rules for the Executing Agent
- Do NOT invent new role types. The canonical roles are in
role-derivation.ts. Everything else must derive from or map to those. - Do NOT delete
RegistrationUserTypeorUserHierarchyTypefrom schemas. These are in MongoDB documents. The schema enums stay (extended withexecutive). What gets deleted are the PARALLEL type definitions in service/component code. - Test each P0 bug fix independently before moving to P1. P0 bugs can ship as a standalone commit.
- When replacing
FEATURES_BY_USER_TYPE, verify that the feature flags inPLATFORM_ROLE_MAPmatch the old values exactly. Diff them side-by-side. - When deleting
VittoLayer, check every tool plugin'slayersarray and map to the replacement vocabulary. Some plugins may have values like['developer', 'platform_builder']that need to become['developer', 'builder']or useconfigAccessstrings. - Commit in phases:
[S242.1] fix: P0 role bugs,[S242.2] refactor: replace VittoUserType with PlatformRole,[S242.3] refactor: replace VittoLayer with VittoTaskTarget,[S242.4] chore: clean up stale role comments and dead code.