[ 'version' => 1, 'subject_outcomes' => [ BaselineSubjectResolutionFixtures::semanticOutcome([ 'reason' => 'unresolved_duplicate_candidates', 'actionability' => 'binding_required', 'readiness_impact' => 'customer_blocker', 'subject' => [ 'subject_domain' => 'baseline', 'subject_class' => SubjectClass::PolicyBacked->value, 'subject_type_key' => 'deviceConfiguration', 'subject_key' => 'legacy-display-key', 'display_label' => 'Duplicate policy', 'candidate_descriptors' => [ $leftDescriptor->toArray(), $rightDescriptor->toArray(), ], ], ]), BaselineSubjectResolutionFixtures::semanticOutcome([ 'reason' => 'verified_no_drift', 'actionability' => 'none', 'readiness_impact' => 'no_impact', 'subject' => [ 'subject_type_key' => 'deviceConfiguration', 'subject_key' => 'resolved-subject', 'display_label' => 'Resolved subject', ], ]), ], ], ], status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::PartiallySucceeded->value, ); $rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [ 'operation_run_id' => (int) $run->getKey(), ]); expect($rows)->toHaveCount(1) ->and($rows[0]['reason'])->toBe('unresolved_duplicate_candidates') ->and($rows[0]['actionability'])->toBe('binding_required') ->and($rows[0]['candidate_count'])->toBe(2) ->and($rows[0]['decision_identity'])->toBeNull() ->and(collect($rows[0]['candidates'])->pluck('identity.provider_resource_id')->all()) ->toContain('candidate-left', 'candidate-right'); expect(app(BaselineSubjectResolutionQuery::class)->rows($tenant, [ 'operation_run_id' => (int) $run->getKey(), 'actionability' => 'binding_required', 'readiness_impact' => 'customer_blocker', 'reason' => 'unresolved_duplicate_candidates', 'resource_type' => 'deviceConfiguration', 'candidates' => 'yes', 'active_binding' => 'no', ]))->toHaveCount(1); $resolvedRows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [ 'operation_run_id' => (int) $run->getKey(), 'include_resolved' => true, ]); expect($resolvedRows)->toHaveCount(2); }); it('does not derive bindable candidates from display label matches alone', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); [$profile, $snapshot] = seedActiveBaselineForTenant($tenant); BaselineSubjectResolutionFixtures::inventoryCandidate( $tenant, ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-left'), 'Duplicate policy', ); BaselineSubjectResolutionFixtures::inventoryCandidate( $tenant, ResourceIdentity::providerResource('fake-provider', 'policy', 'candidate-right'), 'Duplicate policy', ); $run = seedBaselineCompareRun( tenant: $tenant, profile: $profile, snapshot: $snapshot, compareContext: [ 'result_semantics' => [ 'version' => 1, 'subject_outcomes' => [ BaselineSubjectResolutionFixtures::semanticOutcome([ 'reason' => 'unresolved_duplicate_candidates', 'actionability' => 'binding_required', 'readiness_impact' => 'customer_blocker', 'subject' => [ 'subject_domain' => 'baseline', 'subject_class' => SubjectClass::PolicyBacked->value, 'subject_type_key' => 'deviceConfiguration', 'subject_key' => 'legacy-display-key', 'display_label' => 'Duplicate policy', ], ]), ], ], ], status: OperationRunStatus::Completed->value, outcome: OperationRunOutcome::PartiallySucceeded->value, ); $rows = app(BaselineSubjectResolutionQuery::class)->rows($tenant, [ 'operation_run_id' => (int) $run->getKey(), ]); expect($rows)->toHaveCount(1) ->and($rows[0]['candidate_count'])->toBe(0) ->and($rows[0]['candidates'])->toBe([]); }); it('does not treat legacy evidence-gap payloads as authoritative subject decisions', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); [$profile, $snapshot] = seedActiveBaselineForTenant($tenant); $run = seedBaselineCompareRun($tenant, $profile, $snapshot, [ 'evidence_gaps' => [ 'count' => 1, 'by_reason' => ['unresolved_duplicate_candidates' => 1], 'subjects' => [[ 'policy_type' => 'deviceConfiguration', 'subject_key' => 'legacy-only', 'reason_code' => 'unresolved_duplicate_candidates', ]], ], ], outcome: OperationRunOutcome::PartiallySucceeded->value); $query = app(BaselineSubjectResolutionQuery::class); expect($query->rows($tenant, ['operation_run_id' => (int) $run->getKey()]))->toBe([]) ->and($query->summary($tenant, (int) $run->getKey())['legacy_payload_only'])->toBeTrue(); });