TenantAtlas/specs/334-nested-filament-context-contract-hardening/tasks.md
ahmido f967db7983 Spec 334: harden nested Filament Livewire context contract (#395)
## Summary
- harden nested Filament and Livewire tenant-context handling across the backup schedule operation runs relation manager, managed-environment triage arrival continuity, the backup set policy picker table, and the Operate Hub shell
- add architecture, feature, and browser coverage for nested Filament tenant-context continuity and restore-run resource behavior
- add the Spec 334 artifacts (`spec.md`, `plan.md`, `tasks.md`, and the requirements checklist)

## Testing
- Not run as part of this commit/push/PR workflow

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #395
2026-05-24 21:33:19 +00:00

93 lines
7.1 KiB
Markdown

# Tasks: Spec 334 - Nested Filament / Livewire Context Contract Hardening
- Input: `specs/334-nested-filament-context-contract-hardening/spec.md`, `specs/334-nested-filament-context-contract-hardening/plan.md`
- Prerequisites: `spec.md`, `plan.md`
**Tests**: Required. This is runtime-hardening for nested operator surfaces with authorization/scope impact.
## Test Governance Checklist
- [x] Lane assignment is explicit and is the narrowest sufficient proof for the changed behavior.
- [x] New tests stay in the smallest honest family (Feature/Livewire + one architecture guard; browser smoke only for the two user-visible regressions).
- [x] New helpers/factories/seeds/context defaults stay cheap by default.
- [x] Planned validation commands cover the change without pulling in unrelated lane cost.
- [x] Any deviation resolves as `document-in-feature`, `follow-up-spec`, or `reject-or-split`.
## Phase 1: Preparation And Repo Truth
**Purpose**: Confirm repo truth and capture the current failure paths before touching runtime code.
- [x] T001 Re-read `spec.md`, `plan.md`, and this `tasks.md`.
- [x] T002 Confirm working tree intent and record baseline commit (`git status`, `git log -1`).
- [x] T003 Verify confirmed scope file paths exist and inspect current context usage:
- `apps/platform/app/Livewire/BackupSetPolicyPickerTable.php`
- `apps/platform/app/Filament/Resources/RestoreRunResource.php`
- `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`
- `apps/platform/app/Filament/Resources/BackupScheduleResource/RelationManagers/BackupScheduleOperationRunsRelationManager.php`
- `apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php`
- `apps/platform/app/Support/OperateHub/OperateHubShell.php`
- `apps/platform/app/Support/Workspaces/WorkspaceContext.php`
- [x] T004 Capture the current Add Policies modal failure path (tenantless modal → checkbox column hidden) and record the exact call chain and where tenant/context is read.
- Captured via regression: `apps/platform/tests/Feature/Filament/BackupSetPolicyPickerTableTest.php` and browser smoke `apps/platform/tests/Browser/Spec334NestedFilamentContextContractSmokeTest.php`.
- [x] T005 Capture the current Restore Run Create wizard failure path (Livewire update request without route params → tenant resolver throws) and record the exact call chain and closure(s) involved.
- Captured via regression: `apps/platform/tests/Feature/Filament/RestoreRunResourceLivewireTenantContextTest.php` (real Livewire update payload) + browser smoke `apps/platform/tests/Browser/Spec334NestedFilamentContextContractSmokeTest.php`.
- [x] T006 Decide whether any shared helper is justified (≥2 confirmed consumers). If not, keep fixes local to each surface + the existing shared seam.
- No new helper introduced (ABSTR-001). Shared seam hardening applied in `apps/platform/app/Support/OperateHub/OperateHubShell.php`.
## Phase 2: Guardrails And Regression Tests (before refactor)
**Purpose**: Lock “fail-closed and scoped” behavior and block unsafe tenant switching patterns before implementation refactors.
- [x] T007 Add an architecture guard test: `apps/platform/tests/Architecture/FilamentTenantContextContractTest.php`.
- Detect and fail on unsafe `Filament::setTenant($model->...)` patterns in nested surfaces without explicit allowlist.
- Keep an explicit allowlist limited to infrastructure-only context selection locations.
- [x] T008 Add a regression test covering Add Policies picker behavior when ambient tenant is null (authorized user still sees row selection and can select).
- [x] T009 Add a regression test covering Restore Run Create wizard Livewire update lifecycle (no crash when route params are missing; options are scoped).
- [x] T010 Add a regression test for BackupSchedule operation runs relation manager scope (owner record scopes query; ambient tenant missing/wrong does not broaden).
- [x] T011 Add a regression test for the triage widget context (record context preferred; ambient tenant is fallback; missing context fails closed).
## Phase 3: Implement Nested Context Contract (confirmed surfaces only)
**Purpose**: Apply the contract to the confirmed high-risk surfaces without a broad tenancy rewrite.
- [x] T012 Harden `apps/platform/app/Livewire/BackupSetPolicyPickerTable.php`:
- Resolve context from validated BackupSet ownership (workspace + managed environment).
- Scope table query by resolved environment.
- Re-resolve and re-authorize at mutation time (bulk action).
- Never silently override mismatched ambient tenant.
- [x] T013 Harden `apps/platform/app/Filament/Resources/RestoreRunResource.php`:
- Ensure option closures used during Livewire updates can resolve validated environment context without route params.
- Livewire update context recovery is implemented in the shared seam: `apps/platform/app/Support/OperateHub/OperateHubShell.php` (validated referer path candidate for `/livewire-*/update` requests).
- Referer is treated as a candidate only; access is still validated via workspace + membership + operability checks.
- [x] T014 Harden `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php` only if the seam is shared and the fix is not restore-specific.
- No change required (the shared seam hardening in `OperateHubShell` unblocks the failing lifecycle).
- [x] T015 Harden `apps/platform/app/Filament/Resources/BackupScheduleResource/RelationManagers/BackupScheduleOperationRunsRelationManager.php`:
- Prefer owner schedule record as primary context (`$this->getOwnerRecord()`).
- Remove dependencies on ambient tenant where owner context exists.
- [x] T016 Harden `apps/platform/app/Filament/Widgets/ManagedEnvironment/ManagedEnvironmentTriageArrivalContinuity.php`:
- Prefer widget record context.
- Use one resolver consistently for visibility and mutation checks.
- Fail closed when context is missing.
## Phase 4: Browser Smoke (required because the original bugs were user-visible)
- [x] T017 Backup Set Add Policies smoke:
- Open Backup Set detail → Add Policies.
- Verify policies are visible and row selection checkbox column is visible.
- Select one or more rows; verify “Add selected” path works.
- [x] T018 Restore Run Create wizard smoke:
- Open Restore Runs → Create.
- Trigger Livewire interactions (wizard next/previous, selections).
- Verify no “no tenant context selected” crash.
## Phase 5: Validation
- [x] T019 Run narrow tests first (confidence lane):
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Architecture --filter='FilamentTenantContextContract' --compact`
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Feature/Filament --filter='BackupSetPolicyPicker|RestoreRun|BackupScheduleOperationRuns|Triage' --compact`
- [ ] T020 Run broader related suites only if needed (keep lane cost honest):
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Feature/Filament --compact`
- [x] T021 Run `cd apps/platform && ./vendor/bin/sail pint --dirty` and `git diff --check`.
- [x] T022 Report full-suite status honestly if not run.
- Full suite not executed; this spec was validated via targeted Feature/Architecture tests + a dedicated browser smoke file.