*/ function spec317Files(array $roots): array { $files = []; foreach ($roots as $root) { if (is_file($root)) { $files[] = $root; continue; } if (! is_dir($root)) { continue; } $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($root, FilesystemIterator::SKIP_DOTS), ); foreach ($iterator as $file) { if (! $file instanceof SplFileInfo || ! $file->isFile()) { continue; } if ($file->getFilename() === 'LegacyTenantPlatformContextCleanupTest.php') { continue; } if (! in_array($file->getExtension(), ['php', 'md'], true)) { continue; } $files[] = $file->getPathname(); } } sort($files); return array_values(array_unique($files)); } /** * @param list $files * @param list $patterns * @return list */ function spec317PatternHits(array $files, array $patterns): array { $hits = []; foreach ($files as $path) { $contents = file_get_contents($path); if (! is_string($contents)) { continue; } $lines = preg_split('/\R/', $contents) ?: []; foreach ($patterns as $pattern) { foreach ($lines as $lineNumber => $line) { if (preg_match($pattern, $line) !== 1) { continue; } $hits[] = str_replace(repo_path().'/', '', $path).':'.($lineNumber + 1).' -> '.trim($line); } } } return $hits; } it('removes retired platform-context helper and class names from active runtime seams', function (): void { $files = spec317Files([ base_path('app'), base_path('bootstrap/app.php'), base_path('routes/web.php'), base_path('tests/Feature/Guards'), base_path('tests/Feature/Navigation'), base_path('tests/Feature/Reviews'), ]); $hits = spec317PatternHits($files, [ '/\btenantPrefilterUrl\s*\(/', '/\bCanonicalAdminTenantFilterState\b/', '/\bWorkspaceScopedTenantRoutes\b/', '/\bTenantPageCategory\b/', '/\bEnsureFilamentTenantSelected\b/', '/ensure-filament-tenant-selected/', '/\blastTenantId\s*\(/', '/\brememberedTenant\s*\(/', '/\brememberTenantContext\s*\(/', '/\bLAST_TENANT_IDS_SESSION_KEY\b/', '/\bTenantBound\b/', '/\bTenantScopedEvidence\b/', ]); expect($hits)->toBeEmpty("Retired Tenant platform-context names remain:\n".implode("\n", $hits)); }); it('keeps current product-truth docs on workspace and environment terminology', function (): void { $files = spec317Files([ repo_path('docs/HANDOVER.md'), repo_path('docs/product/spec-candidates.md'), repo_path('docs/product/implementation-ledger.md'), repo_path('docs/product/roadmap.md'), repo_path('docs/product/principles.md'), repo_path('docs/ui'), repo_path('docs/architecture-guidelines.md'), repo_path('docs/filament-guidelines.md'), repo_path('docs/testing-guidelines.md'), ]); $hits = spec317PatternHits($files, [ '/\btenantPrefilterUrl\b/', '/\bCanonicalAdminTenantFilterState\b/', '/\bWorkspaceScopedTenantRoutes\b/', '/\bTenantPageCategory\b/', '/\bEnsureFilamentTenantSelected\b/', '/\blastTenantId\b/', '/\btenantScopedUrl\b/', ]); expect($hits)->toBeEmpty("Current docs still describe retired Tenant platform context:\n".implode("\n", $hits)); }); it('keeps workspace hubs free of hidden Filament or remembered Environment scope fallbacks', function (): void { $files = spec317Files([ base_path('app/Filament/Pages/Monitoring/Operations.php'), base_path('app/Filament/Pages/Monitoring/FindingExceptionsQueue.php'), base_path('app/Filament/Pages/Governance/GovernanceInbox.php'), base_path('app/Filament/Pages/Governance/DecisionRegister.php'), base_path('app/Filament/Pages/Monitoring/EvidenceOverview.php'), base_path('app/Filament/Pages/Reviews/ReviewRegister.php'), base_path('app/Filament/Pages/Reviews/CustomerReviewWorkspace.php'), base_path('app/Filament/Resources/ProviderConnectionResource.php'), base_path('app/Filament/Resources/ProviderConnectionResource/Pages/ListProviderConnections.php'), ]); $hits = spec317PatternHits($files, [ '/\bFilament::getTenant\s*\(/', '/\blastEnvironmentId\s*\(/', '/\brememberedEnvironment\s*\(/', '/\brememberEnvironmentContext\s*\(/', ]); expect($hits)->toBeEmpty("Workspace hubs must not derive scope from Filament tenant or remembered Environment state:\n".implode("\n", $hits)); }); it('keeps helper APIs hard-cut to Environment names and canonical filter keys', function (): void { expect(method_exists(CustomerReviewWorkspace::class, 'tenantPrefilterUrl'))->toBeFalse() ->and(method_exists(CustomerReviewWorkspace::class, 'environmentFilterUrl'))->toBeTrue(); $reviewUrlHelper = new ReflectionMethod(EnvironmentReviewResource::class, 'environmentScopedUrl'); $providerConnectionResource = (string) file_get_contents(base_path('app/Filament/Resources/ProviderConnectionResource.php')); expect(method_exists(EnvironmentReviewResource::class, 'tenantScopedUrl'))->toBeFalse() ->and($reviewUrlHelper->getNumberOfParameters())->toBe(3) ->and($providerConnectionResource) ->not->toContain("array_key_exists('tenant', \$parameters)") ->not->toContain('resolveRequestedTenantExternalId() ?? static::resolveContextTenantExternalId()'); }); it('keeps active environment dashboard links free of retired tenant query aliases', function (): void { [$user, $environment] = createUserWithTenant(role: 'owner', workspaceRole: 'owner'); $workspace = $environment->workspace()->firstOrFail(); $this->actingAs($user); Filament::setTenant($environment, true); $response = $this ->withSession([ WorkspaceContext::SESSION_KEY => (int) $workspace->getKey(), WorkspaceContext::LAST_ENVIRONMENT_IDS_SESSION_KEY => [ (string) $workspace->getKey() => (int) $environment->getKey(), ], ]) ->get(ManagedEnvironmentLinks::viewUrl($environment)); $response->assertOk(); $content = html_entity_decode((string) $response->getContent(), ENT_QUOTES | ENT_HTML5); expect($content) ->not->toContain('/admin/t') ->not->toContain('?tenant=') ->not->toContain('&tenant=') ->not->toContain('tenant_id=') ->not->toContain('managed_environment_id=') ->not->toContain('tenant_scope='); }); it('does not register active legacy tenant panel routes or providers', function (): void { $legacyRouteUris = collect(Route::getRoutes()) ->map(fn ($route): string => ltrim((string) $route->uri(), '/')) ->filter(fn (string $uri): bool => preg_match('#^admin/t(?:/|$)#', $uri) === 1) ->values(); $registeredProviders = require base_path('bootstrap/providers.php'); $tenantPanelProviders = collect($registeredProviders) ->filter(fn (string $provider): bool => str_contains($provider, 'TenantPanelProvider')) ->values(); expect($legacyRouteUris)->toBeEmpty() ->and($tenantPanelProviders)->toBeEmpty() ->and(file_exists(app_path('Providers/Filament/TenantPanelProvider.php')))->toBeFalse(); });