TenantAtlas/specs/363-explicit-uiactioncontext-contract/tasks.md
Ahmed Darrazi 9e435ea91f
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m2s
feat: implement explicit UiActionContext contract
2026-06-07 13:12:02 +02:00

187 lines
18 KiB
Markdown

# Tasks: Spec 363 - Explicit UiActionContext Contract for Scoped No-Record Actions
**Input**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/363-explicit-uiactioncontext-contract/spec.md`, `plan.md`, and `checklists/requirements.md`
**Prerequisites**: `spec.md` and `plan.md`
**Tests**: REQUIRED (Pest). Use Unit + Feature/Filament-Livewire + Architecture/guard. Browser is optional only if visible copy/hierarchy changes materially.
**Operations**: Modal open must not create `OperationRun` records, dispatch provider/write jobs, or mutate records. Submit/execute must reauthorize with explicit context.
**RBAC**: Reuse existing policies/gates, `UiEnforcement`, `WorkspaceUiEnforcement`, capability resolvers, and deny-as-not-found semantics. No new capability strings.
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration stays in `apps/platform/bootstrap/providers.php`. No new panel, global-search change, or asset strategy is allowed.
**Organization**: Tasks are ordered by dependency. Tests and guardrails come before or alongside runtime edits.
## Repo Baseline At Prep Time
- **Branch before Spec Kit creation**: `platform-dev`
- **HEAD before Spec Kit creation**: `548a37c8 feat: implement sync capture backup operation semantics (#433)`
- **`git status --short --branch` before Spec Kit creation**: clean
- **Spec Kit branch created**: `363-explicit-uiactioncontext-contract`
- **Implementation PR branch target**: `feat/363-explicit-uiactioncontext-contract` from `dev`; reconcile branch shape before runtime edits
- **Candidate source**: direct user-provided Spec 363 draft in `/Users/ahmeddarrazi/.codex/attachments/36f3aea8-0303-4548-a83c-9f1cdd15f527/pasted-text.txt`
- **Completed-spec context only**: Specs 338, 340, 358, 359, 360, 361, and 362 are dependency/history context and must not be reopened during Spec 363 implementation
- **Scope guardrail**: no migrations, no panel/provider changes, no assets, no global-search changes, no OperationRun redesign, no broad record-backed action migration, and no product-feature expansion
## Test Governance Checklist
- [x] Lane assignment remains explicit and narrowest sufficient (Unit + Feature/Filament-Livewire + Architecture/guard; Browser optional only when visible UI changes require it).
- [x] Shared helpers keep workspace/environment/member/capability setup opt-in and do not create expensive defaults.
- [x] Tests prove business truth: context resolution, RBAC affordance, server reauthorization, no-run/no-job on modal open, and wrong-scope fail-closed behavior.
- [x] Static guard failures are actionable and do not rely on broad permanent legacy allowlists.
- [x] Final close-out records no-migration, no-asset, no-panel-provider, no-global-search, and no-compatibility-shim status.
## Implementation Close-Out Notes
- Runtime implementation ran on `feat/363-explicit-uiactioncontext-contract` from `dev`.
- Repo-truth names differ from the draft: `TenantReviewResource`, `TenantDiagnostics`, and `TenantDashboard` are the current environment review/diagnostics/dashboard surfaces.
- `apps/platform/tests/Support/Filament/ScopedActionAssertions.php` was not added because the final focused tests did not duplicate enough setup to justify a new helper.
- Browser smoke was not run because the implementation does not materially change visible hierarchy or add new visible page/modal copy beyond the existing disabled-context tooltip path.
- No migrations, assets, panel/provider registration changes, global-search changes, new capabilities, new operation types, or compatibility shim were introduced.
## Phase 1: Setup and Repo Truth Inventory
**Purpose**: confirm exact current branch, callsites, action names, and related completed-spec context before runtime edits.
- [x] T001 Re-read `spec.md`, `plan.md`, `checklists/requirements.md`, `.specify/memory/constitution.md`, `docs/ai-coding-rules.md`, `docs/architecture-guidelines.md`, `docs/security-guidelines.md`, `docs/testing-guidelines.md`, `docs/filament-guidelines.md`, `docs/research/filament-v5-notes.md`, and `specs/362-sync-capture-backup-operation-semantics/artifacts/action-context-root-cause-audit.md`.
- [x] T002 Confirm current branch, working tree, and baseline commit with `git status --short --branch` and `git log -1 --oneline`; before runtime edits, ensure implementation runs on `feat/363-explicit-uiactioncontext-contract` from `dev` or document the branch reconciliation in close-out.
- [x] T003 [P] Re-verify current `UiEnforcement` and `WorkspaceUiEnforcement` behavior in `apps/platform/app/Support/Rbac/UiEnforcement.php` and `apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php`.
- [x] T004 [P] Re-verify Livewire referer context behavior in `apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php`; the draft-named `tests/Unit/Filament/ResolvesPanelTenantContextLivewireRefererTest.php` is not present on this branch, so resolver behavior is covered through `ResolvesUiActionContextTest` and admin resolver guard tests.
- [x] T005 [P] Re-inventory scoped no-record action callsites in `apps/platform/app/Filament` and record the exact current action names for Inventory, Policy, Entra Groups, Evidence Snapshot, Review Pack, Environment Review, Environment Diagnostics, Restore Run, and Environment Dashboard.
- [x] T006 Confirm no application implementation from Specs 338/340/358/359/360/361/362 needs to be rewritten; use those packages as context only.
---
## Phase 2: Contract Unit Tests
**Purpose**: define the request-time action-context contract before changing action code.
- [x] T007 [P] Add failing Unit tests in `apps/platform/tests/Unit/Support/Rbac/Actions/UiActionContextTest.php` for workspace context, environment context, record context, system context, missing context, `requireWorkspace()`, and `requireEnvironment()`.
- [x] T008 [P] Add failing Unit tests in `apps/platform/tests/Unit/Support/Rbac/Actions/ResolvesUiActionContextTest.php` or equivalent to prove page resolver, record resolver, workspace resolver, and missing-context behavior against actual repo relation names.
- [x] T009 [P] Add failing Unit tests in `apps/platform/tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php` proving scoped no-record actions require explicit context and missing context is distinct from non-membership/missing capability.
- [x] T010 [P] Add regression tests proving record-backed actions can still resolve scope from records without mandatory no-record context plumbing.
**Checkpoint**: tests describe the contract and fail for the current implicit fallback behavior.
---
## Phase 3: Add Narrow Action Context Contract
**Purpose**: add the smallest support-layer API needed for scoped action context.
- [x] T011 Add `apps/platform/app/Support/Rbac/Actions/UiActionScope.php` with workspace, environment, record, and system scope values.
- [x] T012 Add `apps/platform/app/Support/Rbac/Actions/UiActionContextSource.php` with explicit, page resolver, workspace context, record, Livewire referer, and missing source values where currently justified.
- [x] T013 Add `apps/platform/app/Support/Rbac/Actions/UiActionContext.php` as a readonly request-time value object with `forWorkspace()`, `forEnvironment()`, `forRecord()`, `forSystem()`, `missing()`, `isMissing()`, missing-reason accessors, `requireWorkspace()`, and `requireEnvironment()` behavior or equivalent constructors/accessors.
- [x] T014 Add `apps/platform/app/Support/Rbac/Actions/ResolvesUiActionContext.php` or an equivalent helper that wraps existing `ResolvesPanelTenantContext` and actual model relation names without inventing fake relations.
- [x] T015 Confirm no new persistence, migration, capability, operation type, panel/provider, route, asset, or global-search behavior was introduced.
**Checkpoint**: the new contract is narrow, request-time only, and covered by Unit tests.
---
## Phase 4: Harden UiEnforcement For Scoped No-Record Actions
**Purpose**: make the shared RBAC UI path enforce explicit scoped context without breaking record-backed actions.
- [x] T016 Add an explicit scoped-action entrypoint such as `UiEnforcement::forScopedAction(Action $action, UiActionContext|Closure $context)` or a narrow compatible signature change that cannot be confused with nullable no-record context.
- [x] T017 Update context resolution inside `UiEnforcement` so scoped no-record actions do not silently fall back to `Filament::getTenant()` as product scope truth.
- [x] T018 Add internal missing-context classification so tests can distinguish context-missing from non-member and missing-capability states.
- [x] T019 Preserve existing record/action/table/bulk behavior where product scope is derived from a record or selected records.
- [x] T020 Keep destructive/high-impact action confirmation behavior intact: `Action::make(...)->action(...)`, `->requiresConfirmation()` where applicable, server authorization, audit, and notification paths.
- [x] T021 Run the core Unit gate:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Rbac/Actions tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php tests/Unit/Support/Rbac/UiEnforcementTest.php`
**Checkpoint**: `UiEnforcement` supports explicit context, fails closed for missing context, and does not break existing record-backed tests.
---
## Phase 5: Retrofitted Action Tests First
**Purpose**: protect representative action lifecycle behavior before or during runtime retrofit.
- [x] T022 [P] Extend inventory start-surface coverage in `apps/platform/tests/Feature/Inventory/InventorySyncStartSurfaceTest.php`; `apps/platform/tests/Feature/Filament/InventoryItemResourceTest.php` was also run as the existing resource file.
- [x] T023 [P] Extend `apps/platform/tests/Feature/PolicySyncStartSurfaceTest.php` to keep first-click modal mount, no `OperationRun`, and no queued job on modal open under Livewire referer context.
- [x] T024 [P] Extend `apps/platform/tests/Feature/RunStartAuthorizationTest.php` / directory group coverage for `sync_groups` no-record action: readonly and no run/job until submit; shared missing-context behavior is covered in Unit because the page itself aborts before mounting without environment context.
- [x] T025 [P] Extend `apps/platform/tests/Feature/Evidence/EvidenceSnapshotResourceTest.php` for `create_snapshot` first-click modal/no-run behavior; `create_first_snapshot` is covered by the static guard and existing empty-state coverage because it has no modal-open lifecycle.
- [x] T026 [P] Extend `apps/platform/tests/Feature/ReviewPack/ReviewPackResourceTest.php` for `generate_pack` first-click modal/no-run behavior; `generate_first` stays covered through the shared action factory/static guard and existing readonly/entitlement empty-state assertions.
- [x] T027 [P] Extend Tenant Review coverage for repo-current `TenantReviewResource::makeCreateReviewAction()` / `create_review` in existing tenant review UI tests and static guard.
- [x] T028 [P] Extend Environment Diagnostics coverage for repo-current `TenantDiagnostics` actions `bootstrapOwner` and `mergeDuplicateMemberships` through existing diagnostics tests plus static guard.
- [x] T029 [P] Extend restore UI/enforcement coverage for `RestoreRunResource::makeCreateAction()` and restore create/wizard through existing restore tests and static guard.
- [x] T030 [P] Extend Environment Dashboard support action coverage for repo-current `TenantDashboard` support request and support diagnostics tests; support diagnostics retains its intentional audit-on-open behavior.
**Checkpoint**: tests capture representative action behavior and fail until actions use explicit context consistently.
---
## Phase 6: Retrofit Representative Actions
**Purpose**: move known latent-risk no-record scoped actions to explicit `UiActionContext`.
- [x] T031 Update `apps/platform/app/Filament/Resources/InventoryItemResource/Pages/ListInventoryItems.php` so `run_inventory_sync` uses explicit action context and keeps handler reauthorization/no-run-on-modal-open behavior.
- [x] T032 Update `apps/platform/app/Filament/Resources/PolicyResource.php` and `apps/platform/app/Filament/Resources/PolicyResource/Pages/ListPolicies.php` so Policy Sync uses explicit action context and keeps existing queued OperationRun UX.
- [x] T033 Update `apps/platform/app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php` so `sync_groups` uses explicit environment action context and no longer depends on implicit `Filament::getTenant()` for scoped no-record state.
- [x] T034 Update `apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php` and `apps/platform/app/Filament/Resources/EvidenceSnapshotResource/Pages/ListEvidenceSnapshots.php` so `create_snapshot` and `create_first_snapshot` use explicit environment action context.
- [x] T035 Update `apps/platform/app/Filament/Resources/ReviewPackResource.php` so `generate_pack` and `generate_first` use explicit environment action context and entitlement/readonly checks use the same context.
- [x] T036 Update repo-current `apps/platform/app/Filament/Resources/TenantReviewResource.php` so `create_review` uses explicit environment action context and submit still validates capability/access before creating review/compose work.
- [x] T037 Update repo-current `apps/platform/app/Filament/Pages/TenantDiagnostics.php` so `bootstrapOwner` and `mergeDuplicateMemberships` use explicit environment action context and modal open remains non-mutating.
- [x] T038 Update `apps/platform/app/Filament/Resources/RestoreRunResource.php` so Restore create entry/wizard context is explicit and restore/write gates remain separate.
- [x] T039 Update repo-current `apps/platform/app/Filament/Pages/TenantDashboard.php` so support request and support diagnostics actions use explicit environment action context.
- [x] T040 For any listed action whose current repo name differs from the draft, document the actual action name in the active feature close-out rather than inventing aliases.
**Checkpoint**: representative latent-risk actions use explicit context and tests prove first-click/modal/submit lifecycle behavior.
---
## Phase 7: Test Helper and Static Guard
**Purpose**: prevent recurrence without creating a broad framework.
- [x] T041 Add reusable test helper `apps/platform/tests/Support/Filament/ScopedActionAssertions.php` only if it reduces duplication across at least two retrofitted action tests; evaluated and not added.
- [x] T042 Helper assertion requirements are satisfied inline in focused tests where needed; no helper was introduced.
- [x] T043 Add `apps/platform/tests/Feature/Architecture/ScopedUiActionContextContractTest.php` to scan risky scoped no-record action patterns under `apps/platform/app/Filament`.
- [x] T044 The guard flags guarded no-record action names, scoped-action wrapper markers, and regression to `UiEnforcement::forAction`.
- [x] T045 Tune the guard to avoid record-backed row/table/detail false positives without hiding known risky actions.
- [x] T046 Ensure guard failure output includes file, action or nearest action name, reason, and a fix hint such as using explicit `UiActionContext` / scoped action resolver.
- [x] T047 Do not add a permanent legacy allowlist for old no-record scoped action patterns.
**Checkpoint**: future risky no-record scoped actions fail fast unless they declare explicit context.
---
## Phase 8: Validation
- [x] T048 Run the core context and enforcement Unit gate:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Rbac/Actions tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php tests/Unit/Support/Rbac/UiEnforcementTest.php`
- [x] T049 Run the primary action lifecycle and guard gate:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Architecture/ScopedUiActionContextContractTest.php tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/PolicySyncStartSurfaceTest.php tests/Feature/RunStartAuthorizationTest.php`
- [x] T050 Run the representative contextual action tests:
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php`
- [x] T051 Run additional focused tests for repo-current Tenant Review, Tenant Diagnostics, Restore create, and Tenant Dashboard support files after implementation names the exact existing or new test files, including the relevant existing SupportDiagnostics/SupportRequests action tests when those surfaces are touched.
- [x] T052 Browser smoke not run; implementation changed existing action context behavior but not visible hierarchy/copy materially enough to require a browser pass under this spec's rule.
- [x] T053 Run `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`.
- [x] T054 Run `git diff --check`.
- [x] T055 Record final close-out: changed files, new contract classes, retrofitted actions, intentionally untouched actions, static guard result, tests run, no legacy fallback retained for scoped no-record actions, and no migrations/assets/panel/global-search changes.
## Dependencies & Execution Order
- Phase 1 must complete first.
- Phase 2 and Phase 3 establish the contract and should precede broad action retrofit.
- Phase 4 blocks action retrofit because callsites need the final `UiEnforcement` API.
- Phase 5 tests should be written before or beside Phase 6 runtime changes.
- Phase 7 guard can be developed after the first retrofits clarify the marker pattern, but must pass before close-out.
- Phase 8 closes the package.
## Parallel Opportunities
- T003, T004, and T005 can run in parallel.
- T007, T008, T009, and T010 can run in parallel.
- T022 through T030 can be split by action family after the helper approach is decided.
- T031 through T039 can be split by action family after `UiEnforcement` API stabilizes.
## Explicit Non-Goals For Implementers
- Do not modify completed spec artifacts outside Spec 363.
- Do not add migrations, tables, persisted status, or action-context audit tables.
- Do not add new capabilities or operation types.
- Do not change Filament panel provider registration or panel paths.
- Do not enable or alter global search.
- Do not add assets or require `filament:assets` because of this spec.
- Do not rewrite record-backed actions unless the guard proves they are actually no-record scoped risk.
- Do not turn this into support desk, billing, promotion, governance inbox, restore redesign, or AI runtime implementation.