The problem
When an employee changes role — promotion, transfer, contractor conversion, intern-to-FTE — their access needs to be reconciled across every connected system. Old groups removed, new groups added, Jira project permissions swapped, M365 license tier changed. Manual reconciliation across 4-6 systems takes hours per transition and routinely leaves orphaned permissions that surface as security findings months later. At cohort scale (a sales class of 12 SDRs promoting to AE on the same date, a summer intern cohort converting in September), the manual approach simply doesn't scale.
What AscendCore does
An IT admin invokes /role-change <user-email> <from-role-id> <to-role-id> from Slack (or types role-change ... in Microsoft Teams). AscendCore looks up both roles in its catalog, computes the access diff (groups to add/remove across Okta and Entra, Jira project role swaps, M365 license tier change, distribution list changes), and posts a single approval card to the IT admin channel showing every change. On approval, the orchestrator executes each operation sequentially with per-step outcome capture; a single role_change.executed row appended to the SHA-256 audit chain carries the full per-step outcome list for SOC-2 evidence.
Commands
# Slack
/role-change <user-email> <from-role-id> <to-role-id>
# Teams (DM the bot or @mention)
role-change <user-email> <from-role-id> <to-role-id>
Examples:
/role-change sarah@acme.com support-tier-1 support-tier-2— helpdesk promotion/role-change marcus@acme.com sales-development-rep account-executive— SDR → AE with DocuSign + ZoomInfo + E5 license tier/role-change ben@acme.com engineering-contractor engineering-fte— contractor conversion with VPN + E5 unlock/role-change priya@acme.com hr-generalist hr-manager— HR promotion to payroll-admin + executive comms DL/role-change alex@acme.com intern engineering-fte— September cohort conversion
Seed role catalog
Five real-world roles ship hardcoded in src/lib/runbooks/role-definitions.ts. Each role definition declares its access bundle: Okta + Entra security groups, Jira project roles, M365 license SKU, M365 distribution list memberships. Customers fork the catalog into their own per-tenant config when they need org-specific roles (Phase 2 work — runtime-mutable role catalog).
| Category | Roles | |---|---| | Support | support-tier-1 → support-tier-2 (helpdesk promotion with elevated rights via JIT-eligible group) | | Sales | sales-development-rep → account-executive (cohort onboarding with SSO app provisioning + advanced compliance license) | | Engineering | engineering-contractor → engineering-fte; intern → engineering-fte (security guardrail removal + VPN access + license tier upgrade) | | HR | hr-generalist → hr-manager (PII-elevation flow with payroll admin + executive comms DL) |
Workflow
- Invoke — admin types
/role-change <user-email> <from-role-id> <to-role-id> - Resolve — Okta lookup for the target user; refuse no-op transitions if the two roles resolve to identical access bundles
- Diff — compute groups to add/remove, Jira role swaps, M365 license change, DL changes
- Propose — single approval card with sectioned diff (only non-empty sections rendered for readability)
- Approve — IT admin clicks Approve in the configured admin channel
- Execute — orchestrator runs operations sequentially across systems:
- Phase 1: Add new memberships (Okta groups, Entra groups, distribution lists) — minimizes access gap
- Phase 2: Remove old memberships
- Phase 3: Jira project role swaps (remove old role, add new role per project)
- Phase 4: M365 license change (assign new before removing old to avoid mid-transition license loss)
- Notify — requester DM'd by the bot with success/failure summary; result card in admin channel shows per-step outcomes
- Audit — single
role_change.executed(orrole_change.denied) row appended to the SHA-256 hash chain. Payload carries the full per-step outcome list (succeeded / failed / skipped per group, role, license, DL change). Distinct fromgroup_membership.*verbs because role changes bundle many group-level operations under one approval gate.
Failure model
Continue-on-failure with structured outcome reporting — if a partial failure occurs (e.g., Entra add succeeded but Jira role swap 503'd), the orchestrator continues with remaining operations and the audit row reflects the actual end-state. Silent rollback would just hide the real state and complicate manual reconciliation. The result card shows every step with a clear ✅ / ❌ / ⏭️ icon plus the failure reason, so the admin sees exactly what's done and what needs follow-up. Re-running the role-change after fixing the underlying issue is safe (all underlying helpers are idempotent).
Integrations
- Okta — Group membership reconciliation via
/api/v1/groups/{id}/users/{userId}(PUT for add, DELETE for remove) - Microsoft Entra ID — Security group membership via Graph
/groups/{id}/members/$ref - Jira / Atlassian — Per-project role assignment via
POST /rest/api/3/project/{key}/role/{roleId}and removal via the corresponding DELETE - Microsoft 365 — License SKU change via Graph user license assignment endpoints; distribution list membership via the same group endpoint as Entra security groups
- Slack + Microsoft Teams — Admin-invoked entry point and approval surface, with full Block Kit and Adaptive Card parity
Enterprise-tier configuration roadmap (not yet wired)
- PIM (Privileged Identity Management) eligibility — currently modeled as a standard Entra group with a
-jitsuffix; customer's Conditional Access policy handles the just-in-time semantics if Entra P2 is licensed. Direct PIM API integration is on the Enterprise-tier roadmap. - Conditional Access policy mutations — the runbook never modifies CA policy objects directly (too high-risk; one wrong update can lock everyone out). Network/VPN access is gated by membership in groups like
sg-vpn-allowedand the customer's CA policy excludes that group; the runbook just adds/removes the user from the gating group. - Direct SaaS app provisioning (DocuSign, ZoomInfo, etc.) — modeled as Okta SSO group memberships; Okta's SCIM connector to those apps handles the actual provisioning when the user joins the group. Direct API integration to these apps is on a customer-driven roadmap.
- Manager dual-approval (manager + IT admin both required) — currently single-approval (IT admin); manager-routed approval as an additive policy is on the Enterprise-tier roadmap.
Status
Live in production — orchestrator + 5 seed roles + Slack + Teams parity + per-step audit outcomes shipped May 2026.
