for($tenant)->create(); $exception = FindingException::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'finding_id' => (int) $finding->getKey(), 'requested_by_user_id' => (int) $user->getKey(), 'owner_user_id' => (int) $user->getKey(), 'status' => FindingException::STATUS_PENDING, 'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT, 'request_reason' => 'Temporary exception request', 'requested_at' => now(), 'review_due_at' => now()->addWeek(), 'evidence_summary' => ['reference_count' => 0], ]); $decision = $exception->decisions()->create([ 'tenant_id' => (int) $tenant->getKey(), 'actor_user_id' => (int) $user->getKey(), 'decision_type' => FindingExceptionDecision::TYPE_REQUESTED, 'reason' => 'Temporary exception request', 'metadata' => [], 'decided_at' => now(), ]); $exception->forceFill(['current_decision_id' => (int) $decision->getKey()])->save(); expect($exception->fresh()?->finding)->toBeInstanceOf(Finding::class) ->and($exception->fresh()?->decisions)->toHaveCount(1) ->and($exception->fresh()?->currentDecision)->toBeInstanceOf(FindingExceptionDecision::class); }); it('keeps decision rows append only', function (): void { [$user, $tenant] = createUserWithTenant(role: 'owner'); $finding = Finding::factory()->for($tenant)->create(); $exception = FindingException::query()->create([ 'tenant_id' => (int) $tenant->getKey(), 'finding_id' => (int) $finding->getKey(), 'requested_by_user_id' => (int) $user->getKey(), 'owner_user_id' => (int) $user->getKey(), 'status' => FindingException::STATUS_PENDING, 'current_validity_state' => FindingException::VALIDITY_MISSING_SUPPORT, 'request_reason' => 'Temporary exception request', 'requested_at' => now(), 'review_due_at' => now()->addWeek(), 'evidence_summary' => ['reference_count' => 0], ]); $decision = $exception->decisions()->create([ 'tenant_id' => (int) $tenant->getKey(), 'actor_user_id' => (int) $user->getKey(), 'decision_type' => FindingExceptionDecision::TYPE_REQUESTED, 'reason' => 'Temporary exception request', 'metadata' => [], 'decided_at' => now(), ]); expect(fn () => $decision->update(['reason' => 'Changed'])) ->toThrow(LogicException::class, 'Finding exception decisions are append-only.'); });