account; // Serialize with DeleteWorkspace / other RemoveMember calls on this // account so concurrent removals cannot skip stranded cleanup. if ($account?->id) { Account::query()->whereKey($account->id)->lockForUpdate()->first(); } $user = User::query()->find($userId); $workspace->members()->detach($userId); RevokeWorkspaceApiKeys::forUserOnWorkspace($userId, $workspace); RevokeMcpOAuthGrants::forUserOnWorkspace($userId, $workspace); if (! $user) { return; } $user->refresh(); if ($user->current_workspace_id === $workspace->id) { ReassignCurrentWorkspace::forUserAwayFrom($user, $workspace); $user->refresh(); } // Last membership on this shared account — delete the invitee. if ( $account && $user->account_id === $account->id && $user->id !== $account->owner_id ) { $settlement = SettleStrandedMember::execute($user, $account); } // Safety net for any leftover unbound MCP grants after full removal. $remaining = User::query()->find($userId); if ($remaining instanceof User) { RevokeMcpOAuthGrants::forUserIfLacksWorkspaceAccess($remaining); } }); $settlement->flush(); } }