# Feature Specification: Legacy Purge (Runs / Routes / UI / Test Shims) **Feature Branch**: `092-legacy-purge-final` **Created**: 2026-02-14 **Status**: Draft **Input**: User description: "Spec 092 — Legacy Purge: Runs / Routes / UI / Test-Shims vollständig entfernen" ## Clarifications ### Session 2026-02-14 - Q: For legacy tenant-scoped deep links that were previously served via redirect shims under `/admin/t/{tenant:external_id}/...` (e.g. `/admin/t/{tenant}/operations`), what response semantics do you want? → A: Always `404 Not Found`. - Q: For guard tests scanning for legacy patterns, which paths should be excluded? → A: Exclude `database/migrations/**` + `references/**` + `docs/**`. - Q: For Inventory entry after removing the redirect-only landing page, what should be the canonical target? → A: Inventory Items. - Q: For Drift landing copy, what exact phrase should replace the legacy text “inventory sync runs”? → A: Use “operation runs”. ## User Scenarios & Testing *(mandatory)* ### User Story 1 - Operate without legacy concepts (Priority: P1) As a platform maintainer, I can use the application without encountering legacy run concepts (URLs, labels, redirect-only pages, or test shims), so the system has a single canonical mental model. **Why this priority**: Removing legacy remnants reduces refactor risk, prevents onboarding confusion, and eliminates hidden compatibility logic. **Independent Test**: Navigate through Inventory, Drift, Operations/run history, and Provider Connections using the primary UI entry points; verify no legacy URLs or legacy wording appear and no compatibility shims are required. **Acceptance Scenarios**: 1. **Given** a user navigates via the canonical UI navigation, **When** they open Inventory and Drift entry points, **Then** they land on canonical pages (not redirect-only landing pages) and see canonical operations terminology. 2. **Given** a user is in the admin UI, **When** the context/navigation chrome renders, **Then** it derives its state from the current workspace/tenant context only (not from legacy URL heuristics). --- ### User Story 2 - Legacy deep links fail fast (Priority: P2) As a tenant admin with old bookmarks, I get a clear failure (not a redirect) when accessing legacy tenant-scoped admin paths, so the system enforces a single set of canonical URLs. **Why this priority**: Removing redirects is an intentional breaking change; we want predictable behavior and to avoid ongoing maintenance of compatibility shims. **Independent Test**: Attempt to access representative legacy tenant-scoped admin URLs and confirm they are not handled by the application. **Acceptance Scenarios**: 1. **Given** an old bookmark to a legacy tenant-scoped admin path, **When** it is requested, **Then** the request returns `404 Not Found` and is not redirected by the application. --- ### User Story 3 - Prevent reintroduction (Priority: P3) As a developer, I get fast feedback if I accidentally reintroduce removed legacy patterns (identifiers, parameters, route prefixes, or UI copy), so the cleanup remains permanent. **Why this priority**: Cleanup work regresses easily during refactors; guard tests turn “tribal knowledge” into enforceable rules. **Independent Test**: Introduce a known legacy identifier in a non-migration file and confirm automated guards fail reliably; remove it and confirm the suite is green again. **Acceptance Scenarios**: 1. **Given** a change introduces a removed legacy identifier in non-migration code, **When** the automated guard suite runs, **Then** the build fails with an actionable message. ### Edge Cases - Legacy tenant-scoped paths may still exist in browser history or external references; the application must not rely on redirects to function. - Previously enqueued background work must continue to process safely during the compatibility window; removal of legacy job fields must not cause noisy runtime behavior. - Automated legacy scans must explicitly exclude database migration history (migrations are immutable). - Authorization semantics must not change as a side-effect of cleanup. ## Requirements *(mandatory)* **Constitution alignment (required):** This feature does not introduce new external calls. It does change long-running/queued work APIs (background job payload shape), so it MUST be delivered using a staged rollout to avoid compatibility issues with previously queued payloads. **Constitution alignment (RBAC-UX):** This feature does not change authorization rules. It removes legacy routes and UI heuristics; access semantics must remain consistent and must not introduce new information leaks. **Constitution alignment (OPS-EX-AUTH-001):** Not applicable. **Constitution alignment (BADGE-001):** Not applicable. **Constitution alignment (Filament Action Surfaces):** This feature changes admin UI content and navigation/landing behavior but does not introduce new mutation actions. The Action Surface Contract remains satisfied by existing surfaces. ### Scope (bounded) - In scope: removal of legacy run artifacts in code, routes, UI copy/heuristics, and tests; addition/extension of guard tests that prevent reintroduction. - Out of scope: any changes to the canonical operations data model; any new features; any modifications to historical database migrations. ### Assumptions & Dependencies - Release process supports two deployments/releases for the staged job payload change (compatibility window → final purge). - Migration history is immutable and excluded from legacy-scanning guards. - Release notes will communicate removal of legacy deep links. ### Functional Requirements - **FR-001 (Dead notification removal)**: The unused legacy notification for “backup schedule run dispatched” MUST not exist in active code. - **Verification**: A repository-wide scan of non-migration code finds no references to the removed notification artifact. - **FR-002 (Job API cleanup, staged)**: The backup schedule execution job MUST not require a legacy run identifier at dispatch sites. - **FR-002.A (Compatibility release)**: During a compatibility window, older queued payloads MUST still deserialize safely while new dispatches no longer include a dummy legacy run id. - **FR-002.B (Final purge)**: After the compatibility window, the legacy parameter/property MUST be removed entirely. - **Compatibility window definition**: The compatibility window MUST be considered complete only after Deploy A has been in production for at least 7 calendar days, and the operations team confirms there is no remaining backlog of previously queued backup schedule execution jobs. - **Verification**: After final purge, no non-migration code references the legacy run-id field, and dispatch sites do not include placeholder arguments. - **FR-003 (Inventory landing removal)**: Inventory navigation MUST not rely on redirect-only landing pages or dead views. - **Verification**: Inventory entry points route directly to Inventory Items (canonical index), without using a redirect-only landing page. - **FR-004 (Drift landing copy)**: Drift UI copy MUST not use legacy terminology such as “inventory sync runs”; it MUST use “operation runs”. - **Verification**: Drift landing content shows “operation runs” and no legacy phrase remains visible. - **FR-005 (Legacy redirect routes removal)**: The application MUST not define redirect shims for removed legacy tenant-scoped admin endpoints (e.g. `/admin/t/{tenant:external_id}/operations`). - **Verification**: Routing definitions contain no legacy tenant-scoped redirect shims, and requests to the removed legacy endpoints return `404 Not Found`. - **Scope note**: At the time of writing, the only known legacy tenant-scoped redirect shim endpoint in `routes/**` is `/admin/t/{tenant:external_id}/operations`. If additional legacy redirect shim endpoints are discovered during implementation, they MUST be added to this spec and covered by tests. - **FR-006 (Context chrome heuristic removal)**: Context/navigation chrome MUST not infer state from legacy URL patterns. - **Verification**: Context chrome behavior is correct without any legacy URL detection logic. - **FR-007 (Test shim removal)**: Automated tests MUST not rely on legacy model shims or bootstrap hacks that simulate removed legacy domain concepts. - **Verification**: Test suite passes without any legacy shim files or bootstrapping. - **FR-008 (Guard suite)**: Guard tests MUST fail if removed legacy identifiers/patterns are reintroduced outside migration history. - **Verification**: Guard suite reliably fails on reintroduction and passes when removed. Scans MUST exclude `database/migrations/**`, `references/**`, and `docs/**`. - **FR-009 (Migration immutability)**: Database migrations MUST remain unchanged. - **Verification**: No migration files are modified as part of this feature. ### Legacy identifiers (verification-only glossary) The following legacy identifiers/patterns are considered removed and are used only for verification/guarding (outside migrations): - Notification artifact name: `BackupScheduleRunDispatchedNotification` - Legacy shim model name: `InventorySyncRun` - Legacy job field name: `backupScheduleRunId` - Legacy tenant-scoped deep-link endpoint(s) served by redirect shims (current known set): - `/admin/t/{tenant:external_id}/operations` - Non-legacy note: the tenant-plane prefix `/admin/t/{tenant:external_id}/...` is canonical by itself; only explicitly listed legacy deep-link shim endpoints are treated as removed. - Legacy UI copy phrase: `inventory sync runs` ### Acceptance Criteria (Definition of Done) - No active code (excluding database migration history) contains the removed legacy identifiers/patterns. - No legacy redirect routes exist; legacy tenant-scoped deep links are not supported and return `404 Not Found`. - Inventory entry points are canonical (no redirect-only landing UI). - Drift landing copy uses canonical operations terminology. - Test suite is green; guard tests prevent reintroduction. - Guard scans explicitly exclude `database/migrations/**`, `references/**`, and `docs/**`. ## UI Action Matrix *(mandatory when Filament is changed)* | Surface | Location | Header Actions | Inspect Affordance (List/Table) | Row Actions (max 2 visible) | Bulk Actions (grouped) | Empty-State CTA(s) | View Header Actions | Create/Edit Save+Cancel | Audit log? | Notes / Exemptions | |---|---|---|---|---|---|---|---|---|---|---| | Drift landing content | Drift entry UI | No change | No change | No change | No change | No change | No change | No change | No | Copy-only change; no action surface impact | | Inventory navigation entry | Inventory entry UI | No change | No change | No change | No change | No change | No change | No change | No | Remove redirect-only landing behavior | | Context/navigation chrome | Admin UI chrome | No change | No change | No change | No change | No change | No change | No change | No | Remove legacy URL detection; no actions affected | ### Key Entities *(include if feature involves data)* - **Background job payloads**: Existing queued payloads may contain legacy fields; staged rollout must maintain compatibility until payloads are drained. ## Success Criteria *(mandatory)* ### Measurable Outcomes - **SC-001**: A canonical navigation walkthrough (Inventory → Drift → Operations/run history → Provider connections) shows no legacy deep-link endpoints/redirect shims and no legacy run terminology. - **SC-002**: The application defines zero legacy tenant-scoped redirect shim routes, and removed legacy deep links return `404 Not Found`. - **SC-003**: The automated test suite passes; guard tests fail deterministically when any removed legacy identifier is reintroduced outside migration history. - **SC-004**: The staged rollout completes with no emergency rollback due to queued job payload incompatibilities.