|null $assessment * @return array */ public function explain(stdClass $partnership, stdClass $interest, ?array $assessment = null): array { $assessment ??= json_decode($interest->assessment, true); $payload = json_decode($partnership->payload, true); $weights = config('partnerships.type_weights.'.$partnership->partnership_type, config('partnerships.weights')); $criteria = []; $known = $unknown = 0; $mandatoryUnmet = $mandatoryUnknown = false; foreach ($weights as $code => $weight) { $entry = $assessment[$code] ?? []; $state = $entry['state'] ?? 'unknown'; if (in_array($state, ['met', 'unmet'], true) && empty($entry['evidence'])) { $state = 'unknown'; } $mandatory = in_array($code, $payload['mandatory'] ?? [], true); $known += $state === 'met' ? $weight : 0; $unknown += $state === 'unknown' ? $weight : 0; $mandatoryUnmet = $mandatoryUnmet || ($mandatory && $state === 'unmet'); $mandatoryUnknown = $mandatoryUnknown || ($mandatory && $state === 'unknown'); $criteria[] = ['code' => $code, 'label' => config('partnerships.criteria.'.$code), 'weight' => $weight, 'state' => $state, 'mandatory' => $mandatory, 'evidence' => $entry['evidence'] ?? null, 'explanation' => $state === 'unknown' ? 'Informação insuficiente; declarações sem avaliação documental não provam cumprimento ou incumprimento.' : 'Avaliação fundamentada do responsável; não equivale a certificação ou aprovação.']; } $total = array_sum($weights); return ['algorithm_version' => 'transparent-rules.v1', 'weights_hash' => hash('sha256', json_encode($weights, JSON_THROW_ON_ERROR)), 'score_min' => $total ? round(100 * $known / $total, 1) : null, 'score_max' => $total ? round(100 * ($known + $unknown) / $total, 1) : null, 'eligibility' => $mandatoryUnmet ? 'unmet' : ($mandatoryUnknown ? 'unknown' : 'met'), 'criteria' => $criteria, 'unknown_weight' => $unknown, 'recommendation_is_approval' => false]; } }