TenantAtlas/specs/264-cross-tenant-promotion-execution/spec.md
ahmido 11247c1537 Add cross-tenant promotion execution (spec 264) (#320)
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
2026-05-02 14:38:20 +00:00

34 KiB

Feature Specification: Cross-Tenant Promotion Execution v1

Feature Branch: 264-cross-tenant-promotion-execution Created: 2026-05-02 Status: Ready for implementation Input: User description: "Cross-Tenant Promotion Execution v1"

Inherited Baseline / Explicit Delta

This package is an explicit delta follow-up over Spec 043 and the current cross-tenant compare code path.

Inherited baseline

  • CrossTenantComparePage already owns the canonical /admin/cross-tenant-compare decision surface.
  • CrossTenantCompareSelection, CrossTenantComparePreviewBuilder, and CrossTenantPromotionPreflight already produce reproducible read-only compare and readiness truth.
  • tenant-registry launch context, exact-two compare launch, and return-state preservation already exist.
  • preflight audit already lands on the existing workspace audit pipeline through AuditActionId::CrossTenantPromotionPreflightGenerated.
  • the current slice is intentionally read-only and explicitly deferred actual promotion execution, queueing, OperationRun, persisted compare snapshots, persisted promotion drafts, mapping automation, and customer-facing compare.

Explicit delta in this spec

  • add one bounded Execute promotion action from the current compare and preflight context
  • require explicit confirmation before any target mutation starts
  • queue exactly one canonical OperationRun for promotion execution and reuse the shared start/result UX
  • mutate the target tenant for ready subjects only while keeping blocked and manual_mapping_required subjects excluded and visible
  • keep execution truth on existing OperationRun and audit records instead of adding a new promotion-draft or compare-snapshot table

Everything broader remains inherited or explicitly out of scope.

Spec Candidate Check (mandatory - SPEC-GATE-001)

  • Problem: The product can already compare tenants and generate a read-only promotion preflight, but operators still cannot execute the bounded promotion step that the page recommends.
  • Today's failure: Cross-tenant compare ends at advice. Operators still need manual, off-platform steps to apply source settings to the target tenant and then separately reconstruct whether the action actually ran.
  • User-visible improvement: An authorized workspace operator can review a current compare preflight, confirm the scope, queue one cross-tenant promotion run, and follow that run through the existing Monitoring flow without leaving the canonical compare page.
  • Smallest enterprise-capable version: One compare-page execution action, one confirmation modal, one queued OperationRun, one bounded promotion execution planner and worker, one truthful Monitoring handoff, and explicit audit metadata. No draft persistence, no batch execution, and no rollback workflow ship in v1.
  • Explicit non-goals: No persisted promotion draft entity, no scheduled or recurring promotion, no multi-target batch execution, no approval workflow, no rollback engine, no customer-facing promotion, no cross-workspace execution, and no multi-provider abstraction expansion.
  • Permanent complexity imported: One bounded execution planner or bridge, one queued promotion job, one new canonical operation type plus control key, a small audit extension, and focused unit, feature, and browser proof.
  • Why now: docs/product/spec-candidates.md, docs/product/roadmap.md, and docs/product/implementation-ledger.md all still identify execution as the missing follow-up after the already-implemented read-only compare and preflight slice.
  • Why not local: A page-local mutation button without a shared run contract would bypass the current compare truth, safety gates, audit seams, and Monitoring continuity.
  • Approval class: Core Enterprise
  • Red flags triggered: New mutating action, new queued run type, new write bridge over an existing read-only workflow. Defense: the slice stays on one compare page, one target tenant, one run type, zero new tables, and existing provider write seams.
  • Score: Nutzen: 2 | Dringlichkeit: 2 | Scope: 1 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 2 | Gesamt: 10/12
  • Decision: approve

Spec Scope Fields (mandatory)

  • Scope: canonical-view
  • Primary Routes:
    • existing canonical /admin/cross-tenant-compare page for selection, preflight review, and execution confirmation
    • existing /admin/tenants registry or portfolio-triage launch surfaces as the compare entrypoint and return context
    • existing Monitoring operation-run detail flow as the canonical follow-up after a promotion run is queued
  • Data Ownership:
    • source-of-truth remains the current compare preview, preflight result, source-tenant PolicyVersion or equivalent captured content, and target-tenant inventory or restore truth
    • runtime truth remains on OperationRun, current audit logs, and existing provider-write artifacts; no CrossTenantPromotionDraft, compare snapshot, or promotion-plan table is introduced
    • any execution context must live in OperationRun.context, OperationRun.summary_counts, and audit metadata only
  • RBAC:
    • workspace and tenant scoping stay deny-as-not-found first for out-of-scope actors or tenants
    • compare viewing keeps the existing 043 requirements: workspace baselines view plus tenant view on both source and target
    • execution requires the compare-view permissions plus Capabilities::WORKSPACE_BASELINES_MANAGE on the workspace and Capabilities::TENANT_MANAGE on the target tenant
    • source-tenant access stays read-only (Capabilities::TENANT_VIEW); the mutation boundary is the target tenant only
    • members who can view compare but cannot execute still see the execution affordance only where the page already stays decision-oriented, and that affordance must be disabled with explicit permission guidance while forced execution attempts return 403
    • no new promotion-specific capability family may be introduced in v1

For canonical-view specs, the spec MUST define:

  • Default filter behavior when tenant-context is active: registry and portfolio launches continue to prefill the launched tenant as the target tenant, preserve the return-state token, and keep the source tenant intentionally chosen by the operator unless the current exact-two launch path already supplies both tenants.
  • Explicit entitlement checks preventing cross-tenant leakage: the page must re-resolve workspace membership, source tenant scope, target tenant scope, and execution capability before preflight or execution logic runs. Any inaccessible tenant input is treated as not found, and no OperationRun may be created from inaccessible or stale selection input.

Cross-Cutting / Shared Pattern Reuse (mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write N/A - no shared interaction family touched)

  • Cross-cutting feature?: yes
  • Interaction class(es): compare-page header actions, confirmation modal copy, queued start notifications, Monitoring links, run status messaging, audit metadata, and return-state continuity
  • Systems touched: CrossTenantComparePage, tenant-registry launch context, CrossTenantCompareSelection, CrossTenantComparePreviewBuilder, CrossTenantPromotionPreflight, OperationRunService, OperationCatalog, OperationRunType, OperationRunLinks, OperationUxPresenter, ProviderOperationStartResultPresenter, OpsUxBrowserEvents, WorkspaceAuditLogger, AuditActionId, OperationalControlCatalog, and the current policy-version or restore write seam
  • Existing pattern(s) to extend: canonical compare page, current portfolio launch and return-state contract, shared OperationRun start UX, and existing Monitoring deep-link semantics
  • Shared contract / presenter / builder / renderer to reuse: CanonicalNavigationContext, WorkspaceUiEnforcement, OperationRunService, OperationRunLinks, OperationUxPresenter, ProviderOperationStartResultPresenter, OpsUxBrowserEvents, and the existing compare preview and preflight builders
  • Operation-registry distinction: any ProviderOperationRegistry update in v1 is app-level operation-vocabulary wiring only, and only if the chosen shared start-result seam requires it. It is not Laravel or Filament service-provider registration.
  • Why the existing shared path is sufficient or insufficient: compare and preflight already solve the selection and blocked-reason truth. They are insufficient for v1 execution because they do not produce a queued run, start/result UX, or target mutation plan. The current restore and policy-version seams solve provider write behavior and run lifecycle, but they are tenant-owned and cannot be pointed at a foreign tenant without a bounded promotion bridge.
  • Allowed deviation and why: none. The feature must extend the current compare page and shared run UX instead of creating a second promotion console or a promotion-specific dashboard.
  • Consistency impact: the terms source tenant, target tenant, promotion preflight, Execute promotion, ready, blocked, manual mapping, and Open operation must stay consistent across compare copy, confirmation copy, audit summaries, notifications, and Monitoring labels.
  • Review focus: reviewers must block any persisted draft entity, direct Graph write from the page action, or local notification/run-link flow that bypasses the shared OperationRun UX contract.
  • Touches OperationRun start/completion/link UX?: yes
  • Shared OperationRun UX contract/layer reused: OperationRunService, OperationRunLinks, OperationUxPresenter, ProviderOperationStartResultPresenter, and OpsUxBrowserEvents
  • Delegated start/completion UX behaviors: queued toast, deduped-or-already-running messaging, blocked or scope-busy result messaging, canonical Monitoring link generation, run-enqueued browser event dispatch, and normal terminal notification handling stay delegated to the shared run UX layer
  • Local surface-owned behavior that remains: compare selection state, preflight summary, excluded-subject explanation, and confirmation-modal wording remain owned by CrossTenantComparePage
  • Queued DB-notification policy: no new queued-only database-notification policy is introduced; v1 relies on the compare-page start result plus the existing terminal notification path
  • Terminal notification path: keep the existing initiator-aware OperationRun completion path
  • Exception required?: none

Provider Boundary / Platform Core Check (mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write N/A - no shared provider/platform boundary touched)

  • Shared provider/platform boundary touched?: yes
  • Boundary classification: mixed
  • Seams affected: compare selection to execution planning, source content resolution, target mutation bridge, operation vocabulary, and provider-backed write delegation
  • Neutral platform terms preserved or introduced: source tenant, target tenant, governed subject, promotion execution, ready subject, blocked reason, and manual mapping required
  • Provider-specific semantics retained and why: Microsoft-first policy types, assignment semantics, scope tags, and provider payload translation remain inside the current policy-version, restore, and provider write seams because the repo currently has one real provider domain
  • Why this does not deepen provider coupling accidentally: the page contract stays anchored on compare and preflight truth, and the queued mutation delegates into existing provider-write paths instead of exposing Graph-specific inputs or raw payload editing in the page surface
  • Follow-up path: multi-provider promotion remains a separate follow-up if it ever becomes current-release truth

UI / Surface Guardrail Impact (mandatory when operator-facing surfaces are changed; otherwise write N/A)

Surface / Change Operator-facing surface change? Native vs Custom Shared-Family Relevance State Layers Touched Exception Needed? Low-Impact / N/A Note
Canonical cross-tenant compare page yes Native Filament page plus shared compare and ops-ux primitives compare summary, confirmation modal, run-start UX, Monitoring link continuity page, query state, preflight state, action state, confirmation modal state no Reuses the current compare page; no second promotion surface is allowed
Tenant registry / portfolio launch action no N/A current launch context only none beyond existing deep-link state no Launch behavior remains inherited from Spec 043
Monitoring operation-run detail no N/A existing shared operation-run viewer none beyond normal new-type rendering no v1 reuses the existing Monitoring viewer rather than introducing a promotion-specific detail screen

Decision-First Surface Role (mandatory when operator-facing surfaces are changed)

Surface Decision Role Human-in-the-loop Moment Immediately Visible for First Decision On-Demand Detail / Evidence Why This Is Primary or Why Not Workflow Alignment Attention-load Reduction
Canonical cross-tenant compare page Primary Decision Surface Operator decides whether the ready portion of the current source selection should mutate the target tenant now source and target summary, ready or blocked counts, exclusion counts, mutation scope, and the single next action subject-level execution plan, mapping gaps, target exclusions, source and target drill-down links, and current run link after queueing Primary because the compare page already owns the trusted preflight truth and can keep the execution decision tied to that truth Moves directly from compare to confirmation to queued Monitoring handoff without a second workspace Replaces off-platform handoff and manual note-taking with one bounded action path

Audience-Aware Disclosure (mandatory when operator-facing surfaces are changed)

Surface Audience Modes In Scope Decision-First Default-Visible Content Operator Diagnostics Support / Raw Evidence One Dominant Next Action Hidden / Gated By Default Duplicate-Truth Prevention
Canonical cross-tenant compare page operator-MSP source and target summary, preflight counts, excluded-subject totals, mutation scope, and current run link if a run exists subject-level ready plan, mapping gaps, evidence freshness, and target-safe exclusions raw provider payloads and deep provider diagnostics stay behind existing tenant, inventory, or Monitoring detail surfaces Generate promotion preflight before eligibility, then Execute promotion after a current executable preflight exists raw JSON, provider IDs, worker internals, and low-level payload diffs the compare page owns readiness truth once; the confirmation modal restates only the mutation scope, and Monitoring owns run progress after queueing

UI/UX Surface Classification (mandatory when operator-facing surfaces are changed)

Surface Action Surface Class Surface Type Likely Next Operator Action Primary Inspect/Open Model Row Click Secondary Actions Placement Destructive Actions Placement Canonical Collection Route Canonical Detail Route Scope Signals Canonical Noun Critical Truth Visible by Default Exception Type / Justification
Canonical cross-tenant compare page Utility / Workspace Decision Queued execution decision Execute promotion explicit selectors plus focused compare or preflight panels and confirmation modal forbidden open-source, open-target, return, and open-operation links stay secondary none; Execute promotion is mutating but not destructive and must still use confirmation /admin/cross-tenant-compare same page with shareable query state and current run handoff workspace context plus source and target tenant chips Cross-tenant compare whether the ready part of the current source selection can be promoted now and what will be excluded none

Operator Surface Contract (mandatory when operator-facing surfaces are changed)

Surface Primary Persona Decision / Operator Action Supported Surface Type Primary Operator Question Default-visible Information Diagnostics-only Information Status Dimensions Used Mutation Scope Primary Actions Dangerous Actions
Canonical cross-tenant compare page Workspace operator / MSP operator Decide whether to queue a bounded promotion run against the target tenant Canonical decision page Can I safely apply the ready part of this source selection to the target tenant now, and what will be left out? source and target summary, ready or blocked counts, manual-mapping and blocked totals, mutation scope, confirmation summary, and latest run handoff subject-level execution plan, mapping gaps, source and target drill-downs, and follow-up hints compare readiness, execution availability, and run state Microsoft tenant target only Generate promotion preflight, Execute promotion, Open operation, Open source tenant, Open target tenant Execute promotion (requires confirmation)

Proportionality Review (mandatory when structural complexity is introduced)

  • New source of truth?: no
  • New persisted entity/table/artifact?: no
  • New abstraction?: yes - one bounded promotion execution planner or bridge plus one queued promotion job
  • New enum/state/reason family?: yes - one new canonical operation type and one operational control key, but no new persisted lifecycle family or draft state family
  • New cross-domain UI framework/taxonomy?: no
  • Current operator problem: compare and preflight prove readiness, but operators still cannot execute the bounded next step or observe the result from the same truth.
  • Existing structure is insufficient because: the current compare slice stops before any OperationRun, and the current RestoreService::executeFromPolicyVersion() explicitly rejects foreign-tenant versions, so the execution path cannot be implemented as a naive direct call.
  • Narrowest correct implementation: derive a ready-only execution plan from the current compare and preflight truth, queue one target-tenant-scoped promotion.execute run, and translate source content into target-safe write inputs through an existing provider-write seam without introducing draft persistence.
  • Ownership cost: maintain one new operation vocabulary entry, one bounded execution bridge, one queued worker, small audit metadata expansion, and focused tests.
  • Alternative intentionally rejected: persisted promotion drafts, scheduled promotions, approval chains, and cross-tenant batch execution are intentionally rejected because they import new truth and operator workflow before the bounded execution seam is proven.
  • Release truth: current-release workflow gap, not a future-state platform ambition

Compatibility posture

This feature assumes a pre-production environment.

Backward compatibility, migration shims, and legacy workflow preservation remain out of scope unless the implementation discovers a concrete repo-owned compatibility contract that the current spec missed.

Canonical replacement is preferred over parallel promotion workflows.

Testing / Lane / Runtime Impact (mandatory for runtime behavior changes)

  • Test purpose / classification: Unit, Feature, Browser
  • Validation lane(s): fast-feedback, confidence, browser
  • Why this classification and these lanes are sufficient: unit coverage proves ready-only execution planning and no-draft behavior, focused feature coverage proves page action, authorization, audit, and Monitoring handoff, and one bounded browser smoke proves the confirmation modal and compare-to-operation handoff on the real Filament surface.
  • New or expanded test families: tests/Unit/Support/PortfolioCompare/, tests/Feature/PortfolioCompare/, and one new bounded tests/Browser/PortfolioCompare/ smoke file
  • Fixture / helper cost impact: moderate; reuse the existing portfolio-compare fixtures, current workspace and tenant setup, and current OperationRun assertions rather than introducing a new provider or browser fixture domain
  • Heavy-family visibility / justification: one new browser smoke file is justified because the feature adds a confirmation modal and Monitoring handoff on a live Filament page
  • Special surface test profile: standard-native-filament
  • Standard-native relief or required special coverage: ordinary feature coverage is sufficient for the compare and run-start contract, but the final compare-page handoff to Monitoring must be proven once in the browser
  • Reviewer handoff: reviewers must confirm the slice stays on one compare page, one run type, zero new draft tables, and shared run UX only
  • Budget / baseline / trend impact: low to moderate; one new browser smoke file and one new operation type only
  • Escalation needed: none
  • Active feature PR close-out entry: Smoke Coverage
  • Planned validation commands:
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/PortfolioCompare/CrossTenantPromotionExecutionPlannerTest.php
    • 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
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/PortfolioCompare/CrossTenantPromotionExecutionSmokeTest.php
    • export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent

Scope Boundaries

In Scope

  • one Execute promotion action on the canonical compare page after a current preflight exists
  • one explicit confirmation modal that names the source tenant, target tenant, ready counts, excluded counts, and mutation scope
  • one queued promotion.execute OperationRun
  • one bounded execution planner or bridge that translates ready subjects into target-safe write inputs
  • one truthful Monitoring handoff and run-link continuity
  • start and terminal audit metadata for the promotion execution path
  • compare-page continuity after queueing, including preserved source, target, and return-state context

Non-Goals

  • persisted compare snapshots or promotion-draft tables
  • scheduled or recurring promotion execution
  • approval workflows or multi-actor sign-off
  • rollback or undo workflows
  • multi-target or batch promotion
  • mapping automation for manual-mapping-required subjects
  • customer-facing promotion surfaces
  • cross-workspace execution
  • multi-provider execution frameworks

Assumptions

  • the current compare and preflight contracts expose enough stable subject identity to resolve a bounded ready-only execution plan
  • the current provider-write seams can accept a target-safe execution payload once the source content is normalized through a bounded bridge
  • the existing Monitoring viewer can represent the new run type without a dedicated promotion detail resource
  • current queue workers already provide the runtime model needed for one more OperationRun-backed promotion job

Risks

  • some subjects marked ready by preflight may still fail at execution time because the current target write seam discovers provider constraints later than the read-only preflight can
  • the promotion bridge may be tempted to persist a new draft or snapshot entity; that must be rejected unless a separate follow-up spec is created
  • run-summary truth can drift if the implementation invents non-canonical summary keys instead of staying on the current OperationSummaryKeys set
  • a future implementation could try to broaden the slice into approval, rollback, or batch execution; that is out of scope for this spec

Follow-up Candidates

  • manual mapping workflow for manual_mapping_required subjects
  • portfolio-level batch promotion across many targets
  • approval or sign-off gating before execution
  • rollback or replay workflow after a promotion run completes

User Scenarios & Testing (mandatory)

User Story 1 - Queue one bounded promotion from the current preflight (Priority: P1)

As a workspace operator, I want to confirm and queue one bounded promotion from the current compare and preflight context so I can apply only the ready subjects to the target tenant without manual off-platform execution.

Why this priority: This is the core value gap left by Spec 043. Without queueable execution, compare remains advisory only.

Independent Test: Open the compare page with an executable preflight, confirm the action, and verify that one promotion.execute run is queued with ready subjects only.

Acceptance Scenarios:

  1. Given the current preflight contains a mix of ready, blocked, and manual_mapping_required subjects, When the operator confirms Execute promotion, Then only the ready subjects enter the queued run context and the excluded subjects remain visible on the compare page.
  2. Given the current selection and preflight produce no ready subjects, When the operator tries to execute promotion, Then the action is blocked and no OperationRun is created.
  3. Given an active run already exists for the same source, target, subject scope, and executable plan, When the operator tries to execute again, Then the shared start UX dedupes or reuses the current run instead of creating a second active run.

User Story 2 - Follow the queued promotion through Monitoring with truthful result summary (Priority: P1)

As a workspace operator, I want a canonical run link and truthful result summary after I queue a promotion so I can monitor completion and know what happened without leaving the existing Monitoring path.

Why this priority: Execution is unsafe if the operator cannot observe start, progress, and terminal outcome on the existing shared Monitoring path.

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.

Acceptance Scenarios:

  1. Given a promotion run is successfully queued, When the compare page receives the start result, Then the operator sees the shared queued feedback and one canonical Open operation link.
  2. Given the promotion run reaches a terminal state, When the operator opens the Monitoring detail, Then the run summary clearly distinguishes processed, succeeded, failed, and skipped work using the shared summary-key vocabulary.
  3. Given the run start is blocked by operational control, legitimacy, or target-scoped gating, When the operator attempts execution, Then they receive the shared blocked feedback and no target mutation begins.

User Story 3 - Preserve portfolio context and execution safety boundaries (Priority: P2)

As a workspace operator, I want the execution path to preserve my compare and return-state context while still enforcing target-safe capability and control boundaries so the workflow stays usable and safe inside the portfolio review loop.

Why this priority: The workflow loses value if the operator must rebuild compare context after queueing or if the page hides the reasons why execution is unavailable.

Independent Test: Launch compare from the tenant registry, queue or attempt to queue promotion, and verify that source, target, return-state, and safety boundaries all remain intact.

Acceptance Scenarios:

  1. Given the operator launched compare from a registry or portfolio context, When they queue a promotion, Then the compare page preserves the source tenant, target tenant, governed-subject filters, and return-state continuity.
  2. Given the operator can view compare but lacks target-tenant manage or workspace baseline-manage access, When they reach an otherwise executable compare state, Then execution stays visible only as a disabled safety-gated affordance and any forced execution attempt returns 403.
  3. Given the source or target tenant becomes inaccessible or stale between preflight and confirmation, When the operator attempts execution, Then the request is rejected and no OperationRun is created.

Edge Cases

  • source and target tenant are the same tenant: reject as invalid input and do not queue a run
  • preflight is stale because the compare selection changed after it was generated: require regeneration and do not queue a run
  • no ready subjects remain after current truth is re-evaluated at execution time: fail safe and do not queue or start target mutation
  • the existing provider-write seam cannot resolve a target-safe payload from the source subject: mark the item failed or skipped inside the run; do not invent a draft state family
  • operational control or legitimacy gate blocks promotion.execute: surface the shared blocked message and keep the compare state intact

Requirements (mandatory)

Functional Requirements

  • FR-001: The canonical /admin/cross-tenant-compare page must remain the only operator entrypoint for v1 promotion execution.
  • FR-002: Promotion execution must require a current compare preview and a current promotion preflight before queueing any target mutation.
  • FR-003: The page must expose exactly one dominant next action at a time: Generate promotion preflight before readiness exists, then Execute promotion once the current preflight is executable.
  • FR-004: Execute promotion must require explicit confirmation and must name the source tenant, target tenant, count of ready subjects, count of excluded subjects, and the target-only mutation scope.
  • FR-005: Only ready subjects from the current preflight may enter the queued execution plan; blocked and manual_mapping_required subjects must stay excluded from the run and visible to the operator.
  • FR-006: The execution path must create or reuse exactly one canonical OperationRun for the current executable plan, using one new canonical operation type for promotion execution.
  • FR-007: The feature must keep execution truth on existing OperationRun state, summary counts, and audit metadata only. No persisted promotion-draft, compare-snapshot, or approval entity may be added.
  • FR-008: The run-start path must reuse the shared OperationRun start UX contract for queued, deduped, blocked, and Monitoring-link behaviors.
  • FR-009: The implementation must not pretend that a source-tenant PolicyVersion belongs to the target tenant. Any bridge from source content to target mutation must preserve tenant-owned truth while still reusing existing provider-write semantics.
  • FR-010: Run summary counts must stay on canonical summary keys only. Promotion-specific meaning must be expressed through page or Monitoring copy, not a new summary-key family.
  • FR-011: The feature must record start and terminal audit events for promotion execution with source-tenant, target-tenant, selection, and outcome context.
  • FR-012: Compare and launch context must remain preserved after queueing, including source tenant, target tenant, governed-subject filters, and return-state payload.
  • FR-013: Execution authorization must require workspace baseline-manage and target-tenant manage in addition to the existing compare-view permissions.
  • FR-014: Filament must remain v5 on Livewire v4, and Laravel or Filament service-provider registration must remain unchanged in apps/platform/bootstrap/providers.php.
  • FR-015: No new panel, no new asset registration, no new Laravel or Filament service-provider registration work, and no new globally searchable resource may be introduced for this slice.

Key Entities (include if feature involves data)

  • Cross-tenant compare selection: existing derived scope of source tenant, target tenant, and governed-subject filters; remains read-only input truth.
  • Promotion preflight: existing derived readiness artifact grouping subjects into ready, blocked, and manual_mapping_required; becomes the only allowed execution source.
  • Promotion execution plan: new bounded in-memory or OperationRun.context representation of the ready-only mutation plan; not a persisted standalone entity.
  • Promotion execution run: one canonical OperationRun using the new operation type and existing Monitoring viewer.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: An authorized operator can move from current compare preflight to a queued promotion.execute run without leaving the canonical compare page.
  • SC-002: The compare page never queues blocked or manual-mapping-required subjects for target mutation.
  • SC-003: The queued run can be opened through the shared Monitoring path and exposes truthful processed, succeeded, failed, and skipped counts.
  • SC-004: The implementation ships without a persisted promotion-draft table, second promotion surface, or second queue family.