'array', 'metadata' => 'array', 'assignments' => 'array', 'scope_tags' => 'array', 'secret_fingerprints' => 'array', 'redaction_version' => 'integer', 'captured_at' => 'datetime', 'capture_purpose' => PolicyVersionCapturePurpose::class, ]; public function previous(): ?self { return $this->policy ? $this->policy ->versions() ->where('version_number', '<', $this->version_number) ->orderByDesc('version_number') ->first() : null; } public function tenant(): BelongsTo { return $this->belongsTo(Tenant::class); } public function policy(): BelongsTo { return $this->belongsTo(Policy::class); } public function operationRun(): BelongsTo { return $this->belongsTo(OperationRun::class); } public function baselineProfile(): BelongsTo { return $this->belongsTo(BaselineProfile::class); } public function snapshotSource(): ?string { $source = $this->metadata['source'] ?? $this->metadata['snapshot_source'] ?? null; return is_string($source) && trim($source) !== '' ? trim($source) : null; } /** * @return list */ public function warningMessages(): array { $warnings = $this->metadata['warnings'] ?? []; if (! is_array($warnings)) { return []; } return collect($warnings) ->filter(fn (mixed $warning): bool => is_string($warning) && trim($warning) !== '') ->map(fn (string $warning): string => trim($warning)) ->values() ->all(); } public function assignmentsFetchFailed(): bool { return (bool) ($this->metadata['assignments_fetch_failed'] ?? false); } public function hasOrphanedAssignments(): bool { return (bool) ($this->metadata['has_orphaned_assignments'] ?? false); } public function integrityWarning(): ?string { return RedactionIntegrity::noteForPolicyVersion($this); } public function hasCapturedPayload(): bool { return is_array($this->snapshot) && $this->snapshot !== []; } public function scopePruneEligible($query, int $days = 90) { return $query ->whereNull('deleted_at') ->where('captured_at', '<', now()->subDays($days)) ->whereRaw( 'policy_versions.version_number < (select max(pv2.version_number) from policy_versions pv2 where pv2.policy_id = policy_versions.policy_id and pv2.deleted_at is null)' ); } }