@php $preview = is_array($preview ?? null) ? $preview : null; $preflight = is_array($preflight ?? null) ? $preflight : null; $previewSummary = is_array($preview['summary'] ?? null) ? $preview['summary'] : []; $preflightSummary = is_array($preflight['summary'] ?? null) ? $preflight['summary'] : []; $blockedReasonCounts = is_array($preflight['blockedReasonCounts'] ?? null) ? $preflight['blockedReasonCounts'] : []; $sourceTenantName = data_get($preview, 'selection.sourceTenantName'); $targetTenantName = data_get($preview, 'selection.targetTenantName'); $selectedPolicyTypes = data_get($preview, 'selection.policyTypes', []); @endphp Compare one authorized source tenant to one authorized target tenant from a canonical workspace surface. Preview stays read only and promotion remains preflight only.
{{ $this->form }}
Shareable compare scope

Source tenant, target tenant, and governed-subject filters live on the URL so the same compare preview can be reopened or shared.

Run compare preview @if ($this->hasActiveSelection()) Clear selection @endif
@if (filled($selectionMessage))
{{ $selectionMessage }}
@endif @if ($preview === null)
Choose a source tenant and a target tenant to build a compare preview. The source and target must be different tenants inside the active workspace.
@endif
@if ($preview !== null) Decision-first summary of governed subjects. Raw payloads stay on the existing tenant and baseline surfaces.
Source tenant: {{ $sourceTenantName }} Target tenant: {{ $targetTenantName }} @foreach ($selectedPolicyTypes as $policyType) {{ $this->stateLabel($policyType) }} @endforeach
@if (filled($this->sourceTenantUrl())) Open source tenant @endif @if (filled($this->targetTenantUrl())) Open target tenant @endif

The preview groups governed subjects into reproducible compare states so you can decide whether the target is aligned, missing, blocked, or needs manual review.

@foreach (['match', 'different', 'missing', 'ambiguous', 'blocked', 'total'] as $state)
{{ $this->stateLabel($state) }}
{{ (int) ($previewSummary[$state] ?? 0) }}
@endforeach
Governed subject
Reasoning
Compare state
@foreach (data_get($preview, 'subjects', []) as $subject)
{{ data_get($subject, 'displayName') }}
{{ $this->stateLabel((string) data_get($subject, 'policyType', 'unknown')) }} @if (filled(data_get($subject, 'subjectKey'))) {{ data_get($subject, 'subjectKey') }} @endif
@forelse (data_get($subject, 'reasonCodes', []) as $reasonCode) {{ $this->reasonLabel((string) $reasonCode) }} @empty No blocking reason. @endforelse
{{ $this->stateLabel((string) data_get($subject, 'state', 'unknown')) }}
@endforeach
@endif @if ($preflight !== null) Read-only readiness view. No target mutation, queue dispatch, or operation run is created in this slice.
@foreach (['ready', 'blocked', 'manual_mapping_required', 'total'] as $state)
{{ $this->stateLabel($state) }}
{{ (int) ($preflightSummary[$state] ?? 0) }}
@endforeach
@if ($blockedReasonCounts !== [])
Top blocked reasons
@foreach ($blockedReasonCounts as $reasonCode => $count) {{ $this->reasonLabel((string) $reasonCode) }}: {{ (int) $count }} @endforeach
@endif
@foreach (['ready', 'manual_mapping_required', 'blocked'] as $bucket)
{{ $this->stateLabel($bucket) }}
{{ count(data_get($preflight, 'buckets.'.$bucket, [])) }}
@forelse (data_get($preflight, 'buckets.'.$bucket, []) as $subject)
{{ data_get($subject, 'displayName') }}
@if (data_get($subject, 'preflight.reasonLabels', []) !== [])
@foreach (data_get($subject, 'preflight.reasonLabels', []) as $reasonLabel) {{ $reasonLabel }} @endforeach
@endif
@empty
No governed subjects in this bucket.
@endforelse
@endforeach
@endif