$c["at"], "lines" => array_values(array_filter($c["checks"], fn($l) => !str_starts_with($l["line"], "(exhibit")))]; } return [ "n" => 22, "wing" => "Operations", "title" => "The zoo checks itself", "promise" => "Every self-running exhibit is rechecked on a schedule, and the front page says when.", "block" => "The zoo is an ordinary app: a five-minute job re-runs its exhibits and stores the results, and root's hourly check of the platform arrives in RC_FACTS/platform.json.", "files" => ["bin/selfcheck.php"], "show" => function (?array $me): string { $t = meta("checked_at"); $out = "

Checked " . ago($t ? (int)$t : null) . "" . (($d = meta("checked_ms")) ? " (took " . round($d / 1000, 1) . " s)" : "") . ".

"; $b = back_of_house(); if (!$b) return $out . '

Root\'s check of the back of house is not published to apps yet (RC_FACTS/platform.json is missing).

'; $out .= "

The back of house, checked by root " . ago(strtotime($b["at"])) . ":

"; }, // Runs last in bin/selfcheck.php, after every other exhibit. "check" => function (): array { $red = []; foreach (exhibits() as $n => $e) if ($n !== 22 && $e["kind"] === "self" && light($e)["color"] === "red") $red[] = $n; $b = back_of_house(); if (!$b) return [false, "root's back-of-house check is not readable: RC_FACTS/platform.json is missing"]; if (time() - strtotime($b["at"]) > 3 * 3600) return [false, "root's back-of-house check is " . intdiv(time() - strtotime($b["at"]), 3600) . " hours old"]; $fail = array_filter($b["lines"], fn($l) => $l["status"] !== "pass"); if ($fail) return [false, "back of house: " . implode("; ", array_map(fn($l) => $l["line"], $fail))]; if ($red) return [false, "red: exhibit" . (count($red) > 1 ? "s " : " ") . implode(", ", $red)]; return [true, "every self-running exhibit is green, and root's " . count($b["lines"]) . " back-of-house lines pass"]; }, ];