syncDefaults(); [$user, $environment] = createMinimalUserWithTenant(role: 'owner'); $connection = ProviderConnection::factory()->withCredential()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), ]); $resourceType = spec422PromotionResourceType($canonicalType); $resource = TenantConfigurationResource::factory()->create([ 'workspace_id' => (int) $environment->workspace_id, 'managed_environment_id' => (int) $environment->getKey(), 'provider_connection_id' => (int) $connection->getKey(), 'resource_type_id' => (int) $resourceType->getKey(), 'canonical_type' => $canonicalType, 'canonical_resource_key' => $canonicalType.':provider_external_id:spec422-promotion', 'canonical_key_kind' => CanonicalKeyKind::ProviderExternalId->value, 'source_resource_id' => 'spec422-promotion', 'source_display_name' => 'Spec422 promotion '.$canonicalType, 'source_class' => SourceClass::Tcm->value, 'latest_evidence_state' => EvidenceState::ContentBacked->value, 'latest_identity_state' => IdentityState::Stable->value, 'latest_claim_state' => ClaimState::InternalOnly->value, ]); $run = OperationRun::factory()->withUser($user)->forTenant($environment)->create([ 'type' => OperationRunType::TenantConfigurationCapture->value, 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Succeeded->value, ]); $evidence = app(CoverageEvidenceWriter::class)->append( resource: $resource, resourceType: $resourceType, providerConnection: $connection, operationRun: $run, decision: new CoverageSourceContractDecision( canonicalType: $canonicalType, outcome: CaptureOutcome::Captured, contractKey: 'spec422.synthetic.'.$canonicalType, sourceEndpoint: '/spec422/synthetic/'.$canonicalType, ), rawPayload: $payload, normalizedPayload: $payload, payloadHash: hash('sha256', json_encode($payload, JSON_THROW_ON_ERROR)), ); expect($evidence)->toBeInstanceOf(TenantConfigurationResourceEvidence::class) ->and($evidence->coverage_level)->toBe(CoverageLevel::Renderable) ->and($resource->fresh()->latest_evidence_state)->toBe(EvidenceState::ContentBacked); })->with([ 'transportRule' => ['transportRule', ['DisplayName' => 'Rule', 'Enabled' => true, 'Actions' => ['RedirectMessageTo' => ['security@example.com']]]], 'acceptedDomain' => ['acceptedDomain', ['DomainName' => 'contoso.com', 'DomainType' => 'Authoritative', 'IsDefault' => true]], 'appPermissionPolicy' => ['appPermissionPolicy', ['DisplayName' => 'Policy', 'AllowAppList' => [['DisplayName' => 'Planner', 'AppId' => 'planner-app']]]], 'meetingPolicy' => ['meetingPolicy', ['DisplayName' => 'Meeting', 'AllowTranscription' => true]], ]); it('Spec422 leaves deferred Exchange and Teams types unpromoted without content-backed evidence', function (): void { app(ResourceTypeRegistry::class)->syncDefaults(); $resourceTypes = TenantConfigurationResourceType::query() ->whereIn('canonical_type', [ 'remoteDomain', 'organizationConfig', 'sharedMailbox', 'mailboxPlan', 'appSetupPolicy', 'messagingPolicy', 'teamsUpdateManagementPolicy', 'voiceRoute', ]) ->get() ->keyBy('canonical_type'); expect($resourceTypes)->toHaveCount(8); foreach ($resourceTypes as $resourceType) { expect($resourceType->default_coverage_level)->toBe(CoverageLevel::Detected) ->and($resourceType->default_evidence_state)->toBe(EvidenceState::NotCaptured) ->and($resourceType->allows_certified_claims)->toBeFalse(); } }); function spec422PromotionResourceType(string $canonicalType): TenantConfigurationResourceType { return TenantConfigurationResourceType::query() ->where('canonical_type', $canonicalType) ->where('source_class', SourceClass::Tcm->value) ->firstOrFail(); }