Validate::status(Validate::requireString($body, 'status', 32)), 'notes' => $body['notes'] ?? '', 'reporting_url' => Validate::requireString($body, 'reporting_url', 512), 'autocheck' => isset($body['autocheck']) && is_array($body['autocheck']) ? $body['autocheck'] : null, ]; if (!is_string($row['notes'])) Validate::fail('notes must be a string'); Store::upsertStep($healthcheckId, $stepId, $row); Http::json(200, ['ok' => true]); } public static function history(array $params): void { $stepId = $params['step_id']; $siteKey = $_GET['site_key'] ?? ''; if (!is_string($siteKey) || $siteKey === '') { Http::error(422, 'invalid', 'site_key query param is required'); return; } $limit = max(1, min(50, (int) ($_GET['limit'] ?? 5))); $excludeId = isset($_GET['exclude_id']) && is_string($_GET['exclude_id']) ? $_GET['exclude_id'] : null; Http::json(200, ['history' => Store::stepHistory($stepId, $siteKey, $limit, $excludeId)]); } public static function counts(): void { $siteKey = $_GET['site_key'] ?? ''; if (!is_string($siteKey) || $siteKey === '') { Http::error(422, 'invalid', 'site_key query param is required'); return; } $excludeId = isset($_GET['exclude_id']) && is_string($_GET['exclude_id']) ? $_GET['exclude_id'] : null; Http::json(200, ['counts' => Store::stepCountsForSite($siteKey, $excludeId)]); } }