# 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.
