create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $snapshot = EvidenceSnapshot::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'status' => EvidenceSnapshotStatus::Active->value, 'completeness_state' => EvidenceCompletenessState::Complete->value, 'summary' => [ 'dimension_count' => 5, 'missing_dimensions' => 0, 'stale_dimensions' => 0, ], 'generated_at' => now(), ]); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListEvidenceSnapshots::class) ->callTableAction('expire', $snapshot); $snapshot->refresh(); $truth = app(ArtifactTruthPresenter::class)->forEvidenceSnapshot($snapshot); expect((string) $snapshot->status)->toBe(EvidenceSnapshotStatus::Expired->value) ->and($truth->freshnessState)->toBe('stale') ->and(app(RequestScopedDerivedStateStore::class)->countStored( DerivedStateFamily::ArtifactTruth, EvidenceSnapshot::class, (string) $snapshot->getKey(), 'evidence_snapshot', ))->toBe(1); }); it('refreshes review-pack artifact truth after expiring a pack in the same request', function (): void { $tenant = \App\Models\Tenant::factory()->create(); [$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner'); $pack = ReviewPack::factory()->ready()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'initiated_by_user_id' => (int) $user->getKey(), 'file_disk' => 'exports', 'file_path' => 'review-packs/freshness.zip', ]); \Illuminate\Support\Facades\Storage::fake('exports'); \Illuminate\Support\Facades\Storage::disk('exports')->put('review-packs/freshness.zip', 'PK-fake'); Filament::setTenant($tenant, true); Livewire::actingAs($user) ->test(ListReviewPacks::class) ->callTableAction('expire', $pack); $pack->refresh(); $truth = app(ArtifactTruthPresenter::class)->forReviewPack($pack); expect((string) $pack->status)->toBe(ReviewPackStatus::Expired->value) ->and($truth->freshnessState)->toBe('stale') ->and(app(RequestScopedDerivedStateStore::class)->countStored( DerivedStateFamily::ArtifactTruth, ReviewPack::class, (string) $pack->getKey(), 'review_pack', ))->toBe(1); }); it('returns fresh operation guidance after run state changes within the same request', function (): void { $tenant = \App\Models\Tenant::factory()->create(); createUserWithTenant(tenant: $tenant, role: 'owner'); $run = OperationRun::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'workspace_id' => (int) $tenant->workspace_id, 'type' => 'inventory_sync', 'status' => OperationRunStatus::Queued->value, 'outcome' => OperationRunOutcome::Pending->value, ]); $queuedGuidance = OperationUxPresenter::surfaceGuidance($run); $run->update([ 'status' => OperationRunStatus::Completed->value, 'outcome' => OperationRunOutcome::Blocked->value, 'context' => [ 'reason_code' => 'missing_capability', 'execution_legitimacy' => [ 'reason_code' => 'missing_capability', ], ], 'failure_summary' => [[ 'reason_code' => 'missing_capability', 'message' => 'Missing capability prevented execution.', ]], ]); $staleGuidance = OperationUxPresenter::surfaceGuidance($run->fresh()); $freshGuidance = OperationUxPresenter::surfaceGuidanceFresh($run->fresh()); expect($staleGuidance)->toBe($queuedGuidance) ->and($freshGuidance)->not->toBe($staleGuidance) ->and($freshGuidance)->toBe('Review the blocked prerequisite before retrying.') ->and(app(RequestScopedDerivedStateStore::class)->countStored( DerivedStateFamily::OperationUxGuidance, OperationRun::class, (string) $run->getKey(), 'surface_guidance', ))->toBe(1); }); it('returns fresh related navigation after a finding changes its related policy version', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $this->actingAs($user); Filament::setTenant($tenant, true); $policy = Policy::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), ]); $versionA = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'version_number' => 1, ]); $versionB = PolicyVersion::factory()->create([ 'tenant_id' => (int) $tenant->getKey(), 'policy_id' => (int) $policy->getKey(), 'version_number' => 2, ]); $finding = Finding::factory()->for($tenant)->create([ 'evidence_jsonb' => [ 'current' => [ 'policy_version_id' => (int) $versionA->getKey(), ], ], ]); $resolver = app(RelatedNavigationResolver::class); $firstEntries = collect($resolver->detailEntries(CrossResourceNavigationMatrix::SOURCE_FINDING, $finding)); $first = $firstEntries->firstWhere('key', 'current_policy_version'); $finding->update([ 'evidence_jsonb' => [ 'current' => [ 'policy_version_id' => (int) $versionB->getKey(), ], ], ]); $staleEntries = collect($resolver->detailEntries(CrossResourceNavigationMatrix::SOURCE_FINDING, $finding->fresh())); $freshEntries = collect($resolver->detailEntriesFresh(CrossResourceNavigationMatrix::SOURCE_FINDING, $finding->fresh())); $stale = $staleEntries->firstWhere('key', 'current_policy_version'); $fresh = $freshEntries->firstWhere('key', 'current_policy_version'); expect($first['targetUrl'] ?? null)->toBe($stale['targetUrl'] ?? null) ->and($fresh['targetUrl'] ?? null)->not->toBe($stale['targetUrl'] ?? null) ->and($fresh['targetUrl'] ?? null)->toContain((string) $versionB->getKey()) ->and(app(RequestScopedDerivedStateStore::class)->countStored( DerivedStateFamily::RelatedNavigationDetail, Finding::class, (string) $finding->getKey(), CrossResourceNavigationMatrix::SOURCE_FINDING, ))->toBe(1); });