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:


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:


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):

How to fix:

  1. Delete VittoUserType and FEATURES_BY_USER_TYPE from chat.types.ts
  2. Replace all imports with PlatformRole from @libs-foundational/core-models
  3. Replace FEATURES_BY_USER_TYPE[userType] with derivePermissions(platformRole).features
  4. Replace defaultRoleLevel(userType) with derivePermissions(platformRole).level
  5. Delete ROLE_TO_USER_TYPE in vitto-chat-panel.component.ts — use platformRole directly
  6. Update plugin-presets.ts to key on PlatformRole instead of VittoUserType

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):

How to fix:

  1. In vitto.types.ts: delete VittoLayer, keep VittoTaskTarget
  2. In tool-plugin.types.ts: change layers: VittoLayer[] to use configAccess values from DerivedPermissions or VittoTaskTarget
  3. Update each tool plugin's layers declaration
  4. Fix whistle.plugin.ts which uses invalid values 'space_user' and 'space_admin'
  5. Update tool-registry.service.ts filter 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:

  1. In the registration flow (line 73), convert RegistrationUserType → PlatformRole using platformRoleFromHierarchyType()
  2. Store platformRole on the User document
  3. Use derivePermissions(platformRole).backendRoles to get the JWT roles
  4. Delete mapUserTypeToRoles()

Task 4: Add executive to UserHierarchyType

File: libs/libs-api/backend-core/src/lib/schemas/user-hierarchy.schema.ts

How to fix:

  1. Add 'executive' to the UserHierarchyType union at line 8
  2. Add 'executive' to the @Prop enum at line 89
  3. Update the comment block (lines 5-12) to match the current L0-L4 hierarchy
  4. Fix the level min: 1 validator — 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:

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:


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

  1. Do NOT invent new role types. The canonical roles are in role-derivation.ts. Everything else must derive from or map to those.
  2. Do NOT delete RegistrationUserType or UserHierarchyType from schemas. These are in MongoDB documents. The schema enums stay (extended with executive). What gets deleted are the PARALLEL type definitions in service/component code.
  3. Test each P0 bug fix independently before moving to P1. P0 bugs can ship as a standalone commit.
  4. When replacing FEATURES_BY_USER_TYPE, verify that the feature flags in PLATFORM_ROLE_MAP match the old values exactly. Diff them side-by-side.
  5. When deleting VittoLayer, check every tool plugin's layers array and map to the replacement vocabulary. Some plugins may have values like ['developer', 'platform_builder'] that need to become ['developer', 'builder'] or use configAccess strings.
  6. 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.