create(); $user = User::factory()->create(); WorkspaceMembership::factory()->create([ 'workspace_id' => (int) $workspace->getKey(), 'user_id' => (int) $user->getKey(), 'role' => 'manager', ]); return [$workspace, $user]; } it('falls back to the default plan profile when a workspace has no entitlement settings', function (): void { [$workspace] = entitledWorkspaceManager(); $resolver = app(WorkspaceEntitlementResolver::class); $managedTenantLimit = $resolver->resolve($workspace, WorkspaceEntitlementResolver::KEY_MANAGED_TENANT_ACTIVATION_LIMIT); $reviewPackGeneration = $resolver->resolve($workspace, WorkspaceEntitlementResolver::KEY_REVIEW_PACK_GENERATION_ENABLED); expect($managedTenantLimit) ->toMatchArray([ 'plan_profile_id' => 'standard', 'key' => WorkspaceEntitlementResolver::KEY_MANAGED_TENANT_ACTIVATION_LIMIT, 'effective_value' => 25, 'source' => 'plan_profile_default', 'current_usage' => 0, 'remaining_capacity' => 25, 'is_blocked' => false, ]) ->and($managedTenantLimit['rationale'])->toBe('Balanced defaults for most managed workspaces.') ->and($managedTenantLimit['last_changed_at'])->toBeNull() ->and($managedTenantLimit['last_changed_by'])->toBeNull(); expect($reviewPackGeneration) ->toMatchArray([ 'plan_profile_id' => 'standard', 'key' => WorkspaceEntitlementResolver::KEY_REVIEW_PACK_GENERATION_ENABLED, 'effective_value' => true, 'source' => 'plan_profile_default', 'is_blocked' => false, ]); }); it('applies the selected plan profile defaults when no explicit override is set', function (): void { [$workspace, $user] = entitledWorkspaceManager(); app(SettingsWriter::class)->updateWorkspaceSetting( actor: $user, workspace: $workspace, domain: WorkspaceEntitlementResolver::SETTING_DOMAIN, key: WorkspaceEntitlementResolver::SETTING_PLAN_PROFILE, value: 'starter', ); $resolver = app(WorkspaceEntitlementResolver::class); $managedTenantLimit = $resolver->resolve($workspace, WorkspaceEntitlementResolver::KEY_MANAGED_TENANT_ACTIVATION_LIMIT); $reviewPackGeneration = $resolver->resolve($workspace, WorkspaceEntitlementResolver::KEY_REVIEW_PACK_GENERATION_ENABLED); expect($managedTenantLimit) ->toMatchArray([ 'plan_profile_id' => 'starter', 'effective_value' => 1, 'source' => 'plan_profile_default', 'current_usage' => 0, 'remaining_capacity' => 1, 'is_blocked' => false, ]) ->and($managedTenantLimit['last_changed_by'])->toBe($user->name) ->and($managedTenantLimit['last_changed_at'])->not->toBeNull(); expect($reviewPackGeneration) ->toMatchArray([ 'plan_profile_id' => 'starter', 'effective_value' => false, 'source' => 'plan_profile_default', 'is_blocked' => true, ]) ->and($reviewPackGeneration['block_reason'])->toContain('Starter'); }); it('applies workspace override values, rationale, and usage-aware blocking', function (): void { [$workspace, $user] = entitledWorkspaceManager(); $writer = app(SettingsWriter::class); $writer->updateWorkspaceSetting( actor: $user, workspace: $workspace, domain: WorkspaceEntitlementResolver::SETTING_DOMAIN, key: WorkspaceEntitlementResolver::SETTING_PLAN_PROFILE, value: 'starter', ); $writer->updateWorkspaceSetting( actor: $user, workspace: $workspace, domain: WorkspaceEntitlementResolver::SETTING_DOMAIN, key: WorkspaceEntitlementResolver::SETTING_MANAGED_TENANT_LIMIT_OVERRIDE_VALUE, value: 2, ); $writer->updateWorkspaceSetting( actor: $user, workspace: $workspace, domain: WorkspaceEntitlementResolver::SETTING_DOMAIN, key: WorkspaceEntitlementResolver::SETTING_MANAGED_TENANT_LIMIT_OVERRIDE_REASON, value: 'Temporary support-approved exception', ); Tenant::factory()->count(2)->create([ 'workspace_id' => (int) $workspace->getKey(), 'status' => Tenant::STATUS_ACTIVE, ]); $decision = app(WorkspaceEntitlementResolver::class)->resolve( $workspace, WorkspaceEntitlementResolver::KEY_MANAGED_TENANT_ACTIVATION_LIMIT, ); expect($decision) ->toMatchArray([ 'plan_profile_id' => 'starter', 'effective_value' => 2, 'source' => 'workspace_override', 'rationale' => 'Temporary support-approved exception', 'current_usage' => 2, 'remaining_capacity' => 0, 'is_blocked' => true, 'last_changed_by' => $user->name, ]) ->and($decision['last_changed_at'])->not->toBeNull() ->and($decision['block_reason'])->toContain('workspace override') ->and($decision['block_reason'])->toContain('Temporary support-approved exception'); });