'b', 'status' => 'fail', 'blocking' => false, 'reason_code' => 'missing_configuration', 'severity' => 'high'], ['key' => 'a', 'status' => 'pass', 'blocking' => false, 'reason_code' => 'ok', 'severity' => 'info'], ]; $checksB = [ ['key' => 'a', 'status' => 'pass', 'blocking' => false, 'reason_code' => 'ok', 'severity' => 'info'], ['key' => 'b', 'status' => 'fail', 'blocking' => false, 'reason_code' => 'missing_configuration', 'severity' => 'high'], ]; expect(VerificationReportFingerprint::forChecks($checksA)) ->toBe(VerificationReportFingerprint::forChecks($checksB)); }); it('treats missing severity as empty string for fingerprint determinism', function (): void { $withMissingSeverity = [ ['key' => 'a', 'status' => 'fail', 'blocking' => true, 'reason_code' => 'permission_denied'], ]; $withEmptySeverity = [ ['key' => 'a', 'status' => 'fail', 'blocking' => true, 'reason_code' => 'permission_denied', 'severity' => ''], ]; expect(VerificationReportFingerprint::forChecks($withMissingSeverity)) ->toBe(VerificationReportFingerprint::forChecks($withEmptySeverity)); }); it('treats severity-only changes as different fingerprints (missing != info)', function (): void { $missingSeverity = [ ['key' => 'a', 'status' => 'fail', 'blocking' => false, 'reason_code' => 'unknown_error'], ]; $infoSeverity = [ ['key' => 'a', 'status' => 'fail', 'blocking' => false, 'reason_code' => 'unknown_error', 'severity' => 'info'], ]; expect(VerificationReportFingerprint::forChecks($missingSeverity)) ->not->toBe(VerificationReportFingerprint::forChecks($infoSeverity)); });