Ghost-region detection report
GET/api/v1/system/regions/health
One row per region seen anywhere — in the declared regions system parameter, in a check's regions array, in a check_jobs.region, in a live or previously-live worker's announced region, or in an org agent's bound region — so the caller gets the ghosts and the healthy baseline in one call.
Cloud regions are global: one row per slug, organization absent. Private regions (@<slug>) are org-relative, so they get one row per (organization, slug) with organization set to the org slug: @paris in two orgs is two unrelated rows whose checks, jobs and agents are never summed together.
A ghost is a slug something depends on (a job or a check reference) that nothing live can serve: (jobs > 0 || checksReferencing > 0) && liveWorkers == 0. A declared region with zero live workers and zero references is dark but unused, not a ghost — the alarm condition is work assigned to nobody, not an idle region.
For a cloud region, liveWorkers reuses the exact prefix rule the scheduler claims jobs with (workerRegion has the slug as a prefix, so a us job is served by a us-1 worker) and the same liveness window as the region capability report; system agents count here, through their worker row. lastWorkerSeenAt spans every matching worker, soft-deleted included, so it dates when the region actually went dark. For a private region, liveWorkers counts that org's active agents bound to exactly that slug and seen within the same window (the predicate an agent claims with), and lastWorkerSeenAt is their latest lastSeenAt, revoked agents included. NULL-region (any-region) jobs never count toward any row — they are claimable by every cloud worker by construction.
Read-side companion of POST /system/regions/migrate: its output names exactly the from slugs a migration should target. Cheap and unpaginated — a handful of bounded scans, not a query per region. Super-admin only.
Responses
- 200
- 401
- 403
Ghost-region detection report
Authentication required
Permission denied