45 lines
1.9 KiB
PHP
45 lines
1.9 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Services;
|
|
|
|
/** A human approval must not silently override missing or blocking findings. */
|
|
final class VideoReviewReportValidator
|
|
{
|
|
public static function approvable(array $report): bool
|
|
{
|
|
$coverage = $report['coverage'] ?? null;
|
|
if (!is_array($coverage) || ($coverage['truncated'] ?? true) !== false ||
|
|
!array_key_exists('unprocessed_intervals', $coverage) || $coverage['unprocessed_intervals'] !== [] ||
|
|
!is_array($coverage['section_results'] ?? null) || $coverage['section_results'] === [] ||
|
|
!is_array($coverage['objective_results'] ?? null) || $coverage['objective_results'] === [] ||
|
|
($report['missing_inputs'] ?? null) !== [] || !is_array($report['issues'] ?? null)) {
|
|
return false;
|
|
}
|
|
foreach (['section_results', 'objective_results'] as $field) {
|
|
foreach ($coverage[$field] as $result) {
|
|
if (!is_array($result) || !in_array($result['status'] ?? null, ['covered', 'out_of_declared_scope'], true)) {
|
|
return false;
|
|
}
|
|
if (($result['status'] ?? '') === 'covered' &&
|
|
empty($result['evidence_refs']) && empty($result['evidence_ref'])) {
|
|
return false;
|
|
}
|
|
if (($result['status'] ?? '') === 'out_of_declared_scope' &&
|
|
trim((string)($result['reason'] ?? '')) === '') {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
foreach ($report['issues'] as $issue) {
|
|
if (!is_array($issue) ||
|
|
(in_array($issue['severity'] ?? null, ['critical', 'major'], true) &&
|
|
(($issue['resolution_status'] ?? '') !== 'resolved' ||
|
|
trim((string)($issue['resolution_evidence'] ?? '')) === ''))) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|