|null $recoveryEvidence * @return array{ * concern_family: string, * concern_state: string, * fingerprint: string, * snapshot: array{ * concernFamily: string, * concernState: string, * reasonCode: ?string, * severityKey: ?string, * supportingKey: ?string * } * }|null */ public function forConcernFamily( string $concernFamily, ?TenantBackupHealthAssessment $backupHealth, ?array $recoveryEvidence, ): ?array { return match ($concernFamily) { PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH => $this->forBackupHealth($backupHealth), PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE => $this->forRecoveryEvidence($recoveryEvidence), default => null, }; } /** * @return array{ * concern_family: string, * concern_state: string, * fingerprint: string, * snapshot: array{ * concernFamily: string, * concernState: string, * reasonCode: ?string, * severityKey: ?string, * supportingKey: ?string * } * }|null */ public function forBackupHealth(?TenantBackupHealthAssessment $assessment): ?array { if (! $assessment instanceof TenantBackupHealthAssessment) { return null; } if (! in_array($assessment->posture, [ TenantBackupHealthAssessment::POSTURE_ABSENT, TenantBackupHealthAssessment::POSTURE_STALE, TenantBackupHealthAssessment::POSTURE_DEGRADED, ], true)) { return null; } $snapshot = [ 'concernFamily' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, 'concernState' => $assessment->posture, 'reasonCode' => $assessment->primaryReason, 'severityKey' => $assessment->primaryReason, 'supportingKey' => $assessment->primaryReason, ]; return [ 'concern_family' => PortfolioArrivalContextToken::FAMILY_BACKUP_HEALTH, 'concern_state' => $assessment->posture, 'fingerprint' => $this->hash($snapshot), 'snapshot' => $snapshot, ]; } /** * @param array|null $recoveryEvidence * @return array{ * concern_family: string, * concern_state: string, * fingerprint: string, * snapshot: array{ * concernFamily: string, * concernState: string, * reasonCode: ?string, * severityKey: ?string, * supportingKey: ?string * } * }|null */ public function forRecoveryEvidence(?array $recoveryEvidence): ?array { $state = is_array($recoveryEvidence) ? TenantRecoveryTriagePresentation::recoveryEvidenceState($recoveryEvidence) : null; if (! in_array($state, [ TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_WEAKENED, TenantRecoveryTriagePresentation::RECOVERY_EVIDENCE_UNVALIDATED, ], true)) { return null; } $reason = is_string($recoveryEvidence['reason'] ?? null) ? $recoveryEvidence['reason'] : null; $supportingKey = is_string($recoveryEvidence['latest_relevant_attention_state'] ?? null) ? $recoveryEvidence['latest_relevant_attention_state'] : $reason; $snapshot = [ 'concernFamily' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE, 'concernState' => $state, 'reasonCode' => $reason, 'severityKey' => $reason, 'supportingKey' => $supportingKey, ]; return [ 'concern_family' => PortfolioArrivalContextToken::FAMILY_RECOVERY_EVIDENCE, 'concern_state' => $state, 'fingerprint' => $this->hash($snapshot), 'snapshot' => $snapshot, ]; } /** * @param array{ * concernFamily: string, * concernState: string, * reasonCode: ?string, * severityKey: ?string, * supportingKey: ?string * } $snapshot */ private function hash(array $snapshot): string { try { return hash('sha256', json_encode($snapshot, JSON_THROW_ON_ERROR)); } catch (JsonException) { return hash('sha256', implode(':', array_map( static fn (mixed $value): string => is_scalar($value) || $value === null ? (string) $value : '', $snapshot, ))); } } }