fix: stabilize post-cutover suite baseline #348
@ -8,6 +8,7 @@
|
||||
use App\Filament\Widgets\Operations\OperationsKpiHeader;
|
||||
use App\Models\OperationRun;
|
||||
use App\Models\ManagedEnvironment;
|
||||
use App\Models\Workspace;
|
||||
use App\Support\Filament\CanonicalAdminTenantFilterState;
|
||||
use App\Support\Navigation\CanonicalNavigationContext;
|
||||
use App\Support\OperateHub\OperateHubShell;
|
||||
@ -22,6 +23,7 @@
|
||||
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceType;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use App\Models\User;
|
||||
use App\Services\Auth\WorkspaceCapabilityResolver;
|
||||
use BackedEnum;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Facades\Filament;
|
||||
@ -153,8 +155,55 @@ public static function monitoringPageStateContract(): array
|
||||
return self::MONITORING_PAGE_STATE_CONTRACT;
|
||||
}
|
||||
|
||||
public static function canAccess(): bool
|
||||
{
|
||||
if (Filament::getCurrentPanel()?->getId() !== 'admin') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if (! $user instanceof User) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
|
||||
if (! is_int($workspaceId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$workspace = Workspace::query()->whereKey($workspaceId)->first();
|
||||
|
||||
if (! $workspace instanceof Workspace) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
|
||||
|
||||
if (! $user instanceof User || ! is_int($workspaceId)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$workspace = Workspace::query()->whereKey($workspaceId)->first();
|
||||
|
||||
if (! $workspace instanceof Workspace) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
/** @var WorkspaceCapabilityResolver $resolver */
|
||||
$resolver = app(WorkspaceCapabilityResolver::class);
|
||||
|
||||
if (! $resolver->isMember($user, $workspace)) {
|
||||
abort(404);
|
||||
}
|
||||
|
||||
$this->navigationContextPayload = is_array(request()->query('nav')) ? request()->query('nav') : null;
|
||||
|
||||
$this->applyRequestedTenantScope();
|
||||
|
||||
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 282 KiB |
|
After Width: | Height: | Size: 387 KiB |
|
After Width: | Height: | Size: 238 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 262 KiB |
|
After Width: | Height: | Size: 294 KiB |
|
After Width: | Height: | Size: 219 KiB |
|
After Width: | Height: | Size: 217 KiB |
@ -27,46 +27,32 @@
|
||||
dataset('admin hidden navigation classes', [
|
||||
InventoryCluster::class,
|
||||
InventoryCoverage::class,
|
||||
EntraGroupResource::class,
|
||||
]);
|
||||
|
||||
dataset('admin visible navigation classes', [
|
||||
InventoryItemResource::class,
|
||||
PolicyResource::class,
|
||||
PolicyVersionResource::class,
|
||||
BackupScheduleResource::class,
|
||||
BackupSetResource::class,
|
||||
RestoreRunResource::class,
|
||||
EntraGroupResource::class,
|
||||
FindingResource::class,
|
||||
]);
|
||||
|
||||
dataset('tenant visible navigation classes', [
|
||||
InventoryCluster::class,
|
||||
InventoryCoverage::class,
|
||||
InventoryItemResource::class,
|
||||
PolicyResource::class,
|
||||
PolicyVersionResource::class,
|
||||
BackupScheduleResource::class,
|
||||
BackupSetResource::class,
|
||||
RestoreRunResource::class,
|
||||
EntraGroupResource::class,
|
||||
FindingResource::class,
|
||||
]);
|
||||
|
||||
it('keeps tenant-sensitive surfaces out of admin navigation registration', function (string $class): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get('/admin')
|
||||
->assertOk();
|
||||
it('keeps admin-hidden tenant surfaces out of navigation registration', function (string $class): void {
|
||||
Filament::setCurrentPanel('admin');
|
||||
|
||||
expect($class::shouldRegisterNavigation())->toBeFalse();
|
||||
})->with('admin hidden navigation classes');
|
||||
|
||||
it('registers tenant-sensitive surfaces in the tenant panel navigation', function (string $class): void {
|
||||
it('registers current tenant-owned surfaces on the admin navigation', function (string $class): void {
|
||||
Filament::setCurrentPanel('admin');
|
||||
|
||||
expect($class::shouldRegisterNavigation())->toBeTrue();
|
||||
})->with('admin visible navigation classes');
|
||||
|
||||
it('keeps retired tenant-panel entry routes unavailable', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
@ -74,20 +60,13 @@
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])
|
||||
->get("/admin/t/{$tenant->external_id}")
|
||||
->assertOk();
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
expect($class::shouldRegisterNavigation())->toBeTrue();
|
||||
})->with('tenant visible navigation classes');
|
||||
|
||||
it('keeps baseline navigation in the workspace panel and out of the tenant panel', function (): void {
|
||||
it('keeps baseline navigation on the admin panel and off retired tenant routes', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])
|
||||
->get('/admin')
|
||||
->assertOk();
|
||||
Filament::setCurrentPanel('admin');
|
||||
|
||||
expect(BaselineProfileResource::shouldRegisterNavigation())->toBeTrue();
|
||||
expect(BaselineSnapshotResource::shouldRegisterNavigation())->toBeTrue();
|
||||
@ -96,11 +75,15 @@
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])
|
||||
->get("/admin/t/{$tenant->external_id}")
|
||||
->assertOk();
|
||||
->get("/admin/t/{$tenant->external_id}/baseline-profiles")
|
||||
->assertNotFound();
|
||||
|
||||
expect(BaselineProfileResource::shouldRegisterNavigation())->toBeFalse();
|
||||
expect(BaselineSnapshotResource::shouldRegisterNavigation())->toBeFalse();
|
||||
$this->actingAs($user)
|
||||
->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])
|
||||
->get("/admin/t/{$tenant->external_id}/baseline-snapshots")
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
it('keeps the workspace panel sidebar free of tenant-sensitive entries even with a remembered tenant', function (): void {
|
||||
@ -113,7 +96,7 @@
|
||||
(string) $tenant->workspace_id => (int) $tenant->getKey(),
|
||||
],
|
||||
])
|
||||
->get('/admin')
|
||||
->get(route('admin.workspace.home', ['workspace' => $tenant->workspace_id]))
|
||||
->assertOk();
|
||||
|
||||
$response->assertDontSee('>Items</span>', false);
|
||||
|
||||
@ -518,7 +518,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
->values()
|
||||
->all();
|
||||
|
||||
expect($rowActionNames)->toEqualCanonicalizing(['change_role', 'remove'])
|
||||
expect($rowActionNames)->toEqualCanonicalizing(['remove'])
|
||||
->and($table->getBulkActions())->toBeEmpty()
|
||||
->and($table->getRecordUrl($membership))->toBeNull();
|
||||
});
|
||||
@ -615,7 +615,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
$this->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(TenantResource::getUrl('view', ['record' => $tenant->getRouteKey()], panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('Manage memberships')
|
||||
->assertSee('Manage access scope')
|
||||
->assertSee('href="'.$membershipsUrl.'"', false)
|
||||
->assertDontSeeLivewire(TenantMembershipsRelationManager::class);
|
||||
|
||||
@ -625,7 +625,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
->test(ManageTenantMemberships::class, ['record' => $tenant->getRouteKey()])
|
||||
->assertActionVisible('back_to_overview')
|
||||
->assertActionDoesNotExist('memberships')
|
||||
->assertActionExists('back_to_overview', fn ($action): bool => $action->getLabel() === 'Back to tenant overview'
|
||||
->assertActionExists('back_to_overview', fn ($action): bool => $action->getLabel() === 'Back to environment overview'
|
||||
&& $action->getUrl() === TenantResource::getUrl('view', ['record' => $tenant->getRouteKey()], panel: 'admin'));
|
||||
|
||||
expect($membershipsPage->instance()->getRelationManagers())
|
||||
@ -634,9 +634,9 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
$this->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(TenantResource::getUrl('memberships', ['record' => $tenant->getRouteKey()], panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('Manage tenant memberships')
|
||||
->assertSee('ManagedEnvironment access is managed here. Use the tenant overview for provider state, verification, and operational context.')
|
||||
->assertSee('Back to tenant overview')
|
||||
->assertSee('Manage environment access scope')
|
||||
->assertSee('Workspace membership defines the role. Explicit environment scopes only narrow which workspace members can see this environment.')
|
||||
->assertSee('Back to environment overview')
|
||||
->assertDontSeeLivewire(\App\Filament\Widgets\Tenant\RecentOperationsSummary::class)
|
||||
->assertDontSeeLivewire(\App\Filament\Widgets\Tenant\TenantVerificationReport::class)
|
||||
->assertDontSeeLivewire(\App\Filament\Widgets\Tenant\AdminRolesSummaryWidget::class)
|
||||
@ -750,7 +750,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
->and($headerGroups->get('External links'))->toEqualCanonicalizing(['admin_consent', 'open_in_entra'])
|
||||
->and($headerGroups->get('Setup'))->toEqualCanonicalizing(['syncTenant', 'verify', 'setup_rbac', 'refresh_rbac'])
|
||||
->and($headerGroups->get('Triage'))->toEqualCanonicalizing(['markReviewed', 'markFollowUpNeeded'])
|
||||
->and($headerGroups->get('Lifecycle'))->toEqualCanonicalizing(['archive'])
|
||||
->and($headerGroups->get('Lifecycle'))->toEqualCanonicalizing(['archive', 'remove_from_workspace'])
|
||||
->and($visibleHeaderActionNames)->not->toContain('edit')
|
||||
->and($visibleHeaderActionNames)->toContain('markReviewed')
|
||||
->and($visibleHeaderActionNames)->toContain('markFollowUpNeeded')
|
||||
@ -1522,7 +1522,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
|
||||
expect($rowActionNames)->toEqualCanonicalizing(['restore_to_intune'])
|
||||
->and($table->getBulkActions())->toBeEmpty()
|
||||
->and($table->getRecordUrl($version))->toBe(PolicyVersionResource::getUrl('view', ['record' => $version]));
|
||||
->and($table->getRecordUrl($version))->toBe(PolicyVersionResource::getUrl('view', ['record' => $version], panel: 'admin'));
|
||||
});
|
||||
|
||||
it('uses canonical tenantless View run links on representative operation links', function (): void {
|
||||
@ -1533,7 +1533,10 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
]);
|
||||
|
||||
expect(OperationRunLinks::view($run, $tenant))
|
||||
->toBe(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
->toBe(route('admin.operations.view', [
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
});
|
||||
|
||||
it('keeps canonical operation labels on shared representative links', function (): void {
|
||||
@ -1558,7 +1561,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
|
||||
$this->actingAs($user);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
Filament::setTenant($tenant, true);
|
||||
setAdminPanelContext();
|
||||
|
||||
$livewire = Livewire::test(Operations::class)
|
||||
->assertCanSeeTableRecords([$run]);
|
||||
@ -1609,7 +1612,7 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
->and(EvidenceOverview::actionSurfaceDeclaration()->slot(ActionSurfaceSlot::InspectAffordance)?->details)->toBe(ActionSurfaceInspectAffordance::ClickableRow->value)
|
||||
->and($snapshot)->toBeInstanceOf(EvidenceSnapshot::class)
|
||||
->and(is_array($evidenceRow))->toBeTrue()
|
||||
->and($evidenceRow['view_url'] ?? null)->toBe(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'tenant'));
|
||||
->and($evidenceRow['view_url'] ?? null)->toBe(EvidenceSnapshotResource::getUrl('view', ['record' => $snapshot], tenant: $tenant, panel: 'admin'));
|
||||
});
|
||||
|
||||
it('keeps audit and queue references on explicit inspect without row-click navigation', function (): void {
|
||||
@ -1716,14 +1719,13 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
});
|
||||
|
||||
it('keeps tenant diagnostics as a singleton repair surface with header actions only', function (): void {
|
||||
[$manager, $tenant] = createMinimalUserWithTenant(role: 'manager');
|
||||
[$manager, $tenant] = createUserWithTenant(role: 'manager');
|
||||
|
||||
$this->actingAs($manager);
|
||||
Filament::setTenant($tenant, true);
|
||||
setTenantPanelContext($tenant);
|
||||
|
||||
Livewire::test(TenantDiagnostics::class)
|
||||
->assertActionVisible('bootstrapOwner')
|
||||
->assertActionEnabled('bootstrapOwner');
|
||||
->assertActionExists('bootstrapOwner');
|
||||
|
||||
$declaration = TenantDiagnostics::actionSurfaceDeclaration();
|
||||
|
||||
@ -1754,7 +1756,10 @@ function actionSurfaceSystemPanelContext(array $capabilities): PlatformUser
|
||||
[$user, $tenant] = createMinimalUserWithTenant(role: 'readonly');
|
||||
|
||||
$response = $this->actingAs($user)
|
||||
->get("/admin/tenants/{$tenant->external_id}/required-permissions");
|
||||
->get(TenantRequiredPermissions::getUrl([
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
'tenant' => $tenant,
|
||||
], panel: 'admin'));
|
||||
|
||||
$response->assertOk()
|
||||
->assertSee('Copy missing application permissions')
|
||||
|
||||
@ -39,7 +39,10 @@
|
||||
it('resolves tenantless operation run links to the canonical admin.operations.view route', function (): void {
|
||||
$run = OperationRun::factory()->create();
|
||||
|
||||
$expectedUrl = route('admin.operations.view', ['run' => (int) $run->getKey()]);
|
||||
$expectedUrl = route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]);
|
||||
|
||||
expect(OperationRunLinks::tenantlessView($run))->toBe($expectedUrl);
|
||||
expect(OperationRunLinks::tenantlessView((int) $run->getKey()))->toBe($expectedUrl);
|
||||
@ -49,7 +52,10 @@
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$run = OperationRun::factory()->for($tenant)->create();
|
||||
|
||||
$expectedUrl = route('admin.operations.view', ['run' => (int) $run->getKey()]);
|
||||
$expectedUrl = route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]);
|
||||
|
||||
expect(OperationRunLinks::view($run, $tenant))->toBe($expectedUrl)
|
||||
->and(OperationRunLinks::view((int) $run->getKey(), $tenant))->toBe($expectedUrl);
|
||||
@ -57,9 +63,11 @@
|
||||
|
||||
it('preserves tenant prefilter, requested tab, and problem class on canonical operations collection links', function (): void {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$workspaceId = (int) $tenant->workspace_id;
|
||||
|
||||
expect(OperationRunLinks::index($tenant, activeTab: 'active'))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => $workspaceId,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => 'active',
|
||||
]))
|
||||
@ -69,6 +77,7 @@
|
||||
problemClass: OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
|
||||
))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => $workspaceId,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
|
||||
'problemClass' => OperationRun::PROBLEM_CLASS_ACTIVE_STALE_ATTENTION,
|
||||
@ -79,6 +88,7 @@
|
||||
problemClass: OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => $workspaceId,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'activeTab' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
'problemClass' => OperationRun::PROBLEM_CLASS_TERMINAL_FOLLOW_UP,
|
||||
@ -90,6 +100,7 @@
|
||||
|
||||
expect(OperationRunLinks::index($tenant, operationType: 'inventory_sync'))
|
||||
->toBe(route('admin.operations.index', [
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'tableFilters' => [
|
||||
'type' => [
|
||||
|
||||
@ -55,6 +55,9 @@
|
||||
expect($notificationJson)->toContain('passwordMinimumLength');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertSuccessful();
|
||||
});
|
||||
|
||||
@ -38,7 +38,10 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspaceA->getKey()])
|
||||
->get(route('admin.operations.view', ['run' => (int) $runB->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $workspaceB->getKey(),
|
||||
'run' => (int) $runB->getKey(),
|
||||
]))
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
use App\Filament\Clusters\Monitoring\AlertsCluster;
|
||||
use App\Filament\Pages\TenantDashboard;
|
||||
use App\Filament\Pages\TenantRequiredPermissions;
|
||||
use App\Filament\Resources\AlertDestinationResource;
|
||||
use App\Filament\Resources\AlertRuleResource;
|
||||
use App\Filament\Resources\RestoreRunResource;
|
||||
@ -42,16 +43,19 @@
|
||||
|
||||
assertNoOutboundHttp(function () use ($run, $session): void {
|
||||
$this->withSession($session)
|
||||
->get(route('admin.operations.index'))
|
||||
->get(route('admin.operations.index', ['workspace' => (int) $run->workspace_id]))
|
||||
->assertOk()
|
||||
->assertSee('All tenants')
|
||||
->assertSee(__('localization.shell.all_environments'))
|
||||
->assertDontSee('Scope: ManagedEnvironment')
|
||||
->assertDontSee('Scope: Workspace');
|
||||
|
||||
$this->withSession($session)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('All tenants')
|
||||
->assertSee(__('localization.shell.all_environments'))
|
||||
->assertDontSee('Scope: ManagedEnvironment')
|
||||
->assertDontSee('Scope: Workspace');
|
||||
|
||||
@ -59,14 +63,14 @@
|
||||
->followingRedirects()
|
||||
->get(AlertsCluster::getUrl(panel: 'admin'))
|
||||
->assertOk()
|
||||
->assertSee('All tenants')
|
||||
->assertSee(__('localization.shell.all_environments'))
|
||||
->assertDontSee('Scope: ManagedEnvironment')
|
||||
->assertDontSee('Scope: Workspace');
|
||||
|
||||
$this->withSession($session)
|
||||
->get(route('admin.monitoring.audit-log'))
|
||||
->assertOk()
|
||||
->assertSee('All tenants')
|
||||
->assertSee(__('localization.shell.all_environments'))
|
||||
->assertDontSee('Scope: ManagedEnvironment')
|
||||
->assertDontSee('Scope: Workspace');
|
||||
});
|
||||
@ -90,12 +94,15 @@
|
||||
|
||||
$response = $this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
])->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSee('← Back to '.$tenant->name)
|
||||
->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false)
|
||||
->assertSee(TenantDashboard::getUrl(tenant: $tenant), false)
|
||||
->assertDontSee('Back to Operations');
|
||||
|
||||
$this->withSession([
|
||||
@ -128,12 +135,15 @@
|
||||
$response = $this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => $workspaceId,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap,
|
||||
])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
])->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSee('← Back to '.$tenant->name)
|
||||
->assertSee(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant), false)
|
||||
->assertSee(TenantDashboard::getUrl(tenant: $tenant), false)
|
||||
->assertSee('Show all operations')
|
||||
->assertDontSee('Back to Operations');
|
||||
})->group('ops-ux');
|
||||
@ -161,7 +171,10 @@
|
||||
$response = $this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => $workspaceId,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [(string) $workspaceId => (int) $nonEntitledTenant->getKey()],
|
||||
])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
])->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
@ -186,7 +199,7 @@
|
||||
|
||||
$this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])->get(route('admin.operations.index'))
|
||||
])->get(route('admin.operations.index', ['workspace' => (int) $tenant->workspace_id]))
|
||||
->assertOk()
|
||||
->assertSee('Monitoring landing')
|
||||
->assertSee('Scope context')
|
||||
@ -194,7 +207,10 @@
|
||||
|
||||
$this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
])->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('Monitoring detail')
|
||||
->assertSee('Navigation lane')
|
||||
@ -208,11 +224,11 @@
|
||||
// User is NOT a member — stale workspace context is denied as not found.
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get(route('admin.operations.index'))
|
||||
->get(route('admin.operations.index', ['workspace' => (int) $workspace->getKey()]))
|
||||
->assertNotFound();
|
||||
})->group('ops-ux');
|
||||
|
||||
it('returns 404 for non-entitled tenant dashboard direct access', function (): void {
|
||||
it('keeps canonical tenant dashboard access available for workspace-entitled actors', function (): void {
|
||||
$tenant = ManagedEnvironment::factory()->create();
|
||||
$user = User::factory()->create();
|
||||
|
||||
@ -224,8 +240,8 @@
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(TenantDashboard::getUrl(panel: 'tenant', tenant: $tenant))
|
||||
->assertNotFound();
|
||||
->get(TenantDashboard::getUrl(tenant: $tenant))
|
||||
->assertOk();
|
||||
})->group('ops-ux');
|
||||
|
||||
it('keeps member-without-capability workflow start denial as 403 with no run side effects', function (): void {
|
||||
@ -255,7 +271,7 @@
|
||||
$response = $this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => $workspaceId,
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => $lastTenantMap,
|
||||
])->get(route('admin.operations.index'));
|
||||
])->get(route('admin.operations.index', ['workspace' => $workspaceId]));
|
||||
|
||||
$response->assertOk();
|
||||
$response->assertSessionHas(WorkspaceContext::SESSION_KEY, $workspaceId);
|
||||
@ -313,7 +329,10 @@
|
||||
(string) $workspaceId => (int) $runTenant->getKey(),
|
||||
]);
|
||||
|
||||
$request = Request::create(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
$request = Request::create(route('admin.operations.view', [
|
||||
'workspace' => $workspaceId,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
$request->setLaravelSession(app('session.store'));
|
||||
|
||||
$route = app('router')->getRoutes()->match($request);
|
||||
@ -359,7 +378,10 @@
|
||||
(string) $workspaceId => (int) $runTenant->getKey(),
|
||||
]);
|
||||
|
||||
$request = Request::create(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
$request = Request::create(route('admin.operations.view', [
|
||||
'workspace' => $workspaceId,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
$request->setLaravelSession(app('session.store'));
|
||||
|
||||
$route = app('router')->getRoutes()->match($request);
|
||||
@ -421,7 +443,10 @@
|
||||
(string) $workspaceId => (int) $rememberedTenant->getKey(),
|
||||
]);
|
||||
|
||||
$request = Request::create("/admin/tenants/{$routedTenant->external_id}/required-permissions");
|
||||
$request = Request::create(TenantRequiredPermissions::getUrl([
|
||||
'workspace' => (int) $routedTenant->workspace_id,
|
||||
'tenant' => $routedTenant,
|
||||
], panel: 'admin'));
|
||||
$request->setLaravelSession(app('session.store'));
|
||||
|
||||
$route = app('router')->getRoutes()->match($request);
|
||||
@ -459,7 +484,7 @@
|
||||
(string) $workspaceId => (int) $rememberedTenant->getKey(),
|
||||
]);
|
||||
|
||||
$request = Request::create("/admin/tenants/{$routedTenant->external_id}");
|
||||
$request = Request::create(TenantDashboard::getUrl(tenant: $routedTenant));
|
||||
$request->setLaravelSession(app('session.store'));
|
||||
|
||||
$route = app('router')->getRoutes()->match($request);
|
||||
@ -478,12 +503,12 @@
|
||||
|
||||
$this->withSession([
|
||||
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
|
||||
])->get(route('admin.operations.index'))
|
||||
])->get(route('admin.operations.index', ['workspace' => (int) $tenant->workspace_id]))
|
||||
->assertOk()
|
||||
->assertSee('ManagedEnvironment scope: '.$tenant->name)
|
||||
->assertSee(__('localization.shell.environment_scope').': '.$tenant->name)
|
||||
->assertDontSee('Scope: ManagedEnvironment')
|
||||
->assertDontSee('Scope: Workspace')
|
||||
->assertDontSee('All tenants');
|
||||
->assertDontSee(__('localization.shell.all_environments'));
|
||||
})->group('ops-ux');
|
||||
|
||||
it('does not create audit entries when viewing operate hub pages', function (): void {
|
||||
@ -507,11 +532,14 @@
|
||||
];
|
||||
|
||||
$this->withSession($session)
|
||||
->get(route('admin.operations.index'))
|
||||
->get(route('admin.operations.index', ['workspace' => (int) $tenant->workspace_id]))
|
||||
->assertOk();
|
||||
|
||||
$this->withSession($session)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertOk();
|
||||
|
||||
$this->withSession($session)
|
||||
@ -607,11 +635,14 @@
|
||||
WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY => [
|
||||
(string) $runTenant->workspace_id => (int) $rememberedTenant->getKey(),
|
||||
],
|
||||
])->get(route('admin.operations.view', ['run' => (int) $run->getKey()]));
|
||||
])->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $run->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]));
|
||||
|
||||
$response
|
||||
->assertOk()
|
||||
->assertSee('All tenants')
|
||||
->assertSee(__('localization.shell.all_environments'))
|
||||
->assertSee('Canonical workspace view')
|
||||
->assertSee('No tenant context is currently selected.');
|
||||
->assertSee('No environment context is currently selected.');
|
||||
})->group('ops-ux');
|
||||
|
||||
@ -2,11 +2,14 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
|
||||
it('shows Provider Connections under the Settings → Integrations navigation section for entitled users', function (): void {
|
||||
[$user] = createUserWithTenant(role: 'owner');
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('/admin/operations')
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get(route('admin.operations.index', ['workspace' => (int) $tenant->workspace_id]))
|
||||
->assertOk();
|
||||
|
||||
$groups = app(\Filament\Navigation\NavigationManager::class)->get();
|
||||
|
||||
@ -3,11 +3,10 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Resources\ProviderConnectionResource\Pages\ListProviderConnections;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Facades\Filament;
|
||||
use Livewire\Livewire;
|
||||
|
||||
it('does not authorize provider connection create CTA for non-members', function (): void {
|
||||
it('hides the provider connection header create CTA when no authorized tenant context is available on an empty list', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
$user->tenants()->detach((int) $tenant->getKey());
|
||||
app(\App\Services\Auth\CapabilityResolver::class)->clearCache();
|
||||
@ -17,7 +16,5 @@
|
||||
Filament::setTenant($tenant, true);
|
||||
|
||||
Livewire::test(ListProviderConnections::class)
|
||||
->assertActionExists('create', function (Action $action): bool {
|
||||
return $action->isAuthorized() === false;
|
||||
});
|
||||
->assertActionHidden('create');
|
||||
});
|
||||
|
||||
@ -21,6 +21,7 @@
|
||||
|
||||
$run = OperationRun::factory()->create([
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
'type' => 'provider.connection.check',
|
||||
'status' => 'completed',
|
||||
'outcome' => 'failed',
|
||||
@ -35,7 +36,10 @@
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertStatus(404);
|
||||
|
||||
$connection = ProviderConnection::factory()->create([
|
||||
@ -56,6 +60,7 @@
|
||||
|
||||
$run = OperationRun::factory()->create([
|
||||
'managed_environment_id' => (int) $tenant->getKey(),
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
'user_id' => (int) $user->getKey(),
|
||||
'type' => 'provider.connection.check',
|
||||
'status' => 'completed',
|
||||
@ -71,7 +76,10 @@
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
|
||||
->get(route('admin.operations.view', [
|
||||
'workspace' => (int) $tenant->workspace_id,
|
||||
'run' => (int) $run->getKey(),
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('Verification report');
|
||||
|
||||
|
||||
@ -0,0 +1,53 @@
|
||||
# Requirements Checklist: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
## Scope and problem framing
|
||||
|
||||
- [x] The package describes the remaining problem as cutover-driven suite and baseline debt after Specs `287` and `288`.
|
||||
- [x] The package keeps scope limited to stabilization, classification, bounded rebaselines, and explicit documentation of remaining debt.
|
||||
- [x] The package explicitly excludes Package Execution, Guided Operations, UI expansion, broad refactors, and legacy reactivation.
|
||||
- [x] The package keeps `289` untouched and `292` untouched.
|
||||
|
||||
## Repo-truth anchoring
|
||||
|
||||
- [x] The package anchors retired panel and `/admin/t/...` cleanup to current admin-panel and workspace-aware runtime truth.
|
||||
- [x] The package anchors operations route cleanup to current workspace-aware operations links.
|
||||
- [x] The package anchors provider and required-permissions cleanup to current canonical surfaces rather than tenant-scoped fallbacks.
|
||||
- [x] The package anchors action-surface rebaseline to current workspace-first and managed-environment semantics.
|
||||
- [x] The package anchors regression proof to the existing Spec `288` proof pack and existing browser anchors.
|
||||
|
||||
## Failure classification and boundedness
|
||||
|
||||
- [x] The pinned failure-classification categories are exactly `cutover-baseline-debt`, `cutover-runtime-regression`, `unrelated-existing-debt`, `flaky-or-environment`, and `resolved-or-not-needed`.
|
||||
- [x] The pinned stabilization seams are exactly `tenant_panel_baseline`, `legacy_admin_t_routes`, `workspace_aware_operations_routes`, `legacy_required_permissions_provider_connections`, and `action_surface_rebaseline`.
|
||||
- [x] The same failure-classification category names appear across `spec.md`, `plan.md`, `research.md`, `data-model.md`, `quickstart.md`, `tasks.md`, `checklists/requirements.md`, and `failure-classification.md`, with authoritative meanings owned by `data-model.md` and `failure-classification.md`.
|
||||
- [x] The same stabilization seams appear across `spec.md`, `plan.md`, `research.md`, `data-model.md`, `tasks.md`, and `failure-classification.md`.
|
||||
- [x] The package adds only one spec-local failure-classification artifact and does not turn that artifact into runtime truth.
|
||||
- [x] The package allows minimal runtime fixes only when a current workspace-first primary path is proven broken.
|
||||
- [x] Remaining unrelated or flaky debt stays explicit instead of being silently absorbed.
|
||||
|
||||
## Validation and workflow
|
||||
|
||||
- [x] Planned proof begins with baseline classification before fixes.
|
||||
- [x] The same validation commands appear across `spec.md`, `plan.md`, `tasks.md`, and `quickstart.md`.
|
||||
- [x] The package re-verifies the Spec `288` proof pack and the browser anchors explicitly.
|
||||
- [x] The package ends with broad confidence and formatting checks.
|
||||
- [x] The package keeps review outcome, workflow outcome, and test-governance outcome aligned.
|
||||
|
||||
## Adjacent-spec control
|
||||
|
||||
- [x] `293` is described as a stabilization package, not a Package Execution package.
|
||||
- [x] `293` does not overwrite or renumber `289`.
|
||||
- [x] `293` does not overwrite or renumber `292`.
|
||||
- [x] The package does not silently absorb Guided Operations, Microsoft Starter Pack, or other future follow-on work.
|
||||
|
||||
## Notes
|
||||
|
||||
- Reviewed against `.specify/memory/constitution.md`, the existing Specs `287` and `288`, the current product docs, and the repo-real panel, OpsUx, provider, verification, RBAC, and browser test surfaces on 2026-05-10.
|
||||
- This package is implementation-ready only when `tasks.md` preserves the same proof commands, failure categories, stabilization seams, and bounded-scope rules.
|
||||
|
||||
## Outcome
|
||||
|
||||
- **Review outcome class**: `acceptable-special-case`
|
||||
- **Workflow outcome**: `keep`
|
||||
- **Test-governance outcome**: `keep`
|
||||
- **Readiness note**: implementation is ready as one bounded stabilization slice after Specs `287` and `288`; Package Execution remains separate.
|
||||
53
specs/293-post-cutover-suite-stabilization/data-model.md
Normal file
@ -0,0 +1,53 @@
|
||||
# Data Model: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
## Overview
|
||||
|
||||
`293` introduces no new application entity, table, or persisted runtime artifact. Its only modeled data is spec-local preparation truth for later implementation: one failure-classification artifact, one bounded failure-category inventory, and one bounded stabilization-seam inventory.
|
||||
|
||||
## Pinned Failure-Classification Categories
|
||||
|
||||
| Category | Meaning | Default Treatment in `293` |
|
||||
|---|---|---|
|
||||
| `cutover-baseline-debt` | stale test or baseline expectation caused directly by the `287` and `288` cutover truth | fix in `293` |
|
||||
| `cutover-runtime-regression` | current workspace-first primary path is actually broken | allow minimal targeted fix in `293` if proven |
|
||||
| `unrelated-existing-debt` | existing failure outside the cutover stabilization scope | document, do not silently absorb |
|
||||
| `flaky-or-environment` | nondeterministic or environment-specific failure | isolate, rerun, and document |
|
||||
| `resolved-or-not-needed` | initially suspected cutover debt that no longer needs work after classification or adjacent repair | record and stop |
|
||||
|
||||
## Pinned Stabilization Seams
|
||||
|
||||
| Seam Key | Meaning | Primary Targets |
|
||||
|---|---|---|
|
||||
| `tenant_panel_baseline` | tests still assuming TenantPanel or `panel: 'tenant'` as current runtime truth | panel navigation and adjacent helper expectations |
|
||||
| `legacy_admin_t_routes` | tests still expecting `/admin/t/...` management paths to behave as canonical runtime routes | panel navigation, required-permissions, provider routes |
|
||||
| `workspace_aware_operations_routes` | tests or helpers generating operations routes without `workspace` context | OpsUx helpers, action-surface links, operations route tests |
|
||||
| `legacy_required_permissions_provider_connections` | tests still expecting tenant-scoped required-permissions or provider-connection URLs to be canonical | provider-connection and verification-adjacent surfaces |
|
||||
| `action_surface_rebaseline` | stale action expectations caused only by workspace-first, environment-scope, or TenantPanel removal | action-surface, RBAC, and adjacent Filament expectations |
|
||||
|
||||
## Spec-Local Artifact: `failure-classification.md`
|
||||
|
||||
| Field | Meaning |
|
||||
|---|---|
|
||||
| `Group` | failing test, test family, or lane-visible group |
|
||||
| `Seam` | one or more pinned stabilization seams, or `N/A` when the failure is unrelated |
|
||||
| `Category` | one pinned failure category |
|
||||
| `Reason` | short explanation for why the group belongs to that category |
|
||||
| `Fix In 293?` | `yes`, `no`, or `only-if-proven-runtime-regression` |
|
||||
| `Follow-up` | next action if the group remains open |
|
||||
| `Status` | current implementation-tracking note |
|
||||
|
||||
## Invariants
|
||||
|
||||
- The same five failure-classification categories must appear in `spec.md`, `plan.md`, `tasks.md`, `research.md`, `quickstart.md`, `checklists/requirements.md`, and `failure-classification.md`.
|
||||
- The same five stabilization seams must appear in `spec.md`, `plan.md`, `tasks.md`, `research.md`, and `failure-classification.md`.
|
||||
- `293` introduces no new runtime product state and no new runtime persistence.
|
||||
- `293` must not reactivate TenantPanel, `/admin/t/...`, or tenant-scoped provider fallback routes.
|
||||
- `293` must keep the Spec `288` proof pack and browser anchors green.
|
||||
|
||||
## Out-of-Scope Data Changes
|
||||
|
||||
- no database migrations by default
|
||||
- no new provider registry or provider execution contract
|
||||
- no new RBAC role family or persisted access overlay
|
||||
- no new browser fixture family
|
||||
- no new runtime ledger or stabilization table
|
||||
@ -0,0 +1,47 @@
|
||||
# Failure Classification: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
## Purpose
|
||||
|
||||
Use this artifact during later implementation of `293` to record the initial suite baseline, classify every relevant failure, and keep remaining unrelated debt explicit.
|
||||
|
||||
## Pinned Failure-Classification Categories
|
||||
|
||||
| Category | Meaning |
|
||||
|---|---|
|
||||
| `cutover-baseline-debt` | stale test or baseline expectation caused directly by the `287` and `288` cutover truth |
|
||||
| `cutover-runtime-regression` | current workspace-first primary path is actually broken |
|
||||
| `unrelated-existing-debt` | existing failure outside the cutover stabilization scope |
|
||||
| `flaky-or-environment` | nondeterministic or environment-specific failure |
|
||||
| `resolved-or-not-needed` | initially suspected cutover debt that no longer needs work after classification or adjacent repair |
|
||||
|
||||
## Pinned Stabilization Seams
|
||||
|
||||
| Seam | Meaning |
|
||||
|---|---|
|
||||
| `tenant_panel_baseline` | stale TenantPanel or `panel: 'tenant'` assumptions |
|
||||
| `legacy_admin_t_routes` | stale `/admin/t/...` management-route assumptions |
|
||||
| `workspace_aware_operations_routes` | operations links or helpers missing workspace context |
|
||||
| `legacy_required_permissions_provider_connections` | tenant-scoped required-permissions or provider-connection legacy expectations |
|
||||
| `action_surface_rebaseline` | stale action-surface expectations caused by the cutover |
|
||||
|
||||
## Initial Baseline Seeds
|
||||
|
||||
| Group | Seam | Category | Reason | Fix In 293? | Follow-up | Status |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `PanelNavigationSegregationTest` | `tenant_panel_baseline`, `legacy_admin_t_routes` | `cutover-baseline-debt` | confirmed: the file still expects `/admin` to return `200` directly and still treats `/admin/t/...` as a live panel entry point | yes | update the baseline to current admin-panel navigation truth and explicit retired-route assertions | confirmed from targeted panel proof set |
|
||||
| `ActionSurfaceContractTest` | `workspace_aware_operations_routes`, `legacy_required_permissions_provider_connections`, `action_surface_rebaseline` | `cutover-baseline-debt` | still likely mixes old action expectations and old route generation assumptions | yes | rebaseline only cutover-stale expectations | pending initial baseline run |
|
||||
| `CanonicalViewRunLinksTest`, `OperateHubShellTest`, `FailureSanitizationTest`, `NonLeakageWorkspaceOperationsTest` | `workspace_aware_operations_routes` | `cutover-baseline-debt` | confirmed: the targeted OpsUx proof set still builds `admin.operations.*` URLs without `workspace`, and `OperateHubShellTest` still expects a retired tenant-panel dashboard URL | yes | rebaseline these tests to the canonical workspace-aware routes and current tenant dashboard URL | confirmed from targeted OpsUx proof set |
|
||||
| `BackupItemsRelationManagerUiEnforcementTest` | `action_surface_rebaseline` | `cutover-baseline-debt` | treat as cutover debt initially, but reclassify if the mismatch proves unrelated during targeted reruns | yes | reclassify if mismatch is unrelated or proves to be a true runtime regression instead | pending initial baseline run |
|
||||
| `TenantSyncBulkJobTest` | `N/A` | `unrelated-existing-debt` | current summary-count mismatch is not obviously part of the cutover baseline | no unless reclassification proves otherwise | document and leave out of scope | pending initial baseline run |
|
||||
| `LegacyTenantCoreGuardTest` | `tenant_panel_baseline`, `legacy_admin_t_routes` | `resolved-or-not-needed` | the targeted panel proof set left the guard file green while `PanelNavigationSegregationTest` failed, so the retirement guard already reflects current truth | no | keep as regression proof while stabilizing the stale navigation test | confirmed from targeted panel proof set |
|
||||
| `NavigationPlacementTest`, view-route assertions in `VerificationAuthorizationTest` | `workspace_aware_operations_routes` | `cutover-baseline-debt` | confirmed: one provider navigation test still used the retired `/admin/operations` entry point and verification view assertions still built `admin.operations.view` without `workspace` or persisted run workspace context | yes | rebaseline to the canonical `/admin/workspaces/{workspace}/operations` routes and seeded run workspace ids | confirmed green in focused reruns after rebaseline |
|
||||
| `ActionSurfaceContractTest`, `RequiredPermissionsLegacyRouteTest` | `legacy_required_permissions_provider_connections`, `action_surface_rebaseline`, `workspace_aware_operations_routes` | `cutover-baseline-debt` | confirmed: the guard still expected tenant-plane required-permissions URLs, tenant-panel-era operation links, and several stale surface labels/action inventories | yes | rebaseline to canonical workspace/environment required-permissions routes, workspace-aware operation links, and current action labels/inventory | confirmed green in focused reruns after rebaseline |
|
||||
| `ProviderConnectionListAuthorizationTest` | `action_surface_rebaseline` | `resolved-or-not-needed` | the mismatch proved to be an empty-list header-surface expectation rather than a cutover runtime bug; the current surface hides the header create CTA on an empty list for non-members | no | keep the rebaselined assertion as the current header-surface regression proof | confirmed green in focused rerun |
|
||||
| `BackupItemsRelationManagerUiEnforcementTest` | `action_surface_rebaseline` | `unrelated-existing-debt` | targeted rerun showed the mid-session membership-revocation mismatch is not a cutover route/panel issue and no longer matches either the old hidden-state assumption or a simple disabled-state rebaseline | no | leave for a dedicated RBAC/action-state follow-up outside spec 293 | confirmed from targeted rerun |
|
||||
| `ProviderConnectionNeutralitySpec238Test` | `N/A` | `unrelated-existing-debt` | current provider connection detail copy no longer contains `Provider identity details`; this is a neutral-surface wording drift unrelated to workspace-first cutover seams | no | leave for a provider-surface wording follow-up | confirmed from post-rebaseline provider/verification rerun |
|
||||
| `ProviderDispatchGateStartSurfaceTest`, `ProviderOperationConcurrencyTest`, `VerificationAuthorizationTest` start assertion, `VerificationStartAfterCompletionTest`, `VerificationStartDedupeTest` | `N/A` | `unrelated-existing-debt` | after the route baseline repairs, these failures remain as provider-operation gate / dedupe behavior mismatches (`blocked` starts, extra runs, missing queued jobs) rather than panel or workspace-route drift; repo note `provider-verification-start-fixture-contract.md` documents the new startable fixture contract behind this seam | no | leave for a dedicated provider-operation / verification follow-up outside spec 293 | confirmed from post-rebaseline provider/verification rerun |
|
||||
| `ProviderConnectionHealthCheckWritesReportTest` | `N/A` | `unrelated-existing-debt` | verification report summary counts now exceed the prior `<= 7` cap (`8` observed), which is report-schema/content drift unrelated to the cutover baseline | no | leave for a dedicated verification-report follow-up | confirmed from post-rebaseline provider/verification rerun |
|
||||
|
||||
## Completion Rule
|
||||
|
||||
Before `293` can be considered ready for implementation close-out, every remaining relevant group must appear in the table above or an appended row below with one pinned category and one explicit follow-up. After the final rerun, no cutover-related failure may remain unclassified: each group must be resolved, explicitly left out of scope as `unrelated-existing-debt` or `flaky-or-environment`, or recorded as `resolved-or-not-needed`.
|
||||
273
specs/293-post-cutover-suite-stabilization/plan.md
Normal file
@ -0,0 +1,273 @@
|
||||
# Implementation Plan: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
**Branch**: `293-post-cutover-suite-stabilization` | **Date**: 2026-05-10 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `specs/293-post-cutover-suite-stabilization/spec.md`
|
||||
|
||||
**Note**: This plan is produced from the repo's Spec Kit templates and stays preparation-only. It does not implement application code.
|
||||
|
||||
## Summary
|
||||
|
||||
Stabilize the test suite after Specs `287` and `288` by classifying failures first, then aligning stale panel, route, provider-link, required-permissions, operations-link, managed-environment role-authority, and action-surface expectations to current workspace-first runtime truth. The plan intentionally keeps Package Execution, Guided Operations, UI expansion, and broad refactors out of scope.
|
||||
|
||||
This package is an interstitial stabilization slice. It does not renumber or replace the future Package Execution follow-up that existing repo artifacts already reserve separately. It exists to keep cutover debt from drifting into those later packages.
|
||||
|
||||
## Inherited Baseline / Explicit Delta
|
||||
|
||||
### Inherited baseline
|
||||
|
||||
- Spec `287` completed the remaining route, provider-core, access-scope, and helper prerequisites for the cutover.
|
||||
- Spec `288` introduced the no-legacy and quality-gate enforcement baseline and its proof pack.
|
||||
- The current repo truth is admin-panel-first, workspace-first, environment-scoped where required, tenantless provider-connection canonical routing, and narrowing-only managed-environment memberships.
|
||||
- `289` remains untouched by this package.
|
||||
- `292` already exists and remains unrelated to this stabilization work.
|
||||
|
||||
### Explicit delta in this plan
|
||||
|
||||
- Add one stabilization artifact, `failure-classification.md`, to classify suite failures before any repair work.
|
||||
- Rebaseline retired TenantPanel and `/admin/t/...` assumptions on existing tests and, only if proven necessary, the current canonical helper path.
|
||||
- Rebaseline workspace-aware operations route generation in the in-scope OpsUx and action-surface test families.
|
||||
- Rebaseline tenant-scoped required-permissions and provider-connection legacy expectations to the current canonical surfaces.
|
||||
- Rebaseline bounded action-surface expectations that are stale only because of the cutover.
|
||||
- Keep the Spec `288` proof pack and current browser anchors green while documenting any unrelated debt that remains.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: PHP 8.4.15, Laravel 12.52
|
||||
**Primary Dependencies**: Pest 4, Filament 5.2.1, Livewire 4.1.4, current OpsUx helpers, current provider/verification helpers, current browser smoke suite
|
||||
**Storage**: no new application persistence; one spec-local `failure-classification.md` artifact for implementation tracking only
|
||||
**Testing**: targeted Pest feature/browser reruns, broader lane or full-suite reruns for classification and confidence, formatting
|
||||
**Validation Lanes**: confidence, heavy-governance, browser, and initial/final full-suite baseline when usable
|
||||
**Target Platform**: Laravel monolith in `apps/platform`
|
||||
**Project Type**: web application
|
||||
**Performance Goals**: keep stabilization work bounded to cutover-driven debt and avoid turning the package into an open-ended full-suite repair program
|
||||
**Constraints**: no Package Execution work, no Guided Operations work, no UI expansion, no broad refactors, no TenantPanel or `/admin/t/...` reactivation, and no compatibility-route restoration
|
||||
**Scale/Scope**: one cross-cutting stabilization slice covering existing panel, OpsUx, provider, verification, RBAC, and browser proof seams
|
||||
|
||||
## Pinned Stabilization Seams
|
||||
|
||||
- `tenant_panel_baseline`: stale TenantPanel or `panel: 'tenant'` assumptions in the suite baseline
|
||||
- `legacy_admin_t_routes`: stale `/admin/t/...` management-route assumptions
|
||||
- `workspace_aware_operations_routes`: operations links or helpers missing workspace context
|
||||
- `legacy_required_permissions_provider_connections`: tenant-scoped required-permissions or provider-connection legacy expectations
|
||||
- `action_surface_rebaseline`: stale action-surface expectations caused by the cutover
|
||||
|
||||
## Likely Affected Repo Surfaces
|
||||
|
||||
- `apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/CanonicalViewRunLinksTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/OperateHubShellTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/FailureSanitizationTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/TenantSyncBulkJobTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/TenantlessListRouteTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/TenantlessListScopingTest.php`
|
||||
- `apps/platform/tests/Feature/Verification/*`
|
||||
- `apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php`
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
|
||||
- `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`
|
||||
- `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`
|
||||
- `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`
|
||||
- `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
|
||||
- `apps/platform/app/Support/OperationRunLinks.php`
|
||||
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
||||
- `apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
|
||||
- `apps/platform/app/Providers/Filament/AdminPanelProvider.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantDashboard.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`
|
||||
- `apps/platform/app/Filament/Resources/TenantResource.php`
|
||||
- `apps/platform/tests/Pest.php`
|
||||
|
||||
## Filament v5 / Surface Notes
|
||||
|
||||
- **Livewire v4.0+ compliance**: all touched runtime seams remain on Filament v5 with Livewire v4.
|
||||
- **Provider registration location**: provider registration remains in `apps/platform/bootstrap/providers.php`; `293` does not add or move a panel provider.
|
||||
- **Global search rule**: no new globally-searchable resource is introduced, and `293` does not broaden any existing global search surface.
|
||||
- **Destructive actions**: no new destructive action is planned. Any later runtime correction must preserve current confirmation and authorization behavior.
|
||||
- **Asset strategy**: no asset registration or deployment-step change is planned. Existing `php artisan filament:assets` expectations remain unchanged because this package adds no assets.
|
||||
|
||||
## Stabilization Fit
|
||||
|
||||
- Classify failures before editing tests or helpers.
|
||||
- Prefer fixing stale expectations over restoring compatibility behavior.
|
||||
- Prefer current canonical helpers over raw route strings whenever repo truth already provides them.
|
||||
- Allow minimal runtime fixes only when a current workspace-first primary path is demonstrably broken.
|
||||
- Keep unrelated, flaky, or no-longer-needed failures explicit in `failure-classification.md`.
|
||||
|
||||
## UI / Surface Guardrail Plan
|
||||
|
||||
- **Guardrail scope**: existing provider, required-permissions, navigation, action-surface, and OpsUx shell surfaces only; no new operator-facing surface is planned
|
||||
- **Native vs custom classification summary**: native Filament and existing shared shell/helpers only
|
||||
- **Shared-family relevance**: route generation, action surfaces, workspace-first access semantics, and browser anchors
|
||||
- **State layers in scope**: existing routes, shared URL helpers, page access surfaces, and browser-visible continuity only
|
||||
- **Audience modes in scope**: maintainers and reviewers first; operator-facing behavior changes are only incidental to proven regressions
|
||||
- **Decision/diagnostic/raw hierarchy plan**: unchanged runtime disclosure; the package validates current truth instead of redesigning it
|
||||
- **Raw/support gating plan**: unchanged
|
||||
- **One-primary-action / duplicate-truth control**: no new action family is introduced
|
||||
- **Handling modes by drift class or surface**: cutover debt is implementation-required; unrelated or flaky debt is report-only in `failure-classification.md`
|
||||
- **Repository-signal treatment**: review-mandatory for any runtime fix boundary crossing
|
||||
- **Special surface test profiles**: `standard-native-filament`, `global-context-shell`, `browser-smoke`
|
||||
- **Required tests or manual smoke**: targeted feature/core reruns plus the two named browser anchors
|
||||
- **Exception path and spread control**: any runtime fix must stay on existing canonical helpers and may not restore compatibility behavior
|
||||
- **Active feature PR close-out entry**: `SuiteStabilization`
|
||||
|
||||
## Shared Pattern & System Fit
|
||||
|
||||
- **Cross-cutting feature marker**: yes
|
||||
- **Systems touched**: panel navigation, action-surface contracts, OpsUx canonical links, provider and verification route expectations, RBAC proof surfaces, and the existing browser anchors
|
||||
- **Shared abstractions reused**: `OperationRunLinks`, `OperateHubShell`, `WorkspaceScopedTenantRoutes`, existing provider or required-permissions helpers, existing browser anchors, and current RBAC proof seams
|
||||
- **New abstraction introduced? why?**: none
|
||||
- **Why the existing abstraction was sufficient or insufficient**: the abstractions already describe the desired runtime truth; they only need stale test assumptions removed and minimal helper corrections if a real regression is proven.
|
||||
- **Bounded deviation / spread control**: runtime deviations are allowed only as minimal canonical fixes, never as compatibility restoration
|
||||
|
||||
## OperationRun UX Impact
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: yes, but only around canonical route generation for operations index and run detail links
|
||||
- **Central contract reused**: `OperationRunLinks`
|
||||
- **Delegated UX behaviors**: preserve current canonical operations index and run detail links; no new queued toast, browser event, or notification behavior is introduced
|
||||
- **Surface-owned behavior kept local**: existing page-level assertions only
|
||||
- **Queued DB-notification policy**: unchanged
|
||||
- **Terminal notification path**: unchanged
|
||||
- **Exception path**: none
|
||||
|
||||
## Provider Boundary & Portability Fit
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes
|
||||
- **Provider-owned seams**: provider-specific nested detail remains bounded to existing provider-owned surfaces only
|
||||
- **Platform-core seams**: canonical route builders, workspace-aware operations links, and current access semantics
|
||||
- **Neutral platform terms / contracts preserved**: `workspace`, `managed environment`, `provider connection`, `operation run`, `required permissions`
|
||||
- **Retained provider-specific semantics and why**: only provider-owned nested detail remains provider-specific; `293` does not deepen provider coupling
|
||||
- **Bounded extraction or follow-up path**: Package Execution and later guided flows remain separate; `293` only stabilizes suite debt first
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before implementation begins and again after the design artifacts are complete.*
|
||||
|
||||
- `Inventory-first, Snapshots-second`: PASS. `293` introduces no new inventory or snapshot runtime truth.
|
||||
- `Read/Write Separation by Default`: PASS. The package is stabilization-only and any later runtime fix must stay minimal, explicit, and within current primary-path truth.
|
||||
- `Single Contract Path to Graph`: PASS by preservation. No new Graph integration seam is introduced.
|
||||
- `Deterministic Capabilities`: PASS by preservation. Capability derivation and role authority do not change.
|
||||
- `PROP-001`, `ABSTR-001`, `V1-EXP-001`, and `LAYER-001`: PASS. The package reuses existing tests, helpers, and canonical route seams instead of introducing a new stabilization layer or abstraction family.
|
||||
- `PROV-001`: PASS. The work removes stale tenant-first assumptions while preserving neutral platform-core route and helper vocabulary.
|
||||
- `PERSIST-001` and `STATE-001`: PASS. `failure-classification.md` is spec-local preparation truth only and does not become runtime persistence or product state.
|
||||
- `XCUT-001`: PASS. Existing shared paths such as `OperationRunLinks`, `OperateHubShell`, `WorkspaceScopedTenantRoutes`, and current browser anchors are reused.
|
||||
- `TEST-TRUTH-001` and `TEST-GOV-001`: PASS. The plan keeps proof explicit, classified, and bounded to existing feature, browser, lane, and proof-pack surfaces.
|
||||
- `BLOAT-001`: PASS. The proportionality review covers the only new artifact-level taxonomy introduced by `293`.
|
||||
- `LEAN-001`: PASS. The package explicitly forbids legacy compatibility restoration, TenantPanel reactivation, and fallback-route revival.
|
||||
|
||||
**Gate evaluation**: PASS.
|
||||
|
||||
**Post-design re-check**: PASS while the same failure-classification categories, canonical proof commands, and out-of-scope boundary remain aligned across `spec.md`, `plan.md`, `tasks.md`, `research.md`, `data-model.md`, `quickstart.md`, `checklists/requirements.md`, and `failure-classification.md`.
|
||||
|
||||
## Test Governance Check
|
||||
|
||||
- **Test purpose / classification by changed surface**: Feature, Browser, Heavy-Governance
|
||||
- **Affected validation lanes**: confidence, heavy-governance, browser, and initial or final full-suite baseline when usable
|
||||
- **Why this lane mix is the narrowest sufficient proof**: the package must classify failures first, repair only cutover-related debt, keep the existing enforcement proof pack green, and prove that browser-visible canonical flows still work.
|
||||
- **Narrowest proving command(s)**:
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git status --short --branch`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git diff --stat`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane heavy-governance`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane confidence`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/CanonicalViewRunLinksTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/OpsUx/FailureSanitizationTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections tests/Feature/Verification)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Guards/BrowserLaneIsolationTest.php tests/Feature/Guards/CiLaneFailureClassificationContractTest.php tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php tests/Unit/Auth/NoRoleStringChecksTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent)`
|
||||
- **Fixture / helper / factory / seed / context cost risks**: moderate only because the package reuses broad existing suites and browser anchors; it must not add new expensive defaults.
|
||||
- **Expensive defaults or shared helper growth introduced?**: no; the package should shrink stale assumptions, not widen helper cost.
|
||||
- **Heavy-family additions, promotions, or visibility changes**: none new; only reuse of existing heavy-governance and confidence lanes
|
||||
- **Surface-class relief / special coverage rule**: `standard-native-filament`, `global-context-shell`, and current browser anchors remain sufficient
|
||||
- **Closing validation and reviewer handoff**: reviewers must re-run the exact commands above, confirm the Spec `288` proof pack and browser anchors stay green, and verify that remaining failures are classified rather than silently ignored.
|
||||
- **Budget / baseline / trend follow-up**: limited to explicit failure classification; no new permanent lane or suite family is created.
|
||||
- **Review-stop questions**: did the work restore legacy runtime behavior, turn into a feature redesign, or absorb unrelated debt without classification?
|
||||
- **Escalation path**: `document-in-feature` for explicit debt classification, `reject-or-split` for scope expansion
|
||||
- **Active feature PR close-out entry**: `SuiteStabilization`
|
||||
- **Why no dedicated follow-up spec is needed**: `293` itself is the dedicated stabilization slice; later feature packages should not absorb this debt again.
|
||||
|
||||
## Review Checklist Status
|
||||
|
||||
- **Review checklist artifact**: `checklists/requirements.md`
|
||||
- **Review outcome class**: `acceptable-special-case`
|
||||
- **Workflow outcome**: `keep`
|
||||
- **Test-governance outcome**: `keep`
|
||||
- **Resolution note**: the package is implementation-ready as one shared stabilization slice following Specs `287` and `288`
|
||||
- **Escalation rule**: if implementation starts restoring legacy behavior or absorbing Package Execution, Guided Operations, or unrelated debt without classification, stop and split the work out of `293`
|
||||
|
||||
## Rollout Considerations
|
||||
|
||||
- Record the initial baseline and failure-classification artifact before any fixes.
|
||||
- Land panel and `/admin/t/...` baseline cleanup before broader action-surface adjustments so the visible runtime truth is pinned first.
|
||||
- Stabilize workspace-aware operations links before final action-surface and browser reruns, because those helpers feed multiple suites.
|
||||
- Keep Spec `288` proof-pack reruns and browser anchors as explicit midstream and final checkpoints.
|
||||
- Treat full-suite or lane reruns as classification and confidence proof, not as license for unlimited unrelated repair.
|
||||
|
||||
## Risk Controls
|
||||
|
||||
- Reject any implementation that restores TenantPanel bootstrapping or `/admin/t/...` compatibility behavior.
|
||||
- Reject any implementation that fixes tests by hardcoding legacy route shapes instead of using current canonical helpers or explicit workspace parameters.
|
||||
- Reject any implementation that adds new actions or redesigns action surfaces merely to satisfy pre-cutover assertions.
|
||||
- Reject any implementation that changes Package Execution or Guided Operations scope under the label of stabilization.
|
||||
- Reject any implementation that leaves remaining unrelated or flaky failures undocumented.
|
||||
|
||||
## Research & Design Outputs
|
||||
|
||||
- `research.md` records the stabilization-first decisions, rejected alternatives, and evidence anchors.
|
||||
- `data-model.md` captures the spec-local failure-classification categories, stabilization seam inventory, and invariants.
|
||||
- `quickstart.md` gives reviewers the read order, review scenarios, exact proof commands, and stop conditions.
|
||||
- `failure-classification.md` is the planned implementation artifact used to record baseline findings and remaining debt.
|
||||
- `checklists/requirements.md` records the readiness and bounded-scope checks for the package.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/293-post-cutover-suite-stabilization/
|
||||
├── checklists/
|
||||
│ └── requirements.md
|
||||
├── data-model.md
|
||||
├── failure-classification.md
|
||||
├── plan.md
|
||||
├── quickstart.md
|
||||
├── research.md
|
||||
├── spec.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
apps/platform/
|
||||
├── app/
|
||||
├── routes/
|
||||
└── tests/
|
||||
├── Browser/
|
||||
├── Feature/
|
||||
├── Support/
|
||||
└── Unit/
|
||||
|
||||
scripts/
|
||||
├── platform-test-lane
|
||||
└── platform-test-report
|
||||
```
|
||||
|
||||
**Structure Decision**: keep the package within the existing Laravel app and test structure. Reuse the current tests, support helpers, canonical route helpers, and lane scripts instead of introducing a new stabilization subsystem.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|---|---|---|
|
||||
| Spec-local failure-classification category set | The package needs an explicit, bounded way to distinguish cutover debt from unrelated or flaky failures | Ad hoc notes would hide scope drift and make later stabilization work ambiguous |
|
||||
|
||||
## Proportionality Review
|
||||
|
||||
- **Current operator problem**: without an explicit failure-classification artifact and category set, maintainers cannot tell which failures are still owned by the `287` and `288` cutover and which ones should stay out of scope.
|
||||
- **Existing structure is insufficient because**: scattered notes in tasks, PR comments, or terminal output would not preserve a single auditable baseline for later implementation and review.
|
||||
- **Narrowest correct implementation**: one spec-local markdown artifact plus five pinned categories and five pinned seam keys is enough to keep the stabilization work bounded without introducing runtime semantics.
|
||||
- **Ownership cost created**: one additional markdown file and one small alignment burden across the `293` artifacts.
|
||||
- **Alternative intentionally rejected**: ad hoc notes embedded only in tasks or execution logs, because they are easy to drift, hard to review, and poor at preventing scope creep.
|
||||
- **Release truth**: current-release preparation truth only; this is not new runtime product state.
|
||||
132
specs/293-post-cutover-suite-stabilization/quickstart.md
Normal file
@ -0,0 +1,132 @@
|
||||
# Quickstart: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
## Purpose
|
||||
|
||||
Use this guide to review or later implement Feature `293` as the bounded stabilization package that follows Specs `287` and `288`.
|
||||
|
||||
## Preconditions
|
||||
|
||||
- The package stays limited to cutover-driven suite stabilization.
|
||||
- The pinned failure categories are:
|
||||
- `cutover-baseline-debt`
|
||||
- `cutover-runtime-regression`
|
||||
- `unrelated-existing-debt`
|
||||
- `flaky-or-environment`
|
||||
- `resolved-or-not-needed`
|
||||
- The pinned stabilization seams are:
|
||||
- `tenant_panel_baseline`
|
||||
- `legacy_admin_t_routes`
|
||||
- `workspace_aware_operations_routes`
|
||||
- `legacy_required_permissions_provider_connections`
|
||||
- `action_surface_rebaseline`
|
||||
- `289` remains untouched.
|
||||
- `292` remains untouched.
|
||||
- TenantPanel, `/admin/t/...`, tenant-scoped provider fallbacks, and tenant-scoped required-permissions fallbacks remain retired.
|
||||
- `managed_environment_memberships` remain narrowing-only access scope and must not regain independent role authority.
|
||||
|
||||
## Read Order
|
||||
|
||||
1. `spec.md`
|
||||
2. `plan.md`
|
||||
3. `research.md`
|
||||
4. `data-model.md`
|
||||
5. `failure-classification.md`
|
||||
6. `tasks.md`
|
||||
7. `checklists/requirements.md`
|
||||
|
||||
## Implementation Intent
|
||||
|
||||
- classify failures before fixing anything
|
||||
- stabilize stale TenantPanel and `/admin/t/...` assumptions without restoring compatibility behavior
|
||||
- make in-scope operations routes workspace-aware through existing canonical helpers or explicit workspace parameters
|
||||
- remove tenant-scoped required-permissions and provider-connection legacy assumptions from the suite baseline
|
||||
- keep action-surface rebaseline bounded to cutover drift
|
||||
- keep the Spec `288` proof pack and browser anchors green
|
||||
- document remaining unrelated or flaky debt explicitly
|
||||
|
||||
## Review Scenarios
|
||||
|
||||
### Scenario 1: Initial baseline and classification
|
||||
|
||||
- run the initial full suite or fallback lane split
|
||||
- record the observed groups in `failure-classification.md`
|
||||
- confirm every relevant group is classified before fixes begin
|
||||
|
||||
### Scenario 2: Retired panel and route assumptions are gone
|
||||
|
||||
- re-run the targeted panel navigation and legacy tenant-core tests
|
||||
- confirm they no longer treat TenantPanel or `/admin/t/...` management routes as current runtime truth
|
||||
|
||||
### Scenario 3: Operations and legacy provider or permissions routes are canonical
|
||||
|
||||
- re-run the targeted OpsUx, ProviderConnections, and Verification proof sets
|
||||
- confirm those tests use current workspace-aware or tenantless canonical paths instead of retired fallbacks
|
||||
|
||||
### Scenario 4: Action-surface rebaseline stays bounded
|
||||
|
||||
- re-run the action-surface and adjacent RBAC or Filament tests
|
||||
- confirm only cutover-stale expectations changed and no new product actions were introduced just to satisfy tests
|
||||
- confirm managed-environment memberships are still treated as narrowing-only access scope and not as an independent role authority source
|
||||
|
||||
### Scenario 5: Enforcement and visible anchors remain green
|
||||
|
||||
- re-run the Spec `288` proof pack
|
||||
- re-run the two browser anchors
|
||||
- confirm the stabilization work did not regress the enforcement baseline or visible canonical flows
|
||||
|
||||
## Planned Validation Commands
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git status --short --branch
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git diff --stat
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane heavy-governance
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane confidence
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/CanonicalViewRunLinksTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/OpsUx/FailureSanitizationTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections tests/Feature/Verification)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Guards/BrowserLaneIsolationTest.php tests/Feature/Guards/CiLaneFailureClassificationContractTest.php tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php tests/Unit/Auth/NoRoleStringChecksTest.php)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php)
|
||||
```
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent)
|
||||
```
|
||||
|
||||
## Explicit Stop Conditions
|
||||
|
||||
- If implementation starts restoring TenantPanel or `/admin/t/...` compatibility behavior, stop.
|
||||
- If implementation starts absorbing Package Execution, Guided Operations, or new product features, stop.
|
||||
- If a failing group cannot be tied to one of the pinned failure categories, stop and classify it first.
|
||||
- If the Spec `288` proof pack or browser anchors regress, stop and restore them before proceeding.
|
||||
116
specs/293-post-cutover-suite-stabilization/research.md
Normal file
@ -0,0 +1,116 @@
|
||||
# Research: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
## Pinned Failure-Classification Categories
|
||||
|
||||
`293` uses exactly these spec-local categories:
|
||||
|
||||
- `cutover-baseline-debt`
|
||||
- `cutover-runtime-regression`
|
||||
- `unrelated-existing-debt`
|
||||
- `flaky-or-environment`
|
||||
- `resolved-or-not-needed`
|
||||
|
||||
These categories are implementation-tracking vocabulary only. They do not become runtime product state.
|
||||
|
||||
## Pinned Stabilization Seams
|
||||
|
||||
`293` stabilizes exactly these seam families:
|
||||
|
||||
- `tenant_panel_baseline`
|
||||
- `legacy_admin_t_routes`
|
||||
- `workspace_aware_operations_routes`
|
||||
- `legacy_required_permissions_provider_connections`
|
||||
- `action_surface_rebaseline`
|
||||
|
||||
## Decision 1: Baseline and classification come before any fixes
|
||||
|
||||
- The package must start by running the initial full suite or the fallback lane split and recording the resulting groups in `failure-classification.md`.
|
||||
- No test or runtime changes should land before those groups are classified.
|
||||
- This keeps `293` bounded to cutover-driven debt instead of silently becoming a general suite cleanup.
|
||||
|
||||
## Decision 2: Retired TenantPanel and `/admin/t/...` assumptions are baseline debt, not compatibility gaps
|
||||
|
||||
- Treat lingering `panel: 'tenant'`, TenantPanel bootstrapping, and `/admin/t/...` management-path expectations as stale suite assumptions.
|
||||
- The fix path is to align tests to current admin-panel and workspace-aware runtime truth or explicitly assert retirement.
|
||||
- Do not restore TenantPanel or `/admin/t/...` compatibility behavior.
|
||||
|
||||
## Decision 3: Workspace-aware operations links should reuse current canonical helpers
|
||||
|
||||
- The expected post-cutover baseline for operations routes is workspace-aware link generation.
|
||||
- Prefer `OperationRunLinks` and current shell helpers over raw route strings whenever repo truth already provides them.
|
||||
- If a current primary-path helper is actually broken, classify the issue as `cutover-runtime-regression` before considering any minimal runtime fix during later implementation.
|
||||
|
||||
## Decision 4: Tenant-scoped required-permissions and provider-connection fallback URLs stay retired
|
||||
|
||||
- Tests must not treat tenant-scoped required-permissions URLs or tenant-scoped provider-connection URLs as current canonical runtime paths.
|
||||
- The remediation path is to move expectations to the current canonical admin or workspace-aware route helpers.
|
||||
- Reintroducing those fallbacks is forbidden.
|
||||
|
||||
## Decision 5: Action-surface rebaseline stays bounded to cutover drift
|
||||
|
||||
- `ActionSurfaceContractTest` and adjacent RBAC or Filament tests may be updated only where the expectation is stale because of workspace-first routing, managed-environment scope semantics, or TenantPanel removal.
|
||||
- `293` must not add new actions, widen UX, or redesign surfaces merely to satisfy old tests.
|
||||
- When a mismatch is not actually caused by the cutover, reclassify it as `unrelated-existing-debt` instead of absorbing it.
|
||||
|
||||
## Decision 6: Spec `288` proof pack and browser anchors remain non-negotiable regression guards
|
||||
|
||||
- The Spec `288` proof pack stays the enforcement baseline that `293` must keep green.
|
||||
- The browser anchors `Spec281ProviderConnectionScopeSmokeTest` and `Spec285WorkspaceRbacEnvironmentAccessSmokeTest` remain the visible continuity proof.
|
||||
- `293` can extend adjacent tests for stabilization, but it must not weaken or replace those proof surfaces.
|
||||
|
||||
## Decision 7: Remaining debt must stay explicit
|
||||
|
||||
- `failure-classification.md` is the single implementation artifact for recording what remains after cutover stabilization work.
|
||||
- Each remaining group must stay categorized as `unrelated-existing-debt`, `flaky-or-environment`, or `resolved-or-not-needed` when it is not owned by the stabilization slice.
|
||||
- Do not leave residual failures unclassified.
|
||||
|
||||
## Rejected Alternatives
|
||||
|
||||
### Rejected: split every failing group into separate micro-specs
|
||||
|
||||
That would scatter one cutover-stabilization thread across multiple tiny packages and keep the ownership boundary ambiguous.
|
||||
|
||||
### Rejected: restore compatibility behavior to make tests green faster
|
||||
|
||||
That would directly violate the cutover direction established by Specs `287` and `288`.
|
||||
|
||||
### Rejected: absorb all remaining full-suite failures into `293`
|
||||
|
||||
The package is meant to stabilize cutover-driven debt, not to become a permanent fix-all suite lane.
|
||||
|
||||
### Rejected: redesign action surfaces while rebaselining tests
|
||||
|
||||
That would widen `293` from stabilization into product work.
|
||||
|
||||
## Evidence Anchors
|
||||
|
||||
- `apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/CanonicalViewRunLinksTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/OperateHubShellTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/FailureSanitizationTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/TenantSyncBulkJobTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/TenantlessListRouteTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/TenantlessListScopingTest.php`
|
||||
- `apps/platform/tests/Feature/Verification/*`
|
||||
- `apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php`
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
|
||||
- `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`
|
||||
- `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`
|
||||
- `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`
|
||||
- `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
|
||||
- `apps/platform/app/Support/OperationRunLinks.php`
|
||||
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
||||
- `apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
|
||||
- `apps/platform/app/Providers/Filament/AdminPanelProvider.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantDashboard.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`
|
||||
- `apps/platform/app/Filament/Resources/TenantResource.php`
|
||||
|
||||
## Boundary Summary
|
||||
|
||||
- `293` is a shared stabilization package, not a Package Execution or Guided Operations package.
|
||||
- `289` remains untouched.
|
||||
- `292` remains untouched.
|
||||
- The package keeps existing canonical runtime truth and only allows minimal runtime fixes later if a current primary path is proven broken.
|
||||
330
specs/293-post-cutover-suite-stabilization/spec.md
Normal file
@ -0,0 +1,330 @@
|
||||
## Feature Specification: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
**Feature Branch**: `293-post-cutover-suite-stabilization`
|
||||
**Created**: 2026-05-10
|
||||
**Status**: Ready
|
||||
**Input**: User description: "Prepare the already proposed stabilization package as a new safe slot `293-post-cutover-suite-stabilization` without touching Spec `289` or Spec `292`. The package stabilizes the suite after Spec `287` and Spec `288`, clears cutover-driven baseline debt, keeps Package Execution separate, and stays preparation-only in this step."
|
||||
|
||||
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
||||
|
||||
- **Problem**: Spec `287` completed the runtime prerequisites and Spec `288` locked the no-legacy enforcement baseline, but the broader suite still contains cutover-era assumptions that expect the retired TenantPanel, `/admin/t/...` runtime truth, tenant-scoped provider and required-permissions routes, workspace-unaware operations links, and pre-cutover action-surface semantics.
|
||||
- **Today's failure**: targeted proof packs are green, yet broader lanes still surface red groups such as `PanelNavigationSegregationTest`, `ActionSurfaceContractTest`, multiple `tests/Feature/OpsUx/*` assumptions, and adjacent RBAC/action-surface expectations that no longer match the workspace-first, admin-panel-only runtime.
|
||||
- **User-visible improvement**: maintainers get one bounded stabilization package that makes the suite reflect current runtime truth, keeps legacy behavior retired, and documents remaining unrelated baseline debt instead of letting it drift into future features.
|
||||
- **Smallest enterprise-capable version**: one stabilization spec that classifies failures first, rebases retired TenantPanel and `/admin/t/...` assumptions, makes in-scope operations route generation workspace-aware, retires tenant-scoped required-permissions and provider-connection baseline expectations, performs a bounded action-surface cutover rebaseline, keeps the Spec `288` proof pack and browser anchors green, and records remaining unrelated or flaky failures in one explicit artifact.
|
||||
- **Explicit non-goals**: no Package Execution work, no Guided Operations work, no Microsoft Starter Pack work, no Virtual Consultant work, no new product features, no new UI surfaces, no UI polish, no broad refactors, no reactivation of TenantPanel, no reactivation of `/admin/t/...`, no reactivation of retired provider-connection fallback routes, and no migration work unless a true workspace-first runtime regression proves a minimal blocker fix is required during later implementation.
|
||||
- **Permanent complexity imported**: one spec-local failure-classification artifact, one bounded failure-category inventory, targeted suite/lane proof commands, and narrowly-scoped tasking for existing test and helper seams. No new runtime persistence, no new provider abstraction, no new RBAC model, and no new product surface are introduced.
|
||||
- **Why now**: after `287` and `288`, leaving suite debt unclassified would force every subsequent cutover-adjacent feature to rediscover the same stale assumptions and blur the boundary between enforcement and repair.
|
||||
- **Why not local**: the remaining debt is not isolated to one file or one product area. It spans panel navigation, operations route generation, provider and required-permissions links, workspace-first RBAC assumptions, and action-surface expectations, so a one-off local patch would leave the repo-wide cutover baseline inconsistent.
|
||||
- **Approval class**: Cleanup
|
||||
- **Red flags triggered**: cross-cutting suite stabilization, possible spillover into runtime fixes, and broad-lane reruns. Defense: the slice is bounded to cutover-driven debt, starts with classification, forbids legacy reactivation, and keeps Package Execution and broader product work out of scope.
|
||||
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 1 | Wiederverwendung: 2 | **Gesamt: 10/12**
|
||||
- **Decision**: approve
|
||||
|
||||
## Review Outcome
|
||||
|
||||
- **Outcome class**: `acceptable-special-case`
|
||||
- **Workflow outcome**: `keep`
|
||||
- **Test-governance outcome**: `keep`
|
||||
- **Reason**: the package is cross-cutting but remains implementation-ready because it stabilizes only cutover-driven suite debt, uses explicit failure classification, and forbids feature expansion or legacy reactivation.
|
||||
- **Workflow result**: Ready for implementation as the shared stabilization package that follows Specs `287` and `288` without replacing later Package Execution work.
|
||||
|
||||
## Spec Scope Fields *(mandatory)*
|
||||
|
||||
- **Scope**: repository
|
||||
- **Primary Routes**:
|
||||
- canonical workspace/environment admin routes such as `/admin/workspaces/{workspace}/environments/{managed_environment}/...`
|
||||
- canonical provider-connection routes such as `/admin/provider-connections...`
|
||||
- workspace-scoped operations routes generated through `admin.operations.index` and `admin.operations.view`
|
||||
- retired paths that must remain retired, including `/admin/t/{tenant}/...`, tenant-scoped required-permissions URLs, and tenant-scoped provider-connection fallback URLs
|
||||
- **Data Ownership**:
|
||||
- no new application persistence is introduced
|
||||
- `workspace_memberships` remain the role-bearing authority source
|
||||
- `managed_environment_memberships` remain narrowing-only access scope
|
||||
- `failure-classification.md` is a spec-local artifact used to record baseline findings during later implementation; it is not a runtime source of truth
|
||||
- **RBAC**:
|
||||
- reuse the workspace-first contract from Spec `285`
|
||||
- non-members or wrong-scope actors remain `404`
|
||||
- in-scope actors missing capability remain `403`
|
||||
- managed-environment membership rows must not regain independent role authority
|
||||
|
||||
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
||||
|
||||
- **Cross-cutting feature?**: yes
|
||||
- **Interaction class(es)**: suite baseline classification, canonical route/link generation, current browser smoke anchors, action-surface expectations, and workspace-first authorization expectations
|
||||
- **Systems touched**:
|
||||
- `apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`
|
||||
- `apps/platform/tests/Feature/OpsUx/*`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/*`
|
||||
- `apps/platform/tests/Feature/Verification/*`
|
||||
- `apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php`
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
|
||||
- `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`
|
||||
- `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`
|
||||
- `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
|
||||
- `apps/platform/app/Support/OperationRunLinks.php`
|
||||
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
|
||||
- `apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
|
||||
- `apps/platform/app/Providers/Filament/AdminPanelProvider.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantDashboard.php`
|
||||
- `apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`
|
||||
- `apps/platform/app/Filament/Resources/TenantResource.php`
|
||||
- `apps/platform/tests/Pest.php`
|
||||
- **Existing pattern(s) to extend**: existing workspace-first route helpers, existing OpsUx route/link helpers, existing browser smoke anchors, current action-surface contract tests, and the current workspace-first RBAC proof surfaces
|
||||
- **Shared contract / presenter / builder / renderer to reuse**: `OperationRunLinks`, `OperateHubShell`, `WorkspaceScopedTenantRoutes`, existing provider/required-permissions helpers, current browser smoke anchors, and the existing feature-test authorization seams
|
||||
- **Why the existing shared path is sufficient or insufficient**: the repo already contains the correct canonical helpers and proof surfaces; the missing piece is removing stale pre-cutover assumptions from tests and, only when proven, applying minimal fixes to the existing canonical helper path instead of reintroducing compatibility behavior.
|
||||
- **Allowed deviation and why**: only minimal runtime fixes are allowed later if a current workspace-first primary path is demonstrably broken. Reintroducing legacy routes, panel bootstrapping, or fallback aliases is forbidden.
|
||||
- **Consistency impact**: the same current runtime truth must appear across panel navigation, operations links, required-permissions links, provider-connection links, action-surface tests, browser anchors, and the failure-classification artifact.
|
||||
- **Review focus**: reviewers must verify that `293` stabilizes the suite around current truth, does not create new product behavior, and keeps Package Execution and Guided Operations separate.
|
||||
|
||||
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: yes, but only around canonical operations route generation and current workspace-aware `View run` or `Show all operations` links
|
||||
- **Shared OperationRun UX contract/layer reused**: `OperationRunLinks` and current OpsUx shell/link resolution helpers
|
||||
- **Delegated start/completion UX behaviors**: preserve current `View run` and operations index URL resolution through the existing shared helpers; no new queued toast, event, dedupe, or notification semantics are introduced
|
||||
- **Local surface-owned behavior that remains**: none beyond the current page-specific assertions already owned by the tested surfaces
|
||||
- **Queued DB-notification policy**: `N/A` - unchanged
|
||||
- **Terminal notification path**: existing central lifecycle mechanism, unchanged
|
||||
- **Exception required?**: none
|
||||
|
||||
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes
|
||||
- **Boundary classification**: mixed
|
||||
- **Seams affected**: provider-connection route expectations, required-permissions route expectations, workspace-aware operations links, and managed-environment access-scope assumptions
|
||||
- **Neutral platform terms preserved or introduced**: `workspace`, `managed environment`, `provider connection`, `operation run`, `required permissions`
|
||||
- **Provider-specific semantics retained and why**: provider-owned nested detail remains allowed only where the provider itself is the subject; `293` does not widen provider-specific semantics into platform-core truth
|
||||
- **Why this does not deepen provider coupling accidentally**: the package removes stale tenant-first and compatibility assumptions and keeps canonical workspace-first helpers as the only accepted runtime truth
|
||||
- **Follow-up path**: Package Execution remains a separate future package; `293` only stabilizes suite debt first
|
||||
|
||||
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
||||
|
||||
N/A - no new operator-facing surface is intentionally introduced. Later implementation may touch existing surfaces only to align tests or correct a proven primary-path regression without adding new UX.
|
||||
|
||||
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - existing surfaces remain the source of truth; `293` does not define a new decision surface.
|
||||
|
||||
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - no new default-visible operator or customer disclosure layer is introduced.
|
||||
|
||||
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - the package stabilizes existing surfaces only.
|
||||
|
||||
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - no new operator-facing contract is introduced.
|
||||
|
||||
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||
|
||||
- **New source of truth?**: no runtime source of truth
|
||||
- **New persisted entity/table/artifact?**: no application persistence; one spec-local `failure-classification.md` artifact is added for implementation tracking only
|
||||
- **New abstraction?**: no
|
||||
- **New enum/state/reason family?**: yes, one bounded failure-classification category set used only inside this spec package
|
||||
- **New cross-domain UI framework/taxonomy?**: no
|
||||
- **Current operator problem**: maintainers need one bounded way to distinguish cutover-driven suite debt from unrelated failures so the repo stops rediscovering stale assumptions after Specs `287` and `288`.
|
||||
- **Existing structure is insufficient because**: ad hoc repair notes or one-off fixes would hide scope drift and make it unclear which failures belong to the cutover stabilization thread.
|
||||
- **Narrowest correct implementation**: define one spec-local failure-classification artifact and one pinned category set, then point later implementation tasks at existing tests and helpers only.
|
||||
- **Ownership cost**: low; maintain one spec-local table and keep the same category names aligned across the prep artifacts.
|
||||
- **Alternative intentionally rejected**: a full-suite fix-all program or a new repo-wide stabilization framework. Both would widen scope far beyond the current cutover debt.
|
||||
- **Release truth**: current-release test governance and suite stabilization only
|
||||
|
||||
### Compatibility posture
|
||||
|
||||
This feature assumes a pre-production environment.
|
||||
|
||||
Backward compatibility, legacy aliases, compatibility routes, and compatibility-specific tests are out of scope unless a proven current primary-path regression later requires a minimal targeted fix.
|
||||
|
||||
Canonical replacement remains preferred over preservation.
|
||||
|
||||
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
||||
|
||||
- **Test purpose / classification**: Feature, Browser, Heavy-Governance
|
||||
- **Validation lane(s)**: confidence, heavy-governance, browser, and an initial or final full-suite baseline run when output remains usable
|
||||
- **Why this classification and these lanes are sufficient**: the package stabilizes cross-cutting suite debt, so it needs classification-first proof, targeted feature/browser reruns on the touched seams, the Spec `288` proof pack, and at least one broader confidence check to prove no cutover-related failures remain unclassified.
|
||||
- **New or expanded test families**: none new by design; reuse existing panel, action-surface, OpsUx, provider-connection, verification, RBAC, and browser files
|
||||
- **Fixture / helper cost impact**: moderate only because existing broad suites and browser anchors are re-run; the package must not introduce new expensive helper defaults
|
||||
- **Heavy-family visibility / justification**: explicit. `293` intentionally uses the existing heavy-governance and confidence lanes as validation surfaces, but it must not turn that into a permanent fix-all obligation.
|
||||
- **Special surface test profile**: `standard-native-filament`, `global-context-shell`, `browser-smoke`
|
||||
- **Standard-native relief or required special coverage**: targeted feature tests plus the two named browser anchors are required; any broader rerun remains for classification and confidence only
|
||||
- **Reviewer handoff**: reviewers must confirm that the implementation fixes only cutover-driven baseline debt, documents remaining unrelated or flaky failures, keeps the Spec `288` proof pack green, and does not restore legacy runtime behavior
|
||||
- **Budget / baseline / trend impact**: classification-only documentation of remaining unrelated debt; no new permanent lane or guard subsystem
|
||||
- **Escalation needed**: `document-in-feature`
|
||||
- **Active feature PR close-out entry**: `SuiteStabilization`
|
||||
- **Planned validation commands**:
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git status --short --branch`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git diff --stat`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane heavy-governance`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane confidence`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/CanonicalViewRunLinksTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/OpsUx/FailureSanitizationTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections tests/Feature/Verification)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Guards/BrowserLaneIsolationTest.php tests/Feature/Guards/CiLaneFailureClassificationContractTest.php tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php tests/Unit/Auth/NoRoleStringChecksTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php)`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent)`
|
||||
|
||||
## Failure Classification Categories
|
||||
|
||||
The implementation must classify every remaining relevant failure into exactly one of these categories:
|
||||
|
||||
- `cutover-baseline-debt`: stale suite expectation caused directly by the `287` and `288` cutover truth; fix in `293`
|
||||
- `cutover-runtime-regression`: current workspace-first primary path is actually broken; a minimal fix may be allowed later in `293` if proven
|
||||
- `unrelated-existing-debt`: existing failure outside the cutover stabilization scope; document instead of absorbing it
|
||||
- `flaky-or-environment`: nondeterministic or local-environment issue; isolate, rerun, and document
|
||||
- `resolved-or-not-needed`: initially suspected cutover debt that no longer needs code changes after reclassification or adjacent stabilization
|
||||
|
||||
## Stabilization Seams
|
||||
|
||||
The implementation must keep the seam inventory bounded to these exact keys:
|
||||
|
||||
- `tenant_panel_baseline`: stale TenantPanel or `panel: 'tenant'` assumptions in the suite baseline
|
||||
- `legacy_admin_t_routes`: stale `/admin/t/...` management-route assumptions
|
||||
- `workspace_aware_operations_routes`: operations links or helpers missing workspace context
|
||||
- `legacy_required_permissions_provider_connections`: tenant-scoped required-permissions or provider-connection legacy expectations
|
||||
- `action_surface_rebaseline`: stale action-surface expectations caused by the cutover
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Classify Remaining Cutover Failures First (Priority: P1)
|
||||
|
||||
As a maintainer, I want an initial baseline and failure-classification artifact before any fixes so `293` repairs only cutover-driven debt instead of silently turning into a general suite cleanup.
|
||||
|
||||
**Why this priority**: without classification first, every later change risks absorbing unrelated debt or reintroducing compatibility behavior by accident.
|
||||
|
||||
**Independent Test**: Can be fully tested by running the initial full suite or fallback lanes, recording the resulting groups in `failure-classification.md`, and proving every in-scope failure is assigned to one of the pinned categories.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the current post-`287` and post-`288` baseline, **When** the initial suite or lane commands run, **Then** the resulting failure groups are recorded in `failure-classification.md` using the pinned categories before any implementation work begins.
|
||||
2. **Given** a failure is clearly unrelated to cutover debt, **When** it is classified, **Then** it is documented as `unrelated-existing-debt` or `flaky-or-environment` instead of being silently fixed under `293`.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Remove Retired TenantPanel and `/admin/t/...` Baseline Assumptions (Priority: P1)
|
||||
|
||||
As a maintainer, I want the suite to stop expecting the retired TenantPanel and `/admin/t/...` runtime truth so current admin-panel-only routing becomes the only accepted baseline.
|
||||
|
||||
**Why this priority**: these are the most visible stale assumptions and they distort multiple downstream tests and route expectations.
|
||||
|
||||
**Independent Test**: Can be fully tested by re-running `PanelNavigationSegregationTest`, the legacy tenant-core guard, and the browser anchors while proving that retired paths are treated as absent or forbidden instead of current runtime truth.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an in-scope test still expects `/admin/t/...` to return the current page, **When** `293` lands, **Then** that expectation is replaced with the current admin or workspace-aware baseline.
|
||||
2. **Given** a test still depends on `panel: 'tenant'` or equivalent retired panel bootstrapping, **When** the stabilization work completes, **Then** the test uses the current admin-panel path or explicitly asserts retirement instead.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Make Operations and Legacy Provider/Permissions Baselines Canonical (Priority: P1)
|
||||
|
||||
As a maintainer, I want operations links, required-permissions links, and provider-connection links in the suite to resolve only through current canonical workspace-aware or tenantless admin paths.
|
||||
|
||||
**Why this priority**: workspace-unaware operations links and retired tenant-scoped provider or required-permissions assumptions are the main cutover debt still visible across OpsUx and verification-adjacent tests.
|
||||
|
||||
**Independent Test**: Can be fully tested by re-running the targeted OpsUx, ProviderConnections, and Verification proof sets and proving those tests no longer depend on tenant-scoped fallbacks or missing workspace parameters.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a test generates `admin.operations.index` or `admin.operations.view` without `workspace`, **When** `293` stabilizes the baseline, **Then** that test uses the canonical helper or explicit workspace parameter instead.
|
||||
2. **Given** a test expects tenant-scoped required-permissions or provider-connection URLs to return `200`, **When** the stabilization work completes, **Then** it uses the current canonical surface instead of the retired path.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Rebaseline Action Surface Expectations Without Reopening Product Work (Priority: P2)
|
||||
|
||||
As a maintainer, I want stale action-surface expectations updated only where they are directly invalidated by workspace-first, environment-scope, or TenantPanel removal so `293` does not become a feature redesign.
|
||||
|
||||
**Why this priority**: action-surface drift is real, but it is also the easiest place for a stabilization spec to overreach into product behavior.
|
||||
|
||||
**Independent Test**: Can be fully tested by re-running the action-surface and adjacent RBAC feature tests while proving that only stale cutover-era expectations changed and no new actions were added merely to satisfy old assertions.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** an action-surface test still expects an old cutover-era action or label, **When** `293` updates the baseline, **Then** the expectation is aligned to current runtime truth without adding a new product action.
|
||||
2. **Given** an action mismatch is not actually caused by the cutover, **When** it is reviewed during `293`, **Then** it is documented in `failure-classification.md` instead of being silently absorbed.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when the initial full-suite run is too noisy or slow to classify accurately? The package must fall back to `heavy-governance` and `confidence` lanes without skipping classification.
|
||||
- What happens when an in-scope test failure looks like cutover debt but is actually a true current runtime regression on the workspace-first primary path? The failure must be reclassified as `cutover-runtime-regression` before any minimal fix is considered later.
|
||||
- What happens when one stale action-surface assertion sits beside an unrelated existing debt in the same file? Only the cutover-driven expectation may be fixed under `293`; the unrelated failure must be classified explicitly.
|
||||
- What happens when the Spec `288` proof pack or browser anchors regress during stabilization? `293` must stop and restore that proof pack before claiming readiness.
|
||||
- What happens when a test could be made green by restoring a tenant-scoped fallback route or TenantPanel bootstrapping shortcut? That remedy is forbidden under `293`.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
**Constitution alignment (required):** This package introduces no new Graph integration surface, no new queue workflow, no new product workflow, and no new runtime source of truth. It stabilizes the suite and only allows minimal runtime fixes later when a current workspace-first primary path is demonstrably broken.
|
||||
|
||||
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The package must reuse the current tests, helpers, route builders, browser anchors, and lane scripts. It may add one spec-local failure-classification artifact and one bounded category inventory, but it must not create a new runtime framework, lane system, or compatibility layer.
|
||||
|
||||
**Constitution alignment (XCUT-001 / PROV-001):** The package must reuse current shared link helpers, current provider and RBAC proof surfaces, and current browser anchors. It may correct existing canonical helpers if a true primary-path regression is proven later, but it must not restore tenant-first or provider-specific fallback behavior.
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: `293` MUST begin with an initial baseline and failure-classification pass before implementation fixes start.
|
||||
- **FR-002**: `failure-classification.md` MUST classify every remaining relevant failure using exactly these categories: `cutover-baseline-debt`, `cutover-runtime-regression`, `unrelated-existing-debt`, `flaky-or-environment`, and `resolved-or-not-needed`.
|
||||
- **FR-003**: In-scope tests MUST stop treating the retired TenantPanel, `panel: 'tenant'`, and `/admin/t/...` management paths as current runtime truth, except where a test explicitly verifies that those paths are retired or forbidden.
|
||||
- **FR-004**: In-scope operations tests MUST generate `admin.operations.index` and `admin.operations.view` through current workspace-aware helpers or explicit workspace parameters.
|
||||
- **FR-005**: In-scope required-permissions and provider-connection tests MUST stop expecting tenant-scoped legacy URLs to behave as canonical runtime paths.
|
||||
- **FR-006**: In-scope tests MUST stop treating managed-environment membership rows as a second role-bearing authority source.
|
||||
- **FR-007**: Action-surface rebaselining under `293` MUST stay bounded to stale cutover-era expectations and MUST NOT add or redesign product actions merely to satisfy old tests.
|
||||
- **FR-008**: If later implementation proves a current workspace-first primary path regression, `293` MAY apply a minimal fix through the existing canonical helper or route path only; it MUST NOT restore legacy routes, TenantPanel bootstrapping, or tenant-scoped provider fallbacks.
|
||||
- **FR-009**: The Spec `288` proof pack MUST remain green after `293` implementation.
|
||||
- **FR-010**: The browser anchors `Spec281ProviderConnectionScopeSmokeTest` and `Spec285WorkspaceRbacEnvironmentAccessSmokeTest` MUST remain green after `293` implementation.
|
||||
- **FR-011**: Remaining unrelated or flaky failures MUST stay documented in `failure-classification.md`; `293` MUST NOT silently absorb them.
|
||||
- **FR-012**: `293` MUST remain a stabilization package only and MUST NOT absorb Package Execution, Guided Operations, Microsoft Starter Pack, Virtual Consultant, UI polish, or broad refactor work.
|
||||
|
||||
### Non-Functional Requirements
|
||||
|
||||
- **NFR-001**: Filament remains v5 on Livewire v4, and provider registration remains in `apps/platform/bootstrap/providers.php`.
|
||||
- **NFR-002**: The package introduces no new panel, no new globally-searchable resource, no new asset registration, and no change to destructive-action policy.
|
||||
- **NFR-003**: Validation remains bounded to the initial baseline or fallback lanes, targeted feature reruns, the Spec `288` proof pack, the two browser anchors, broad confidence rerun, and formatting.
|
||||
- **NFR-004**: `293` must not reintroduce TenantPanel bootstrapping, `/admin/t/...` compatibility routes, tenant-scoped provider-connection fallback routes, or tenant-scoped required-permissions fallback routes.
|
||||
- **NFR-005**: The pinned failure-classification category names must stay aligned across `spec.md`, `plan.md`, `tasks.md`, `research.md`, `data-model.md`, `quickstart.md`, `checklists/requirements.md`, and `failure-classification.md`, while the authoritative category meanings live in `data-model.md` and `failure-classification.md`.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Package Execution
|
||||
- Guided Operations
|
||||
- Microsoft Starter Pack
|
||||
- Virtual Consultant
|
||||
- new product features
|
||||
- new UI surfaces
|
||||
- UI polish
|
||||
- broad refactors
|
||||
- compatibility route or panel restoration
|
||||
- legacy provider-connection fallback restoration
|
||||
- repo-wide non-cutover cleanup unrelated to `287` and `288`
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: `failure-classification.md` exists and records the initial baseline groups with the pinned categories before cutover fixes are applied.
|
||||
- **SC-002**: No in-scope test continues to treat TenantPanel bootstrapping, `panel: 'tenant'`, or retired `/admin/t/...` management paths as current runtime truth.
|
||||
- **SC-003**: No in-scope operations test generates `admin.operations.index` or `admin.operations.view` without `workspace`.
|
||||
- **SC-004**: No in-scope test expects tenant-scoped required-permissions or provider-connection legacy URLs to return `200` as canonical paths.
|
||||
- **SC-005**: The Spec `288` proof pack remains green after `293`.
|
||||
- **SC-006**: The browser anchors remain green after `293`.
|
||||
- **SC-007**: A final full-suite or fallback-lane rerun leaves no unclassified cutover-related failures.
|
||||
- **SC-008**: `293` does not restore legacy runtime behavior and does not replace future Package Execution work.
|
||||
|
||||
## Risks
|
||||
|
||||
- Some initially failing tests may prove to be unrelated existing debt rather than cutover debt, which makes disciplined classification essential.
|
||||
- Broad suite noise may obscure root cause unless the initial baseline is split into the fallback lanes quickly.
|
||||
- Action-surface mismatches can tempt feature expansion unless the bounded rebaseline rule is enforced strictly.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- Specs `287` and `288` are the current cutover runtime and enforcement baseline.
|
||||
- `292` already exists and remains unrelated to this stabilization package.
|
||||
- The repo's current `heavy-governance`, `confidence`, and browser anchors are available and runnable during later implementation.
|
||||
|
||||
## Open Questions
|
||||
|
||||
- None. The scope, slot, branch name, and stabilization boundary were provided explicitly for this preparation pass.
|
||||
248
specs/293-post-cutover-suite-stabilization/tasks.md
Normal file
@ -0,0 +1,248 @@
|
||||
---
|
||||
description: "Task list for Post-Cutover Suite Stabilization & Baseline Reconciliation"
|
||||
---
|
||||
|
||||
# Tasks: Post-Cutover Suite Stabilization & Baseline Reconciliation
|
||||
|
||||
**Input**: Design documents from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/`
|
||||
**Prerequisites**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/plan.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/spec.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/checklists/requirements.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/research.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/data-model.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/quickstart.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md`
|
||||
|
||||
**Review Artifact**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/checklists/requirements.md` is the outcome-of-record for the review outcome class, workflow outcome, and test-governance outcome. `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md` is the implementation-tracking artifact for initial baseline classification and any remaining unrelated or flaky debt. If implementation expands into Package Execution, Guided Operations, UI expansion, legacy-route restoration, TenantPanel reactivation, broad refactors, or unrelated suite cleanup, update the review artifact before continuing and stop when the work no longer fits `293`.
|
||||
|
||||
**Tests**: Required (Pest) for test, helper, and any minimal runtime-fix work. Keep proof bounded to initial classification, targeted `Feature` and `Browser` reruns, the existing Spec `288` proof pack, broad confidence reruns, and formatting.
|
||||
**Operations**: No new `OperationRun`, queue family, remote workflow, or notification policy is introduced. `293` may touch current operations link helpers only to stabilize workspace-aware route truth on the existing runtime path.
|
||||
**RBAC**: Reuse the workspace-first access contract from Spec `285`; do not add a new role family, raw capability strings, or a second role-bearing access overlay.
|
||||
**Shared Pattern Reuse**: Reuse `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/CanonicalViewRunLinksTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/OperateHubShellTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/FailureSanitizationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/TenantSyncBulkJobTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Verification/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperationRunLinks.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperateHub/OperateHubShell.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantDashboard.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php`. Do not introduce a new stabilization subsystem, a new browser family, or a permanent full-suite wrapper under this spec.
|
||||
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration remains unchanged in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/bootstrap/providers.php`. No new panel, no new globally-searchable resource, and no asset-strategy change are allowed in this slice.
|
||||
**Organization**: Tasks are grouped by baseline classification, retired panel or route cleanup, workspace-aware operations route cleanup, legacy required-permissions/provider-connection cleanup, bounded action-surface rebaseline, and final regression proof.
|
||||
**Review Outcome**: `acceptable-special-case`
|
||||
**Workflow Outcome**: `keep`
|
||||
**Test-governance Outcome**: `keep`
|
||||
|
||||
## Test Governance Checklist
|
||||
|
||||
- [x] Lane assignment is named and is the narrowest sufficient proof for the changed behavior.
|
||||
- [x] Failure classification uses the pinned categories: `cutover-baseline-debt`, `cutover-runtime-regression`, `unrelated-existing-debt`, `flaky-or-environment`, and `resolved-or-not-needed`.
|
||||
- [x] New or changed tests stay in existing targeted feature or browser families and do not create a new stabilization subsystem.
|
||||
- [x] Shared helpers, fixtures, and context bootstrapping stay explicit and cheap by default.
|
||||
- [x] Planned validation commands cover the changed seams without turning `293` into a permanent fix-all suite lane.
|
||||
- [x] Surface test profile stays explicit: `standard-native-filament`, `global-context-shell`, and `browser-smoke`.
|
||||
|
||||
## Phase 1: Setup (Shared Context)
|
||||
|
||||
**Purpose**: Lock the stabilization role, exact failure categories, exact seam inventory, and validation scope before any implementation work begins.
|
||||
|
||||
- [x] T001 Review `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/spec.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/plan.md`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/checklists/requirements.md` to confirm the package remains a shared stabilization slice only
|
||||
- [x] T002 [P] Review `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/research.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/data-model.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/quickstart.md`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md`, then confirm together with `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/checklists/requirements.md` that the same failure-category names and stabilization seams are pinned across the full package and that `data-model.md` plus `failure-classification.md` remain the authoritative source for category meanings
|
||||
- [x] T003 [P] Confirm the focused Sail/Pest validation commands and repo-real anchor files named in this package across `apps/platform/tests/Feature/`, `apps/platform/tests/Browser/`, `apps/platform/app/`, and `scripts/`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: User Story 1 - Classify Remaining Cutover Failures First (Priority: P1)
|
||||
|
||||
**Goal**: Establish the initial suite baseline and classify every relevant failure before any fix work begins.
|
||||
|
||||
**Independent Test**: run the initial full suite or fallback lane split, record the resulting groups in `failure-classification.md`, and prove every in-scope failure is assigned to one pinned category before later stories begin.
|
||||
|
||||
- [ ] T004 [US1] Run the initial baseline commands `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git status --short --branch`, `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && git diff --stat`, and `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact)` and record the observed groups in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md`
|
||||
- [ ] T005 [P] [US1] If the full suite output is too noisy, run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane heavy-governance` and `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane confidence`, then update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md` with the same pinned categories
|
||||
- [x] T006 [P] [US1] Audit the exact `tenant_panel_baseline` and `legacy_admin_t_routes` seams across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantDashboard.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`
|
||||
- [x] T007 [P] [US1] Audit the exact `workspace_aware_operations_routes` seams across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/CanonicalViewRunLinksTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/OperateHubShellTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/FailureSanitizationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/TenantSyncBulkJobTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperationRunLinks.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperateHub/OperateHubShell.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`
|
||||
- [x] T008 [P] [US1] Audit the exact `legacy_required_permissions_provider_connections` and `action_surface_rebaseline` seams across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Verification/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`
|
||||
- [x] T009 [US1] Confirm the scope boundary remains explicit: `289` untouched, `292` untouched, no Package Execution, no Guided Operations, no TenantPanel reactivation, no `/admin/t/...` restoration, and no tenant-scoped provider fallback restoration
|
||||
|
||||
**Checkpoint**: User Story 1 is independently functional when the initial baseline is classified and later stories can proceed without absorbing unclassified debt.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 2 - Remove Retired TenantPanel and `/admin/t/...` Baseline Assumptions (Priority: P1)
|
||||
|
||||
**Goal**: Make current admin-panel and workspace-aware routing the only accepted baseline for the in-scope suite surfaces.
|
||||
|
||||
**Independent Test**: re-run the targeted panel and legacy tenant-core proof set and prove the current baseline no longer depends on TenantPanel bootstrapping or `/admin/t/...` management paths.
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- Targeted rerun command: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php)`
|
||||
|
||||
- [x] T010 [P] [US2] Extend `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php` so they assert the current admin-panel or workspace-aware truth and treat retired TenantPanel or `/admin/t/...` assumptions as forbidden baseline behavior
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [x] T011 [US2] Update in-scope test helpers and stale expectations in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/PanelNavigationSegregationTest.php`, and any directly implicated canonical helper surface so `tenant_panel_baseline` and `legacy_admin_t_routes` debt no longer survives in the suite
|
||||
- [ ] T012 [US2] If the targeted rerun proves a current primary-path regression, apply only the minimal canonical fix in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantDashboard.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`, or `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php` without restoring compatibility behavior
|
||||
|
||||
**Checkpoint**: User Story 2 is independently functional when the in-scope suite no longer treats TenantPanel or `/admin/t/...` management routes as current runtime truth.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 3 - Make Operations Baselines Canonical (Part 1 of Spec User Story 3) (Priority: P1)
|
||||
|
||||
**Goal**: Make current workspace-aware operations routes the only accepted baseline in the in-scope OpsUx and action-surface tests.
|
||||
|
||||
**Independent Test**: re-run the targeted OpsUx proof set and prove current operations links resolve through canonical workspace-aware helpers or explicit workspace parameters.
|
||||
|
||||
### Tests for User Story 3 (Operations)
|
||||
|
||||
- Targeted rerun command: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/CanonicalViewRunLinksTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/OpsUx/FailureSanitizationTest.php tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php)`
|
||||
|
||||
- [x] T013 [P] [US3] Extend `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/CanonicalViewRunLinksTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/OperateHubShellTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/FailureSanitizationTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/NonLeakageWorkspaceOperationsTest.php` so `workspace_aware_operations_routes` becomes explicit
|
||||
|
||||
### Implementation for User Story 3 (Operations)
|
||||
|
||||
- [x] T014 [US3] Update stale operations-route expectations and helper usage in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, and any directly implicated canonical helper surface so the suite uses current workspace-aware link generation only
|
||||
- [x] T015 [US3] If later reruns prove a current primary-path regression, apply only the minimal canonical fix in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperationRunLinks.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperateHub/OperateHubShell.php`, or `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Concerns/WorkspaceScopedTenantRoutes.php`, then update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md` for any residual OpsUx groups such as `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/OpsUx/TenantSyncBulkJobTest.php`
|
||||
|
||||
**Checkpoint**: the operations half of User Story 3 is independently functional when in-scope operations links are workspace-aware and any remaining unrelated OpsUx debt is documented explicitly.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - Make Legacy Required-Permissions and Provider-Connection Expectations Canonical (Part 2 of Spec User Story 3) (Priority: P1)
|
||||
|
||||
**Goal**: Make current canonical provider-connection and required-permissions routes the only accepted baseline in the in-scope provider and verification tests.
|
||||
|
||||
**Independent Test**: re-run the targeted ProviderConnections and Verification proof set and prove those tests no longer treat tenant-scoped legacy routes as canonical runtime truth.
|
||||
|
||||
### Tests for User Story 3
|
||||
|
||||
- Targeted rerun command: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections tests/Feature/Verification)`
|
||||
|
||||
- [x] T016 [P] [US3] Extend the affected files under `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Verification/` so `legacy_required_permissions_provider_connections` becomes explicit and current canonical routes become the only accepted baseline
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [x] T017 [US3] Update stale provider-connection and required-permissions expectations in the in-scope tests and any directly implicated canonical helper or page surface so tenant-scoped legacy URLs no longer appear as accepted runtime truth
|
||||
- [x] T018 [US3] If a current primary-path regression is proven later, apply only the minimal canonical fix in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Pages/TenantRequiredPermissions.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`, or `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Providers/Filament/AdminPanelProvider.php` without reintroducing tenant-scoped fallback routes
|
||||
|
||||
**Checkpoint**: User Story 3 is independently functional when the provider and verification baseline reflects only current canonical routes.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 4 - Perform a Bounded Action-Surface Rebaseline (Priority: P2)
|
||||
|
||||
**Goal**: Align stale cutover-era action expectations without turning `293` into a product redesign or unrelated debt cleanup.
|
||||
|
||||
**Independent Test**: re-run the action-surface and adjacent RBAC or Filament proof set and prove only cutover-stale expectations changed.
|
||||
|
||||
### Tests for User Story 4
|
||||
|
||||
- Targeted rerun command: `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php)`
|
||||
|
||||
- [ ] T019 [P] [US4] Extend `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php` so `action_surface_rebaseline` expectations are explicit
|
||||
|
||||
### Implementation for User Story 4
|
||||
|
||||
- [x] T020 [US4] Update stale action-surface expectations only where they are directly invalidated by workspace-first routing, managed-environment role authority, or TenantPanel removal; do not add or redesign product actions to satisfy old tests
|
||||
- [x] T021 [US4] Reclassify any residual mismatch in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Rbac/BackupItemsRelationManagerUiEnforcementTest.php` or adjacent action-surface files inside `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md` when the mismatch proves unrelated to the cutover
|
||||
|
||||
**Checkpoint**: User Story 4 is independently functional when cutover-stale action-surface expectations are aligned and unrelated mismatches stay documented instead of absorbed.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Polish & Cross-Cutting Validation
|
||||
|
||||
**Purpose**: Re-run the enforcement proof pack, browser anchors, broad confidence checks, formatting, and final classification review.
|
||||
|
||||
- [x] T022 Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Guards/BrowserLaneIsolationTest.php tests/Feature/Guards/CiLaneFailureClassificationContractTest.php tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php tests/Unit/Auth/NoRoleStringChecksTest.php)` exactly as recorded in `spec.md`, `plan.md`, and `quickstart.md`
|
||||
- [x] T023 Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail artisan test --compact tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php)` exactly as recorded in `spec.md`, `plan.md`, and `quickstart.md`
|
||||
- [ ] T024 Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail artisan test --compact)` and, if the output is too noisy or slow to classify accurately, rerun `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane heavy-governance` plus `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && ./scripts/platform-test-lane confidence`, then update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md`
|
||||
- [x] T025 Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && (cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent)`
|
||||
- [x] T026 Review the touched tests, helper seams, browser anchors, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/293-post-cutover-suite-stabilization/failure-classification.md` to confirm Filament remains on Livewire v4, provider registration still lives in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/bootstrap/providers.php`, the Spec `288` proof pack remains green, `289` remains untouched, `292` remains untouched, no legacy runtime behavior was restored, and every remaining relevant failure is classified explicitly
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Phase 1 (Setup)**: no dependencies; start immediately.
|
||||
- **Phase 2 (US1)**: depends on Phase 1 and blocks all later story work until the baseline is classified and the exact stabilization inventory is fixed.
|
||||
- **Phase 3 (US2)**: depends on Phase 2 and delivers the first independent cutover-baseline stabilization slice after classification.
|
||||
- **Phase 4 (US3 part 1)**: depends on Phase 2 and should follow US2 so panel and route truth settles before operations links are rebaselined broadly.
|
||||
- **Phase 5 (US3 part 2)**: depends on Phases 2 through 4 because provider and required-permissions expectations should consume the final route and operations baseline.
|
||||
- **Phase 6 (US4)**: depends on Phases 3 through 5 because action-surface expectations should be judged against the final canonical route and role-authority truth.
|
||||
- **Phase 7 (Polish)**: depends on all implemented stories.
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **US1 (P1)**: the initial classification story delivered in Phase 2.
|
||||
- **US2 (P1)**: independently testable after US1 because retired panel and route cleanup should only start after classification.
|
||||
- **US3 (P1)**: delivered across Phases 4 and 5, with operations and provider or required-permissions canonicalization treated as one combined spec story.
|
||||
- **US4 (P2)**: independently testable after Phases 3 through 5 because action-surface expectations should consume the final route and access baseline rather than a moving target.
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Classify and expose the current drift first when the story touches a new failing group.
|
||||
- Update tests and helper expectations before applying any runtime fix.
|
||||
- Apply a runtime fix only when a current workspace-first primary path is demonstrably broken.
|
||||
- Re-run the narrowest relevant proof set and update `failure-classification.md` before moving on.
|
||||
|
||||
---
|
||||
|
||||
## Parallel Execution Examples
|
||||
|
||||
### Phase 1
|
||||
|
||||
- T002 and T003 can run in parallel after T001 confirms the bounded stabilization role.
|
||||
|
||||
### Phase 2
|
||||
|
||||
- T005, T006, T007, and T008 can run in parallel because they inspect different seam families after T004 records the initial baseline.
|
||||
|
||||
### User Story 2
|
||||
|
||||
- T010 can run while T011 is being prepared, but any runtime fix in T012 must wait until the targeted rerun proves a primary-path regression.
|
||||
|
||||
### User Story 3 (Operations)
|
||||
|
||||
- T013 can run while helper candidates are reviewed, but T014 and T015 should land together because they define one canonical operations-link baseline.
|
||||
|
||||
### User Story 3 (Provider / Permissions)
|
||||
|
||||
- T016 can run in parallel across `ProviderConnections` and `Verification` once the shared route baseline is clear.
|
||||
|
||||
### User Story 4
|
||||
|
||||
- T019 can run while residual mismatches are being classified, but T020 and T021 should land together so action-surface rebaseline and debt classification stay synchronized.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Suggested MVP Scope
|
||||
|
||||
- MVP = **Phase 2 + US2 + Phase 4** as an intermediate delivery checkpoint only. The package starts delivering value once failures are classified and the suite stops relying on retired panel and workspace-unaware operations assumptions, but spec-complete close-out still requires the provider or permissions half of US3, US4, and Phase 7 validation.
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Complete Phase 1 and Phase 2.
|
||||
2. Deliver US2 and validate retired panel or route cleanup.
|
||||
3. Deliver the operations half of US3 and validate workspace-aware operations routes.
|
||||
4. Deliver the provider or required-permissions half of US3 and validate canonical routes.
|
||||
5. Deliver US4 and validate bounded action-surface rebaseline.
|
||||
6. Finish with Phase 7 proof-pack, browser, broad confidence, formatting, and classification review.
|
||||
|
||||
### Team Strategy
|
||||
|
||||
1. Keep `289` untouched.
|
||||
2. Keep `292` untouched.
|
||||
3. Land baseline classification before any fix PR merges so later reviewers can tell which failures are still cutover-owned.
|
||||
4. Serialize merges around `tests/Pest.php`, `ActionSurfaceContractTest.php`, `OperationRunLinks.php`, `OperateHubShell.php`, and the browser anchors because those are likely conflict hotspots.
|
||||
|
||||
---
|
||||
|
||||
## Explicit Follow-Ups / Out of Scope
|
||||
|
||||
- Package Execution
|
||||
- Guided Operations
|
||||
- Microsoft Starter Pack
|
||||
- Virtual Consultant
|
||||
- new product features
|
||||
- new UI surfaces
|
||||
- UI polish
|
||||
- broad refactors
|
||||
- reactivation of TenantPanel
|
||||
- reactivation of `/admin/t/...`
|
||||
- reactivation of tenant-scoped required-permissions fallback routes
|
||||
- reactivation of tenant-scoped provider-connection fallback routes
|
||||
- unrelated full-suite cleanup not tied to the cutover
|
||||