, * sections: list> * } */ public function compose(EvidenceSnapshot $snapshot, ?TenantReview $review = null): array { $tenant = $snapshot->tenant; if ($tenant === null) { throw new \RuntimeException('Evidence snapshot tenant is required for review composition.'); } $sections = $this->sectionFactory->make($snapshot); $blockers = $this->readinessGate->blockersForSections($sections); $sectionStateCounts = $this->readinessGate->sectionStateCounts($sections); $completeness = $this->readinessGate->completenessForSections($sections); $status = $this->readinessGate->statusForSections($sections); if ($review instanceof TenantReview && $review->isPublished()) { $status = TenantReviewStatus::Published; } return [ 'fingerprint' => $this->fingerprint->forSnapshot($tenant, $snapshot), 'completeness_state' => $completeness->value, 'status' => $status->value, 'summary' => [ 'evidence_basis' => [ 'snapshot_id' => (int) $snapshot->getKey(), 'snapshot_fingerprint' => (string) $snapshot->fingerprint, 'snapshot_completeness_state' => (string) $snapshot->completeness_state, 'snapshot_generated_at' => $snapshot->generated_at?->toIso8601String(), ], 'section_count' => count($sections), 'section_state_counts' => $sectionStateCounts, 'publish_blockers' => $blockers, 'has_ready_export' => false, 'finding_count' => (int) data_get($sections, '0.summary_payload.finding_count', 0), 'report_count' => 2, 'operation_count' => (int) data_get($sections, '5.summary_payload.operation_count', 0), 'highlights' => data_get($sections, '0.render_payload.highlights', []), 'recommended_next_actions' => data_get($sections, '0.render_payload.next_actions', []), 'last_composed_at' => now()->toIso8601String(), ], 'sections' => $sections, ]; } }