cleanup: retire dead transitional residue
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 52s
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 52s
This commit is contained in:
parent
6fdd45fb02
commit
d4dbd4ff0b
4
.github/agents/copilot-instructions.md
vendored
4
.github/agents/copilot-instructions.md
vendored
@ -244,6 +244,8 @@ ## Active Technologies
|
||||
- PostgreSQL-backed existing `operation_runs`, `tenants`, and `workspaces` records plus current session-backed canonical navigation state; no new persistence (232-operation-run-link-contract)
|
||||
- PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 + Filament widgets/resources/pages, Pest v4, `App\Models\OperationRun`, `App\Support\Operations\OperationRunFreshnessState`, `App\Services\Operations\OperationLifecycleReconciler`, `App\Support\OpsUx\OperationUxPresenter`, `App\Support\OpsUx\ActiveRuns`, `App\Support\Badges\BadgeCatalog` / `BadgeRenderer`, `App\Support\Workspaces\WorkspaceOverviewBuilder`, `App\Support\OperationRunLinks` (233-stale-run-visibility)
|
||||
- Existing PostgreSQL `operation_runs` records and current session/query-backed monitoring navigation state; no new persistence (233-stale-run-visibility)
|
||||
- PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 + `App\Models\BaselineProfile`, `App\Support\Baselines\BaselineProfileStatus`, `App\Support\Badges\BadgeCatalog`, `App\Support\Badges\BadgeDomain`, `Database\Factories\TenantFactory`, `App\Console\Commands\SeedBackupHealthBrowserFixture`, existing tenant-truth and baseline-profile Pest tests (234-dead-transitional-residue)
|
||||
- Existing PostgreSQL `baseline_profiles` and `tenants` tables; no new persistence and no schema migration in this slice (234-dead-transitional-residue)
|
||||
|
||||
- PHP 8.4.15 (feat/005-bulk-operations)
|
||||
|
||||
@ -278,9 +280,9 @@ ## Code Style
|
||||
PHP 8.4.15: Follow standard conventions
|
||||
|
||||
## Recent Changes
|
||||
- 234-dead-transitional-residue: Added PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 + `App\Models\BaselineProfile`, `App\Support\Baselines\BaselineProfileStatus`, `App\Support\Badges\BadgeCatalog`, `App\Support\Badges\BadgeDomain`, `Database\Factories\TenantFactory`, `App\Console\Commands\SeedBackupHealthBrowserFixture`, existing tenant-truth and baseline-profile Pest tests
|
||||
- 233-stale-run-visibility: Added PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 + Filament widgets/resources/pages, Pest v4, `App\Models\OperationRun`, `App\Support\Operations\OperationRunFreshnessState`, `App\Services\Operations\OperationLifecycleReconciler`, `App\Support\OpsUx\OperationUxPresenter`, `App\Support\OpsUx\ActiveRuns`, `App\Support\Badges\BadgeCatalog` / `BadgeRenderer`, `App\Support\Workspaces\WorkspaceOverviewBuilder`, `App\Support\OperationRunLinks`
|
||||
- 232-operation-run-link-contract: Added PHP 8.4.15, Laravel 12, Filament v5, Livewire v4 + Filament Resources/Pages/Widgets, Pest v4, `App\Support\OperationRunLinks`, `App\Support\System\SystemOperationRunLinks`, `App\Support\Navigation\CanonicalNavigationContext`, `App\Support\Navigation\RelatedNavigationResolver`, existing workspace and tenant authorization helpers
|
||||
- 231-finding-outcome-taxonomy: Added PHP 8.4.15, Laravel 12, Filament v5, Livewire v4, Blade + `App\Models\Finding`, `App\Filament\Resources\FindingResource`, `App\Services\Findings\FindingWorkflowService`, `App\Services\Baselines\BaselineAutoCloseService`, `App\Services\EntraAdminRoles\EntraAdminRolesFindingGenerator`, `App\Services\PermissionPosture\PermissionPostureFindingGenerator`, `App\Jobs\CompareBaselineToTenantJob`, `App\Filament\Pages\Reviews\ReviewRegister`, `App\Filament\Resources\TenantReviewResource`, `BadgeCatalog`, `BadgeRenderer`, `AuditLog` metadata via `AuditLogger`
|
||||
<!-- MANUAL ADDITIONS START -->
|
||||
|
||||
### Pre-production compatibility check
|
||||
|
||||
@ -67,7 +67,6 @@ public function handle(): int
|
||||
'name' => (string) ($scenarioConfig['tenant_name'] ?? 'Spec 180 Blocked Backup Tenant'),
|
||||
'tenant_id' => $tenantRouteKey,
|
||||
'app_certificate_thumbprint' => null,
|
||||
'app_status' => 'ok',
|
||||
'app_notes' => null,
|
||||
'status' => Tenant::STATUS_ACTIVE,
|
||||
'environment' => 'dev',
|
||||
|
||||
@ -20,21 +20,6 @@ class BaselineProfile extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* @deprecated Use BaselineProfileStatus::Draft instead.
|
||||
*/
|
||||
public const string STATUS_DRAFT = 'draft';
|
||||
|
||||
/**
|
||||
* @deprecated Use BaselineProfileStatus::Active instead.
|
||||
*/
|
||||
public const string STATUS_ACTIVE = 'active';
|
||||
|
||||
/**
|
||||
* @deprecated Use BaselineProfileStatus::Archived instead.
|
||||
*/
|
||||
public const string STATUS_ARCHIVED = 'archived';
|
||||
|
||||
/** @var list<string> */
|
||||
protected $fillable = [
|
||||
'workspace_id',
|
||||
|
||||
@ -38,7 +38,6 @@ final class BadgeCatalog
|
||||
BadgeDomain::BooleanEnabled->value => Domains\BooleanEnabledBadge::class,
|
||||
BadgeDomain::BooleanHasErrors->value => Domains\BooleanHasErrorsBadge::class,
|
||||
BadgeDomain::TenantStatus->value => Domains\TenantStatusBadge::class,
|
||||
BadgeDomain::TenantAppStatus->value => Domains\TenantAppStatusBadge::class,
|
||||
BadgeDomain::TenantRbacStatus->value => Domains\TenantRbacStatusBadge::class,
|
||||
BadgeDomain::TenantPermissionStatus->value => Domains\TenantPermissionStatusBadge::class,
|
||||
BadgeDomain::PolicySnapshotMode->value => Domains\PolicySnapshotModeBadge::class,
|
||||
|
||||
@ -29,7 +29,6 @@ enum BadgeDomain: string
|
||||
case BooleanEnabled = 'boolean_enabled';
|
||||
case BooleanHasErrors = 'boolean_has_errors';
|
||||
case TenantStatus = 'tenant_status';
|
||||
case TenantAppStatus = 'tenant_app_status';
|
||||
case TenantRbacStatus = 'tenant_rbac_status';
|
||||
case TenantPermissionStatus = 'tenant_permission_status';
|
||||
case PolicySnapshotMode = 'policy_snapshot_mode';
|
||||
|
||||
@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Support\Badges\Domains;
|
||||
|
||||
use App\Support\Badges\BadgeCatalog;
|
||||
use App\Support\Badges\BadgeMapper;
|
||||
use App\Support\Badges\BadgeSpec;
|
||||
|
||||
final class TenantAppStatusBadge implements BadgeMapper
|
||||
{
|
||||
public function spec(mixed $value): BadgeSpec
|
||||
{
|
||||
$state = BadgeCatalog::normalizeState($value);
|
||||
|
||||
return match ($state) {
|
||||
'ok' => new BadgeSpec('OK', 'success', 'heroicon-m-check-circle'),
|
||||
'configured' => new BadgeSpec('Configured', 'success', 'heroicon-m-check-circle'),
|
||||
'pending' => new BadgeSpec('Pending', 'warning', 'heroicon-m-clock'),
|
||||
'requires_consent', 'consent_required' => new BadgeSpec('Consent required', 'warning', 'heroicon-m-exclamation-triangle'),
|
||||
'error' => new BadgeSpec('Error', 'danger', 'heroicon-m-x-circle'),
|
||||
default => BadgeSpec::unknown(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -42,7 +42,6 @@ public function definition(): array
|
||||
'app_client_id' => fake()->uuid(),
|
||||
'app_client_secret' => null, // Skip encryption in tests
|
||||
'app_certificate_thumbprint' => null,
|
||||
'app_status' => 'ok',
|
||||
'app_notes' => null,
|
||||
'status' => 'active',
|
||||
'environment' => 'other',
|
||||
|
||||
@ -43,6 +43,10 @@
|
||||
it('archives baseline profiles for authorized workspace members', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
expect(defined(BaselineProfile::class.'::STATUS_DRAFT'))->toBeFalse()
|
||||
->and(defined(BaselineProfile::class.'::STATUS_ACTIVE'))->toBeFalse()
|
||||
->and(defined(BaselineProfile::class.'::STATUS_ARCHIVED'))->toBeFalse();
|
||||
|
||||
$profile = BaselineProfile::factory()->active()->create([
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
]);
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
use App\Filament\Resources\BaselineProfileResource;
|
||||
use App\Models\BaselineProfile;
|
||||
use App\Support\Baselines\BaselineProfileStatus;
|
||||
use Filament\Facades\Filament;
|
||||
|
||||
it('keeps baseline profiles out of tenant panel registration and tenant navigation URLs', function (): void {
|
||||
@ -23,6 +25,11 @@
|
||||
it('keeps baseline profile urls workspace-owned even when a tenant context exists', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
$profile = BaselineProfile::factory()->create([
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
'status' => BaselineProfileStatus::Archived->value,
|
||||
]);
|
||||
|
||||
$this->actingAs($user)
|
||||
->withSession([\App\Support\Workspaces\WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]);
|
||||
|
||||
@ -32,5 +39,8 @@
|
||||
expect($workspaceUrl)->not->toContain("/admin/t/{$tenant->external_id}/baseline-profiles");
|
||||
|
||||
$this->get($workspaceUrl)->assertOk();
|
||||
$this->get(BaselineProfileResource::getUrl('view', ['record' => $profile], panel: 'admin'))->assertOk();
|
||||
$this->get("/admin/t/{$tenant->external_id}/baseline-profiles")->assertNotFound();
|
||||
|
||||
expect($profile->fresh()->status)->toBe(BaselineProfileStatus::Archived);
|
||||
});
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
it('filters baseline profiles by status inside the current workspace', function (): void {
|
||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||
|
||||
expect(defined(BaselineProfile::class.'::STATUS_ACTIVE'))->toBeFalse();
|
||||
|
||||
$active = BaselineProfile::factory()->active()->create([
|
||||
'workspace_id' => (int) $tenant->workspace_id,
|
||||
]);
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
use App\Filament\Resources\BaselineProfileResource\Pages\EditBaselineProfile;
|
||||
use App\Filament\Resources\BaselineProfileResource\Pages\ViewBaselineProfile;
|
||||
use App\Models\BaselineProfile;
|
||||
use App\Support\Baselines\BaselineProfileStatus;
|
||||
use App\Support\Governance\GovernanceSubjectTaxonomyRegistry;
|
||||
use App\Support\Workspaces\WorkspaceContext;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@ -45,7 +46,7 @@
|
||||
expect($profile->scope_jsonb)->toBe([
|
||||
'policy_types' => ['deviceConfiguration'],
|
||||
'foundation_types' => ['assignmentFilter'],
|
||||
]);
|
||||
])->and($profile->status)->toBe(BaselineProfileStatus::Draft);
|
||||
|
||||
expect($profile->canonicalScopeJsonb())->toBe([
|
||||
'version' => 2,
|
||||
@ -83,7 +84,7 @@
|
||||
'name' => 'Legacy baseline profile',
|
||||
'description' => null,
|
||||
'version_label' => null,
|
||||
'status' => 'active',
|
||||
'status' => BaselineProfileStatus::Active->value,
|
||||
'capture_mode' => 'opportunistic',
|
||||
'scope_jsonb' => json_encode([
|
||||
'policy_types' => [],
|
||||
@ -178,7 +179,7 @@
|
||||
'name' => 'Legacy lineage profile',
|
||||
'description' => null,
|
||||
'version_label' => null,
|
||||
'status' => 'active',
|
||||
'status' => BaselineProfileStatus::Active->value,
|
||||
'capture_mode' => 'opportunistic',
|
||||
'scope_jsonb' => json_encode([
|
||||
'policy_types' => ['deviceConfiguration'],
|
||||
|
||||
@ -25,6 +25,8 @@
|
||||
role: 'owner',
|
||||
);
|
||||
|
||||
expect($tenant->fresh()->app_status)->toBe('consent_required');
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
Filament::setTenant($tenant, true);
|
||||
@ -33,11 +35,14 @@
|
||||
->assertSee('Lifecycle summary')
|
||||
->assertSee('This tenant is still onboarding. It remains visible on management and review surfaces, but it is not selectable as active context until onboarding completes.')
|
||||
->assertDontSee('App status')
|
||||
->assertDontSee('Consent required')
|
||||
->assertSee('RBAC status')
|
||||
->assertSee('Failed');
|
||||
});
|
||||
|
||||
it('keeps referenced tenant lifecycle context separate from run status in the tenantless operations viewer', function (): void {
|
||||
expect(array_key_exists('app_status', Tenant::factory()->onboarding()->raw()))->toBeFalse();
|
||||
|
||||
$tenant = Tenant::factory()->onboarding()->create([
|
||||
'name' => 'Viewer Separation Tenant',
|
||||
]);
|
||||
|
||||
@ -38,6 +38,8 @@
|
||||
'verification_status' => ProviderVerificationStatus::Unknown->value,
|
||||
]);
|
||||
|
||||
expect($tenant->fresh()->app_status)->toBe('ok');
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
@ -61,6 +63,17 @@
|
||||
->and($visibleColumnNames)->not->toContain('provider_connection_state');
|
||||
});
|
||||
|
||||
it('keeps legacy app status as opt-in test setup instead of a factory default', function (): void {
|
||||
expect(array_key_exists('app_status', Tenant::factory()->raw()))->toBeFalse();
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'name' => 'Explicit Historical App Status Tenant',
|
||||
'app_status' => 'error',
|
||||
]);
|
||||
|
||||
expect($tenant->fresh()->app_status)->toBe('error');
|
||||
});
|
||||
|
||||
it('keeps lifecycle and rbac separate while leading the provider summary with consent and verification', function (): void {
|
||||
$tenant = Tenant::factory()->create([
|
||||
'status' => Tenant::STATUS_ONBOARDING,
|
||||
@ -86,6 +99,8 @@
|
||||
'verification_status' => ProviderVerificationStatus::Blocked->value,
|
||||
]);
|
||||
|
||||
expect($tenant->fresh()->app_status)->toBe('consent_required');
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
|
||||
@ -97,6 +112,7 @@
|
||||
->assertSee('RBAC status')
|
||||
->assertSee('Failed')
|
||||
->assertDontSee('App status')
|
||||
->assertDontSee('Consent required')
|
||||
->assertSee('Truth Cleanup Connection')
|
||||
->assertSee('Lifecycle')
|
||||
->assertSee('Disabled')
|
||||
|
||||
@ -48,3 +48,14 @@
|
||||
expect(BadgeCatalog::mapper(BadgeDomain::BooleanEnabled))->not->toBeNull()
|
||||
->and($domainValues)->not->toContain('provider_connection.status', 'provider_connection.health');
|
||||
});
|
||||
|
||||
it('keeps retired tenant app-status out of the central catalog while active tenant domains remain registered', function (): void {
|
||||
$domainValues = collect(BadgeDomain::cases())
|
||||
->map(fn (BadgeDomain $domain): string => $domain->value)
|
||||
->all();
|
||||
|
||||
expect($domainValues)->not->toContain('tenant_app_status')
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantStatus))->not->toBeNull()
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantRbacStatus))->not->toBeNull()
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantPermissionStatus))->not->toBeNull();
|
||||
});
|
||||
|
||||
@ -23,18 +23,15 @@
|
||||
expect($error->color)->toBe('danger');
|
||||
});
|
||||
|
||||
it('maps tenant app status values to legacy diagnostic badge semantics', function (): void {
|
||||
$ok = BadgeCatalog::spec(BadgeDomain::TenantAppStatus, 'ok');
|
||||
expect($ok->label)->toBe('OK');
|
||||
expect($ok->color)->toBe('success');
|
||||
it('does not expose retired app status as active tenant badge semantics', function (): void {
|
||||
$domainValues = collect(BadgeDomain::cases())
|
||||
->map(fn (BadgeDomain $domain): string => $domain->value)
|
||||
->all();
|
||||
|
||||
$consentRequired = BadgeCatalog::spec(BadgeDomain::TenantAppStatus, 'consent_required');
|
||||
expect($consentRequired->label)->toBe('Consent required');
|
||||
expect($consentRequired->color)->toBe('warning');
|
||||
|
||||
$error = BadgeCatalog::spec(BadgeDomain::TenantAppStatus, 'error');
|
||||
expect($error->label)->toBe('Error');
|
||||
expect($error->color)->toBe('danger');
|
||||
expect($domainValues)->not->toContain('tenant_app_status')
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantStatus))->not->toBeNull()
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantRbacStatus))->not->toBeNull()
|
||||
->and(BadgeCatalog::mapper(BadgeDomain::TenantPermissionStatus))->not->toBeNull();
|
||||
});
|
||||
|
||||
it('maps tenant RBAC status values to canonical badge semantics', function (): void {
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
# Specification Quality Checklist: Dead Transitional Residue Cleanup
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-04-23
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- Validated against the current cleanup sequencing in `docs/product/spec-candidates.md` and the active near-term roadmap focus in `docs/product/roadmap.md` on 2026-04-23.
|
||||
- Scope stays intentionally narrow: remove dead residue first, defer schema removal and adjacent cleanup strands to follow-up specs.
|
||||
86
specs/234-dead-transitional-residue/data-model.md
Normal file
86
specs/234-dead-transitional-residue/data-model.md
Normal file
@ -0,0 +1,86 @@
|
||||
# Phase 1 Data Model: Dead Transitional Residue Cleanup
|
||||
|
||||
## Overview
|
||||
|
||||
This feature introduces no new table, enum, or persisted artifact. It narrows the active runtime language around two already-existing truth domains:
|
||||
|
||||
1. Baseline profile lifecycle truth should flow only through `BaselineProfileStatus`.
|
||||
2. Tenant app-status should remain, at most, historical stored data, not active runtime/support truth.
|
||||
|
||||
## Persistent Source Truths
|
||||
|
||||
### BaselineProfile
|
||||
|
||||
**Purpose**: Workspace-owned baseline profile record.
|
||||
|
||||
**Key fields**:
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `name`
|
||||
- `status`
|
||||
- `capture_mode`
|
||||
- `active_snapshot_id`
|
||||
|
||||
**Validation rules**:
|
||||
- `status` is cast to `BaselineProfileStatus` and is the only active lifecycle contract for draft, active, and archived behavior.
|
||||
- Deprecated alias constants on the model are not part of persistent truth and can be removed once no runtime caller depends on them.
|
||||
|
||||
### Tenant
|
||||
|
||||
**Purpose**: Tenant-owned lifecycle and management record.
|
||||
|
||||
**Key fields**:
|
||||
- `id`
|
||||
- `workspace_id`
|
||||
- `name`
|
||||
- `status`
|
||||
- `rbac_status`
|
||||
- `app_status` (historical legacy field)
|
||||
|
||||
**Validation rules**:
|
||||
- `status` remains the active tenant lifecycle truth.
|
||||
- `rbac_status` remains a separate active management truth.
|
||||
- `app_status` may remain stored historically, but current runtime/support paths must not treat it as active default truth.
|
||||
|
||||
## Support Artifacts In Scope
|
||||
|
||||
### Deprecated alias layer
|
||||
|
||||
**Artifact**: `BaselineProfile::STATUS_DRAFT`, `STATUS_ACTIVE`, `STATUS_ARCHIVED`
|
||||
|
||||
**Role after cleanup**:
|
||||
- removed from active runtime language
|
||||
|
||||
### Legacy badge layer
|
||||
|
||||
**Artifacts**:
|
||||
- `BadgeDomain::TenantAppStatus`
|
||||
- `BadgeCatalog` mapper entry for tenant app status
|
||||
- `TenantAppStatusBadge`
|
||||
|
||||
**Role after cleanup**:
|
||||
- removed if no runtime consumer remains
|
||||
|
||||
### Legacy default setup
|
||||
|
||||
**Artifacts**:
|
||||
- `TenantFactory` default `app_status => 'ok'`
|
||||
- `SeedBackupHealthBrowserFixture` default `app_status => 'ok'`
|
||||
|
||||
**Role after cleanup**:
|
||||
- removed as ambient defaults
|
||||
- legacy `app_status` becomes explicit per-test or per-scenario setup only
|
||||
|
||||
## Behavioral Rules
|
||||
|
||||
1. Removing dead residue must not change baseline profile archive/list/workspace behavior.
|
||||
2. Removing dead residue must not change tenant lifecycle or RBAC truth behavior.
|
||||
3. Tests that still need a legacy `app_status` value must set it explicitly in the scenario.
|
||||
4. Historical schema and migrations remain historical artifacts, not cleanup targets in this slice.
|
||||
|
||||
## No New Persistence
|
||||
|
||||
- No new table is introduced.
|
||||
- No new enum or reason family is introduced.
|
||||
- No new derived readiness or cleanup artifact is introduced.
|
||||
- No stored field is repurposed into a new active truth contract.
|
||||
245
specs/234-dead-transitional-residue/plan.md
Normal file
245
specs/234-dead-transitional-residue/plan.md
Normal file
@ -0,0 +1,245 @@
|
||||
# Implementation Plan: Dead Transitional Residue Cleanup
|
||||
|
||||
**Branch**: `234-dead-transitional-residue` | **Date**: 2026-04-23 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/234-dead-transitional-residue/spec.md`
|
||||
|
||||
**Note**: This plan keeps historical tenant `app_status` storage and historical migrations intact. It removes only dead runtime alias/support paths and tightens fixtures/tests so legacy values become explicit opt-in setup rather than ambient repo truth.
|
||||
|
||||
## Summary
|
||||
|
||||
Remove the dead `BaselineProfile::STATUS_*` alias layer and retire tenant app-status residue from the centralized badge catalog, default test fixtures, browser smoke seed data, and legacy-facing tests. The implementation stays intentionally small: no schema change, no new status family, no operator-surface redesign, and no compatibility shim. The proof burden is that current tenant truth and baseline profile behavior remain unchanged while the dead semantics disappear from active runtime language.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: PHP 8.4.15, Laravel 12, Filament v5, Livewire v4
|
||||
**Primary Dependencies**: `App\Models\BaselineProfile`, `App\Support\Baselines\BaselineProfileStatus`, `App\Support\Badges\BadgeCatalog`, `App\Support\Badges\BadgeDomain`, `Database\Factories\TenantFactory`, `App\Console\Commands\SeedBackupHealthBrowserFixture`, existing tenant-truth and baseline-profile Pest tests
|
||||
**Storage**: Existing PostgreSQL `baseline_profiles` and `tenants` tables; no new persistence and no schema migration in this slice
|
||||
**Testing**: Pest v4 feature and unit tests through Laravel Sail
|
||||
**Validation Lanes**: `fast-feedback`, `confidence`
|
||||
**Target Platform**: Laravel admin web application in Sail containers with admin routes under `/admin`
|
||||
**Project Type**: Monorepo with one Laravel runtime in `apps/platform` and spec artifacts at repository root
|
||||
**Performance Goals**: Preserve current request/query behavior; cleanup must not add runtime branching, new queries, or new UI layers
|
||||
**Constraints**: No schema change, no compatibility aliases, no new badge/readiness domain, no authorization changes, no global-search broadening, and no new operator-facing surface
|
||||
**Scale/Scope**: One Eloquent model, one central badge registry path, one legacy badge mapper, one tenant factory, one browser fixture command, and focused tenant/baseline regression families
|
||||
|
||||
## Filament v5 Implementation Contract
|
||||
|
||||
- **Livewire v4.0+ compliance**: Preserved. The cleanup does not introduce any legacy Livewire patterns and does not add new Filament component types.
|
||||
- **Provider registration location**: Unchanged. Panel providers remain registered in `bootstrap/providers.php`.
|
||||
- **Global search coverage**: `TenantResource` remains globally searchable and already has View/Edit pages. `BaselineProfileResource` keeps global search disabled via `$isGloballySearchable = false` and already has View/Edit pages. This cleanup adds no new global-search exposure.
|
||||
- **Destructive actions**: No destructive action is introduced or changed. Existing tenant and baseline profile destructive flows remain on their current confirmation and authorization paths.
|
||||
- **Asset strategy**: No new assets are planned. Deployment expectations remain unchanged, including `cd apps/platform && php artisan filament:assets` only when future work adds registered assets.
|
||||
- **Testing plan**: Prove the cleanup with focused feature tests for tenant-truth continuity and baseline-profile list/view/edit/archive continuity, plus unit coverage for central badge-catalog cleanup.
|
||||
|
||||
## UI / Surface Guardrail Plan
|
||||
|
||||
- **Guardrail scope**: no operator-facing surface change
|
||||
- **Native vs custom classification summary**: `N/A`
|
||||
- **Shared-family relevance**: none
|
||||
- **State layers in scope**: none
|
||||
- **Handling modes by drift class or surface**: `report-only`
|
||||
- **Repository-signal treatment**: `review-mandatory` because this is a repo-hygiene cleanup that removes active residue rather than hiding it
|
||||
- **Special surface test profiles**: `N/A`
|
||||
- **Required tests or manual smoke**: `functional-core`
|
||||
- **Exception path and spread control**: none
|
||||
- **Active feature PR close-out entry**: `Guardrail`
|
||||
|
||||
## Shared Pattern & System Fit
|
||||
|
||||
- **Cross-cutting feature marker**: no
|
||||
- **Systems touched**: centralized badge registry, baseline profile status model language, tenant default fixtures, browser smoke fixture command, and focused tenant/baseline regression files
|
||||
- **Shared abstractions reused**: `BaselineProfileStatus`, `BadgeCatalog`, `BadgeDomain`, and the existing tenant/baseline regression families
|
||||
- **New abstraction introduced? why?**: none
|
||||
- **Why the existing abstraction was sufficient or insufficient**: Existing abstractions are sufficient because this work removes dead support paths instead of creating a new semantic or presentation layer.
|
||||
- **Bounded deviation / spread control**: none
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Passed before Phase 0 research. Re-check after Phase 1 design: still passed with no new persistence, no new semantic family, and no operator-surface expansion.*
|
||||
|
||||
| Gate | Status | Plan Notes |
|
||||
|------|--------|------------|
|
||||
| Inventory-first / read-write separation | PASS | No Graph path, no new mutation flow, and no snapshot or restore behavior change. |
|
||||
| RBAC, workspace isolation, tenant isolation | PASS | No route, policy, capability, or resource visibility behavior changes are planned. |
|
||||
| Run observability / Ops-UX lifecycle | PASS | No `OperationRun` is created or modified; this cleanup is outside queued or remote execution semantics. |
|
||||
| Shared pattern first | PASS | The plan simplifies the central badge path by removing an unused legacy domain rather than bypassing it with a local mapping. |
|
||||
| Proportionality / no premature abstraction | PASS | The plan removes existing residue and introduces no new abstraction, enum, registry, or persistence. |
|
||||
| Persisted truth / behavioral state | PASS | Historical columns and migrations remain untouched; no new state or artifact is introduced. |
|
||||
| Badge semantics / Filament-native discipline | PASS | Central badge semantics remain authoritative, and no page-local or view-local replacement badge language is added. |
|
||||
| Filament v5 / Livewire v4 contract | PASS | Existing resources remain unchanged in behavior; provider registration and global-search posture stay compliant. |
|
||||
| Test governance | PASS | Proof stays in focused feature/unit lanes with no heavy-family promotion and a net reduction in fixture-default ambiguity. |
|
||||
|
||||
## Test Governance Check
|
||||
|
||||
- **Test purpose / classification by changed surface**: `Feature` for tenant-truth and baseline-profile continuity; `Unit` for central badge-catalog cleanup
|
||||
- **Affected validation lanes**: `fast-feedback`, `confidence`
|
||||
- **Why this lane mix is the narrowest sufficient proof**: The business truth is continuity after residue removal. Feature tests prove runtime behavior on current tenant and baseline flows, while one small unit slice proves the central badge cleanup without widening into browser or heavy-governance coverage.
|
||||
- **Narrowest proving command(s)**:
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantTruthCleanupSpec179Test.php tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineProfileArchiveActionTest.php tests/Feature/Filament/BaselineProfileListFiltersTest.php tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Badges/TenantBadgesTest.php tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd /Users/ahmeddarrazi/Documents/projects/wt-plattform && rg -n "BaselineProfile::STATUS_|TenantAppStatus|tenant_app_status" apps/platform/app apps/platform/tests apps/platform/database/factories && rg -n -- "app_status" apps/platform/app apps/platform/tests apps/platform/database/factories`
|
||||
- **Fixture / helper / factory / seed / context cost risks**: Low to moderate. Removing the default `app_status` from `TenantFactory` and browser fixture setup can expose hidden reliance on ambient legacy values in tests or smoke commands.
|
||||
- **Expensive defaults or shared helper growth introduced?**: No. The change reduces a misleading default rather than adding a new helper burden.
|
||||
- **Heavy-family additions, promotions, or visibility changes**: none
|
||||
- **Surface-class relief / special coverage rule**: `standard-native relief`
|
||||
- **Closing validation and reviewer handoff**: Reviewers should verify that removed residue had no active runtime dependency, that tenant/baseline tests still pass without ambient legacy defaults, and that no migration or new compatibility path slipped in.
|
||||
- **Budget / baseline / trend follow-up**: none
|
||||
- **Review-stop questions**: Did any test or fixture still need `app_status` but fail to set it explicitly? Did badge cleanup remove a still-used domain? Did alias removal trigger any runtime or static reference outside the planned scope? Did the cleanup expand into schema or route changes?
|
||||
- **Escalation path**: `document-in-feature`
|
||||
- **Active feature PR close-out entry**: `Guardrail`
|
||||
- **Why no dedicated follow-up spec is needed**: This is routine current-release cleanup. A follow-up spec is only needed if a hidden runtime dependency forces a broader domain decision rather than simple residue removal.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/234-dead-transitional-residue/
|
||||
├── spec.md
|
||||
├── plan.md
|
||||
├── research.md
|
||||
├── data-model.md
|
||||
├── quickstart.md
|
||||
├── checklists/
|
||||
│ └── requirements.md
|
||||
└── tasks.md
|
||||
```
|
||||
|
||||
No contracts artifact is planned because this cleanup changes no route, API, or standalone logical interaction contract.
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
apps/platform/
|
||||
├── app/
|
||||
│ ├── Console/Commands/
|
||||
│ │ └── SeedBackupHealthBrowserFixture.php
|
||||
│ ├── Models/
|
||||
│ │ └── BaselineProfile.php
|
||||
│ └── Support/Badges/
|
||||
│ ├── BadgeCatalog.php
|
||||
│ ├── BadgeDomain.php
|
||||
│ └── Domains/
|
||||
│ └── TenantAppStatusBadge.php
|
||||
├── database/
|
||||
│ └── factories/
|
||||
│ └── TenantFactory.php
|
||||
└── tests/
|
||||
├── Feature/
|
||||
│ ├── Baselines/
|
||||
│ │ ├── BaselineProfileArchiveActionTest.php
|
||||
│ │ ├── BaselineProfileAuthorizationTest.php
|
||||
│ │ └── BaselineProfileWorkspaceOwnershipTest.php
|
||||
│ └── Filament/
|
||||
│ ├── BaselineProfileListFiltersTest.php
|
||||
│ ├── BaselineProfileScopeV2PersistenceTest.php
|
||||
│ ├── TenantLifecycleStatusDomainSeparationTest.php
|
||||
│ └── TenantTruthCleanupSpec179Test.php
|
||||
└── Unit/
|
||||
└── Badges/
|
||||
├── BadgeCatalogTest.php
|
||||
└── TenantBadgesTest.php
|
||||
```
|
||||
|
||||
**Structure Decision**: Keep the work entirely inside the existing Laravel application in `apps/platform`. The plan updates one model, one central badge path, one default tenant factory, one browser fixture command, and focused regression files rather than touching resource layout or introducing a cleanup subsystem.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
No constitutional violation is planned. No new structure is introduced, so no complexity exception is required.
|
||||
|
||||
| Violation | Why Needed | Simpler Alternative Rejected Because |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| — | — | — |
|
||||
|
||||
## Proportionality Review
|
||||
|
||||
> No new enum, persisted entity, abstraction layer, taxonomy, or cross-domain UI framework is planned in this slice.
|
||||
|
||||
- **Current operator problem**: Dead alias and legacy-support residue still make it easy for contributors and tests to treat retired semantics as current repo truth.
|
||||
- **Existing structure is insufficient because**: The current code already has the canonical `BaselineProfileStatus` path and current tenant-truth behavior, but dead support artifacts continue to conserve the older semantics around them.
|
||||
- **Narrowest correct implementation**: Remove only the dead alias/support paths and make any still-needed legacy values explicit in the few tests or fixtures that truly need them.
|
||||
- **Ownership cost created**: Small one-time cleanup across a handful of files, followed by lower ongoing cognitive and maintenance cost.
|
||||
- **Alternative intentionally rejected**: Keeping deprecated aliases, badge domains, or factory defaults for convenience was rejected because this is a pre-production repo and the residue already undermines cleanup discipline.
|
||||
- **Release truth**: Current-release truth cleanup.
|
||||
|
||||
## Phase 0 Research Summary
|
||||
|
||||
- `BaselineProfile::STATUS_DRAFT`, `STATUS_ACTIVE`, and `STATUS_ARCHIVED` exist only in `apps/platform/app/Models/BaselineProfile.php`; no current `apps/platform` runtime or test reference still needs them.
|
||||
- The tenant app-status badge path is now pure residue: `BadgeDomain::TenantAppStatus`, the `BadgeCatalog` mapper entry, and `TenantAppStatusBadge` remain, but the only confirmed consumers are badge tests, not current runtime surfaces.
|
||||
- `TenantFactory` still defaults `app_status` to `ok`, and `SeedBackupHealthBrowserFixture` still writes `app_status => 'ok'`, which keeps a retired value ambient in test and smoke data even though current tenant surfaces no longer depend on it.
|
||||
- Existing tenant-truth regressions intentionally set `app_status` in a few scenarios to prove suppression. Those explicit setups should remain where meaningful; only ambient defaults should go away.
|
||||
- Historical migrations and historical stored columns are not part of this cleanup. The correct scope is runtime/support residue removal first, not schema deletion.
|
||||
|
||||
## Phase 1 Design Summary
|
||||
|
||||
- `research.md` records the cleanup decisions and rejected alternatives.
|
||||
- `data-model.md` documents the still-active persistent truths and the support artifacts that should stop acting as active repo truth.
|
||||
- `quickstart.md` gives the narrow validation order for alias removal, badge cleanup, fixture cleanup, and regression verification.
|
||||
- No contracts artifact is created because the feature changes no route, API, or new user interaction contract.
|
||||
|
||||
## Phase 1 — Agent Context Update
|
||||
|
||||
Run after artifact generation:
|
||||
|
||||
- `.specify/scripts/bash/update-agent-context.sh copilot`
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### Phase A — Remove dead baseline profile alias language
|
||||
|
||||
**Goal**: Make `BaselineProfileStatus` the only active baseline profile status contract.
|
||||
|
||||
| Step | File | Change |
|
||||
|------|------|--------|
|
||||
| A.1 | `apps/platform/app/Models/BaselineProfile.php` | Remove deprecated `STATUS_DRAFT`, `STATUS_ACTIVE`, and `STATUS_ARCHIVED` constants. |
|
||||
| A.2 | Targeted grep + baseline regression files | Confirm no runtime or test path in `apps/platform` still references the removed aliases; keep baseline profile behavior proved through existing feature tests rather than adding a new alias-specific shim. |
|
||||
|
||||
### Phase B — Retire the dead tenant app-status badge path centrally
|
||||
|
||||
**Goal**: Remove the last active runtime support entry point for tenant app-status semantics.
|
||||
|
||||
| Step | File | Change |
|
||||
|------|------|--------|
|
||||
| B.1 | `apps/platform/app/Support/Badges/BadgeDomain.php` | Remove the `TenantAppStatus` enum case if no active runtime consumer remains. |
|
||||
| B.2 | `apps/platform/app/Support/Badges/BadgeCatalog.php` | Remove the `TenantAppStatus` mapper registration. |
|
||||
| B.3 | `apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php` | Remove the mapper class once the registry path is gone. |
|
||||
| B.4 | `apps/platform/tests/Unit/Badges/TenantBadgesTest.php` and `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php` | Update badge coverage to prove the canonical tenant lifecycle/RBAC/permission domains still work and that the removed legacy domain no longer acts as active repo truth. |
|
||||
|
||||
### Phase C — Make legacy app-status explicit instead of ambient in defaults and smoke data
|
||||
|
||||
**Goal**: Stop silently injecting retired tenant app-status semantics into factories and browser fixture setup.
|
||||
|
||||
| Step | File | Change |
|
||||
|------|------|--------|
|
||||
| C.1 | `apps/platform/database/factories/TenantFactory.php` | Remove the default `app_status => 'ok'` assignment so tests must opt in explicitly when they need a historical value. |
|
||||
| C.2 | `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php` | Remove or conditionalize the forced `app_status => 'ok'` write unless the scenario explicitly requires it for a still-active smoke purpose. |
|
||||
| C.3 | Targeted tenant-truth tests | Keep explicit `app_status` setup only in cases that intentionally prove the legacy field no longer surfaces as truth. |
|
||||
|
||||
### Phase D — Rebalance regression coverage around explicit legacy setup
|
||||
|
||||
**Goal**: Preserve current behavior while making the cleanup durable.
|
||||
|
||||
| Step | File | Change |
|
||||
|------|------|--------|
|
||||
| D.1 | `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php` | Keep explicit legacy `app_status` values where they prove suppression; stop depending on factory defaults. |
|
||||
| D.2 | `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php` | Keep lifecycle/RBAC separation assertions intact with explicit historical setup where needed. |
|
||||
| D.3 | `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, and `apps/platform/tests/Feature/Baselines/BaselineProfileAuthorizationTest.php` | Use these existing baseline profile tests as continuity proof after alias removal across archive, list/filter, view/edit, and workspace-owned behavior. |
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
- **Hidden dependency on removed badge domain**: A helper or test outside the initial grep scope may still call `BadgeDomain::TenantAppStatus`. Mitigation: targeted grep before merge plus running `TenantBadgesTest` and `BadgeCatalogTest` after central removal.
|
||||
- **Ambient fixture reliance on `app_status`**: Removing the factory default can reveal tests or smoke commands that only passed because `app_status` was silently set to `ok`. Mitigation: convert those cases to explicit setup rather than restoring the default.
|
||||
- **Baseline alias removal reaches farther than expected**: A non-obvious reference could still exist outside the model. Mitigation: grep for `BaselineProfile::STATUS_` before merge and rely on existing baseline feature tests for continuity.
|
||||
- **Cleanup scope drifts into schema deletion**: The presence of migrations and stored columns can tempt a larger cut. Mitigation: keep historical schema/migrations explicitly out of scope in both plan and tasks.
|
||||
|
||||
## Post-Design Re-check
|
||||
|
||||
The plan remains constitution-compliant, Livewire v4 / Filament v5 compliant, and appropriately narrow. It removes dead runtime/support residue, preserves existing tenant and baseline behavior, introduces no new persistence or abstraction, and is ready for `/speckit.tasks`.
|
||||
|
||||
## Implementation Close-Out
|
||||
|
||||
- **Residue search result**: Clean for active runtime/support paths. Remaining `tenant_app_status` and `BaselineProfile::class.'::STATUS_*'` matches are negative regression assertions only.
|
||||
- **Remaining `app_status` usage**: Explicit historical setup and suppression assertions in tenant-truth tests only. `TenantFactory` and the backup-health browser fixture no longer write ambient `app_status` defaults.
|
||||
- **Follow-up decision**: No hidden runtime dependency was found, so no follow-up cleanup spec is needed for this slice.
|
||||
80
specs/234-dead-transitional-residue/quickstart.md
Normal file
80
specs/234-dead-transitional-residue/quickstart.md
Normal file
@ -0,0 +1,80 @@
|
||||
# Quickstart: Dead Transitional Residue Cleanup
|
||||
|
||||
## Goal
|
||||
|
||||
Validate that dead baseline profile alias language and dead tenant app-status support residue are removed without changing current tenant-truth or baseline-profile behavior.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Start Sail for `apps/platform`.
|
||||
2. Ensure the current branch is `234-dead-transitional-residue`.
|
||||
3. Be ready to update tests that intentionally use historical `app_status` values so they set those values explicitly.
|
||||
|
||||
## Implementation Validation Order
|
||||
|
||||
### 1. Format touched files
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- Touched PHP and test files follow project formatting rules.
|
||||
|
||||
### 2. Run tenant-truth continuity coverage
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantTruthCleanupSpec179Test.php tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- Tenant lifecycle and RBAC truth remain unchanged.
|
||||
- Any legacy `app_status` used in those tests is explicit scenario setup, not a hidden factory default.
|
||||
|
||||
### 3. Run baseline-profile continuity coverage
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineProfileArchiveActionTest.php tests/Feature/Filament/BaselineProfileListFiltersTest.php tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php tests/Feature/Baselines/BaselineProfileAuthorizationTest.php
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- Baseline profile archive, list, view, and edit behavior still work after removing deprecated status aliases.
|
||||
|
||||
### 4. Run central badge cleanup coverage
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Badges/TenantBadgesTest.php tests/Unit/Badges/BadgeCatalogTest.php
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- The central badge catalog still resolves active tenant badge domains correctly.
|
||||
- The removed tenant app-status badge path no longer acts as active runtime truth.
|
||||
|
||||
### 5. Run a focused residue grep before merge
|
||||
|
||||
```bash
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd /Users/ahmeddarrazi/Documents/projects/wt-plattform && rg -n "BaselineProfile::STATUS_|TenantAppStatus|tenant_app_status" apps/platform/app apps/platform/tests apps/platform/database/factories
|
||||
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd /Users/ahmeddarrazi/Documents/projects/wt-plattform && rg -n -- "app_status" apps/platform/app apps/platform/tests apps/platform/database/factories
|
||||
```
|
||||
|
||||
Expected outcome:
|
||||
- No unexpected alias or badge-domain references remain.
|
||||
- Any remaining `app_status` matches are deliberate explicit historical setup or reviewed historical artifacts, not ambient defaults or active truth.
|
||||
|
||||
Implementation close-out:
|
||||
- Active runtime/support paths are clean.
|
||||
- Remaining `tenant_app_status` and `BaselineProfile::class.'::STATUS_*'` matches are negative regression assertions.
|
||||
- Remaining `app_status` matches are explicit tenant-truth setup or suppression assertions; no follow-up spec is needed.
|
||||
|
||||
## Optional Manual Smoke
|
||||
|
||||
1. Open `/admin/tenants` and verify current tenant truth still behaves as before.
|
||||
2. Open `/admin/baseline-profiles`, then a baseline profile view page and edit page, and verify list, view, edit, and archive behavior still read normally.
|
||||
3. If the backup-health browser fixture command is still used locally, run it once and confirm it no longer depends on ambient `app_status` defaults.
|
||||
|
||||
## Non-Goals For This Slice
|
||||
|
||||
- No database migration.
|
||||
- No route or global-search change.
|
||||
- No new readiness or badge framework.
|
||||
- No onboarding or provider-connection cleanup outside the approved dead-residue scope.
|
||||
41
specs/234-dead-transitional-residue/research.md
Normal file
41
specs/234-dead-transitional-residue/research.md
Normal file
@ -0,0 +1,41 @@
|
||||
# Phase 0 Research: Dead Transitional Residue Cleanup
|
||||
|
||||
## Decision: Remove the deprecated `BaselineProfile::STATUS_*` aliases entirely
|
||||
|
||||
**Rationale**: The only confirmed definitions of `BaselineProfile::STATUS_DRAFT`, `STATUS_ACTIVE`, and `STATUS_ARCHIVED` are in `apps/platform/app/Models/BaselineProfile.php`. No current `apps/platform` runtime or test reference still depends on those aliases. The canonical contract is already the `BaselineProfileStatus` enum cast, so keeping the constants adds dead language without serving current behavior.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Keep the aliases but leave them deprecated: rejected because they no longer protect any active caller and continue to advertise parallel truth.
|
||||
- Replace them with forwarding helpers: rejected because that would add new residue to preserve dead semantics.
|
||||
|
||||
## Decision: Remove the tenant app-status badge domain from the central badge path
|
||||
|
||||
**Rationale**: The remaining runtime path for tenant app-status semantics is the central badge registry: `BadgeDomain::TenantAppStatus`, the `BadgeCatalog` mapper entry, and `TenantAppStatusBadge`. Current confirmed consumers are badge tests, not active tenant surfaces. Once the legacy badge domain has no runtime consumer, removing it centrally is cleaner than keeping it as diagnostic folklore.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Keep the badge domain as a dormant diagnostic mapping: rejected because no current runtime surface needs it and dormant central mappings make it easier to reintroduce dead semantics accidentally.
|
||||
- Move the mapping into a test helper: rejected because test-only preservation would still keep the dead semantics alive as sanctioned language.
|
||||
|
||||
## Decision: Remove ambient `app_status` defaults from test and smoke setup
|
||||
|
||||
**Rationale**: `TenantFactory` still defaults `app_status` to `ok`, and `SeedBackupHealthBrowserFixture` still writes `app_status => 'ok'`. That keeps a retired value ambient in new tenant records and smoke data even though current tenant surfaces no longer depend on it. The safer contract is explicit legacy setup only where a test or fixture intentionally proves suppression.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Keep the default for convenience: rejected because convenience is exactly how dead semantics keep surviving.
|
||||
- Remove `app_status` from every explicit test and fixture immediately: rejected because a few tests intentionally set historical values to prove they no longer surface as truth.
|
||||
|
||||
## Decision: Keep historical schema and stored fields out of scope
|
||||
|
||||
**Rationale**: The repo still contains historical migrations and the stored `tenants.app_status` column. This cleanup is about active runtime/support residue, not schema deletion. Removing columns or historical migrations would widen the slice beyond the approved cleanup boundary.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Drop the column now: rejected because the spec explicitly forbids schema work in this slice.
|
||||
- Add a migration shim or deprecation wrapper: rejected because this is pre-production cleanup, not a compatibility exercise.
|
||||
|
||||
## Decision: Reuse existing tenant-truth and baseline-profile regressions instead of creating a new cleanup harness
|
||||
|
||||
**Rationale**: The current proof burden is continuity after residue removal. Existing tenant-truth feature tests and baseline-profile feature tests already exercise the active behavior we need to protect. A small badge-catalog unit slice is enough for the central registry cleanup. A new meta guard framework would add more long-term burden than value.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Add grep-driven guard tests for every removed symbol: rejected because behavior-facing tests are the primary proof and repo grep is sufficient as a review aid.
|
||||
- Rely on manual inspection only: rejected because cleanup regressions are easy to reintroduce silently.
|
||||
223
specs/234-dead-transitional-residue/spec.md
Normal file
223
specs/234-dead-transitional-residue/spec.md
Normal file
@ -0,0 +1,223 @@
|
||||
# Feature Specification: Dead Transitional Residue Cleanup
|
||||
|
||||
**Feature Branch**: `234-dead-transitional-residue`
|
||||
**Created**: 2026-04-23
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Dead Transitional Residue Cleanup"
|
||||
|
||||
## Spec Candidate Check *(mandatory — SPEC-GATE-001)*
|
||||
|
||||
- **Problem**: The repo still carries dead transitional residue around tenant truth and baseline profile status language. Deprecated baseline profile status aliases and retired tenant app-status support artifacts still survive in support code, fixtures, and tests even though the current product no longer treats them as active truth.
|
||||
- **Today's failure**: Contributors and regressions can still conserve or reintroduce dead semantics because the repo keeps them available as if they were valid current-release language. That weakens earlier tenant-truth cleanup and makes follow-up cleanup strands harder to land cleanly.
|
||||
- **User-visible improvement**: Existing tenant and baseline profile surfaces keep the same current truth, but retired app-status and deprecated status-alias semantics stop leaking back through defaults, badges, fixtures, and tests.
|
||||
- **Smallest enterprise-capable version**: Remove dead baseline profile status aliases and tenant app-status residue from active runtime support code, factories, seeds, fixtures, and tests after verifying no productive dependency still exists. Do not redesign tenant readiness, baseline semantics, or storage.
|
||||
- **Explicit non-goals**: No new readiness model, no new status family, no schema redesign, no provider-connection cleanup beyond the dead tenant app-status residue, no onboarding fallback cleanup, and no canonical operation-type convergence work.
|
||||
- **Permanent complexity imported**: None. The feature reduces permanent complexity by removing dead symbols, dead badge semantics, and fixture conservatism while keeping focused regression coverage.
|
||||
- **Why now**: This is the first step in the active repository cleanup strand. Leaving dead residue in place makes the next cleanup slices and source-of-truth work riskier because they must keep fighting old semantics that should already be gone.
|
||||
- **Why not local**: Deleting only one constant or one test would leave the same dead semantics alive in other seams such as badge registration, factories, browser fixtures, or seed data. The problem is distributed residue, not one stray reference.
|
||||
- **Approval class**: Cleanup
|
||||
- **Red flags triggered**: One mild red flag: the cleanup spans model, badge, fixture, seed, and test seams. Defense: those seams all conserve the same retired semantics, so one bounded cleanup spec is smaller and safer than several micro-specs.
|
||||
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexität: 2 | Produktnähe: 1 | Wiederverwendung: 2 | **Gesamt: 11/12**
|
||||
- **Decision**: approve
|
||||
|
||||
## Spec Scope Fields *(mandatory)*
|
||||
|
||||
- **Scope**: workspace + tenant
|
||||
- **Primary Routes**:
|
||||
- `/admin/tenants`
|
||||
- `/admin/tenants/{tenant}`
|
||||
- `/admin/baseline-profiles`
|
||||
- `/admin/baseline-profiles/{profile}`
|
||||
- `/admin/baseline-profiles/{profile}/edit`
|
||||
- **Data Ownership**:
|
||||
- `tenants` remain the tenant-owned source of lifecycle, provider, and RBAC truth. This feature does not add, remove, or reinterpret tenant lifecycle semantics.
|
||||
- `baseline_profiles` remain the workspace-owned source of baseline profile truth. This feature does not change profile lifecycle behavior; it removes deprecated alias language around that existing truth.
|
||||
- No new persisted truth, mirror field, or cleanup ledger is introduced.
|
||||
- **RBAC**:
|
||||
- Workspace membership remains required for the affected admin resources.
|
||||
- Tenant isolation and current capability checks remain unchanged.
|
||||
- This feature does not broaden visibility, alter 404 versus 403 semantics, or add new authorization paths.
|
||||
|
||||
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
|
||||
|
||||
N/A - no shared interaction family touched.
|
||||
|
||||
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
|
||||
|
||||
N/A - no operator-facing surface change. Existing tenant and baseline profile surfaces must keep their current behavior while dead supporting residue is removed.
|
||||
|
||||
## 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.
|
||||
- **New cross-domain UI framework/taxonomy?**: No.
|
||||
- **Current operator problem**: Dead residue keeps retired semantics available, which makes it easier for tests, fixtures, and future changes to treat them as current truth again.
|
||||
- **Existing structure is insufficient because**: The existing structure is the problem; it still contains aliases and support artifacts that no longer represent active product language.
|
||||
- **Narrowest correct implementation**: Remove only the dead residue that has no active runtime contract and update the focused regressions that still conserve it.
|
||||
- **Ownership cost**: One bounded cleanup pass across affected support code, fixtures, and tests, followed by lower long-term cognitive and maintenance cost.
|
||||
- **Alternative intentionally rejected**: Leaving deprecated aliases and legacy support artifacts in place "just in case" was rejected because this is a pre-production repo and the residue already causes semantic drift.
|
||||
- **Release truth**: Current-release truth cleanup.
|
||||
|
||||
### Compatibility posture
|
||||
|
||||
This feature assumes a pre-production environment.
|
||||
|
||||
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
|
||||
|
||||
Canonical replacement is preferred over preservation.
|
||||
|
||||
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
|
||||
|
||||
- **Test purpose / classification**: Feature
|
||||
- **Validation lane(s)**: fast-feedback, confidence
|
||||
- **Why this classification and these lanes are sufficient**: The proof burden is that existing tenant and baseline profile behaviors still work after dead residue is removed, and that dead semantics no longer survive in active support paths. Focused feature coverage with one small badge-regression slice is sufficient.
|
||||
- **New or expanded test families**: Update the existing tenant-truth cleanup regressions, tenant lifecycle domain-separation regressions, baseline profile behavior regressions, and badge catalog regressions. Add a narrow baseline-status cleanup regression only if an existing file cannot express the assertion cleanly.
|
||||
- **Fixture / helper cost impact**: Lower overall. Factories, seeds, and browser fixtures should stop carrying dead app-status defaults unless a still-active boundary proves they are needed.
|
||||
- **Heavy-family visibility / justification**: none
|
||||
- **Special surface test profile**: standard-native-filament
|
||||
- **Standard-native relief or required special coverage**: Ordinary feature coverage is sufficient. The cleanup must also prove that central badge registration and default fixtures do not conserve retired semantics.
|
||||
- **Reviewer handoff**: Reviewers must confirm that no active runtime dependency still needs the removed residue, that tenant and baseline profile behavior remains unchanged for current truth, and that dead semantics are removed rather than rewrapped in a compatibility shim.
|
||||
- **Budget / baseline / trend impact**: none
|
||||
- **Escalation needed**: none
|
||||
- **Active feature PR close-out entry**: Guardrail
|
||||
- **Planned validation commands**:
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantTruthCleanupSpec179Test.php tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineProfileArchiveActionTest.php tests/Feature/Filament/BaselineProfileListFiltersTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Badges/TenantBadgesTest.php tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Keep tenant truth free of retired app-status semantics (Priority: P1)
|
||||
|
||||
As an operator, I can continue to use tenant surfaces without retired app-status semantics resurfacing through defaults, badges, or seeded examples, so the current lifecycle, provider, and RBAC truth stays trustworthy.
|
||||
|
||||
**Why this priority**: Tenant truth cleanup already happened on primary surfaces. The highest-value part of this cleanup is making sure dead supporting residue cannot silently undo that work.
|
||||
|
||||
**Independent Test**: Can be fully tested by exercising the existing tenant list and tenant detail regressions with records that still contain legacy app-status values and proving that current tenant truth stays unchanged.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a tenant record still stores a legacy app-status value, **When** the operator opens the existing tenant list or tenant detail surface, **Then** that legacy value does not regain current-status meaning.
|
||||
2. **Given** seeded or factory-created tenant examples are used in current tenant-truth regressions, **When** those regressions run after cleanup, **Then** they no longer depend on app-status defaults to make the surfaces work.
|
||||
3. **Given** lifecycle, provider, and RBAC truth already coexist on a tenant surface, **When** the cleanup is complete, **Then** those active truths remain separate and unchanged.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Use one baseline profile status language (Priority: P1)
|
||||
|
||||
As a maintainer, I can reason about baseline profile state through one canonical status contract, so draft, active, and archived behavior is not split between live status truth and deprecated aliases.
|
||||
|
||||
**Why this priority**: The deprecated baseline profile aliases are explicitly dead residue. Removing them is the cleanest proof that the repo now has one active baseline profile status language.
|
||||
|
||||
**Independent Test**: Can be fully tested by running existing baseline profile archive, list/filter, and view/edit continuity regressions after the deprecated alias language is removed and confirming that current baseline profile behavior stays intact.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** baseline profiles still move through draft, active, and archived behavior today, **When** existing baseline profile regressions run after cleanup, **Then** the behavior still works without deprecated status aliases.
|
||||
2. **Given** a contributor updates baseline profile logic or tests, **When** they read current profile status semantics, **Then** only the canonical status contract is available as active language.
|
||||
3. **Given** an operator opens or saves an existing baseline profile through the current view and edit surfaces, **When** the cleanup is complete, **Then** those surfaces continue to render and persist through the canonical status contract without depending on deprecated aliases.
|
||||
|
||||
---
|
||||
|
||||
### Cross-Cutting Verification - Prove the residue is fully retired (Release Gate)
|
||||
|
||||
As a reviewer, I can verify the cleanup in one focused pass, so the repo does not keep half-dead semantics alive in support code, fixtures, or tests.
|
||||
|
||||
**Why this priority**: Cleanup value is only real if the dead semantics are actually gone rather than merely hidden in one layer.
|
||||
|
||||
**Release Gate**: This verification runs after User Story 1 and User Story 2 are complete and confirms that the touched runtime and test paths no longer expose the retired semantics as active language.
|
||||
|
||||
**Note**: This is not an independently shippable MVP slice; it is the feature-level closeout check that proves the cleanup is complete.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** the cleanup branch, **When** the reviewer runs the focused validation commands, **Then** current tenant and baseline profile behaviors still pass without the retired residue.
|
||||
2. **Given** a touched support path, fixture, or test previously conserved dead semantics, **When** the cleanup is reviewed, **Then** that path is either removed, rewritten to current truth, or explicitly deferred as a follow-up rather than silently preserved.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- A legacy storage field may still exist historically or in migrations even when it no longer has any active runtime meaning.
|
||||
- A browser fixture or seeder may still populate a retired value for historical realism; this spec must remove mandatory dependency on that value without changing unrelated fixture intent.
|
||||
- Some tests may use literal status values rather than deprecated aliases; the cleanup must distinguish current canonical value usage from dead alias usage.
|
||||
- Central badge registration may still contain dormant legacy entries even when no current surface consumes them; dormant entries count as cleanup scope if they no longer support active truth.
|
||||
- Baseline profile archive, list, view, and edit behavior must continue to work because the active status contract already exists independently of the deprecated aliases.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
**Constitution alignment (required):** This feature adds no Microsoft Graph calls, no long-running work, and no new write workflow. It is a bounded runtime and test cleanup over existing tenant and baseline profile truth.
|
||||
|
||||
**Constitution alignment (PROP-001 / ABSTR-001 / PERSIST-001 / STATE-001 / BLOAT-001):** This feature introduces no new persistence, abstraction, state family, or semantic layer. It removes dead structure that no longer represents current-release truth.
|
||||
|
||||
**Constitution alignment (XCUT-001):** Not applicable. The feature does not add or modify a shared operator interaction family.
|
||||
|
||||
**Constitution alignment (TEST-GOV-001):** Focused feature and badge-regression coverage is the narrowest sufficient proof because the business risk is dead semantics surviving in active support paths, not a new workflow or surface family.
|
||||
|
||||
**Constitution alignment (RBAC-UX):** No authorization behavior changes. Existing workspace membership, tenant isolation, and capability enforcement remain authoritative.
|
||||
|
||||
**Constitution alignment (BADGE-001):** Centralized badge semantics remain authoritative. If the retired tenant app-status badge domain has no active consumer, it must be removed centrally rather than replaced with any page-local or test-local mapping.
|
||||
|
||||
**Constitution alignment (UI-FIL-001):** No new Filament screen, action surface, or custom markup is introduced. Existing tenant and baseline profile surfaces must continue to rely on their current native presentation.
|
||||
|
||||
**Constitution alignment (UI-SEM-001 / LAYER-001 / TEST-TRUTH-001):** The feature removes dead interpretation residue rather than adding another semantic layer. Tests must prove current business truth survives while the residue disappears.
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-234-001**: The system MUST remove deprecated baseline profile status aliases from active runtime language once the cleanup proves no productive dependency remains.
|
||||
- **FR-234-002**: The system MUST treat the canonical baseline profile status contract as the only active source of draft, active, and archived profile semantics.
|
||||
- **FR-234-003**: The system MUST remove retired tenant app-status support residue from active badge registration, factory defaults, browser fixtures, seeds, and tests when those paths no longer serve a current runtime contract.
|
||||
- **FR-234-004**: Existing tenant list and tenant detail behavior MUST remain unchanged for current lifecycle, provider, and RBAC truth after the retired residue is removed.
|
||||
- **FR-234-005**: Existing baseline profile list, view, edit, and archive behavior MUST remain unchanged for current profile status truth after deprecated aliases are removed.
|
||||
- **FR-234-006**: Every removed residue item MUST be checked for hidden runtime, UI, filter, cast, policy, or API dependency before deletion.
|
||||
- **FR-234-007**: If a hidden dependency is found, the dependency MUST be documented and moved to a follow-up cleanup decision rather than preserving the residue as silent compatibility lore.
|
||||
- **FR-234-008**: The feature MUST NOT introduce compatibility aliases, fallback readers, migration shims, or new legacy fixtures to preserve removed residue.
|
||||
- **FR-234-009**: The feature MUST NOT introduce a new readiness model, new status family, new cleanup ledger, or any other replacement semantic layer.
|
||||
- **FR-234-010**: Historical storage or migration remnants MAY remain only as historical artifacts and MUST NOT regain default-visible operator meaning.
|
||||
- **FR-234-011**: Focused regression coverage MUST prove both tenant-truth continuity and baseline-profile continuity after the cleanup.
|
||||
- **FR-234-012**: The feature MUST stay bounded to dead transitional residue cleanup and MUST NOT absorb onboarding fallback retirement, provider-connection legacy cleanup, or canonical operation-type convergence.
|
||||
|
||||
### Key Entities *(include if feature involves data)*
|
||||
|
||||
- **Canonical baseline profile status**: The active status language that already governs baseline profile lifecycle behavior.
|
||||
- **Deprecated baseline profile status aliases**: Retired alias constants that mirror current profile statuses but no longer represent active repo truth.
|
||||
- **Tenant app-status residue**: Retired support artifacts around a legacy tenant-level status signal that current tenant surfaces no longer treat as authoritative.
|
||||
- **Residual support artifacts**: Factories, fixtures, seeds, tests, and badge registrations that can conserve dead semantics even when primary product surfaces no longer use them.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-234-001**: In acceptance review, no targeted tenant surface or supporting default path reintroduces tenant app-status as current truth.
|
||||
- **SC-234-002**: 100% of targeted tenant-truth regressions pass after the retired tenant app-status residue is removed.
|
||||
- **SC-234-003**: 100% of targeted baseline profile regressions pass after the deprecated baseline profile status aliases are removed.
|
||||
- **SC-234-004**: The cleanup ships without adding any new persistence, status family, compatibility shim, or replacement semantic layer.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The current baseline profile status contract is already sufficient for existing profile behavior.
|
||||
- Existing tenant surfaces no longer require app-status to express current tenant truth.
|
||||
- Historical migration files may retain old field names or values as history without counting as active runtime truth.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Dropping legacy database columns in this slice
|
||||
- Redesigning tenant readiness, provider readiness, or baseline readiness semantics
|
||||
- Performing onboarding fallback retirement
|
||||
- Performing provider-connection legacy cleanup outside the dead tenant app-status residue
|
||||
- Resolving the canonical operation-type source-of-truth conflict
|
||||
|
||||
## Dependencies
|
||||
|
||||
- Existing tenant lifecycle, provider, and RBAC truth separation on current tenant surfaces
|
||||
- Existing baseline profile behavior and current baseline profile status contract
|
||||
- Existing focused regressions for tenant truth, baseline profile behavior, and central badge registration
|
||||
|
||||
## Definition of Done
|
||||
|
||||
- Deprecated baseline profile status aliases are gone from active runtime language.
|
||||
- Retired tenant app-status residue is gone from active badge registration, default fixtures, seeds, and tests unless an explicit still-active dependency is documented.
|
||||
- Existing tenant and baseline profile behaviors remain unchanged for current truth.
|
||||
- No new compatibility path or replacement status layer was introduced.
|
||||
- Focused regression coverage passes.
|
||||
225
specs/234-dead-transitional-residue/tasks.md
Normal file
225
specs/234-dead-transitional-residue/tasks.md
Normal file
@ -0,0 +1,225 @@
|
||||
# Tasks: Dead Transitional Residue Cleanup
|
||||
|
||||
**Input**: Design documents from `/specs/234-dead-transitional-residue/`
|
||||
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`, `quickstart.md`
|
||||
|
||||
**Tests**: Required. This feature changes runtime behavior by removing active runtime/support residue, so Pest coverage must be added or updated in `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`, `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`, `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`, and `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`.
|
||||
**Operations**: No new `OperationRun`, audit-only DB action, or queued workflow is introduced. This cleanup stays inside existing runtime behavior, fixture defaults, and regression coverage.
|
||||
**RBAC**: No authorization semantics change. Existing tenant/admin Filament access, tenant isolation, and current `404` versus `403` behavior must remain unchanged in the touched tenant and baseline regression files.
|
||||
**UI / Surface Guardrails**: No operator-facing surface is added or redesigned. Keep `standard-native-filament` relief and use the existing tenant and baseline pages only as continuity proof.
|
||||
**Filament UI Action Surfaces**: No new Filament Resource, Page, RelationManager, or action surface is introduced. `TenantResource` and `BaselineProfileResource` keep their current surfaces and global-search posture.
|
||||
**Badges**: `BadgeCatalog` remains authoritative. The legacy tenant app-status badge domain must be removed centrally from `apps/platform/app/Support/Badges/BadgeCatalog.php` and `apps/platform/app/Support/Badges/BadgeDomain.php`, and active badge domains must remain covered by tests.
|
||||
|
||||
**Organization**: Tasks are grouped by user story so each slice stays independently testable after the shared proof surfaces are prepared. Recommended delivery order is `US1` and `US2` in parallel after Foundational, then a final cross-cutting verification phase, because the retirement proof only matters once the tenant and baseline cleanup slices are both in place.
|
||||
|
||||
## Test Governance Checklist
|
||||
|
||||
- [X] Lane assignment is named and is the narrowest sufficient proof for the changed behavior.
|
||||
- [X] New or changed tests stay in the smallest honest family, and any heavy-governance or browser addition is explicit.
|
||||
- [X] Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default; any widening is isolated or documented.
|
||||
- [X] Planned validation commands cover the change without pulling in unrelated lane cost.
|
||||
- [X] The declared surface test profile or `standard-native-filament` relief is explicit.
|
||||
- [X] Any material budget, baseline, trend, or escalation note is recorded in the active spec or PR.
|
||||
|
||||
## Phase 1: Setup (Shared Cleanup Anchors)
|
||||
|
||||
**Purpose**: Lock the cleanup inventory and proving commands before editing runtime or test files.
|
||||
|
||||
- [X] T001 [P] Verify the cleanup anchor inventory across `apps/platform/app/Models/BaselineProfile.php`, `apps/platform/app/Support/Badges/BadgeCatalog.php`, `apps/platform/app/Support/Badges/BadgeDomain.php`, `apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php`, `apps/platform/database/factories/TenantFactory.php`, and `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php`
|
||||
- [X] T002 [P] Verify the narrow validation lane and proving commands in `specs/234-dead-transitional-residue/plan.md` and `specs/234-dead-transitional-residue/quickstart.md`
|
||||
|
||||
**Checkpoint**: Cleanup scope and proving commands are locked before code changes begin.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: Foundational (Blocking Proof Surfaces)
|
||||
|
||||
**Purpose**: Audit the real consumer boundaries before removing residue so story work does not rediscover hidden dependencies mid-slice.
|
||||
|
||||
**CRITICAL**: No user story work should begin until this phase is complete.
|
||||
|
||||
- [X] T003 [P] Audit all `TenantAppStatus` and `TenantAppStatusBadge` consumers across `apps/platform/app/Support/Badges/BadgeCatalog.php`, `apps/platform/app/Support/Badges/BadgeDomain.php`, `apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php`, `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`, and `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
- [X] T004 [P] Audit every ambient or explicit `app_status` usage boundary across `apps/platform/database/factories/TenantFactory.php`, `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php`, `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`, and `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
- [X] T005 [P] Audit every `BaselineProfile::STATUS_` consumer and baseline continuity proof file across `apps/platform/app/Models/BaselineProfile.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, and `apps/platform/tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`
|
||||
- [X] T006 [P] Lock the cross-cutting retirement proof and follow-up decision sink in `specs/234-dead-transitional-residue/plan.md`, `specs/234-dead-transitional-residue/quickstart.md`, and `specs/234-dead-transitional-residue/tasks.md`
|
||||
|
||||
**Checkpoint**: Hidden-dependency boundaries are explicit and the story slices can proceed without overlapping proof setup work.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 1 - Keep Tenant Truth Free Of Retired App-Status Semantics (Priority: P1) 🎯 MVP
|
||||
|
||||
**Goal**: Remove tenant app-status residue from active badge/default paths without changing current tenant lifecycle, provider, or RBAC truth.
|
||||
|
||||
**Independent Test**: Run the tenant-truth regressions with explicit legacy `app_status` values and verify the tenant list/detail surfaces still suppress them while active tenant truth remains unchanged.
|
||||
|
||||
### Tests for User Story 1
|
||||
|
||||
- [X] T007 [P] [US1] Add tenant list/detail assertions that explicit historical `app_status` values stay suppressed in `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`
|
||||
- [X] T008 [P] [US1] Add lifecycle and RBAC separation assertions that do not rely on `TenantFactory` defaults in `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
- [X] T009 [P] [US1] Add tenant badge assertions that the legacy app-status domain no longer participates in active tenant semantics in `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`
|
||||
|
||||
### Implementation for User Story 1
|
||||
|
||||
- [X] T010 [P] [US1] Remove the `TenantAppStatus` registration path from `apps/platform/app/Support/Badges/BadgeDomain.php` and `apps/platform/app/Support/Badges/BadgeCatalog.php`
|
||||
- [X] T011 [US1] Delete the retired mapper in `apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php`
|
||||
- [X] T012 [P] [US1] Remove the ambient `app_status` default from `apps/platform/database/factories/TenantFactory.php`
|
||||
- [X] T013 [P] [US1] Remove the forced tenant `app_status` fixture value from `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php`
|
||||
- [X] T014 [US1] Reconcile explicit legacy setup and active-domain expectations in `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`, `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`, and `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`
|
||||
|
||||
**Checkpoint**: User Story 1 is independently functional and tenant truth no longer depends on the retired badge path or ambient `app_status` defaults.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: User Story 2 - Use One Baseline Profile Status Language (Priority: P1)
|
||||
|
||||
**Goal**: Remove deprecated baseline profile alias language so `BaselineProfileStatus` is the only active lifecycle contract.
|
||||
|
||||
**Independent Test**: Run the existing baseline profile archive, list/filter, view/edit continuity, and workspace-ownership regressions after alias removal and verify behavior is unchanged.
|
||||
|
||||
### Tests for User Story 2
|
||||
|
||||
- [X] T015 [P] [US2] Add archive-flow assertions that only `BaselineProfileStatus` drives lifecycle behavior in `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`
|
||||
- [X] T016 [P] [US2] Add list/filter assertions that baseline profile behavior does not require alias constants in `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`
|
||||
- [X] T017 [P] [US2] Add view/edit continuity assertions after alias removal in `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`
|
||||
- [X] T018 [P] [US2] Add workspace-ownership continuity assertions after alias removal in `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`
|
||||
|
||||
### Implementation for User Story 2
|
||||
|
||||
- [X] T019 [US2] Remove deprecated `STATUS_DRAFT`, `STATUS_ACTIVE`, and `STATUS_ARCHIVED` constants from `apps/platform/app/Models/BaselineProfile.php`
|
||||
- [X] T020 [US2] Update baseline profile regressions to use only `App\Support\Baselines\BaselineProfileStatus` in `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, and `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`
|
||||
|
||||
**Checkpoint**: User Story 2 is independently functional and baseline profile lifecycle behavior now has one canonical status language.
|
||||
|
||||
---
|
||||
|
||||
## Phase 5: Cross-Cutting Verification - Prove The Residue Is Fully Retired
|
||||
|
||||
**Goal**: Lock in regression proof that the retired semantics are gone from active runtime/support paths.
|
||||
|
||||
**Release Gate**: Run the focused regression pack plus the residue searches after User Story 1 and User Story 2 are complete, and confirm there are no unexpected matches or hidden-default dependencies left in the touched files.
|
||||
|
||||
### Verification for Cross-Cutting Closeout
|
||||
|
||||
- [X] T021 [P] Add badge catalog assertions that the retired tenant app-status domain is absent while active domains remain registered in `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
- [X] T022 [P] Add regression assertions that legacy `app_status` is always opt-in setup in `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php` and `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
|
||||
### Implementation for Cross-Cutting Closeout
|
||||
|
||||
- [X] T023 Run and review the residue searches for `BaselineProfile::STATUS_|TenantAppStatus|tenant_app_status` and `app_status` across `apps/platform/app/Models/BaselineProfile.php`, `apps/platform/app/Support/Badges/BadgeCatalog.php`, `apps/platform/app/Support/Badges/BadgeDomain.php`, `apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php`, `apps/platform/database/factories/TenantFactory.php`, `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php`, `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`, `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`, and `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
- [X] T024 Record any hidden-dependency follow-up or confirm clean retirement in `specs/234-dead-transitional-residue/plan.md` and `specs/234-dead-transitional-residue/quickstart.md`
|
||||
|
||||
**Checkpoint**: The feature has explicit proof that the dead residue is no longer part of active truth.
|
||||
|
||||
---
|
||||
|
||||
## Phase 6: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Finish formatting and run the narrow proving workflow for the full cleanup.
|
||||
|
||||
- [X] T025 Run formatting for `apps/platform/app/Models/BaselineProfile.php`, `apps/platform/app/Support/Badges/BadgeCatalog.php`, `apps/platform/app/Support/Badges/BadgeDomain.php`, `apps/platform/database/factories/TenantFactory.php`, `apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php`, `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`, `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`, `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`, `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, and `apps/platform/tests/Feature/Baselines/BaselineProfileAuthorizationTest.php` with `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
|
||||
- [X] T026 [P] Run the tenant-truth validation pack from `specs/234-dead-transitional-residue/quickstart.md` against `apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php` and `apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
|
||||
- [X] T027 [P] Run the baseline-profile and badge validation pack from `specs/234-dead-transitional-residue/quickstart.md` against `apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php`, `apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php`, `apps/platform/tests/Feature/Baselines/BaselineProfileAuthorizationTest.php`, `apps/platform/tests/Unit/Badges/TenantBadgesTest.php`, and `apps/platform/tests/Unit/Badges/BadgeCatalogTest.php`
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: Starts immediately and locks the cleanup inventory plus proving commands.
|
||||
- **Foundational (Phase 2)**: Depends on Setup and blocks all story work until the hidden-dependency boundaries and closeout proof sinks are explicit.
|
||||
- **User Story 1 (Phase 3)**: Depends on Foundational and is the recommended MVP cut.
|
||||
- **User Story 2 (Phase 4)**: Depends on Foundational and can proceed in parallel with User Story 1 because it touches a separate runtime truth domain.
|
||||
- **Cross-Cutting Verification (Phase 5)**: Depends on User Story 1 and User Story 2 because the final retirement proof only makes sense after both cleanup slices land.
|
||||
- **Polish (Phase 6)**: Depends on all desired user stories and the cross-cutting verification phase being complete.
|
||||
|
||||
### User Story Dependencies
|
||||
|
||||
- **US1**: No dependencies beyond Foundational.
|
||||
- **US2**: No dependencies beyond Foundational.
|
||||
|
||||
### Within Each User Story
|
||||
|
||||
- Write the story tests first and confirm they fail before implementation is considered complete.
|
||||
- Keep the cleanup canonical: no compatibility aliases, no fallback readers, and no restoration of ambient legacy defaults.
|
||||
- Keep `BadgeCatalog` authoritative for tenant badge semantics and `BaselineProfileStatus` authoritative for baseline lifecycle semantics.
|
||||
- Finish story-level verification before moving to the next dependent slice.
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- `T001` and `T002` can run in parallel during Setup.
|
||||
- `T003`, `T004`, `T005`, and `T006` can run in parallel during Foundational work.
|
||||
- `T007`, `T008`, and `T009` can run in parallel for User Story 1, followed by `T010`, `T011`, `T012`, and `T013` in parallel before reconciling tests in `T014`.
|
||||
- `T015`, `T016`, `T017`, and `T018` can run in parallel for User Story 2.
|
||||
- User Story 1 and User Story 2 can proceed in parallel after Foundational is complete.
|
||||
- `T021` and `T022` can run in parallel during cross-cutting verification.
|
||||
- `T026` and `T027` can run in parallel during final validation.
|
||||
|
||||
---
|
||||
|
||||
## Parallel Example: User Story 1
|
||||
|
||||
```bash
|
||||
# User Story 1 tests in parallel
|
||||
T007 apps/platform/tests/Feature/Filament/TenantTruthCleanupSpec179Test.php
|
||||
T008 apps/platform/tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php
|
||||
T009 apps/platform/tests/Unit/Badges/TenantBadgesTest.php
|
||||
|
||||
# User Story 1 implementation in parallel after the tests are in place
|
||||
T010 apps/platform/app/Support/Badges/BadgeDomain.php + apps/platform/app/Support/Badges/BadgeCatalog.php
|
||||
T011 apps/platform/app/Support/Badges/Domains/TenantAppStatusBadge.php
|
||||
T012 apps/platform/database/factories/TenantFactory.php
|
||||
T013 apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php
|
||||
```
|
||||
|
||||
## Parallel Example: User Story 2
|
||||
|
||||
```bash
|
||||
# User Story 2 tests in parallel
|
||||
T015 apps/platform/tests/Feature/Baselines/BaselineProfileArchiveActionTest.php
|
||||
T016 apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php
|
||||
T017 apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php
|
||||
T018 apps/platform/tests/Feature/Baselines/BaselineProfileWorkspaceOwnershipTest.php
|
||||
```
|
||||
|
||||
## Parallel Example: Cross-Story Delivery After Foundational
|
||||
|
||||
```bash
|
||||
# Tenant cleanup and baseline cleanup can proceed in parallel after Phase 2
|
||||
T010-T014 apps/platform/app/Support/Badges/* + apps/platform/database/factories/TenantFactory.php + apps/platform/app/Console/Commands/SeedBackupHealthBrowserFixture.php
|
||||
T019-T020 apps/platform/app/Models/BaselineProfile.php + apps/platform/tests/Feature/Baselines/* + apps/platform/tests/Feature/Filament/BaselineProfileListFiltersTest.php + apps/platform/tests/Feature/Filament/BaselineProfileScopeV2PersistenceTest.php
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Story 1 Only)
|
||||
|
||||
1. Complete Phase 1: Setup.
|
||||
2. Complete Phase 2: Foundational.
|
||||
3. Complete Phase 3: User Story 1.
|
||||
4. Run `T025` and `T026` before widening the slice.
|
||||
|
||||
### Incremental Delivery
|
||||
|
||||
1. Ship User Story 1 to remove tenant app-status residue from active badge/default paths.
|
||||
2. Ship User Story 2 to collapse baseline lifecycle language onto `BaselineProfileStatus` only.
|
||||
3. Run the cross-cutting verification phase to lock in proof that the residue is fully retired.
|
||||
4. Finish with formatting and the focused validation workflow.
|
||||
|
||||
### Parallel Team Strategy
|
||||
|
||||
1. One contributor can prepare the badge and tenant-truth proof surfaces while another prepares the baseline continuity proof surfaces in Phase 2.
|
||||
2. After Foundational is complete, one contributor can execute User Story 1 while another executes User Story 2.
|
||||
3. Once both cleanup slices land, a final pass can focus on cross-cutting retirement proof and the narrow validation commands.
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- `[P]` tasks target different files and can be worked independently once upstream blockers are cleared.
|
||||
- `[US1]` and `[US2]` map directly to the feature specification user stories.
|
||||
- The suggested MVP scope is Phase 1 through Phase 3 only.
|
||||
- All tasks above follow the required checklist format with task ID, optional parallel marker, story label where applicable, and exact file paths.
|
||||
Loading…
Reference in New Issue
Block a user