Automated PR created by Copilot: adds implementation and tests for specs/264 cross-tenant promotion execution. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #320
18 KiB
| 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
- Lane assignment stays
fast-feedback,confidence, plus one boundedbrowsersmoke and remains the narrowest sufficient proof. - New or changed tests stay in
apps/platform/tests/Unit/Support/PortfolioCompare/,apps/platform/tests/Feature/PortfolioCompare/, and one newapps/platform/tests/Browser/PortfolioCompare/smoke file only. - Existing portfolio-compare fixtures and current
OperationRunassertions are reused; no new heavy provider or browser fixture domain is introduced. - Planned validation commands stay consistent across spec, plan, and tasks.
- The declared surface test profile remains
standard-native-filamentwith explicit real-browser confirmation coverage. - Any drift toward persisted drafts, approvals, rollback, or batch promotion is handled as
reject-or-splitrather 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.
- 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, anddocs/product/implementation-ledger.mdtogether so the slice stays on the current execution gap only. - 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, andapps/platform/tests/Feature/PortfolioCompare/CrossTenantCompareLaunchContextTest.php. - 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. - 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, andapps/platform/app/Services/Providers/ProviderOperationRegistry.phponly to determine whether app-level operation-registry wiring is required by the chosen shared start-result seam. - 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, andapps/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.
- T006 [P] Add
apps/platform/tests/Unit/Support/PortfolioCompare/CrossTenantPromotionExecutionPlannerTest.phpto require ready-only execution planning, blocked and manual exclusion, stable run-identity inputs, and no-ready rejection. - T007 [P] Add
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.phpto require404for out-of-scope tenants, disabled execution affordance for compare-only actors, and403for forced execution without target-manage or workspace-manage access. - T008 [P] Add
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionRunUxTest.phpto require one canonicalpromotion.executerun type, shared start-result statuses, and active-run dedupe for the same executable plan. - 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.phponly if the shared start-result seam requires app-level operation-registry wiring,apps/platform/app/Support/Audit/AuditActionId.php, and the boundedPortfolioCompareexecution planner or bridge chosen for v1 so the feature has one canonical operation vocabulary and no draft persistence. NoProviderOperationRegistrychange 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
- T010 [P] [US1] Add
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionActionTest.phpto 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. - T011 [P] [US1] Extend
apps/platform/tests/Feature/PortfolioCompare/CrossTenantComparePageTest.phponly 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
- T012 [US1] Add one bounded
PortfolioCompareexecution planner or bridge plus one execution service inapps/platform/app/Support/PortfolioCompare/and orapps/platform/app/Services/PortfolioCompare/that translates the current ready subjects into target-safe mutation inputs without creating a persisted promotion draft. - T013 [US1] Update
apps/platform/app/Filament/Pages/CrossTenantComparePage.phpso the page exposesExecute promotionwith explicit confirmation, preserves one-primary-action discipline, and keeps source, target, governed-subject filters, and return-state context intact after queueing. - T014 [US1] Add one queued promotion execution job under
apps/platform/app/Jobs/Operations/that consumesOperationRun.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
- T015 [P] [US2] Extend
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionRunUxTest.phpto assert queued, deduped, blocked, and Monitoring-link outcomes plus canonical run-context fields for the new operation type. - T016 [P] [US2] Add
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuditTest.phpto assert queued and terminal audit metadata and the absence of any persisted promotion-draft or compare-snapshot writes. - T017 [P] [US2] Add
apps/platform/tests/Browser/PortfolioCompare/CrossTenantPromotionExecutionSmokeTest.phpto prove the live compare page can move from generated preflight to confirmation to queuedOpen operationhandoff without breaking the existing action hierarchy.
Implementation for User Story 2
- 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, andapps/platform/app/Support/OpsUx/OpsUxBrowserEvents.phpso compare-page execution uses canonical queued, deduped, blocked, and run-link messaging. No additionalOperationRunServiceorOperationUxPresenterchanges were required beyond compare-page reuse of the shared presenter, link, and browser-event seams. - 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 sopromotion.executeopens the current Monitoring viewer without a promotion-specific detail screen. ExistingOperationRunLinks::tenantlessView()continuity already satisfied this path without further runtime changes. - T020 [US2] Extend
apps/platform/app/Services/Audit/WorkspaceAuditLogger.phpandapps/platform/app/Support/Audit/AuditActionId.phponly 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
- T021 [P] [US3] Extend
apps/platform/tests/Feature/PortfolioCompare/CrossTenantCompareLaunchContextTest.phpto 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. - T022 [P] [US3] Extend
apps/platform/tests/Feature/PortfolioCompare/CrossTenantPromotionExecutionAuthorizationTest.phponly where needed to prove stale-preflight, operational-control, and inaccessible-tenant execution attempts never create a run.
Implementation for User Story 3
- T023 [US3] Preserve compare-page launch and return context after queueing, and add any secondary
Open operationcontinuity 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. - T024 [US3] Integrate operational-control and legitimacy blocking for
promotion.executeso 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.
- 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. - 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. - 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. - T028 [P] Run
export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent. - 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. - 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.
- 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
PortfolioCompareexecution seam, sharedOperationRunUX, 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
- Complete Phase 1 and Phase 2.
- Deliver US1 and US2 together on the current compare page and shared run UX.
- Add US3 to keep return-state and safety boundaries intact.
- Finish with the focused validation and guardrail review tasks in Phase 6.
Team Strategy
- Settle the bounded execution bridge first.
- Parallelize failing tests within each story before runtime edits.
- 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