feat(spec-288): add no-legacy quality gates #347
10
README.md
10
README.md
@ -91,6 +91,16 @@ ### Workflow Expectation
|
||||
- Review treats wrong lane fit, hidden default cost, accidental heavy-family growth, or undocumented runtime drift as merge issues, not later cleanup.
|
||||
- Routine lane recalibration belongs inside the affecting feature spec or PR; open a dedicated follow-up spec only when recurring pain or structural lane changes justify it.
|
||||
|
||||
### Spec 288 Cutover Proof
|
||||
|
||||
- Spec `288` is an enforcement-only package. It owns the named no-legacy guards, the two named browser smokes, and contributor-facing quality-gate wording. It does not own runtime cutover repair, Package Execution work, or a full-suite stabilization pass.
|
||||
- The pinned no-legacy heavy-governance proof is:
|
||||
`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)`
|
||||
- The pinned browser proof is:
|
||||
`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)`
|
||||
- Keep the source-scan inventory narrow and explicit. The Spec `288` guard family is limited to the named route/helper and provider/role guard files; do not widen it with broad `tests/Feature/Guards` path allowlists or repo-wide tenant-panel helper bans.
|
||||
- When `heavy-governance` or `browser` reports broader baseline fallout outside those named proofs, classify it in the lane output and follow up separately. Under Spec `288`, that broader fallout remains classification-only and does not by itself expand repair ownership.
|
||||
|
||||
### Authoring And Review Guardrails
|
||||
|
||||
- Start with the smallest honest surface: `Unit` for isolated logic, `Feature` for HTTP, Livewire, Filament, jobs, or non-browser integration, `heavy-governance` for intentionally expensive governance scans, and `Browser` only for end-to-end workflow coverage.
|
||||
|
||||
@ -56,11 +56,18 @@
|
||||
],
|
||||
]);
|
||||
|
||||
$providerConnectionViewPath = (string) parse_url(ProviderConnectionResource::getUrl('view', [
|
||||
'record' => $connection,
|
||||
'managed_environment_id' => $tenant->external_id,
|
||||
], panel: 'admin'), PHP_URL_PATH);
|
||||
$tenantViewPath = (string) parse_url(TenantResource::getUrl('view', ['record' => $tenant], panel: 'admin'), PHP_URL_PATH);
|
||||
|
||||
visit(ProviderConnectionResource::getUrl('view', [
|
||||
'record' => $connection,
|
||||
'managed_environment_id' => $tenant->external_id,
|
||||
], panel: 'admin'))
|
||||
->waitForText('Spec 281 Browser Connection')
|
||||
->assertScript("window.location.pathname === '{$providerConnectionViewPath}'", true)
|
||||
->assertSee('Target scope')
|
||||
->assertSee('Spec 281 Browser Environment')
|
||||
->assertSee('Provider context')
|
||||
@ -77,6 +84,7 @@
|
||||
|
||||
visit(TenantResource::getUrl('view', ['record' => $tenant], panel: 'admin'))
|
||||
->waitForText('Provider connection')
|
||||
->assertScript("window.location.pathname === '{$tenantViewPath}'", true)
|
||||
->assertSee('Spec 281 Browser Connection')
|
||||
->assertSee('Target scope')
|
||||
->assertSee('Spec 281 Browser Environment')
|
||||
|
||||
@ -58,8 +58,12 @@
|
||||
]);
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $workspace->getKey());
|
||||
|
||||
$managedTenantsPath = (string) parse_url(route('admin.workspace.managed-tenants.index', ['workspace' => $workspace]), PHP_URL_PATH);
|
||||
$findingsIndexPath = (string) parse_url(FindingResource::getUrl('index', tenant: $allowedTenant, panel: 'admin'), PHP_URL_PATH);
|
||||
|
||||
visit(route('admin.workspace.managed-tenants.index', ['workspace' => $workspace]))
|
||||
->waitForText('Spec 285 Allowed')
|
||||
->assertScript("window.location.pathname === '{$managedTenantsPath}'", true)
|
||||
->assertSee('Spec 285 Allowed')
|
||||
->assertDontSee('Spec 285 Denied')
|
||||
->assertNoJavaScriptErrors()
|
||||
@ -67,7 +71,7 @@
|
||||
|
||||
visit(FindingResource::getUrl('index', tenant: $allowedTenant, panel: 'admin'))
|
||||
->waitForText('Findings')
|
||||
->assertScript("window.location.pathname.includes('/admin/workspaces/{$workspace->getRouteKey()}/environments/{$allowedTenant->getRouteKey()}/findings')", true)
|
||||
->assertScript("window.location.pathname === '{$findingsIndexPath}'", true)
|
||||
->assertNoJavaScriptErrors()
|
||||
->assertNoConsoleLogs();
|
||||
});
|
||||
|
||||
@ -8,19 +8,38 @@
|
||||
|
||||
it('keeps browser tests isolated behind their dedicated lane and class', function (): void {
|
||||
$lane = TestLaneManifest::lane('browser');
|
||||
$browserFamily = TestLaneManifest::family('browser-smoke');
|
||||
$files = new Collection(TestLaneManifest::discoverFiles('browser'));
|
||||
$validation = TestLaneManifest::validateLanePlacement(
|
||||
laneId: 'browser',
|
||||
filePath: 'tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php',
|
||||
);
|
||||
$providerScopeValidation = TestLaneManifest::validateLanePlacement(
|
||||
laneId: 'browser',
|
||||
filePath: 'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
);
|
||||
$workspaceRbacValidation = TestLaneManifest::validateLanePlacement(
|
||||
laneId: 'browser',
|
||||
filePath: 'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
);
|
||||
|
||||
expect($lane['includedFamilies'])->toContain('browser')
|
||||
->and($lane['defaultEntryPoint'])->toBeFalse()
|
||||
->and($lane['scopeBoundaryNote'])->toContain('classification-only')
|
||||
->and($files)->not->toBeEmpty()
|
||||
->and($files->every(static fn (string $path): bool => str_starts_with($path, 'tests/Browser/')))->toBeTrue()
|
||||
->and($browserFamily['hotspotFiles'])->toContain(
|
||||
'tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php',
|
||||
'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
)
|
||||
->and($validation['valid'])->toBeTrue()
|
||||
->and($validation['resolvedClassificationId'])->toBe('browser')
|
||||
->and($validation['familyId'])->toBe('browser-smoke');
|
||||
->and($validation['familyId'])->toBe('browser-smoke')
|
||||
->and($providerScopeValidation['valid'])->toBeTrue()
|
||||
->and($providerScopeValidation['familyId'])->toBe('browser-smoke')
|
||||
->and($workspaceRbacValidation['valid'])->toBeTrue()
|
||||
->and($workspaceRbacValidation['familyId'])->toBe('browser-smoke');
|
||||
});
|
||||
|
||||
it('rejects browser placement in non-browser lanes and keeps the default loops clean', function (): void {
|
||||
@ -33,6 +52,8 @@
|
||||
|
||||
expect(TestLaneManifest::buildCommand('browser'))->toContain('--configuration='.$configurationPath)
|
||||
->and($configurationContents)->toContain('tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php')
|
||||
->and($configurationContents)->toContain('tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php')
|
||||
->and($configurationContents)->toContain('tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php')
|
||||
->and($misplaced['valid'])->toBeFalse()
|
||||
->and($misplaced['allowance'])->toBe('forbidden');
|
||||
|
||||
|
||||
@ -7,11 +7,18 @@
|
||||
it('keeps heavy-governance manual and scheduled execution inside the dedicated workflow file with schedule gating', function (): void {
|
||||
$manualProfile = TestLaneManifest::workflowProfile('heavy-governance-manual');
|
||||
$scheduledProfile = TestLaneManifest::workflowProfile('heavy-governance-scheduled');
|
||||
$noLegacyFamily = TestLaneManifest::family('no-legacy-guardrail');
|
||||
$workflowContents = (string) file_get_contents(repo_path($manualProfile['filePath']));
|
||||
|
||||
expect(file_exists(repo_path($manualProfile['filePath'])))->toBeTrue()
|
||||
->and($manualProfile['filePath'])->toBe($scheduledProfile['filePath'])
|
||||
->and($manualProfile['laneBindings'])->toBe(['heavy-governance'])
|
||||
->and(TestLaneManifest::lane('heavy-governance')['scopeBoundaryNote'])->toContain('full-suite repair ownership')
|
||||
->and($noLegacyFamily['targetLaneId'])->toBe('heavy-governance')
|
||||
->and($noLegacyFamily['hotspotFiles'])->toContain(
|
||||
'tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php',
|
||||
'tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php',
|
||||
)
|
||||
->and($scheduledProfile['scheduleCron'])->toBe('17 4 * * 1-5')
|
||||
->and($workflowContents)->toContain('workflow_dispatch:')
|
||||
->and($workflowContents)->toContain('schedule:')
|
||||
@ -32,11 +39,17 @@
|
||||
it('keeps browser manual and scheduled execution isolated from pull-request and confidence validation', function (): void {
|
||||
$manualProfile = TestLaneManifest::workflowProfile('browser-manual');
|
||||
$scheduledProfile = TestLaneManifest::workflowProfile('browser-scheduled');
|
||||
$browserFamily = TestLaneManifest::family('browser-smoke');
|
||||
$workflowContents = (string) file_get_contents(repo_path($manualProfile['filePath']));
|
||||
|
||||
expect(file_exists(repo_path($manualProfile['filePath'])))->toBeTrue()
|
||||
->and($manualProfile['filePath'])->toBe($scheduledProfile['filePath'])
|
||||
->and($manualProfile['laneBindings'])->toBe(['browser'])
|
||||
->and(TestLaneManifest::lane('browser')['scopeBoundaryNote'])->toContain('classification-only')
|
||||
->and($browserFamily['hotspotFiles'])->toContain(
|
||||
'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
)
|
||||
->and($scheduledProfile['scheduleCron'])->toBe('43 4 * * 1-5')
|
||||
->and($workflowContents)->toContain('workflow_dispatch:')
|
||||
->and($workflowContents)->toContain('schedule:')
|
||||
|
||||
@ -70,4 +70,28 @@
|
||||
|
||||
expect($summary['primaryFailureClassId'])->toBe('artifact-publication-failure')
|
||||
->and($summary['blockingStatus'])->toBe('blocking');
|
||||
});
|
||||
|
||||
it('surfaces classification-only scope boundaries for heavy governance and browser reports', function (): void {
|
||||
$heavySummary = TestLaneReport::buildCiSummary(
|
||||
report: [
|
||||
'laneId' => 'heavy-governance',
|
||||
'budgetStatus' => 'within-budget',
|
||||
'ciContext' => ['workflowId' => 'heavy-governance-manual'],
|
||||
],
|
||||
exitCode: 1,
|
||||
artifactPublicationStatus: ['complete' => true, 'publishedArtifacts' => []],
|
||||
);
|
||||
$browserSummary = TestLaneReport::buildCiSummary(
|
||||
report: [
|
||||
'laneId' => 'browser',
|
||||
'budgetStatus' => 'within-budget',
|
||||
'ciContext' => ['workflowId' => 'browser-manual'],
|
||||
],
|
||||
exitCode: 1,
|
||||
artifactPublicationStatus: ['complete' => true, 'publishedArtifacts' => []],
|
||||
);
|
||||
|
||||
expect($heavySummary['scopeBoundaryNote'])->toContain('full-suite repair ownership')
|
||||
->and($browserSummary['scopeBoundaryNote'])->toContain('classification-only');
|
||||
});
|
||||
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
it('keeps cutover-owned route emission seams free of retired management paths', function (): void {
|
||||
$root = base_path();
|
||||
|
||||
$forbiddenPatternsByFile = [
|
||||
'routes/web.php' => [
|
||||
'/\/admin\/tenants\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/required-permissions(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/memberships(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/t\//',
|
||||
],
|
||||
'app/Providers/Filament/AdminPanelProvider.php' => [
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/\/admin\/tenants\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/required-permissions(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/memberships(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/t\//',
|
||||
],
|
||||
'app/Filament/Resources/TenantResource.php' => [
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/\/admin\/tenants\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/required-permissions(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/memberships(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/t\//',
|
||||
],
|
||||
'app/Support/OperationRunLinks.php' => [
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/\/admin\/tenants\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/required-permissions(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/memberships(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/t\//',
|
||||
],
|
||||
'app/Support/Verification/VerificationLinkBehavior.php' => [
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/\/admin\/tenants\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/provider-connections(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/required-permissions(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/[^\'"\n]*\/memberships(?:[\/?"\']|$)/',
|
||||
'/\/admin\/t\/t\//',
|
||||
],
|
||||
];
|
||||
|
||||
$hits = [];
|
||||
|
||||
foreach ($forbiddenPatternsByFile as $relativePath => $patterns) {
|
||||
$absolutePath = $root.'/'.$relativePath;
|
||||
|
||||
expect(is_file($absolutePath))->toBeTrue("Expected guard-owned seam [{$relativePath}] to exist.");
|
||||
|
||||
$contents = file_get_contents($absolutePath);
|
||||
|
||||
if (! is_string($contents) || $contents === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines = preg_split('/\R/', $contents) ?: [];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
foreach ($lines as $index => $line) {
|
||||
if (preg_match($pattern, $line) !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hits[] = $relativePath.':'.($index + 1).' -> '.trim($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect($hits)->toBeEmpty("Retired management path or tenant-panel route emission detected on a Spec 288 seam:\n".implode("\n", $hits));
|
||||
});
|
||||
|
||||
it('keeps spec 288 proof seams free of retired tenant-panel helper bootstrapping', function (): void {
|
||||
$root = base_path();
|
||||
|
||||
$forbiddenPatternsByFile = [
|
||||
'tests/Pest.php' => [
|
||||
'/Filament::setCurrentPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
'/Filament::getPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
],
|
||||
'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php' => [
|
||||
'/setTenantPanelContext\s*\(/',
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/Filament::setCurrentPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
'/Filament::getPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
],
|
||||
'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php' => [
|
||||
'/setTenantPanelContext\s*\(/',
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
'/Filament::setCurrentPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
'/Filament::getPanel\(\s*[\'\"]tenant[\'\"]\s*\)/',
|
||||
],
|
||||
'tests/Feature/ProviderConnections/LegacyRedirectTest.php' => [
|
||||
'/setTenantPanelContext\s*\(/',
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
],
|
||||
'tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php' => [
|
||||
'/setTenantPanelContext\s*\(/',
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
],
|
||||
'tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php' => [
|
||||
'/setTenantPanelContext\s*\(/',
|
||||
'/panel:\s*[\'\"]tenant[\'\"]/',
|
||||
],
|
||||
];
|
||||
|
||||
$hits = [];
|
||||
|
||||
foreach ($forbiddenPatternsByFile as $relativePath => $patterns) {
|
||||
$absolutePath = $root.'/'.$relativePath;
|
||||
|
||||
expect(is_file($absolutePath))->toBeTrue("Expected Spec 288 proof seam [{$relativePath}] to exist.");
|
||||
|
||||
$contents = file_get_contents($absolutePath);
|
||||
|
||||
if (! is_string($contents) || $contents === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$lines = preg_split('/\R/', $contents) ?: [];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
foreach ($lines as $index => $line) {
|
||||
if (preg_match($pattern, $line) !== 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hits[] = $relativePath.':'.($index + 1).' -> '.trim($line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect($hits)->toBeEmpty("Retired tenant-panel helper or bootstrapping detected on a Spec 288 proof seam:\n".implode("\n", $hits));
|
||||
});
|
||||
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Support\Providers\Boundary\ProviderBoundaryCatalog;
|
||||
|
||||
it('pins the spec 288 platform-core provider boundary inventory to the documented seams', function (): void {
|
||||
$catalog = app(ProviderBoundaryCatalog::class);
|
||||
|
||||
$expectedPlatformCoreSeams = [
|
||||
'provider.identity_resolution' => [
|
||||
'paths' => [
|
||||
'app/Services/Providers/ProviderIdentityResolution.php',
|
||||
'app/Services/Providers/ProviderIdentityResolver.php',
|
||||
'app/Services/Providers/PlatformProviderIdentityResolver.php',
|
||||
],
|
||||
'neutral_terms' => [
|
||||
'provider connection',
|
||||
'target scope',
|
||||
'credential source',
|
||||
'effective client identity',
|
||||
'provider context',
|
||||
],
|
||||
],
|
||||
'provider.operation_registry' => [
|
||||
'paths' => [
|
||||
'app/Services/Providers/ProviderOperationRegistry.php',
|
||||
],
|
||||
'neutral_terms' => [
|
||||
'operation type',
|
||||
'operation module',
|
||||
'required capability',
|
||||
'provider binding',
|
||||
'unsupported binding',
|
||||
],
|
||||
],
|
||||
'provider.operation_start_gate' => [
|
||||
'paths' => [
|
||||
'app/Services/Providers/ProviderOperationStartGate.php',
|
||||
],
|
||||
'neutral_terms' => [
|
||||
'operation',
|
||||
'provider binding',
|
||||
'target scope',
|
||||
'execution authority',
|
||||
'required capability',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($expectedPlatformCoreSeams as $seamKey => $expectations) {
|
||||
$seam = $catalog->get($seamKey);
|
||||
|
||||
expect($seam->isPlatformCore())->toBeTrue("Expected [{$seamKey}] to remain platform-core.")
|
||||
->and($seam->implementationPaths)->toEqualCanonicalizing($expectations['paths'])
|
||||
->and($seam->neutralTerms)->toEqualCanonicalizing($expectations['neutral_terms'])
|
||||
->and($seam->followUpAction)->toBe('document-in-feature');
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps managed-environment scope persistence narrowing-only in the role-authority seam', function (): void {
|
||||
$tenantMembershipManager = base_path('app/Services/Auth/TenantMembershipManager.php');
|
||||
|
||||
expect(is_file($tenantMembershipManager))->toBeTrue('Expected TenantMembershipManager.php to exist for the narrowing-only role-authority guard.');
|
||||
|
||||
$contents = (string) file_get_contents($tenantMembershipManager);
|
||||
|
||||
expect($contents)
|
||||
->toContain("private const string SCOPE_PLACEHOLDER_ROLE = 'readonly';")
|
||||
->toContain("'role' => self::SCOPE_PLACEHOLDER_ROLE,")
|
||||
->toContain("Managed-environment access scopes do not manage roles. Change the workspace role instead.")
|
||||
->not->toContain("'role' => \$memberWorkspaceRole")
|
||||
->not->toContain("'role' => \$newRole");
|
||||
});
|
||||
@ -112,7 +112,9 @@
|
||||
|
||||
expect(TestLaneManifest::lane('confidence')['includedFamilies'])->toContain('ui-light', 'ui-workflow')
|
||||
->and(TestLaneManifest::lane('confidence')['excludedFamilies'])->toContain('surface-guard', 'discovery-heavy')
|
||||
->and(TestLaneManifest::lane('heavy-governance')['includedFamilies'])->toContain('surface-guard', 'discovery-heavy');
|
||||
->and(TestLaneManifest::lane('heavy-governance')['includedFamilies'])->toContain('surface-guard', 'discovery-heavy')
|
||||
->and(TestLaneManifest::lane('heavy-governance')['scopeBoundaryNote'])->toContain('full-suite repair ownership')
|
||||
->and(TestLaneManifest::lane('browser')['scopeBoundaryNote'])->toContain('classification-only');
|
||||
});
|
||||
|
||||
it('exposes the spec 208 classification catalog and seeded family inventory with required metadata', function (): void {
|
||||
@ -138,7 +140,13 @@
|
||||
->and($families->has('workspace-settings-slice-management'))->toBeTrue()
|
||||
->and($families->has('provider-dispatch-gate-coverage'))->toBeTrue()
|
||||
->and($families->has('baseline-compare-matrix-workflow'))->toBeTrue()
|
||||
->and($families->has('browser-smoke'))->toBeTrue();
|
||||
->and($families->has('browser-smoke'))->toBeTrue()
|
||||
->and($families->has('no-legacy-guardrail'))->toBeTrue()
|
||||
->and($families->get('browser-smoke')['hotspotFiles'])->toContain(
|
||||
'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
)
|
||||
->and($families->get('no-legacy-guardrail')['targetLaneId'])->toBe('heavy-governance');
|
||||
|
||||
foreach (TestLaneManifest::families() as $family) {
|
||||
expect(trim($family['purpose']))->not->toBe('')
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Resources\ProviderConnectionResource;
|
||||
use App\Filament\Resources\TenantResource;
|
||||
use App\Models\AuditLog;
|
||||
use App\Models\ProviderConnection;
|
||||
@ -80,7 +79,7 @@
|
||||
->assertOk();
|
||||
});
|
||||
|
||||
it('requires tenant entitlement for the contracted tenant operational routes', function (): void {
|
||||
it('keeps retired tenant panel operational routes unavailable even for entitled workspace members', function (): void {
|
||||
$workspace = Workspace::factory()->create();
|
||||
|
||||
$tenant = ManagedEnvironment::factory()->create([
|
||||
@ -101,12 +100,12 @@
|
||||
$this->actingAs($entitledUser)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get("/admin/t/{$tenant->external_id}")
|
||||
->assertOk();
|
||||
->assertNotFound();
|
||||
|
||||
$this->actingAs($entitledUser)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
->get("/admin/t/{$tenant->external_id}/diagnostics")
|
||||
->assertOk();
|
||||
->assertNotFound();
|
||||
|
||||
$this->actingAs($nonEntitledUser)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $workspace->getKey()])
|
||||
@ -119,13 +118,13 @@
|
||||
->assertNotFound();
|
||||
});
|
||||
|
||||
it('keeps tenant panel route shape canonical and rejects duplicated /t prefixes', function (): void {
|
||||
it('keeps retired tenant panel route shapes unavailable and rejects duplicated /t prefixes', function (): void {
|
||||
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get("/admin/t/{$tenant->external_id}/diagnostics")
|
||||
->assertOk();
|
||||
->assertNotFound();
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
@ -189,9 +188,14 @@
|
||||
->assertForbidden();
|
||||
});
|
||||
|
||||
it('writes canonical membership audit entries for membership mutations', function (): void {
|
||||
it('writes managed-environment access scope audit entries for scope mutations', function (): void {
|
||||
[$owner, $tenant] = createMinimalUserWithTenant(role: 'owner');
|
||||
$member = User::factory()->create();
|
||||
WorkspaceMembership::factory()->create([
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
'user_id' => (int) $member->getKey(),
|
||||
'role' => 'readonly',
|
||||
]);
|
||||
|
||||
/** @var TenantMembershipManager $manager */
|
||||
$manager = app(TenantMembershipManager::class);
|
||||
@ -204,13 +208,6 @@
|
||||
source: 'manual',
|
||||
);
|
||||
|
||||
$manager->changeRole(
|
||||
tenant: $tenant,
|
||||
actor: $owner,
|
||||
membership: $membership,
|
||||
newRole: 'operator',
|
||||
);
|
||||
|
||||
$manager->removeMember(
|
||||
tenant: $tenant,
|
||||
actor: $owner,
|
||||
@ -220,16 +217,15 @@
|
||||
$actions = AuditLog::query()
|
||||
->where('managed_environment_id', (int) $tenant->getKey())
|
||||
->whereIn('action', [
|
||||
AuditActionId::TenantMembershipAdd->value,
|
||||
AuditActionId::TenantMembershipRoleChange->value,
|
||||
AuditActionId::TenantMembershipRemove->value,
|
||||
AuditActionId::ManagedEnvironmentAccessScopeGrant->value,
|
||||
AuditActionId::ManagedEnvironmentAccessScopeRemove->value,
|
||||
])
|
||||
->pluck('action')
|
||||
->all();
|
||||
|
||||
expect($actions)->toContain(AuditActionId::TenantMembershipAdd->value);
|
||||
expect($actions)->toContain(AuditActionId::TenantMembershipRoleChange->value);
|
||||
expect($actions)->toContain(AuditActionId::TenantMembershipRemove->value);
|
||||
expect($actions)->toContain(AuditActionId::ManagedEnvironmentAccessScopeGrant->value)
|
||||
->and($actions)->toContain(AuditActionId::ManagedEnvironmentAccessScopeRemove->value)
|
||||
->and($actions)->not->toContain(AuditActionId::TenantMembershipRoleChange->value);
|
||||
});
|
||||
|
||||
it('keeps workspace navigation entries after panel split', function (): void {
|
||||
@ -246,16 +242,13 @@
|
||||
});
|
||||
|
||||
it('does not expose tenant-management resources in tenant panel registration or navigation URLs', function (): void {
|
||||
$tenantPanelResources = Filament::getPanel('tenant')->getResources();
|
||||
|
||||
expect($tenantPanelResources)->not->toContain(TenantResource::class);
|
||||
expect($tenantPanelResources)->not->toContain(ProviderConnectionResource::class);
|
||||
expect(Filament::getPanel('tenant'))->toBeNull();
|
||||
|
||||
[$user, $tenant] = createMinimalUserWithTenant(role: 'owner');
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id])
|
||||
->get("/admin/t/{$tenant->external_id}")
|
||||
->get("/admin/tenants/{$tenant->external_id}")
|
||||
->assertOk()
|
||||
->assertDontSee("/admin/t/{$tenant->external_id}/provider-connections", false)
|
||||
->assertDontSee("/admin/t/{$tenant->external_id}/tenants", false);
|
||||
|
||||
@ -761,6 +761,35 @@ public static function families(): array
|
||||
'costSignals' => ['ops-ux governance breadth', 'cross-surface workflow coverage', 'alert and credential guard fan-out'],
|
||||
'validationStatus' => 'guarded',
|
||||
],
|
||||
[
|
||||
'familyId' => 'no-legacy-guardrail',
|
||||
'classificationId' => 'surface-guard',
|
||||
'purpose' => 'Keep the Spec 288 no-legacy route/helper and provider/role guardrails isolated inside heavy-governance ownership.',
|
||||
'currentLaneId' => 'heavy-governance',
|
||||
'targetLaneId' => 'heavy-governance',
|
||||
'selectors' => [
|
||||
[
|
||||
'selectorType' => 'file',
|
||||
'selectorValue' => 'tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php',
|
||||
'selectorRole' => 'include',
|
||||
'sourceOfTruth' => 'manifest',
|
||||
'rationale' => 'Spec 288 route and helper source-scan guard remains heavy-governance-only.',
|
||||
],
|
||||
[
|
||||
'selectorType' => 'file',
|
||||
'selectorValue' => 'tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php',
|
||||
'selectorRole' => 'include',
|
||||
'sourceOfTruth' => 'manifest',
|
||||
'rationale' => 'Spec 288 provider-core and role-authority seam guard remains heavy-governance-only.',
|
||||
],
|
||||
],
|
||||
'hotspotFiles' => [
|
||||
'tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php',
|
||||
'tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php',
|
||||
],
|
||||
'costSignals' => ['source-scan guard inventory', 'provider-boundary contract enforcement', 'cutover drift coverage'],
|
||||
'validationStatus' => 'guarded',
|
||||
],
|
||||
[
|
||||
'familyId' => 'browser-smoke',
|
||||
'classificationId' => 'browser',
|
||||
@ -789,9 +818,25 @@ public static function families(): array
|
||||
'sourceOfTruth' => 'manifest',
|
||||
'rationale' => 'Seeded browser hotspot for Spec 208.',
|
||||
],
|
||||
[
|
||||
'selectorType' => 'file',
|
||||
'selectorValue' => 'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
'selectorRole' => 'inventory-only',
|
||||
'sourceOfTruth' => 'manifest',
|
||||
'rationale' => 'Spec 288 keeps the provider-connection browser continuity anchor explicit.',
|
||||
],
|
||||
[
|
||||
'selectorType' => 'file',
|
||||
'selectorValue' => 'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
'selectorRole' => 'inventory-only',
|
||||
'sourceOfTruth' => 'manifest',
|
||||
'rationale' => 'Spec 288 keeps the workspace RBAC browser continuity anchor explicit.',
|
||||
],
|
||||
],
|
||||
'hotspotFiles' => [
|
||||
'tests/Browser/Spec190BaselineCompareMatrixSmokeTest.php',
|
||||
'tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php',
|
||||
'tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php',
|
||||
],
|
||||
'costSignals' => ['real-browser interaction', 'dense DOM continuity', 'end-to-end smoke'],
|
||||
'validationStatus' => 'guarded',
|
||||
@ -1781,6 +1826,7 @@ public static function lanes(): array
|
||||
'includedFamilies' => ['browser'],
|
||||
'excludedFamilies' => ['fast-feedback', 'confidence', 'heavy-governance'],
|
||||
'ownershipExpectations' => 'Run when a change touches browser behavior or before promoting browser-sensitive work.',
|
||||
'scopeBoundaryNote' => 'Browser lane failures keep the named smoke anchors honest; broader browser fallout stays classification-only unless the active feature explicitly owns repair.',
|
||||
'defaultEntryPoint' => false,
|
||||
'parallelMode' => 'forbidden',
|
||||
'selectors' => [
|
||||
@ -1816,6 +1862,7 @@ public static function lanes(): array
|
||||
'includedFamilies' => ['architecture-governance', 'ops-ux', 'ui-workflow', 'surface-guard', 'discovery-heavy'],
|
||||
'excludedFamilies' => ['browser', 'ui-light'],
|
||||
'ownershipExpectations' => 'Run intentionally when touching governance scans, discovery-heavy parity, or broad UI contract families.',
|
||||
'scopeBoundaryNote' => 'Heavy-governance output classifies cutover guard drift and broader baseline fallout, but it does not by itself claim full-suite repair ownership.',
|
||||
'defaultEntryPoint' => false,
|
||||
'parallelMode' => 'optional',
|
||||
'selectors' => [
|
||||
@ -2255,7 +2302,7 @@ public static function failureClasses(): array
|
||||
'sourceStep' => 'tests/Support/TestLaneBudget.php',
|
||||
'blockingOn' => ['pull-request'],
|
||||
'summaryLabel' => 'Budget breach',
|
||||
'remediationHint' => 'Review the measured runtime against the documented variance allowance and update the lane or spec evidence if the baseline legitimately changed.',
|
||||
'remediationHint' => 'Review the measured runtime against the documented variance allowance, classify broader lane fallout explicitly, and only take on repair when the active feature owns that expanded scope.',
|
||||
],
|
||||
[
|
||||
'failureClassId' => 'artifact-publication-failure',
|
||||
|
||||
@ -137,6 +137,8 @@ public static function buildCiSummary(
|
||||
'budget-breach' => (string) ($budgetOutcome['blockingStatus'] ?? 'non-blocking-warning'),
|
||||
default => 'informational',
|
||||
};
|
||||
$scopeBoundaryNote = (string) ($report['scopeBoundaryNote']
|
||||
?? (TestLaneManifest::lane((string) $report['laneId'])['scopeBoundaryNote'] ?? ''));
|
||||
|
||||
return [
|
||||
'runId' => (string) (getenv('GITEA_RUN_ID') ?: getenv('GITHUB_RUN_ID') ?: sprintf('local-%s', $report['laneId'])),
|
||||
@ -148,6 +150,7 @@ public static function buildCiSummary(
|
||||
'blockingStatus' => $blockingStatus,
|
||||
'primaryFailureClassId' => $primaryFailureClassId,
|
||||
'publishedArtifacts' => $artifactPublicationStatus['publishedArtifacts'],
|
||||
'scopeBoundaryNote' => $scopeBoundaryNote !== '' ? $scopeBoundaryNote : null,
|
||||
];
|
||||
}
|
||||
|
||||
@ -490,6 +493,7 @@ classificationAttribution: $attribution['classificationAttribution'],
|
||||
TestLaneManifest::workflowProfilesForLane($laneId),
|
||||
)),
|
||||
'failureClasses' => TestLaneManifest::failureClasses(),
|
||||
'scopeBoundaryNote' => TestLaneManifest::lane($laneId)['scopeBoundaryNote'] ?? null,
|
||||
];
|
||||
|
||||
if ($heavyGovernanceContext !== []) {
|
||||
@ -656,6 +660,10 @@ private static function buildSummaryMarkdown(array $report): string
|
||||
}
|
||||
}
|
||||
|
||||
if (is_string($report['scopeBoundaryNote'] ?? null) && trim((string) $report['scopeBoundaryNote']) !== '') {
|
||||
$lines[] = sprintf('- Scope boundary: %s', (string) $report['scopeBoundaryNote']);
|
||||
}
|
||||
|
||||
if (($report['laneId'] ?? null) === 'heavy-governance' && isset($report['budgetContract']) && is_array($report['budgetContract'])) {
|
||||
$lines[] = sprintf(
|
||||
'- Budget contract: %.0f seconds (%s)',
|
||||
|
||||
@ -354,6 +354,12 @@ hydrate_trend_history
|
||||
|
||||
./vendor/bin/sail composer run --timeout=0 "${COMPOSER_SCRIPT}"
|
||||
|
||||
case "${LANE}" in
|
||||
heavy-governance|browser)
|
||||
echo "classification-only note: broader lane fallout stays reportable, but it does not by itself expand repair ownership beyond the active feature."
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "${CAPTURE_BASELINE}" == true ]]; then
|
||||
copy_heavy_baseline_artifacts
|
||||
fi
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
# Requirements Checklist: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
## Scope and problem framing
|
||||
|
||||
- [x] The package describes the real repo problem as missing enforcement over an already-completed cutover baseline.
|
||||
- [x] The package keeps scope limited to guards, targeted browser proof, quality-gate docs, and classification-only baseline handling.
|
||||
- [x] The package explicitly excludes runtime cutover work, provider-core rewrites, RBAC rewrites, UI copy cleanup, Review Pack export work, Guided Operations, and full-suite repair.
|
||||
- [x] The package explicitly moves Package Execution Contract work to Spec `289`.
|
||||
|
||||
## Repo-truth anchoring
|
||||
|
||||
- [x] The package anchors route/path enforcement to exact retired management families instead of broad `/admin/t` bans.
|
||||
- [x] The package anchors helper enforcement to retired tenant-panel bootstrapping patterns on owned seams.
|
||||
- [x] The package anchors provider-core enforcement to the existing provider-boundary seams and operation-definition guards.
|
||||
- [x] The package anchors role-authority enforcement to the existing workspace-first policy and managed-environment scope tests.
|
||||
- [x] The package anchors baseline classification to `TestLaneManifest`, `TestLaneReport`, the current classification-contract tests, and `README.md`.
|
||||
|
||||
## Enforcement inventory and boundedness
|
||||
|
||||
- [x] The same enforcement categories appear across `spec.md`, `plan.md`, `research.md`, `data-model.md`, `quickstart.md`, the logical contract, and `tasks.md`.
|
||||
- [x] Historical and immutable scan exclusions are pinned explicitly.
|
||||
- [x] The package keeps provider-owned detail nested and bounded instead of pretending it disappears entirely.
|
||||
- [x] The package forbids open-ended route, helper, or source-scan allowlists.
|
||||
- [x] The package keeps broader baseline fallout classification-only.
|
||||
|
||||
## Validation and workflow
|
||||
|
||||
- [x] Planned proof stays bounded to targeted guard tests, targeted browser validation, and formatting.
|
||||
- [x] The same validation commands appear in `spec.md`, `plan.md`, `tasks.md`, and `quickstart.md`.
|
||||
- [x] The task package explicitly re-verifies Filament/Livewire/provider-registration invariants and the no-asset-registration boundary.
|
||||
- [x] The package keeps review outcome, workflow outcome, and test-governance outcome aligned.
|
||||
- [x] The package uses `NoLegacyGuardrail` as the close-out intent.
|
||||
|
||||
## Adjacent-spec control
|
||||
|
||||
- [x] Spec `289` is named as the explicit Package Execution Contract follow-up.
|
||||
- [x] The package does not silently absorb runtime cutover work from Spec `287`.
|
||||
- [x] The package does not silently absorb UI copy cleanup from Spec `286`.
|
||||
- [x] The package does not silently absorb broader provider-core or RBAC rewrites.
|
||||
|
||||
## Notes
|
||||
|
||||
- Reviewed against `.specify/memory/constitution.md`, the cutover sequence in Specs `279` through `287`, the current guard/browser/lane seams, and the user-corrected `288` scope on 2026-05-10.
|
||||
- This artifact package is implementation-ready only when the execution task map exists and the companion artifacts remain aligned.
|
||||
|
||||
## Outcome
|
||||
|
||||
- **Review outcome class**: `acceptable-special-case`
|
||||
- **Workflow outcome**: `keep`
|
||||
- **Test-governance outcome**: `keep`
|
||||
- **Readiness note**: implementation is ready as a bounded enforcement slice following Spec `287`; broader baseline repair remains out of scope
|
||||
@ -0,0 +1,335 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Quality Gates / No-Legacy Enforcement Logical Contract
|
||||
version: 0.1.0
|
||||
summary: Logical enforcement contract for the cutover guardrails that follow Spec 287.
|
||||
x-canonical-command-authority:
|
||||
- specs/288-quality-gates-no-legacy-enforcement/spec.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/plan.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/tasks.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/quickstart.md
|
||||
paths:
|
||||
/__logical/guardrails/legacy-route-paths:
|
||||
get:
|
||||
summary: Retired route/path enforcement contract
|
||||
operationId: getLegacyRoutePathGuardContract
|
||||
responses:
|
||||
'200':
|
||||
description: Exact retired route/path families and scan exclusions for cutover enforcement
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/LegacyRoutePathGuardContract'
|
||||
/__logical/guardrails/route-emission:
|
||||
get:
|
||||
summary: Canonical emitted URL enforcement contract
|
||||
operationId: getRouteEmissionGuardContract
|
||||
responses:
|
||||
'200':
|
||||
description: Canonical launch-point URL rules for cutover-owned seams
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RouteEmissionGuardContract'
|
||||
/__logical/guardrails/tenant-panel-helper:
|
||||
get:
|
||||
summary: Retired tenant-panel helper enforcement contract
|
||||
operationId: getTenantPanelHelperGuardContract
|
||||
responses:
|
||||
'200':
|
||||
description: Forbidden bootstrapping helpers and panel-selection patterns on owned seams
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TenantPanelHelperGuardContract'
|
||||
/__logical/guardrails/provider-core-boundary:
|
||||
get:
|
||||
summary: Provider-core boundary enforcement contract
|
||||
operationId: getProviderCoreBoundaryGuardContract
|
||||
responses:
|
||||
'200':
|
||||
description: Shared provider-boundary seams and forbidden platform-core regressions
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ProviderCoreBoundaryGuardContract'
|
||||
/__logical/guardrails/environment-scope-role-authority:
|
||||
get:
|
||||
summary: Workspace-role and environment-scope authority enforcement contract
|
||||
operationId: getEnvironmentScopeRoleAuthorityGuardContract
|
||||
responses:
|
||||
'200':
|
||||
description: Current authority invariants that must remain true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/EnvironmentScopeRoleAuthorityGuardContract'
|
||||
/__logical/guardrails/browser-smoke-gates:
|
||||
get:
|
||||
summary: Targeted browser smoke contract
|
||||
operationId: getBrowserSmokeGateContract
|
||||
responses:
|
||||
'200':
|
||||
description: Named browser smoke anchors and their visible continuity obligations
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/BrowserSmokeGateContract'
|
||||
/__logical/guardrails/baseline-classification:
|
||||
get:
|
||||
summary: Classification-only broader baseline handling contract
|
||||
operationId: getBaselineClassificationContract
|
||||
responses:
|
||||
'200':
|
||||
description: Current lane/report seams used to classify broader baseline fallout without owning repair
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/BaselineClassificationContract'
|
||||
/__logical/guardrails/targeted-validation:
|
||||
get:
|
||||
summary: Targeted validation contract
|
||||
operationId: getTargetedValidationContract
|
||||
responses:
|
||||
'200':
|
||||
description: Exact minimal proof commands and the out-of-scope repair boundary
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/TargetedValidationContract'
|
||||
components:
|
||||
schemas:
|
||||
LegacyRoutePathGuardContract:
|
||||
type: object
|
||||
required:
|
||||
- retiredPathFamilies
|
||||
- scanExclusions
|
||||
- enforcementBehavior
|
||||
properties:
|
||||
retiredPathFamilies:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- /admin/tenants/{tenant:slug}/provider-connections...
|
||||
- /admin/t/{tenant}/provider-connections
|
||||
- /admin/t/{tenant}/required-permissions
|
||||
- /admin/t/{tenant}/memberships
|
||||
- /admin/t/t/{tenant}/...
|
||||
scanExclusions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- database/migrations/**
|
||||
- references/**
|
||||
- docs/**
|
||||
- specs/**
|
||||
- spechistory/**
|
||||
- vendor/**
|
||||
- storage/**
|
||||
- public/build/**
|
||||
- bootstrap/cache/**
|
||||
enforcementBehavior:
|
||||
type: string
|
||||
const: Exact retired route/path families fail targeted guards with path-specific messages.
|
||||
RouteEmissionGuardContract:
|
||||
type: object
|
||||
required:
|
||||
- canonicalFamilies
|
||||
- ownedLaunchPointSeams
|
||||
- forbiddenEmissions
|
||||
properties:
|
||||
canonicalFamilies:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- /admin/provider-connections...
|
||||
- /admin/workspaces/{workspace}/environments/{managed_environment}/...
|
||||
ownedLaunchPointSeams:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- apps/platform/app/Providers/Filament/AdminPanelProvider.php
|
||||
- apps/platform/app/Filament/Resources/TenantResource.php
|
||||
- apps/platform/app/Support/OperationRunLinks.php
|
||||
- apps/platform/app/Support/Verification/VerificationLinkBehavior.php
|
||||
forbiddenEmissions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- /admin/tenants/{tenant:slug}/provider-connections...
|
||||
- /admin/t/{tenant}/provider-connections
|
||||
- /admin/t/{tenant}/required-permissions
|
||||
- /admin/t/{tenant}/memberships
|
||||
- /admin/t/t/{tenant}/...
|
||||
TenantPanelHelperGuardContract:
|
||||
type: object
|
||||
required:
|
||||
- forbiddenPatterns
|
||||
- ownedSeams
|
||||
- exceptionRule
|
||||
properties:
|
||||
forbiddenPatterns:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- setTenantPanelContext(
|
||||
- getPanel('tenant')
|
||||
- setCurrentPanel('tenant')
|
||||
ownedSeams:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- apps/platform/tests/Pest.php
|
||||
- apps/platform/tests/Feature/Guards/**
|
||||
- apps/platform/tests/Browser/**
|
||||
exceptionRule:
|
||||
type: string
|
||||
const: Exceptions beyond pinned historical directories must be file-scoped and justified.
|
||||
ProviderCoreBoundaryGuardContract:
|
||||
type: object
|
||||
required:
|
||||
- seamInputs
|
||||
- forbiddenPlatformCoreSignals
|
||||
- allowedProviderOwnedDetail
|
||||
properties:
|
||||
seamInputs:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- apps/platform/app/Support/Providers/Boundary/ProviderBoundaryCatalog.php
|
||||
- apps/platform/app/Services/Providers/ProviderIdentityResolution.php
|
||||
- apps/platform/app/Services/Providers/ProviderOperationRegistry.php
|
||||
forbiddenPlatformCoreSignals:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- graphOptions
|
||||
- client_request_id
|
||||
- provider binding truth in operation definitions
|
||||
allowedProviderOwnedDetail:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- provider-specific identifiers nested under provider-owned detail
|
||||
- provider-specific consent links nested under provider-owned detail
|
||||
- provider-specific diagnostics nested under provider-owned detail
|
||||
EnvironmentScopeRoleAuthorityGuardContract:
|
||||
type: object
|
||||
required:
|
||||
- authoritySource
|
||||
- invariants
|
||||
- forbiddenBehaviors
|
||||
properties:
|
||||
authoritySource:
|
||||
type: string
|
||||
const: workspace_memberships
|
||||
invariants:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- wrong-scope denials stay 404
|
||||
- in-scope capability denials stay 403
|
||||
- direct role edits on managed-environment scope remain rejected
|
||||
forbiddenBehaviors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- managed-environment scope acting as a second role matrix
|
||||
- mirrored workspace role values becoming environment role truth
|
||||
BrowserSmokeGateContract:
|
||||
type: object
|
||||
required:
|
||||
- smokeAnchors
|
||||
- requiredAssertions
|
||||
- laneOwnership
|
||||
properties:
|
||||
smokeAnchors:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php
|
||||
- apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php
|
||||
requiredAssertions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- canonical route continuity
|
||||
- no JavaScript errors
|
||||
- no console errors
|
||||
laneOwnership:
|
||||
type: string
|
||||
const: browser
|
||||
BaselineClassificationContract:
|
||||
type: object
|
||||
required:
|
||||
- classificationSeams
|
||||
- reviewRule
|
||||
- forbiddenOwnershipClaim
|
||||
properties:
|
||||
classificationSeams:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- apps/platform/tests/Support/TestLaneManifest.php
|
||||
- apps/platform/tests/Support/TestLaneReport.php
|
||||
- apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php
|
||||
- apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php
|
||||
- apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php
|
||||
- README.md
|
||||
- scripts/platform-test-report
|
||||
reviewRule:
|
||||
type: string
|
||||
const: Broader baseline fallout is classified only under Spec 288.
|
||||
forbiddenOwnershipClaim:
|
||||
type: string
|
||||
const: Spec 288 does not own unrelated full-suite repair.
|
||||
TargetedValidationContract:
|
||||
type: object
|
||||
required:
|
||||
- commandAuthorities
|
||||
- commandIds
|
||||
- outOfScopeProof
|
||||
properties:
|
||||
commandAuthorities:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- specs/288-quality-gates-no-legacy-enforcement/spec.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/plan.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/tasks.md
|
||||
- specs/288-quality-gates-no-legacy-enforcement/quickstart.md
|
||||
commandIds:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- guard-proof-command
|
||||
- browser-proof-command
|
||||
- formatting-command
|
||||
outOfScopeProof:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
default:
|
||||
- no runtime cutover repair
|
||||
- no provider-core rewrite
|
||||
- no RBAC rewrite
|
||||
- no Package Execution Contract work
|
||||
- no Guided Operations work
|
||||
- no full-suite repair program
|
||||
68
specs/288-quality-gates-no-legacy-enforcement/data-model.md
Normal file
68
specs/288-quality-gates-no-legacy-enforcement/data-model.md
Normal file
@ -0,0 +1,68 @@
|
||||
# Data Model: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
## Overview
|
||||
|
||||
`288` introduces no new persisted entity, table, lifecycle state, or runtime DTO. The "data model" for this package is a bounded enforcement inventory that defines which route/path families, helper patterns, provider-core seams, role-authority invariants, browser gates, and baseline-classification rules must remain true after Spec `287`.
|
||||
|
||||
## Canonical Enforcement Categories
|
||||
|
||||
| Enforcement Key | Meaning | Primary Targets | Canonical Enforcement |
|
||||
|---|---|---|---|
|
||||
| `legacy_route_path_contract` | exact retired management route/path families must stay forbidden | guard scans, legacy redirect tests, route emission assertions | targeted no-legacy route/path guard plus supporting runtime regression tests |
|
||||
| `route_emission_contract` | cutover-owned builders and launch points emit canonical admin/workspace routes only | runtime launch-point tests and emitted URL assertions | emitted URLs use canonical admin/workspace managed-environment shapes |
|
||||
| `tenant_panel_helper_contract` | retired tenant-panel bootstrapping must not re-enter shared test support or other owned seams | `tests/Pest.php` and owned test/support seams | explicit helper/panel-bootstrapping guard inventory |
|
||||
| `provider_core_boundary_contract` | platform-core provider seams stay provider-neutral | provider-boundary guards and shared provider catalogs | shared identity/operation seams reject provider-specific request shaping or binding truth |
|
||||
| `environment_scope_role_authority_contract` | workspace membership stays role-bearing and environment scope stays narrowing-only | policy tests, managed-environment scope tests, role-string guard | current wrong-scope `404`, in-scope `403`, and direct role-edit rejection semantics remain true |
|
||||
| `browser_smoke_gate_contract` | the visible canonical provider and RBAC environment flows stay honest | Spec `281` and Spec `285` browser smokes | targeted browser proof only |
|
||||
| `baseline_classification_contract` | broader baseline fallout is classified without becoming repair scope | lane manifest, report contract, README guidance | classification-only wording via existing report seams |
|
||||
|
||||
## Pinned Forbidden Families and Replacements
|
||||
|
||||
| Enforcement Key | Retired Pattern / Drift | Canonical Replacement |
|
||||
|---|---|---|
|
||||
| `legacy_route_path_contract` | `/admin/tenants/{tenant:slug}/provider-connections...` | `/admin/provider-connections...` |
|
||||
| `legacy_route_path_contract` | `/admin/t/{tenant}/provider-connections`, `/admin/t/{tenant}/required-permissions`, `/admin/t/{tenant}/memberships` | canonical admin/workspace managed-environment routes and launch points |
|
||||
| `legacy_route_path_contract` | duplicate `/admin/t/t/{tenant}/...` emission | one canonical managed-environment route prefix only |
|
||||
| `tenant_panel_helper_contract` | `setTenantPanelContext()` or direct `tenant` panel bootstrapping on owned seams | admin/workspace context setup or an explicit file-scoped exception |
|
||||
| `provider_core_boundary_contract` | `graphOptions`, `client_request_id`, or provider binding keys in platform-core seams | provider-neutral shared seams with provider-owned nested detail only |
|
||||
| `environment_scope_role_authority_contract` | managed-environment scope acting like a second role-bearing matrix | workspace membership role truth plus narrowing-only scope rows |
|
||||
| `baseline_classification_contract` | broader baseline fallout silently becoming repair scope | explicit classification-only documentation and report labeling |
|
||||
|
||||
## Pinned Historical / Immutable Exclusions
|
||||
|
||||
| Exclusion Class | Meaning | Representative Paths |
|
||||
|---|---|---|
|
||||
| `immutable_history` | files that intentionally preserve removed vocabulary or route families as historical truth | `database/migrations/**`, `references/**` |
|
||||
| `spec_history` | spec and planning artifacts that must be able to mention retired patterns explicitly | `specs/**`, `spechistory/**`, `docs/**` |
|
||||
| `generated_or_external` | code or artifacts outside normal enforcement ownership | `vendor/**`, `storage/**`, `public/build/**`, `bootstrap/cache/**` |
|
||||
|
||||
## Allowed Provider-Owned Detail
|
||||
|
||||
| Detail Class | Meaning | Examples |
|
||||
|---|---|---|
|
||||
| `provider_owned_profile_detail` | provider-specific detail is allowed where the provider itself is the subject | Microsoft tenant identifiers, authority tenant strings, consent URLs |
|
||||
| `provider_owned_support_detail` | lower-level support detail remains nested provider truth | provider-specific diagnostics or raw metadata |
|
||||
|
||||
## Role-Authority Invariants
|
||||
|
||||
- `workspace_memberships` remain the only role-bearing authority source.
|
||||
- `managed_environment_memberships` remain a narrowing-only scope overlay.
|
||||
- Wrong-scope denials stay `404`.
|
||||
- In-scope capability denials stay `403`.
|
||||
- Direct role edits on managed-environment scope rows remain rejected.
|
||||
|
||||
## Invariants
|
||||
|
||||
- `288` introduces no new persistence and no new product-facing workflow surface.
|
||||
- The same enforcement categories and the same Spec `289` follow-up boundary must appear across `spec.md`, `plan.md`, `tasks.md`, `quickstart.md`, `data-model.md`, the logical contract, and `checklists/requirements.md`.
|
||||
- The literal proof commands live only in `spec.md`, `plan.md`, `tasks.md`, and `quickstart.md`; the remaining artifacts reference that canonical command set rather than restating another variant.
|
||||
- Browser proof remains limited to the two named browser smoke files.
|
||||
- Baseline fallout remains classification-only and must not silently become repair scope.
|
||||
|
||||
## Out of Scope Data Changes
|
||||
|
||||
- no database migrations
|
||||
- no new provider registry or provider-core abstraction layer
|
||||
- no new role family or persisted access overlay
|
||||
- no full-suite baseline artifact or new baseline ledger
|
||||
- no package execution state or workflow contract
|
||||
238
specs/288-quality-gates-no-legacy-enforcement/plan.md
Normal file
238
specs/288-quality-gates-no-legacy-enforcement/plan.md
Normal file
@ -0,0 +1,238 @@
|
||||
# Implementation Plan: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
**Branch**: `288-quality-gates-no-legacy-enforcement` | **Date**: 2026-05-10 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `specs/288-quality-gates-no-legacy-enforcement/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Add the cutover enforcement layer that follows Spec `287` without reopening runtime work. The narrow implementation path adds bounded no-legacy and route-emission guards, forbids retired tenant-panel helper bootstrapping on owned seams, reinforces provider-core and role-authority boundaries, keeps targeted browser smoke proof on the current canonical admin/workspace surfaces, and documents that broader baseline fallout is classified only through existing lane/report seams instead of repaired under this spec.
|
||||
|
||||
This plan is intentionally not a runtime cutover package and not a Package Execution package. Filament remains v5 on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no new asset or deployment step is introduced, no new globally-searchable resource is created, no destructive-action contract changes are planned, and Spec `289` remains the explicit follow-up for Package Execution Contract work.
|
||||
|
||||
## Inherited Baseline / Explicit Delta
|
||||
|
||||
### Inherited baseline
|
||||
|
||||
- Spec `279` established the managed-environment core cutover and remains historical context only.
|
||||
- Spec `280` established workspace-first routing and route-family cleanup patterns.
|
||||
- Spec `281` established provider-boundary groundwork and the current provider-connection browser smoke anchor.
|
||||
- Spec `282` retargeted governance artifact surfaces and remains adjacent history only.
|
||||
- Spec `285` established the workspace-role and environment-scope authority direction and the current RBAC browser smoke anchor.
|
||||
- Spec `286` owns UI copy cleanup and remains explicitly out of scope here.
|
||||
- Spec `287` completed the remaining runtime and helper prerequisites and explicitly handed quality gates and no-legacy enforcement to this spec.
|
||||
|
||||
### Explicit delta in this plan
|
||||
|
||||
- Add one bounded guard pack for retired route/path families and retired tenant-panel helper patterns.
|
||||
- Add one bounded guard pack for provider-core forbidden seams and environment-scope role-authority regressions.
|
||||
- Extend the existing Spec `281` and Spec `285` browser smokes so the guard pack keeps visible canonical route continuity honest.
|
||||
- Document the quality-gate contract and the rule that broader baseline/full-suite fallout is classified only, not repaired, under this spec.
|
||||
- Keep Package Execution Contract explicitly deferred to Spec `289`.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: PHP 8.4.15, Laravel 12.52
|
||||
**Primary Dependencies**: Pest 4, Filament 5.2.1, Livewire 4.1.4, existing guard-test seams, `TestLaneManifest`, `TestLaneReport`, and the current browser smoke suite
|
||||
**Storage**: no new persistence; this package updates tests, contributor-facing documentation, and lane/report classification seams only
|
||||
**Testing**: targeted Pest feature/unit guards, targeted browser validation, and formatting
|
||||
**Validation Lanes**: heavy-governance, browser
|
||||
**Target Platform**: Laravel monolith in `apps/platform`
|
||||
**Project Type**: web application
|
||||
**Performance Goals**: keep proof bounded to the named guard and browser files; no full-suite rerun or repair program
|
||||
**Constraints**: no runtime cutover rewrites, no provider-core rewrite, no RBAC rewrite, no Package Execution work, no Guided Operations work, and no broad compatibility layer
|
||||
**Scale/Scope**: one bounded enforcement slice over existing cutover-owned seams and contributor workflow documentation
|
||||
|
||||
## Likely Affected Repo Surfaces
|
||||
|
||||
- `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`
|
||||
- `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php`
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
|
||||
- `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`
|
||||
- `apps/platform/tests/Unit/Auth/NoRoleStringChecksTest.php`
|
||||
- `apps/platform/tests/Pest.php`
|
||||
- `apps/platform/tests/Support/TestLaneManifest.php`
|
||||
- `apps/platform/tests/Support/TestLaneReport.php`
|
||||
- `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`
|
||||
- `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
|
||||
- `README.md`
|
||||
- `scripts/platform-test-report`
|
||||
|
||||
## Filament v5 / Surface Notes
|
||||
|
||||
- **Livewire v4.0+ compliance**: all touched surfaces remain on Filament v5 with Livewire v4.
|
||||
- **Provider registration location**: provider registration remains in `apps/platform/bootstrap/providers.php`; this package does not add a panel or move provider registration.
|
||||
- **Global search rule**: this package introduces no new globally-searchable resource and does not modify an existing resource's search surface.
|
||||
- **Destructive actions**: no new destructive runtime action is introduced. Any touched browser smoke continues to observe existing destructive-action semantics only.
|
||||
- **Asset strategy**: no new asset registration or deployment step is planned. Existing `php artisan filament:assets` expectations remain unchanged because this package adds no assets.
|
||||
|
||||
## Enforcement Fit
|
||||
|
||||
- Prefer exact retired route/path inventories over broad, ambiguous bans.
|
||||
- Prefer explicit scan exclusions for immutable or historical material over open-ended allowlists.
|
||||
- Prefer extending existing provider-boundary and role-authority tests over introducing a second policy or provider framework.
|
||||
- Prefer targeted browser smoke on the two current high-signal cutover surfaces over a broader browser lane expansion.
|
||||
- Prefer classification-only baseline/report wording over any ownership claim for unrelated full-suite repair.
|
||||
|
||||
## UI / Surface Guardrail Plan
|
||||
|
||||
- **Guardrail scope**: browser proof and route continuity over existing canonical provider and workspace/environment surfaces only
|
||||
- **Native vs custom classification summary**: existing native Filament resources and pages only; no new operator-facing surface
|
||||
- **Shared-family relevance**: route emission continuity, environment access continuity, and contributor proof obligations
|
||||
- **State layers in scope**: emitted URLs, browser-visible route continuity, test-support helper usage, provider-core seam inventories, and lane/report classification wording
|
||||
- **Audience modes in scope**: maintainers and reviewers first; operator-facing surfaces are observed but not redesigned
|
||||
- **Decision/diagnostic/raw hierarchy plan**: unchanged runtime disclosure; docs point maintainers to guard-first and browser-second proof
|
||||
- **Raw/support gating plan**: provider-owned raw or support detail remains nested and out of platform-core enforcement seams
|
||||
- **One-primary-action / duplicate-truth control**: no new action family is introduced
|
||||
- **Handling modes by drift class or surface**: implementation-required for the named guards and browser smokes only; classification-only for broader baseline fallout
|
||||
- **Repository-signal treatment**: review-mandatory, but bounded to cutover-owned seams
|
||||
- **Special surface test profiles**: standard-native-filament, global-context-shell, browser-smoke
|
||||
- **Required tests or manual smoke**: functional-core, targeted browser-smoke
|
||||
- **Exception path and spread control**: any scan exception must be file-specific beyond the pinned historical exclusions
|
||||
- **Active feature PR close-out entry**: NoLegacyGuardrail
|
||||
|
||||
## Shared Pattern & System Fit
|
||||
|
||||
- **Cross-cutting feature marker**: yes
|
||||
- **Systems touched**: guard tests, browser smoke tests, shared test helpers, lane/report classification seams, and contributor-facing quality-gate documentation
|
||||
- **Shared abstractions reused**: `ProviderBoundaryCatalog`, `ProviderOperationRegistry`, existing RBAC feature tests, `TestLaneManifest`, `TestLaneReport`, and the existing browser smoke anchors
|
||||
- **New abstraction introduced? why?**: none
|
||||
- **Why the existing abstraction was sufficient or insufficient**: the abstractions already describe the current cutover truth; the missing piece is an explicit, bounded enforcement layer that uses them consistently.
|
||||
- **Bounded deviation / spread control**: explicit exclusions for immutable or historical material only
|
||||
|
||||
## OperationRun UX Impact
|
||||
|
||||
- **Touches OperationRun start/completion/link UX?**: no
|
||||
- **Central contract reused**: N/A
|
||||
- **Delegated UX behaviors**: N/A
|
||||
- **Surface-owned behavior kept local**: N/A
|
||||
- **Queued DB-notification policy**: N/A
|
||||
- **Terminal notification path**: N/A
|
||||
- **Exception path**: none
|
||||
|
||||
## Provider Boundary & Portability Fit
|
||||
|
||||
- **Shared provider/platform boundary touched?**: yes
|
||||
- **Provider-owned seams**: provider-specific identifiers, consent links, and diagnostics remain provider-owned nested detail only
|
||||
- **Platform-core seams**: shared identity resolution and shared operation-definition contracts
|
||||
- **Neutral platform terms / contracts preserved**: `provider connection`, `target scope`, `workspace`, `managed environment`
|
||||
- **Retained provider-specific semantics and why**: current-release provider flows still need provider-owned nested detail, but the platform-core guard layer must not depend on it
|
||||
- **Bounded extraction or follow-up path**: Spec `289` for Package Execution Contract work after this enforcement baseline lands
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before implementation begins and again after design artifacts are complete.*
|
||||
|
||||
- Inventory-first: PASS. No new inventory or snapshot truth is introduced.
|
||||
- Read/write separation: PASS. The package adds guardrails and documentation only.
|
||||
- Graph contract path: PASS by preservation. No new Graph integration surface is introduced.
|
||||
- Deterministic capabilities: PASS by preservation. Capability families do not expand.
|
||||
- RBAC-UX: PASS. Workspace membership remains role-bearing and environment scope remains narrowing-only.
|
||||
- Workspace isolation: PASS. The package reinforces existing route and entitlement isolation.
|
||||
- Managed-environment isolation: PASS. Wrong-scope and in-scope denial semantics remain distinct.
|
||||
- Run observability: PASS. No new OperationRun behavior is introduced.
|
||||
- OperationRun start UX: PASS. N/A for this package.
|
||||
- Data minimization: PASS. No new persistence or ledger is introduced.
|
||||
- Test governance: PASS. The proof set is explicit and bounded.
|
||||
- Proportionality / no premature abstraction: PASS. Existing guard and report seams are extended instead of replaced.
|
||||
- Persisted truth / behavioral state: PASS. No new state family is introduced.
|
||||
- Provider boundary: PASS. Shared provider-boundary enforcement becomes stricter without widening runtime coupling.
|
||||
|
||||
**Gate evaluation**: PASS.
|
||||
|
||||
**Post-design re-check**: PASS while `spec.md`, `plan.md`, `tasks.md`, and `quickstart.md` keep the same literal proof commands and while the supporting artifacts keep the same retired-route, helper, provider-boundary, role-authority, and classification-only boundary.
|
||||
|
||||
## Test Governance Check
|
||||
|
||||
- **Test purpose / classification by changed surface**: Feature, Browser
|
||||
- **Affected validation lanes**: heavy-governance, browser
|
||||
- **Why this lane mix is the narrowest sufficient proof**: route/helper scans and classification contracts are broad guard work, while visible route continuity belongs in targeted browser smoke. Anything broader would be a different package.
|
||||
- **Narrowest proving command(s)**:
|
||||
- `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" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)`
|
||||
- **Fixture / helper / factory / seed / context cost risks**: low to moderate only because the package relies on explicit source-scan inventories and the current browser fixtures.
|
||||
- **Expensive defaults or shared helper growth introduced?**: no; the guard pack should reduce legacy helper spread, not add new implicit defaults.
|
||||
- **Heavy-family additions, promotions, or visibility changes**: none beyond the bounded cutover guard files and the matching classification wording.
|
||||
- **Surface-class relief / special coverage rule**: `standard-native-filament`, `global-context-shell`, and `browser-smoke` remain sufficient; no broader browser lane ownership is justified.
|
||||
- **Closing validation and reviewer handoff**: rerun the exact commands above, verify Filament stays on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no global-search or asset drift was added, no destructive-action contract drift was introduced, and confirm Spec `289` remains the Package Execution follow-up.
|
||||
- **Budget / baseline / trend follow-up**: classification-only; no full-suite refresh or repair ownership is taken here.
|
||||
- **Review-stop questions**: did the implementation widen into runtime cutover, provider-core rewrite, RBAC rewrite, UI copy cleanup, review-pack export, package execution, guided operations, or full-suite repair?
|
||||
- **Escalation path**: `document-in-feature` for bounded classification wording, `reject-or-split` for scope expansion
|
||||
- **Active feature PR close-out entry**: NoLegacyGuardrail
|
||||
|
||||
## 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 a bounded enforcement slice following Spec `287`
|
||||
- **Escalation rule**: if implementation starts repairing unrelated full-suite failures or reopening runtime cutover work, stop and split the work out of `288`
|
||||
|
||||
## Rollout Considerations
|
||||
|
||||
- Land the route/helper guard inventories before touching browser-smoke or classification docs so the core enforcement vocabulary stabilizes first.
|
||||
- Keep provider-core and role-authority enforcement adjacent so reviewers can judge shared-boundary and authorization truth together.
|
||||
- Update contributor-facing quality-gate guidance only after the final proof-command set is stable.
|
||||
- Do not let baseline classification wording imply ownership of unrelated full-suite repair.
|
||||
|
||||
## Risk Controls
|
||||
|
||||
- Reject any implementation that broad-bans all `/admin/t/...` paths instead of the exact retired management-only families already defined by the cutover.
|
||||
- Reject any implementation that solves helper enforcement by leaving open-ended or directory-wide allowlists.
|
||||
- Reject any implementation that rewrites provider-core runtime services instead of extending the guard inventory.
|
||||
- Reject any implementation that changes RBAC behavior instead of proving the current workspace-role and environment-scope contract.
|
||||
- Reject any implementation that promotes `288` into a full-suite stabilization effort.
|
||||
|
||||
## Research & Design Outputs
|
||||
|
||||
- `research.md` records the guard-first decisions, explicit exclusions, and rejected full-suite repair alternative.
|
||||
- `data-model.md` captures the exact guard categories, forbidden pattern families, and classification-only boundary.
|
||||
- `quickstart.md` gives reviewers the scope boundary, review scenarios, and exact targeted proof commands.
|
||||
- `contracts/quality-gates-no-legacy-enforcement.logical.openapi.yaml` models the logical enforcement contracts and the targeted validation authority.
|
||||
- `checklists/requirements.md` records the review outcome, bounded scope rules, and the explicit Spec `289` follow-up.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/288-quality-gates-no-legacy-enforcement/
|
||||
├── checklists/
|
||||
│ └── requirements.md
|
||||
├── contracts/
|
||||
│ └── quality-gates-no-legacy-enforcement.logical.openapi.yaml
|
||||
├── data-model.md
|
||||
├── plan.md
|
||||
├── quickstart.md
|
||||
├── research.md
|
||||
├── spec.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
apps/platform/
|
||||
├── app/
|
||||
├── tests/
|
||||
│ ├── Browser/
|
||||
│ ├── Feature/
|
||||
│ ├── Support/
|
||||
│ └── Unit/
|
||||
└── routes/
|
||||
|
||||
scripts/
|
||||
├── platform-test-lane
|
||||
└── platform-test-report
|
||||
```
|
||||
|
||||
**Structure Decision**: keep the package inside the existing Laravel tests, support, and wrapper structure. Extend the current guard, browser, and lane/report seams instead of creating a new enforcement subsystem or documentation tree.
|
||||
84
specs/288-quality-gates-no-legacy-enforcement/quickstart.md
Normal file
84
specs/288-quality-gates-no-legacy-enforcement/quickstart.md
Normal file
@ -0,0 +1,84 @@
|
||||
# Quickstart: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
## Purpose
|
||||
|
||||
Use this guide to review or implement Feature `288` as the bounded enforcement layer that follows Spec `287`.
|
||||
|
||||
## Preconditions
|
||||
|
||||
- The package stays limited to:
|
||||
- no-legacy guard tests
|
||||
- route emission guards
|
||||
- forbidden legacy route/path checks
|
||||
- forbidden tenant-panel helper checks
|
||||
- provider-core forbidden seam checks
|
||||
- environment-scope role-authority guard checks
|
||||
- quality-gate documentation
|
||||
- targeted browser smoke gates
|
||||
- full-suite baseline classification only, not full-suite repair
|
||||
- Package Execution Contract remains deferred to Spec `289`.
|
||||
- The implementation does not reopen runtime cutover, provider-core rewrites, RBAC rewrites, Guided Operations, UI copy cleanup, Review Pack export work, or a full-suite repair program.
|
||||
- Filament remains v5 on Livewire v4 and provider registration remains in `apps/platform/bootstrap/providers.php`.
|
||||
|
||||
## Read Order
|
||||
|
||||
1. `spec.md`
|
||||
2. `plan.md`
|
||||
3. `research.md`
|
||||
4. `data-model.md`
|
||||
5. `contracts/quality-gates-no-legacy-enforcement.logical.openapi.yaml`
|
||||
6. `tasks.md`
|
||||
7. `checklists/requirements.md`
|
||||
|
||||
## Implementation Intent
|
||||
|
||||
- add bounded no-legacy and route-emission guards instead of reopening route migration work
|
||||
- add bounded provider-core and role-authority guards instead of rewriting provider-core or RBAC
|
||||
- keep browser proof on the existing Spec `281` and Spec `285` smoke anchors
|
||||
- document the quality-gate contract and the rule that broader baseline fallout is classified only under this spec
|
||||
- keep Spec `289` as the explicit follow-up for Package Execution Contract work
|
||||
|
||||
## Review Scenarios
|
||||
|
||||
### Scenario 1: Retired management routes and helper patterns fail fast
|
||||
|
||||
- introduce or simulate a retired route/path or helper token on an owned seam
|
||||
- run the targeted guard suite
|
||||
- confirm the failure message names the offending path or helper pattern explicitly
|
||||
|
||||
### Scenario 2: Provider-core seams stay provider-neutral and role authority stays workspace-owned
|
||||
|
||||
- run the targeted provider-boundary and role-authority proof set
|
||||
- confirm platform-core seams do not reintroduce provider-specific request shaping or binding truth
|
||||
- confirm wrong-scope `404`, in-scope `403`, and direct role-edit rejection semantics remain intact
|
||||
|
||||
### Scenario 3: Browser proof still reflects canonical visible continuity
|
||||
|
||||
- run the two targeted browser smoke tests
|
||||
- confirm the provider-connection and workspace/environment drill-down flows render their canonical route continuity
|
||||
- confirm the browser suite reports no JavaScript or console errors
|
||||
|
||||
### Scenario 4: Broader baseline fallout stays classification-only
|
||||
|
||||
- review the contributor-facing quality-gate docs and any changed report/manifest wording
|
||||
- confirm the package classifies wider baseline fallout without taking ownership of unrelated repair work
|
||||
|
||||
## Planned Validation Commands
|
||||
|
||||
```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" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)
|
||||
```
|
||||
|
||||
## Explicit Stop Conditions
|
||||
|
||||
- If implementation starts repairing unrelated full-suite failures, stop and split that work out of `288`.
|
||||
- If implementation starts reopening runtime cutover, provider-core rewrite, RBAC rewrite, or product-surface cleanup, stop and split the extra work out of `288`.
|
||||
- If implementation starts absorbing Package Execution Contract work, stop and move that work to Spec `289`.
|
||||
76
specs/288-quality-gates-no-legacy-enforcement/research.md
Normal file
76
specs/288-quality-gates-no-legacy-enforcement/research.md
Normal file
@ -0,0 +1,76 @@
|
||||
# Research: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
## Decision 1: Spec `288` owns enforcement only, not runtime completion
|
||||
|
||||
- Use this package to enforce the post-`287` cutover truth through bounded guard tests, targeted browser smoke, and contributor-facing quality-gate docs.
|
||||
- Do not reopen route migration, provider-core runtime rewrites, RBAC redesign, or any product-surface rewrite here.
|
||||
- Keep Spec `289` explicitly reserved for Package Execution Contract work.
|
||||
|
||||
## Decision 2: Guard exact retired route/path families instead of broad `/admin/t` bans
|
||||
|
||||
- The cutover still has valid canonical managed-environment routes, so the guard layer must forbid only the exact retired management-only families and duplicate-prefix emissions.
|
||||
- The enforcement inventory should pin concrete forbidden shapes such as `/admin/tenants/{tenant:slug}/provider-connections...`, `/admin/t/{tenant}/provider-connections`, `/admin/t/{tenant}/required-permissions`, `/admin/t/{tenant}/memberships`, and duplicate `/admin/t/t/{tenant}/...` emissions.
|
||||
- Do not turn this package into a blanket ban on every surviving `/admin/t/...` route without repo proof that the whole family is retired.
|
||||
|
||||
## Decision 3: Helper enforcement targets retired panel bootstrapping, not generic tenant vocabulary
|
||||
|
||||
- The risk to guard is the return of retired tenant-panel bootstrapping semantics, not the presence of every `tenant`-named helper or variable.
|
||||
- Guard scans should target direct `tenant` panel selection, retired bootstrapping helpers such as `setTenantPanelContext()`, and any similar owned-seam helper that would recreate panel-era assumptions.
|
||||
- Any exception beyond pinned historical directories must be file-scoped and justified.
|
||||
|
||||
## Decision 4: Provider-core enforcement should reuse existing boundary seams
|
||||
|
||||
- Reuse `ProviderBoundaryCatalog`, `ProviderOperationRegistry`, and the current provider-boundary tests instead of inventing a new provider-core validator.
|
||||
- The enforcement targets are shared identity resolution and shared operation-definition seams where provider-specific request shaping or provider binding truth would be a regression.
|
||||
- Provider-owned nested detail remains allowed only where the provider itself is the subject.
|
||||
|
||||
## Decision 5: Role-authority enforcement should prove current semantics, not redesign them
|
||||
|
||||
- Reuse the existing workspace-first policy and managed-environment scope tests to prove the current contract remains true.
|
||||
- The core invariants are: workspace membership is the only role-bearing authority, wrong-scope denials stay `404`, in-scope capability denials stay `403`, and direct role edits on managed-environment scope rows remain rejected.
|
||||
- Do not let this package become an RBAC rewrite.
|
||||
|
||||
## Decision 6: Targeted browser proof should stay anchored to the current Spec `281` and Spec `285` smoke tests
|
||||
|
||||
- The two highest-signal user-visible anchors already exist in `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php` and `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`.
|
||||
- Extend those tests to keep canonical route continuity honest after the new guard pack lands.
|
||||
- Do not widen the browser lane beyond those named surfaces under this spec.
|
||||
|
||||
## Decision 7: Broader baseline fallout is classified only through the current lane/report seams
|
||||
|
||||
- Use `apps/platform/tests/Support/TestLaneManifest.php`, `apps/platform/tests/Support/TestLaneReport.php`, and the existing classification-contract tests to describe how cutover guard or browser failures should be reported.
|
||||
- Do not run or own a full-suite repair program here.
|
||||
- README guidance should point contributors to the targeted proof commands and the classification-only boundary.
|
||||
|
||||
## Rejected Alternatives
|
||||
|
||||
### Rejected: absorb runtime cutover repair into `288`
|
||||
|
||||
That would collapse the intentional `287` / `288` split and make it impossible to tell whether the package is guardrail work or unfinished runtime work.
|
||||
|
||||
### Rejected: ban every `tenant`-named helper or route token globally
|
||||
|
||||
That would create false positives and force ad hoc exceptions because some canonical managed-environment flows still use bounded tenant-language or route segments legitimately.
|
||||
|
||||
### Rejected: introduce a new linting or baseline-report framework
|
||||
|
||||
The repo already has working guard, browser, manifest, and report seams. A second framework would increase ownership cost without improving the cutover signal.
|
||||
|
||||
### Rejected: take ownership of full-suite repair under the label of “baseline classification”
|
||||
|
||||
The user explicitly excluded full-suite repair work. Classification is in scope; broad stabilization is not.
|
||||
|
||||
## Evidence Anchors
|
||||
|
||||
- `apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php` already proves one retired provider-management path family must stay `404` without redirects.
|
||||
- `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php` already proves the legacy `tenant` panel is gone at runtime, but it does not yet own the full helper and route inventory.
|
||||
- `apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php` already guards one provider-boundary seam and current provider operation definitions.
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php` and `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php` already prove the intended role-authority semantics.
|
||||
- `apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php`, `apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php`, `apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php`, `apps/platform/tests/Support/TestLaneManifest.php`, and `apps/platform/tests/Support/TestLaneReport.php` already define the current classification/report seams.
|
||||
- `README.md` already documents lane ownership and budgets, making it the right place for the contributor-facing quality-gate rule.
|
||||
|
||||
## Implementation Boundary Summary
|
||||
|
||||
- The package is implementation-ready only when the enforcement layer stays inside the named guard, browser, and documentation seams.
|
||||
- If implementation starts changing live provider-core behavior, RBAC behavior, or unrelated product flows to make the guards pass, stop and split that work out of `288`.
|
||||
- The canonical executable command set lives only in `spec.md`, `plan.md`, `tasks.md`, and `quickstart.md`; this note references that authority without restating a second variant.
|
||||
265
specs/288-quality-gates-no-legacy-enforcement/spec.md
Normal file
265
specs/288-quality-gates-no-legacy-enforcement/spec.md
Normal file
@ -0,0 +1,265 @@
|
||||
# Feature Specification: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
**Feature Branch**: `288-quality-gates-no-legacy-enforcement`
|
||||
**Created**: 2026-05-10
|
||||
**Status**: Ready
|
||||
**Input**: User description: "Introduce the no-legacy and quality-gate enforcement layer now that Spec 287 completed the prerequisites. In scope: no-legacy guard tests, route emission guards, forbidden legacy route/path checks, forbidden tenant-panel helper checks, provider-core forbidden seam checks, environment-scope role-authority guard checks, quality gate documentation, targeted browser smoke gates, and full-suite baseline classification only, not full-suite repair. Package Execution Contract must move to Spec 289."
|
||||
|
||||
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
||||
|
||||
- **Problem**: Specs `279` through `287` established or completed the workspace-first, provider-neutral, and role-authority runtime baseline, but the repo still lacks one bounded enforcement layer that keeps those truths from drifting back through emitted route strings, retired helper patterns, provider-core seams, or role-authority regressions.
|
||||
- **Today's failure**: repo truth already contains fragmented protection in `apps/platform/tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php`, `apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`, `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`, `apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php`, `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`, `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`, and `apps/platform/tests/Unit/Auth/NoRoleStringChecksTest.php`, but there is still no single cutover guard package that pins the exact retired route/path inventory, forbids retired tenant-panel helper bootstrapping on owned seams, classifies broader baseline fallout without taking repair ownership, and names the targeted browser smoke obligations in contributor-facing docs.
|
||||
- **User-visible improvement**: operators keep the existing canonical admin/workspace managed-environment flows without legacy route drift, while maintainers get fast, actionable failures before tenant- or Microsoft-centric seams silently re-enter the product.
|
||||
- **Smallest enterprise-capable version**: add one bounded enforcement layer that (1) fails on reintroduced retired management route/path families and bad emitted URLs, (2) blocks retired tenant-panel helper or panel-bootstrapping patterns on owned seams, (3) blocks provider-core forbidden seam regressions on shared identity and operation-definition paths, (4) proves workspace membership remains the only role-bearing authority while environment scope stays narrowing-only, (5) adds targeted browser smoke gates on the existing provider and RBAC environment surfaces, and (6) documents that broader baseline fallout is classified only, not repaired, under this spec.
|
||||
- **Explicit non-goals**: no Package Execution Contract work, no Guided Operations work, no Microsoft Starter Pack work, no runtime cutover work, no provider-core rewrite, no RBAC rewrite, no UI copy cleanup, no Review Pack export change, no global compatibility layer, and no full-suite repair program.
|
||||
- **Permanent complexity imported**: two bounded guard-test inventories, targeted browser smoke obligations on existing browser tests, one contributor-facing quality-gate documentation update, and one classification-only baseline-report rule using the existing lane manifest/report seams. No new panel, no new persisted truth, and no new guard subsystem are introduced.
|
||||
- **Why now**: Spec `287` explicitly moved runtime and helper prerequisites out of the way. Without `288`, the cutover remains vulnerable to silent regressions, and future work such as Spec `289` would start from an unguarded baseline.
|
||||
- **Why not local**: the enforcement work spans route emission, provider boundaries, test helpers, role-authority semantics, browser proof, and lane/report classification. A local test patch on one surface would leave the rest of the cutover unprotected.
|
||||
- **Approval class**: Cleanup
|
||||
- **Red flags triggered**: source-scan guard breadth, browser-gate ownership, and contributor-workflow classification changes. Defense: the package reuses existing guard families, existing browser-smoke anchors, and the current `TestLaneManifest` / `TestLaneReport` seams; it explicitly forbids runtime rewrites and full-suite repair.
|
||||
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | **Gesamt: 11/12**
|
||||
- **Decision**: approve
|
||||
|
||||
## Review Outcome
|
||||
|
||||
- **Outcome class**: acceptable-special-case
|
||||
- **Workflow outcome**: keep
|
||||
- **Test-governance outcome**: keep
|
||||
- **Reason**: the package is cross-cutting but still implementation-ready because it hardens an already-finished runtime baseline through bounded guard tests, targeted browser proof, and classification-only documentation updates.
|
||||
- **Workflow result**: Ready for implementation as the quality-gates and no-legacy enforcement layer that follows Spec `287`.
|
||||
|
||||
## Spec Scope Fields *(mandatory)*
|
||||
|
||||
- **Scope**: repository
|
||||
- **Primary Routes**:
|
||||
- canonical admin provider-connection routes such as `/admin/provider-connections...`
|
||||
- canonical workspace/environment drill-down routes such as `/admin/workspaces/{workspace}/environments/{managed_environment}/...`
|
||||
- exact retired management-only route/path families that now must stay forbidden, including `/admin/tenants/{tenant:slug}/provider-connections...`, `/admin/t/{tenant}/provider-connections`, `/admin/t/{tenant}/required-permissions`, `/admin/t/{tenant}/memberships`, and duplicate-prefix emissions such as `/admin/t/t/{tenant}/...`
|
||||
- **Data Ownership**:
|
||||
- no new persisted entity, table, or artifact is introduced
|
||||
- guard inventories remain derived enforcement truth backed by tests and existing documentation
|
||||
- `workspace_memberships` remain the only role-bearing authority
|
||||
- `managed_environment_memberships` remain a narrowing-only scope overlay and must not become a second role-bearing matrix
|
||||
- existing lane report artifacts remain observational outputs only; this package does not establish a new baseline ledger
|
||||
- **RBAC**:
|
||||
- workspace membership remains the first entitlement boundary and the only role-bearing authority
|
||||
- managed-environment scope may narrow access only
|
||||
- wrong-workspace or wrong-environment access remains `404`
|
||||
- in-scope actors missing capability remain `403`
|
||||
|
||||
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, navigation entry points, alerts, 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)**: no-legacy guard tests, route emission guardrails, shared provider-boundary enforcement, targeted browser-smoke gates, and baseline classification documentation
|
||||
- **Systems touched**:
|
||||
- `apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/AdminWorkspaceRoutesGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php`
|
||||
- `apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php`
|
||||
- `apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`
|
||||
- `apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`
|
||||
- `apps/platform/tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php`
|
||||
- `apps/platform/tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php`
|
||||
- `apps/platform/tests/Unit/Auth/NoRoleStringChecksTest.php`
|
||||
- `apps/platform/tests/Pest.php`
|
||||
- `apps/platform/tests/Support/TestLaneManifest.php`
|
||||
- `apps/platform/tests/Support/TestLaneReport.php`
|
||||
- `apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php`
|
||||
- `apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php`
|
||||
- `README.md`
|
||||
- `scripts/platform-test-report`
|
||||
- **Existing pattern(s) to extend**: current no-legacy source-scan guard style, current provider-boundary guard style, current role-authority feature assertions, existing browser-smoke route assertions, and the current test-lane manifest/report contract style
|
||||
- **Shared contract / presenter / builder / renderer to reuse**: `ProviderBoundaryCatalog`, `ProviderOperationRegistry`, existing workspace-first policy tests, existing browser smoke tests, `TestLaneManifest`, `TestLaneReport`, and the existing lane wrapper scripts
|
||||
- **Why the existing shared path is sufficient or insufficient**: the repo already has the right guard and reporting seams, but they are fragmented. Extending them is sufficient; creating a new lint framework or a second baseline-report system would be wider than necessary.
|
||||
- **Allowed deviation and why**: scan exclusions are allowed only for immutable or historical material such as `database/migrations/**`, `references/**`, `docs/**`, `specs/**`, `spechistory/**`, `vendor/**`, and generated build or storage outputs. Any additional exception must be file-specific and justified.
|
||||
- **Consistency impact**: route/path truth, helper truth, provider-boundary truth, role-authority truth, browser proof, and classification wording must all describe the same post-`287` cutover baseline.
|
||||
- **Review focus**: reviewers must verify that the package adds enforcement only, keeps runtime/product rewrites out of scope, and leaves Spec `289` as the Package Execution Contract follow-up.
|
||||
|
||||
## 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`)*
|
||||
|
||||
N/A - no OperationRun start or link semantics touched.
|
||||
|
||||
## 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**: shared provider identity resolution, shared provider operation definitions, and provider-boundary enforcement on platform-core seams
|
||||
- **Neutral platform terms preserved or introduced**: `provider connection`, `target scope`, `scope kind`, `scope identifier`, `scope display name`, `workspace`, and `managed environment`
|
||||
- **Provider-specific semantics retained and why**: provider-owned nested detail such as Microsoft tenant identifiers, consent links, or diagnostics may remain where the provider itself is the subject, but they must not re-enter platform-core identity or operation-definition truth.
|
||||
- **Why this does not deepen provider coupling accidentally**: the package forbids Microsoft-shaped request option helpers and provider binding status keys on platform-core seams and reuses the current provider-boundary catalogs instead of inventing a second provider-core layer.
|
||||
- **Follow-up path**: Spec `289` owns Package Execution Contract work once the cutover enforcement baseline is in place.
|
||||
|
||||
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
||||
|
||||
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
||||
|---|---|---|---|---|---|---|
|
||||
| Provider-connection detail and managed-environment launch-point smoke gate | no direct runtime change | Native Filament resources | route emission truth and browser continuity | URL, query, detail, browser proof | no | smoke gate only |
|
||||
| Workspace/environment drill-down smoke gate | no direct runtime change | Native Filament resources | role-authority proof and browser continuity | route, page, detail, browser proof | no | smoke gate only |
|
||||
| Quality gate docs and lane classification wording | no operator surface change | N/A | contributor workflow only | docs, report classification, wrapper wording | no | repository workflow only |
|
||||
|
||||
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - the package does not change the decision contract of an operator-facing surface; it only proves the existing decision surfaces through targeted browser smoke.
|
||||
|
||||
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - browser smoke gates observe existing audience-aware disclosure but do not change it.
|
||||
|
||||
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - no new runtime surface or action model is introduced.
|
||||
|
||||
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
|
||||
|
||||
N/A - existing operator surface contracts remain unchanged.
|
||||
|
||||
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||
|
||||
- **New source of truth?**: no
|
||||
- **New persisted entity/table/artifact?**: no
|
||||
- **New abstraction?**: no
|
||||
- **New enum/state/reason family?**: no independent family; reuse the existing test-lane classification and failure-class framework if a new cutover label is needed there
|
||||
- **New cross-domain UI framework/taxonomy?**: no
|
||||
- **Current operator problem**: a completed cutover can still regress silently if emitted URLs, helper patterns, provider-core seams, or role-authority boundaries are not enforced.
|
||||
- **Existing structure is insufficient because**: isolated runtime tests exist, but they do not yet form one explicit enforcement layer with targeted browser proof and a documented classification-only boundary for broader baseline fallout.
|
||||
- **Narrowest correct implementation**: add bounded guard tests, targeted browser smoke assertions, and classification-only documentation updates on the existing lane/report seams.
|
||||
- **Ownership cost**: one guard inventory for routes/helpers, one guard inventory for provider-core/role-authority, small browser smoke updates, and bounded docs/report wording updates.
|
||||
- **Alternative intentionally rejected**: reopening runtime cutover work or taking ownership of full-suite repair. That would widen the package beyond enforcement.
|
||||
- **Release truth**: current-release truth
|
||||
|
||||
### Compatibility posture
|
||||
|
||||
This feature assumes a pre-production environment.
|
||||
|
||||
Canonical cutover truth is preferred over legacy compatibility shims.
|
||||
|
||||
Historical and immutable references may remain in excluded documentation or migration paths only.
|
||||
|
||||
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
||||
|
||||
- **Test purpose / classification**: Feature, Browser
|
||||
- **Validation lane(s)**: heavy-governance, browser
|
||||
- **Why this classification and these lanes are sufficient**: the source-scan and contract checks are intentionally broad guard work and belong to the existing heavy-governance-style guard family, while the visible continuity proof belongs to the isolated browser lane. No full-suite run or repair is required.
|
||||
- **New or expanded test families**: cutover route/helper no-legacy guards, provider-core and role-authority guard coverage, targeted browser smoke assertions on existing Spec `281` and Spec `285` smoke anchors, and classification-contract coverage for the new guard/browser ownership
|
||||
- **Fixture / helper cost impact**: low to moderate. The broadest cost comes from explicit scan inventories and existing browser fixtures; no new expensive default helper or full-suite harness is introduced.
|
||||
- **Heavy-family visibility / justification**: yes. The enforcement pack is intentionally cross-cutting and belongs in the existing guard-heavy validation posture, but it must stay bounded to cutover-owned seams.
|
||||
- **Special surface test profile**: standard-native-filament, global-context-shell, browser-smoke
|
||||
- **Standard-native relief or required special coverage**: ordinary feature and unit coverage remains sufficient for role-authority semantics; browser smoke is required only for the two named user-visible path-continuity surfaces.
|
||||
- **Reviewer handoff**: reviewers must verify that Filament remains v5 on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no global-search contract changes are introduced, no new destructive action semantics are added, no asset registration or deployment step changes are introduced, the proof commands remain targeted, and Package Execution stays deferred to Spec `289`.
|
||||
- **Budget / baseline / trend impact**: classification-only documentation and failure-contract updates are allowed; no full-suite baseline refresh or repair is owned by this package.
|
||||
- **Escalation needed**: document-in-feature
|
||||
- **Active feature PR close-out entry**: NoLegacyGuardrail
|
||||
- **Planned validation commands**:
|
||||
- `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" && REPO_ROOT="$(git rev-parse --show-toplevel)" && (cd "$REPO_ROOT/apps/platform" && ./vendor/bin/sail bin pint --dirty --format agent)`
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Guard retired routes, paths, and helper bootstrapping (Priority: P1)
|
||||
|
||||
As a maintainer, I want explicit no-legacy guards for retired management route families, emitted URL shapes, and retired tenant-panel helper bootstrapping so the cutover cannot silently regress through small convenience changes.
|
||||
|
||||
**Why this priority**: if route/path or helper drift returns, the cutover fails at its edges before broader provider or RBAC guarantees matter.
|
||||
|
||||
**Independent Test**: Can be fully tested by running the targeted route/helper guard suite plus the existing runtime regression tests that already assert legacy provider and tenant-core paths stay not found.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a change reintroduces a retired provider-management route or emitted URL shape, **When** the targeted guard suite runs, **Then** it fails with an actionable path-specific message.
|
||||
2. **Given** a shared test helper or owned seam attempts to boot the retired tenant panel again, **When** the targeted guard suite runs, **Then** it fails before that pattern spreads.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Guard provider-core seams and role authority (Priority: P1)
|
||||
|
||||
As a maintainer or reviewer, I want shared provider-core and role-authority guard checks so platform-core seams stay provider-neutral and environment scope stays narrowing-only.
|
||||
|
||||
**Why this priority**: provider-core leakage and role-authority drift would reintroduce exactly the cross-cutting coupling that the cutover removed.
|
||||
|
||||
**Independent Test**: Can be fully tested by running the provider-core and role-authority guard suite alongside the existing policy and membership regression tests.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a shared provider identity or operation-definition seam reintroduces provider-specific request shaping or provider binding truth, **When** the guard suite runs, **Then** it fails with a seam-specific message.
|
||||
2. **Given** a change lets managed-environment scope act like a second role-bearing matrix, **When** the role-authority tests run, **Then** the regression is caught as either wrong-scope `404` drift, in-scope `403` drift, or illegal direct role-edit behavior.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Keep browser proof and quality-gate docs honest (Priority: P2)
|
||||
|
||||
As a maintainer, I want the guard package to name and run the existing high-signal browser smoke gates and document the quality-gate boundary so contributors know what proof is mandatory and what repair work is intentionally excluded.
|
||||
|
||||
**Why this priority**: browser proof and docs make the guard package actionable rather than purely theoretical.
|
||||
|
||||
**Independent Test**: Can be fully tested by running the two targeted browser smoke tests and verifying the contributor-facing quality-gate documentation points at the same proof set and the same classification-only boundary.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a change affects canonical provider-connection or workspace/environment drill-down continuity, **When** the targeted browser smoke tests run, **Then** they prove the visible canonical route shapes and stay free of JavaScript or console errors.
|
||||
2. **Given** a maintainer reads the quality-gate docs for this pack, **When** they follow the guidance, **Then** they see the targeted proof commands and the rule that broader baseline fallout is classified only under Spec `288`.
|
||||
|
||||
---
|
||||
|
||||
### User Story 4 - Classify broader baseline fallout without owning repair (Priority: P3)
|
||||
|
||||
As a maintainer or reviewer, I want broader baseline fallout to be classified through the existing lane/report contracts so cutover-specific failures are visible without turning this package into a full-suite stabilization effort.
|
||||
|
||||
**Why this priority**: the repo needs reviewable signal, but this package must stay on enforcement rather than becoming a general test-repair lane.
|
||||
|
||||
**Independent Test**: Can be fully tested by extending the current classification-contract tests and verifying that the updated manifest/report wording distinguishes guard/browser ownership from unrelated broader failures.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a wider baseline or report includes cutover guard failures, **When** classification contracts render the result, **Then** they identify the guard/browser ownership without implying that Spec `288` repairs unrelated failures.
|
||||
2. **Given** unrelated full-suite failures already exist, **When** this package is implemented, **Then** the package records or classifies them as external to `288` instead of silently absorbing repair work.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when a canonical `/admin/t/{tenant}` operational path remains valid while adjacent management-only `/admin/t/{tenant}/provider-connections` or duplicate `/admin/t/t/{tenant}` paths must stay forbidden?
|
||||
- How do source scans avoid flagging immutable historical references inside `database/migrations/**`, `references/**`, `docs/**`, `specs/**`, or `spechistory/**` while still failing on live code drift?
|
||||
- What happens when a helper still carries legacy naming but no longer boots the retired panel? Any allowed exception must be explicit and path-specific rather than global.
|
||||
- How does the package distinguish wrong-scope `404` behavior from in-scope capability `403` behavior when role-authority drift is introduced?
|
||||
- How is a broader baseline or lane report handled when the package surfaces a cutover regression but unrelated failures are already present?
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
**Constitution alignment (required):** This package introduces no new Graph integration surface, no new queue workflow, no new persisted entity, and no new operator product flow. It hardens the completed cutover through bounded tests, browser proof, and documentation only.
|
||||
|
||||
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** The feature must reuse existing guard-test, browser-smoke, and lane/report structures. It may pin new inventories inside those seams, but it must not create a second enforcement framework or a new baseline data store.
|
||||
|
||||
**Constitution alignment (XCUT-001 / PROV-001):** The package must enforce shared provider/platform boundaries through existing catalogs and tests. It may extend those guardrails, but it must not rewrite provider-core runtime behavior under the banner of enforcement.
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The package MUST add targeted no-legacy guard tests that fail when exact retired management route/path families or duplicate route emissions reappear on cutover-owned seams.
|
||||
- **FR-002**: Route emission guards MUST verify that cutover-owned launch points and shared URL builders emit canonical admin/workspace managed-environment URLs instead of retired provider-management or duplicate-prefix route shapes.
|
||||
- **FR-003**: Forbidden route/path scans MUST use explicit exclusions for immutable or historical material such as `database/migrations/**`, `references/**`, `docs/**`, `specs/**`, `spechistory/**`, generated build output, vendor code, and storage artifacts.
|
||||
- **FR-004**: The package MUST add forbidden tenant-panel helper checks that fail when retired tenant-panel bootstrapping patterns such as `setTenantPanelContext()` or direct `tenant` panel selection re-enter the shared test harness or other owned seams outside explicit, file-scoped exceptions.
|
||||
- **FR-005**: Provider-core forbidden seam checks MUST fail when shared provider identity or operation-definition seams reintroduce request-option shaping or provider binding truth that belongs only in provider-owned seams.
|
||||
- **FR-006**: Environment-scope role-authority guard checks MUST prove that workspace membership remains the only role-bearing authority, wrong-scope denials remain `404`, in-scope capability denials remain `403`, and direct role edits on managed-environment scope records remain rejected.
|
||||
- **FR-007**: Targeted browser smoke gates MUST keep the existing provider-connection and workspace/environment drill-down surfaces green while asserting canonical route continuity and absence of browser-console or JavaScript errors.
|
||||
- **FR-008**: Quality-gate documentation MUST name the exact targeted proof set, the browser-smoke obligations, the scan-exclusion rules, and the classification-only rule for broader baseline fallout.
|
||||
- **FR-009**: Existing lane/report classification contracts MUST be updated only enough to classify cutover guard/browser ownership and broader baseline fallout; this package MUST NOT take ownership of unrelated full-suite repair.
|
||||
- **FR-010**: The package MUST NOT reopen runtime cutover work, provider-core rewrites, RBAC rewrites, UI copy cleanup, Review Pack export work, or Guided Operations work in order to make the guard suite pass.
|
||||
- **FR-011**: Spec `289` MUST remain the explicit follow-up for Package Execution Contract work; `288` must not absorb it.
|
||||
|
||||
### 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, and no change to destructive-action semantics.
|
||||
- **NFR-003**: The package introduces no new asset registration and no new deployment step. Existing deployment expectations such as `php artisan filament:assets` remain unchanged because this spec adds no assets.
|
||||
- **NFR-004**: Validation remains bounded to the targeted guard tests, the two named browser smoke tests, and formatting. No full-suite baseline rerun or repair is required.
|
||||
- **NFR-005**: Any exception added to a route/path, helper, or source-scan guard must be explicit, file-scoped, and justified; broad namespace or directory allowlists outside the pinned historical exclusions are forbidden.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: Reintroducing any pinned retired route/path family or retired tenant-panel helper pattern on a live owned seam causes the targeted guard suite to fail with an actionable, path-specific message.
|
||||
- **SC-002**: The targeted browser smoke tests for Spec `281` and Spec `285` pass while still asserting canonical route continuity and no JavaScript or console drift.
|
||||
- **SC-003**: Contributor-facing quality-gate documentation points to the same proof commands and explicitly states that broader baseline fallout is classified only, not repaired, under Spec `288`.
|
||||
- **SC-004**: Package Execution Contract remains deferred to Spec `289`, and no runtime cutover, provider-core rewrite, RBAC rewrite, or full-suite repair work is absorbed into the implementation.
|
||||
225
specs/288-quality-gates-no-legacy-enforcement/tasks.md
Normal file
225
specs/288-quality-gates-no-legacy-enforcement/tasks.md
Normal file
@ -0,0 +1,225 @@
|
||||
---
|
||||
description: "Task list for Quality Gates / No-Legacy Enforcement"
|
||||
---
|
||||
|
||||
# Tasks: Quality Gates / No-Legacy Enforcement
|
||||
|
||||
**Input**: Design documents from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/`
|
||||
**Prerequisites**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/plan.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/spec.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/checklists/requirements.md` (required), `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/research.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/data-model.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/contracts/quality-gates-no-legacy-enforcement.logical.openapi.yaml`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/quickstart.md`
|
||||
|
||||
**Review Artifact**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/checklists/requirements.md` is the outcome-of-record for the review outcome class, workflow outcome, and test-governance outcome. If implementation expands into runtime cutover repair, Package Execution Contract work, Guided Operations, Review Pack export changes, or full-suite repair, update that artifact before continuing and stop when the work no longer fits `288`.
|
||||
|
||||
**Tests**: Required (Pest) for guard, browser, and classification-contract changes. Keep proof bounded to the named guard and browser files plus formatting. Broader baseline fallout may be classified but not repaired under this spec.
|
||||
**Operations**: No new `OperationRun`, queue family, remote workflow, or notification policy is introduced. `288` only adds enforcement and contributor-facing quality-gate documentation.
|
||||
**RBAC**: Reuse the workspace-first access contract from Spec `285`; do not add a new role family, raw capability strings, or a second role matrix.
|
||||
**Shared Pattern Reuse**: Reuse `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.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/Unit/Auth/NoRoleStringChecksTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneManifest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneReport.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/README.md`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/scripts/platform-test-report`. Do not introduce a new lint framework, a second baseline-report system, or a full-suite repair 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 route/helper guardrails, provider-core and role-authority guardrails, browser-smoke and documentation obligations, and the classification-only broader-baseline boundary.
|
||||
**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] New source scans use explicit exclusions and avoid broad, ambiguous allowlists.
|
||||
- [x] Targeted browser smoke gates are named explicitly and remain isolated to the browser lane.
|
||||
- [x] Planned validation commands cover the changed seams without becoming a full-suite baseline or repair program.
|
||||
- [x] Surface test profile stays explicit: `standard-native-filament`, `global-context-shell`, and `browser-smoke`.
|
||||
- [x] The active package records that Spec `289` owns Package Execution Contract work after this slice lands.
|
||||
|
||||
## Phase 1: Setup (Shared Context)
|
||||
|
||||
**Purpose**: Lock the bounded enforcement role, exact retired inventories, and targeted validation scope before test or documentation edits begin.
|
||||
|
||||
- [x] T001 Review `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/spec.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/plan.md`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/checklists/requirements.md` to confirm the package stays on enforcement only
|
||||
- [x] T002 [P] Review `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/research.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/data-model.md`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/contracts/quality-gates-no-legacy-enforcement.logical.openapi.yaml` to confirm the same retired-route, helper, provider-boundary, role-authority, and classification-only inventories are pinned everywhere
|
||||
- [x] T003 [P] Confirm the focused Sail/Pest validation commands in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/288-quality-gates-no-legacy-enforcement/quickstart.md` and the current guard, browser, and classification surfaces in `apps/platform/tests/Feature/Guards/`, `apps/platform/tests/Browser/`, `apps/platform/tests/Support/`, and `README.md`
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Prerequisites)
|
||||
|
||||
**Purpose**: Fix the exact enforcement inventory before story work begins and keep runtime rewrites and broader repair explicitly out of scope.
|
||||
|
||||
**Critical**: No user-story work should begin until this phase is complete.
|
||||
|
||||
- [x] T004 Audit the exact retired route/path and emitted-URL inventories across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/routes/web.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Providers/Filament/AdminPanelProvider.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Filament/Resources/TenantResource.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/OperationRunLinks.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/Verification/VerificationLinkBehavior.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php`
|
||||
- [x] T005 [P] Audit retired tenant-panel helper and panel-bootstrapping seams across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/`, and any directly affected support path named by this package
|
||||
- [x] T006 [P] Audit provider-core and role-authority enforcement seams across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/Providers/Boundary/ProviderBoundaryCatalog.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Services/Providers/ProviderIdentityResolution.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Services/Providers/ProviderOperationRegistry.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.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/Unit/Auth/NoRoleStringChecksTest.php`
|
||||
- [x] T007 Confirm the classification-only broader-baseline boundary across `/Users/ahmeddarrazi/Documents/projects/wt-plattform/README.md`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneManifest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneReport.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/scripts/platform-test-report`, and verify that Spec `289` remains the explicit follow-up
|
||||
|
||||
**Checkpoint**: the enforcement inventories and scope boundary are fixed before story work begins.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - Guard retired routes, paths, and helper bootstrapping (Priority: P1)
|
||||
|
||||
**Goal**: Fail fast when retired management route/path families or retired tenant-panel bootstrapping patterns re-enter cutover-owned seams.
|
||||
|
||||
**Independent Test**: run the targeted route/helper guard suite plus the existing legacy redirect and tenant-core runtime regression tests to prove the exact retired path families and helper patterns fail with actionable messages.
|
||||
|
||||
### Tests for User Story 1
|
||||
|
||||
- [x] T008 [P] [US1] Add or extend route/path and helper enforcement coverage in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ProviderConnections/LegacyRedirectTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [x] T009 [US1] Implement the exact retired route/path inventory, emitted-URL assertions on the audited launch-point seams, and scan exclusions in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` using the route and launch-point seams audited in Phase 2
|
||||
- [x] T010 [US1] Implement forbidden tenant-panel helper and panel-bootstrapping checks in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288NoLegacyRouteAndHelperGuardTest.php` and any minimal supporting seam references in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Pest.php` without widening into a repo-wide helper rewrite
|
||||
|
||||
**Checkpoint**: User Story 1 is independently functional when retired route/path and helper patterns fail targeted guards and the known runtime regressions still stay not found.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - Guard provider-core seams and role authority (Priority: P1)
|
||||
|
||||
**Goal**: Keep shared provider-core seams provider-neutral and keep workspace membership as the only role-bearing authority.
|
||||
|
||||
**Independent Test**: run the targeted provider-boundary and role-authority guard suite plus the current policy and scope-management regressions to prove platform-core neutrality and narrowing-only environment scope.
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- [x] T011 [P] [US2] Add or extend provider-boundary and role-authority coverage in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/ProviderBoundaryPlatformCoreGuardTest.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/Unit/Auth/NoRoleStringChecksTest.php`
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [x] T012 [US2] Implement the provider-core forbidden seam inventory in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php` using `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Support/Providers/Boundary/ProviderBoundaryCatalog.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Services/Providers/ProviderIdentityResolution.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/app/Services/Providers/ProviderOperationRegistry.php` without rewriting provider-core runtime behavior
|
||||
- [x] T013 [US2] Implement environment-scope role-authority guard coverage in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/Spec288ProviderCoreAndRoleAuthorityGuardTest.php` and any minimal supporting assertions in the named feature and unit tests without rewriting the RBAC model
|
||||
|
||||
**Checkpoint**: User Story 2 is independently functional when provider-core regressions fail targeted guards and role-authority semantics remain unchanged on the existing proof surfaces.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: User Story 3 - Keep browser proof and quality-gate docs honest (Priority: P2)
|
||||
|
||||
**Goal**: Preserve visible canonical route continuity on the current cutover browser anchors and document the same proof boundary for contributors.
|
||||
|
||||
**Independent Test**: run the two targeted browser smoke tests and verify the contributor-facing quality-gate docs point to the same proof commands and the same classification-only baseline rule.
|
||||
|
||||
### Tests for User Story 3
|
||||
|
||||
- [x] T014 [P] [US3] Extend `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec281ProviderConnectionScopeSmokeTest.php` and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Browser/Spec285WorkspaceRbacEnvironmentAccessSmokeTest.php` so they assert canonical admin/workspace route continuity and remain free of JavaScript or console errors after the guard pack lands
|
||||
|
||||
### Implementation for User Story 3
|
||||
|
||||
- [x] T015 [US3] Update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/README.md` with the cutover quality-gate guidance, exact targeted proof commands, pinned scan-exclusion rule, and the statement that broader baseline/full-suite fallout is classified only under Spec `288`
|
||||
|
||||
**Checkpoint**: User Story 3 is independently functional when browser proof stays green and contributors can follow the same quality-gate contract from the docs.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: User Story 4 - Classify broader baseline fallout without owning repair (Priority: P3)
|
||||
|
||||
**Goal**: Make broader baseline fallout reviewable through the current lane/report seams without turning `288` into a full-suite stabilization package.
|
||||
|
||||
**Independent Test**: run the classification-contract tests and verify that the manifest/report wording distinguishes cutover guard/browser ownership from unrelated broader failures.
|
||||
|
||||
### Tests for User Story 4
|
||||
|
||||
- [x] T016 [P] [US4] Extend `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/BrowserLaneIsolationTest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/CiLaneFailureClassificationContractTest.php`, and `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Feature/Guards/CiHeavyBrowserWorkflowContractTest.php` to cover the new Spec `288` guard/browser ownership and classification semantics
|
||||
|
||||
### Implementation for User Story 4
|
||||
|
||||
- [x] T017 [US4] Update `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneManifest.php`, `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/tests/Support/TestLaneReport.php`, and any minimal wrapper wording in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/scripts/platform-test-report` so Spec `288` guard/browser failures and broader baseline fallout are classified without implying full-suite repair ownership
|
||||
|
||||
**Checkpoint**: User Story 4 is independently functional when broader baseline fallout is reviewable but still explicitly outside the repair scope of this package.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Polish & Cross-Cutting Validation
|
||||
|
||||
**Purpose**: Run the canonical targeted proof commands, format touched files, and confirm Spec `289` remains the next package instead of leaking back into `288`.
|
||||
|
||||
- [x] T018 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] T019 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`
|
||||
- [x] T020 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 bin pint --dirty --format agent)`
|
||||
- [x] T021 Review the touched guard, browser, documentation, and classification seams plus the review artifact to confirm Filament remains v5 on Livewire v4, provider registration still lives in `/Users/ahmeddarrazi/Documents/projects/wt-plattform/apps/platform/bootstrap/providers.php`, no global-search or destructive-action contract drift was introduced, no asset registration or deployment-step drift was introduced, no runtime cutover repair, provider-core rewrite, RBAC rewrite, Package Execution work, Guided Operations work, Review Pack export work, UI copy cleanup, or full-suite repair was absorbed, and Spec `289` remains the explicit follow-up
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Phase 1 (Setup)**: no dependencies; start immediately.
|
||||
- **Phase 2 (Foundational)**: depends on Phase 1 and blocks all user-story work until the enforcement inventories and classification boundary are settled.
|
||||
- **Phase 3 (US1)**: depends on Phase 2 and delivers the first independent guardrail slice.
|
||||
- **Phase 4 (US2)**: depends on Phase 2 and should follow US1 so route/helper truth is pinned before provider-core and role-authority guardrails reuse it.
|
||||
- **Phase 5 (US3)**: depends on Phases 3 and 4 because browser proof and docs should reflect the final guard inventories.
|
||||
- **Phase 6 (US4)**: depends on Phases 3 through 5 so classification wording reflects the final proof ownership rather than a moving target.
|
||||
- **Phase 7 (Polish)**: depends on all implemented stories.
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **US1 (P1)**: first independently testable increment once the enforcement inventory is settled.
|
||||
- **US2 (P1)**: independently testable after Phase 2, but safer after US1 because route/helper truth should stabilize before provider-boundary and role-authority enforcement are judged.
|
||||
- **US3 (P2)**: independently testable after US1 and US2 because browser smoke and docs should reflect final proof obligations.
|
||||
- **US4 (P3)**: independently testable after Phases 3 through 5 because classification wording must describe the final guard/browser ownership.
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Add or extend the targeted tests first and make the current drift visible.
|
||||
- Complete the minimum guard or documentation seam needed for that story.
|
||||
- Re-run the narrowest relevant validation command after each story checkpoint before moving on.
|
||||
|
||||
---
|
||||
|
||||
## Parallel Execution Examples
|
||||
|
||||
### Phase 1
|
||||
|
||||
- T002 and T003 can run in parallel after T001 confirms the bounded package role.
|
||||
|
||||
### Phase 2
|
||||
|
||||
- T004, T005, and T006 can run in parallel because they inspect different seam families.
|
||||
|
||||
### User Story 1
|
||||
|
||||
- T008 can run while T009 and T010 are being prepared, but the route and helper guard inventory should land as one coherent slice.
|
||||
|
||||
### User Story 2
|
||||
|
||||
- T011 can run in parallel with the seam audit, but T012 and T013 should land together because they define one shared provider-core and role-authority enforcement slice.
|
||||
|
||||
### User Story 4
|
||||
|
||||
- T016 can run in parallel across the named classification-contract tests once T017's target classification wording is clear.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Suggested MVP Scope
|
||||
|
||||
- MVP = **Phase 2 + US1 + US2**. The package starts delivering value once the cutover can fail fast on retired routes/helpers and provider/role-authority regressions.
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Complete Phase 1 and Phase 2.
|
||||
2. Deliver US1 and validate route/helper enforcement.
|
||||
3. Deliver US2 and validate provider-core and role-authority enforcement.
|
||||
4. Deliver US3 and validate browser proof plus contributor-facing docs.
|
||||
5. Deliver US4 and validate classification-only broader-baseline handling.
|
||||
6. Finish with Phase 7 targeted validation, formatting, and scope review.
|
||||
|
||||
### Team Strategy
|
||||
|
||||
1. Keep Spec `289` explicitly out of implementation commits for this slice.
|
||||
2. Land guard inventories before browser or documentation wording so the contributor-facing proof contract reflects final enforcement truth.
|
||||
3. Serialize merges around `apps/platform/tests/Pest.php`, `apps/platform/tests/Support/TestLaneManifest.php`, `README.md`, and the new Spec `288` guard files because those are likely conflict hotspots.
|
||||
|
||||
---
|
||||
|
||||
## Explicit Follow-Ups / Out of Scope
|
||||
|
||||
- Package Execution Contract, which moves to Spec `289`
|
||||
- Guided Operations
|
||||
- Microsoft Starter Pack
|
||||
- runtime cutover work
|
||||
- provider-core rewrites
|
||||
- RBAC rewrites
|
||||
- UI copy cleanup from Spec `286`
|
||||
- Review Pack export changes
|
||||
- any full-suite repair or stabilization program
|
||||
Loading…
Reference in New Issue
Block a user