TenantAtlas/specs/264-cross-tenant-promotion-execution/tasks.md
Ahmed Darrazi 983abb18a1
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m22s
chore: commit workspace changes (automated)
2026-05-02 16:36:21 +02:00

184 lines
18 KiB
Markdown

---
description: "Task list for Cross-Tenant Promotion Execution v1"
---
# Tasks: Cross-Tenant Promotion Execution v1
**Input**: Design documents from `specs/264-cross-tenant-promotion-execution/`
**Prerequisites**: `specs/264-cross-tenant-promotion-execution/spec.md`, `specs/264-cross-tenant-promotion-execution/plan.md`, `specs/264-cross-tenant-promotion-execution/checklists/requirements.md`
**Tests**: REQUIRED (Pest plus one bounded Browser smoke). Keep proof bounded to `PortfolioCompare` unit and feature families plus one new `Browser/PortfolioCompare` smoke file only.
**Operations**: Introduce one canonical `promotion.execute` `OperationRun` type and reuse the shared `OperationRun` start UX, Monitoring links, and current provider-write seams. No promotion-draft table, no compare-snapshot table, no second queue family, and no second promotion dashboard are allowed.
**RBAC**: Non-members and out-of-scope tenants remain `404`. Compare-view permissions stay inherited from Spec 043. Execution adds target-tenant manage plus workspace baseline-manage enforcement, with disabled affordance guidance and server-side `403` on forced execution. No new capability family may be introduced.
**Shared Pattern Reuse**: Reuse `CrossTenantComparePage`, current launch and return context, `CrossTenantComparePreviewBuilder`, `CrossTenantPromotionPreflight`, `OperationRunService`, `OperationUxPresenter`, `ProviderOperationStartResultPresenter`, `OperationRunLinks`, `OpsUxBrowserEvents`, `WorkspaceAuditLogger`, `AuditActionId`, and current provider-write seams. Do not create persisted promotion drafts or a local run-start UX.
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Laravel or Filament service-provider registration remains unchanged in `apps/platform/bootstrap/providers.php`. No new panel, no new globally searchable resource, and no new asset strategy are allowed.
**Organization**: Tasks are grouped by user story so the execution contract, Monitoring continuity, and safety boundaries remain independently testable and implementable. This package is an explicit delta follow-up over Spec 043 and current code.
## Test Governance Checklist
- [x] Lane assignment stays `fast-feedback`, `confidence`, plus one bounded `browser` smoke and remains the narrowest sufficient proof.
- [x] New or changed tests stay in `apps/platform/tests/Unit/Support/PortfolioCompare/`, `apps/platform/tests/Feature/PortfolioCompare/`, and one new `apps/platform/tests/Browser/PortfolioCompare/` smoke file only.
- [x] Existing portfolio-compare fixtures and current `OperationRun` assertions are reused; no new heavy provider or browser fixture domain is introduced.
- [x] Planned validation commands stay consistent across spec, plan, and tasks.
- [x] The declared surface test profile remains `standard-native-filament` with explicit real-browser confirmation coverage.
- [x] Any drift toward persisted drafts, approvals, rollback, or batch promotion is handled as `reject-or-split` rather than hidden inside this feature.
## Phase 1: Setup (Shared Context)
**Purpose**: Confirm the current compare, preflight, run UX, and provider-write seams before any implementation change.
- [x] T001 Review `specs/264-cross-tenant-promotion-execution/spec.md`, `specs/264-cross-tenant-promotion-execution/plan.md`, `specs/264-cross-tenant-promotion-execution/checklists/requirements.md`, `specs/043-cross-tenant-compare-and-promotion/spec.md`, `docs/product/spec-candidates.md`, `docs/product/roadmap.md`, and `docs/product/implementation-ledger.md` together so the slice stays on the current execution gap only.
- [x] T002 [P] Confirm the current compare-page and launch-context seams in `apps/platform/app/Filament/Pages/CrossTenantComparePage.php`, `apps/platform/tests/Feature/PortfolioCompare/CrossTenantComparePageTest.php`, and `apps/platform/tests/Feature/PortfolioCompare/CrossTenantCompareLaunchContextTest.php`.
- [x] T003 [P] Confirm the current compare-preview and preflight seams in `apps/platform/app/Support/PortfolioCompare/CrossTenantComparePreviewBuilder.php`, `apps/platform/app/Support/PortfolioCompare/CrossTenantPromotionPreflight.php`, and the current PortfolioCompare test coverage.
- [x] T004 [P] Confirm the current shared run-start, Monitoring-link, and operation-vocabulary seams in `apps/platform/app/Services/OperationRunService.php`, `apps/platform/app/Support/OperationCatalog.php`, `apps/platform/app/Support/OperationRunType.php`, `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php`, `apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php`, and `apps/platform/app/Services/Providers/ProviderOperationRegistry.php` only to determine whether app-level operation-registry wiring is required by the chosen shared start-result seam.
- [x] T005 [P] Confirm the current target-write seam and its constraints in `apps/platform/app/Services/Intune/RestoreService.php`, `apps/platform/app/Jobs/BulkPolicyVersionRestoreJob.php`, and `apps/platform/app/Jobs/Operations/PolicyVersionRestoreWorkerJob.php`, especially the current rule that foreign-tenant policy versions cannot be executed directly.
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Lock the bounded execution contract before surface-level implementation begins.
**Critical**: No user-story work should begin until this phase is complete.
- [x] T006 [P] Add `apps/platform/tests/Unit/Support/PortfolioCompare/CrossTenantPromotionExecutionPlannerTest.php` to require ready-only execution planning, blocked and manual exclusion, stable run-identity inputs, and no-ready rejection.
- [x] T007 [P] Add `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.php` to require `404` for out-of-scope tenants, disabled execution affordance for compare-only actors, and `403` for forced execution without target-manage or workspace-manage access.
- [x] T008 [P] Add `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionRunUxTest.php` to require one canonical `promotion.execute` run type, shared start-result statuses, and active-run dedupe for the same executable plan.
- [x] T009 Implement the foundational execution contract in `apps/platform/app/Support/OperationCatalog.php`, `apps/platform/app/Support/OperationRunType.php`, `apps/platform/app/Support/Operations/OperationRunCapabilityResolver.php`, `apps/platform/app/Support/OperationalControls/OperationalControlCatalog.php`, `apps/platform/app/Services/Providers/ProviderOperationRegistry.php` only if the shared start-result seam requires app-level operation-registry wiring, `apps/platform/app/Support/Audit/AuditActionId.php`, and the bounded `PortfolioCompare` execution planner or bridge chosen for v1 so the feature has one canonical operation vocabulary and no draft persistence. No `ProviderOperationRegistry` change was required because the shared start-result seam worked through the existing presenter/link contract.
**Checkpoint**: The canonical run vocabulary, control wiring, audit ids, and ready-only execution plan are locked before page and job work begins.
---
## Phase 3: User Story 1 - Queue one bounded promotion from the current preflight (Priority: P1)
**Goal**: An authorized operator can confirm and queue a target mutation for ready subjects only from the current compare and preflight context.
**Independent Test**: Open the compare page, generate a preflight with ready work, confirm `Execute promotion`, and verify that one `promotion.execute` run is queued with ready subjects only.
### Tests for User Story 1
- [x] T010 [P] [US1] Add `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionActionTest.php` to assert that preflight is required, only ready subjects enter the queued run context, blocked and manual subjects stay excluded, and no-ready execution is blocked.
- [x] T011 [P] [US1] Extend `apps/platform/tests/Feature/PortfolioCompare/CrossTenantComparePageTest.php` only where needed to prove the compare page keeps one dominant next action at a time and does not regress the current same-tenant or stale-selection safeguards once execution exists.
### Implementation for User Story 1
- [x] T012 [US1] Add one bounded `PortfolioCompare` execution planner or bridge plus one execution service in `apps/platform/app/Support/PortfolioCompare/` and or `apps/platform/app/Services/PortfolioCompare/` that translates the current ready subjects into target-safe mutation inputs without creating a persisted promotion draft.
- [x] T013 [US1] Update `apps/platform/app/Filament/Pages/CrossTenantComparePage.php` so the page exposes `Execute promotion` with explicit confirmation, preserves one-primary-action discipline, and keeps source, target, governed-subject filters, and return-state context intact after queueing.
- [x] T014 [US1] Add one queued promotion execution job under `apps/platform/app/Jobs/Operations/` that consumes `OperationRun.context`, performs target mutation for ready subjects only, and records canonical summary counts (`total`, `processed`, `succeeded`, `failed`, `skipped`, `created`, `updated`) instead of inventing a new summary-key family.
**Checkpoint**: The canonical compare page can queue one bounded target mutation without persisting a draft or mutating blocked subjects.
---
## Phase 4: User Story 2 - Follow the queued promotion through Monitoring with truthful run UX (Priority: P1)
**Goal**: The operator receives shared queued feedback, one canonical Monitoring link, and truthful run summary after starting a promotion.
**Independent Test**: Queue a promotion run from the compare page and verify that the start result, Monitoring link, and run-summary truth all stay on the shared `OperationRun` contract.
### Tests for User Story 2
- [x] T015 [P] [US2] Extend `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionRunUxTest.php` to assert queued, deduped, blocked, and Monitoring-link outcomes plus canonical run-context fields for the new operation type.
- [x] T016 [P] [US2] Add `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuditTest.php` to assert queued and terminal audit metadata and the absence of any persisted promotion-draft or compare-snapshot writes.
- [x] T017 [P] [US2] Add `apps/platform/tests/Browser/PortfolioCompare/CrossTenantPromotionExecutionSmokeTest.php` to prove the live compare page can move from generated preflight to confirmation to queued `Open operation` handoff without breaking the existing action hierarchy.
### Implementation for User Story 2
- [x] T018 [US2] Wire the shared start-result UX through `apps/platform/app/Services/OperationRunService.php`, `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/OpsUx/OperationUxPresenter.php`, `apps/platform/app/Services/Providers/ProviderOperationStartResultPresenter.php`, and `apps/platform/app/Support/OpsUx/OpsUxBrowserEvents.php` so compare-page execution uses canonical queued, deduped, blocked, and run-link messaging. No additional `OperationRunService` or `OperationUxPresenter` changes were required beyond compare-page reuse of the shared presenter, link, and browser-event seams.
- [x] T019 [US2] Extend `apps/platform/app/Support/OperationRunLinks.php`, `apps/platform/app/Support/Navigation/RelatedNavigationResolver.php`, and any minimal Monitoring label surface only as needed so `promotion.execute` opens the current Monitoring viewer without a promotion-specific detail screen. Existing `OperationRunLinks::tenantlessView()` continuity already satisfied this path without further runtime changes.
- [x] T020 [US2] Extend `apps/platform/app/Services/Audit/WorkspaceAuditLogger.php` and `apps/platform/app/Support/Audit/AuditActionId.php` only as needed so promotion execution records start and terminal audit truth with source-tenant, target-tenant, selection, and outcome metadata.
**Checkpoint**: The execution path starts, dedupes, blocks, links, and audits on the shared `OperationRun` seams only.
---
## Phase 5: User Story 3 - Preserve portfolio context and safety boundaries (Priority: P2)
**Goal**: Execution preserves compare and return-state context while enforcing target-safe control and capability boundaries.
**Independent Test**: Launch compare from the tenant registry, queue or attempt to queue a promotion, and verify that source, target, return-state, and safety boundaries all remain intact.
### Tests for User Story 3
- [x] T021 [P] [US3] Extend `apps/platform/tests/Feature/PortfolioCompare/CrossTenantCompareLaunchContextTest.php` to prove queued promotion keeps source-tenant, target-tenant, governed-subject, and return-state continuity. The stable proof now uses the mounted compare-page instance on the exact-two registry launch path, which avoids the flaky secondary Livewire snapshot hop while still exercising the same launched page state and queued promotion contract.
- [x] T022 [P] [US3] Extend `apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.php` only where needed to prove stale-preflight, operational-control, and inaccessible-tenant execution attempts never create a run.
### Implementation for User Story 3
- [x] T023 [US3] Preserve compare-page launch and return context after queueing, and add any secondary `Open operation` continuity only where it does not compete with the primary action. No additional runtime change was required in the bounded slice beyond the existing compare-page state handling and shared operation link seams; T021 now provides the explicit queued launch-context continuity proof.
- [x] T024 [US3] Integrate operational-control and legitimacy blocking for `promotion.execute` so blocked, stale, or inaccessible execution attempts fail safely without widening into approvals, rollback, or batch controls.
**Checkpoint**: The execution path stays usable inside the portfolio workflow and still fails closed at every safety boundary.
---
## Phase 6: Polish & Cross-Cutting Validation
**Purpose**: Validate the bounded slice and stop without widening scope.
- [x] T025 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/PortfolioCompare/CrossTenantPromotionExecutionPlannerTest.php`.
- [x] T026 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionActionTest.php tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.php tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuditTest.php tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionRunUxTest.php tests/Feature/PortfolioCompare/CrossTenantComparePageTest.php tests/Feature/PortfolioCompare/CrossTenantCompareLaunchContextTest.php`.
- [x] T027 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/PortfolioCompare/CrossTenantPromotionExecutionSmokeTest.php`.
- [x] T028 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`.
- [x] T029 [P] Review touched code to confirm Filament stays on Livewire v4, Laravel or Filament service-provider registration remains unchanged in `apps/platform/bootstrap/providers.php`, no globally searchable resource contract changes appear, and the mutating compare-page action uses explicit confirmation.
- [x] T030 [P] Review touched code to confirm the feature introduces no promotion-draft persistence, no compare-snapshot persistence, no second queue family, no second promotion surface, no approval workflow, and no rollback workflow.
- [x] T031 [P] Record the final guardrail, smoke, and scope-boundary outcomes in the active feature close-out without reopening batch promotion, approvals, rollback, or multi-provider follow-up work.
---
## Dependencies & Execution Order
### Phase Dependencies
- **Phase 1 (Setup)**: no dependencies; start immediately.
- **Phase 2 (Foundational)**: depends on Phase 1 and blocks all user stories.
- **Phase 3 (US1)**: depends on Phase 2 and establishes the bounded execution path.
- **Phase 4 (US2)**: depends on Phase 2 and should land with US1 so the start-result UX and Monitoring truth do not drift from the queued path.
- **Phase 5 (US3)**: depends on Phase 2 and hardens context and safety behavior after the execution path exists.
- **Phase 6 (Polish)**: depends on all desired user stories being complete.
### User Story Dependencies
- **US1 (P1)**: independently testable after Phase 2 and delivers the core execution value.
- **US2 (P1)**: independently testable after Phase 2 and should ship with US1 so the operator gets truthful Monitoring handoff.
- **US3 (P2)**: independently testable after Phase 2 and hardens the bounded execution path.
### Within Each User Story
- Write the listed Pest coverage first and make it fail for the intended gap.
- Keep implementation inside the compare page, bounded `PortfolioCompare` execution seam, shared `OperationRun` UX, and current provider-write paths named above.
- Re-run the narrowest relevant validation command after each story checkpoint before moving on.
---
## Implementation Strategy
### Suggested MVP Scope
- MVP = **US1 + US2 together**. The feature is only useful when the compare page can both queue promotion and hand the operator into truthful Monitoring continuity.
### Incremental Delivery
1. Complete Phase 1 and Phase 2.
2. Deliver US1 and US2 together on the current compare page and shared run UX.
3. Add US3 to keep return-state and safety boundaries intact.
4. Finish with the focused validation and guardrail review tasks in Phase 6.
### Team Strategy
1. Settle the bounded execution bridge first.
2. Parallelize failing tests within each story before runtime edits.
3. Serialize merges around `CrossTenantComparePage`, operation-catalog wiring, and shared Monitoring links so operator vocabulary stays coherent.
---
## Deferred Follow-Ups / Non-Goals
- persisted promotion drafts or compare snapshots
- approval workflow before execution
- rollback or replay workflow after execution
- batch or multi-target promotion
- automated manual-mapping resolution
- customer-facing promotion surfaces
- multi-provider execution framework