Skip to main content

Health Status Reference

Reference

Lookup material for the health status that one evaluator produces and every health surface shares: the status values and the rules behind them, the issue fields, the source-prefix vocabulary, and the endpoints that return them. For how to read this on the Health page, see Monitor system health.

Status values​

One evaluator computes a single rolled-up status. It's the same value shown on the Health page banner, the public status page, and the developer portal's status indicator.

StatusBanner labelMeaning
okOperationalNo down or degraded issue is open. Warnings may still be listed.
degradedDegradedAIControls is still serving traffic, but at least one degraded issue is open.
downDownAt least one down issue is open. AIControls cannot serve traffic normally.

When the admin UI can't load a status at all, it shows Unknown instead of guessing. That value is never returned by the API.

Status rules​

Each rule below raises one issue with the listed severity. The rolled-up status is the worst severity among open issues; warning issues never change it.

SeverityRaised whenSource
downThe replica isn't ready to serve traffic.readiness
downThe storage backend returns an error.storage
downThe policy engine failed to load policies.policy_engine
downEvery critical upstream is unreachable.upstream:<name>
degradedA critical upstream is unreachable or degraded (while at least one other critical upstream still responds).upstream:<name>
degradedA required service is unhealthy.service:<key>
degradedThe audit pipeline dropped events.audit:dropped
degradedThe gateway error rate is above the threshold.gateway:error_rate
degradedThe gateway's P95 overhead is above the threshold.gateway:overhead_p95
degradedA background job is failing.job:<name>
degradedGateway requests were refused in the last 15 minutes because of a setup problem: an upstream with no credential, a model the routed upstream can't serve, or an ambiguous or unsupported upstream.gateway:config:<reason>
warningCallers sent a credential the gateway refused: passthrough mode is disabled, or the upstream doesn't accept it.gateway:config:<reason>
warningA non-critical upstream is unreachable or degraded.upstream:<name>
warningAn optional service is unhealthy.service:<key>
warningOne or more policies failed to compile.policy:compile
warningA background job is stale.job:<name>

Upstreams marked as ignored are never evaluated.

Upstream criticality​

Each LLM or MCP upstream has a criticality that sets how its problems count toward the rolled-up status. Every upstream is critical until an admin changes it — see Mark an upstream non-critical or ignored.

CriticalityWhen the upstream is unreachable or degradedCounted in critical_total
criticalRaises a degraded issue, or a down issue when every critical upstream is unreachable.Yes
non_criticalRaises a warning issue. The rolled-up status doesn't change.No
ignoredRaises no issue. The upstream is still listed with its probe and traffic data.No

Provider status pages are informational and have no criticality.

The Issue shape​

Each problem the evaluator finds is one issue:

FieldTypeMeaning
severity"down" | "degraded" | "warning"How this issue affects the rolled-up status — see Status rules.
sourcestringWhich component raised the issue — see Source prefixes.
messagestringHuman-readable description of what's wrong.
sincetimestampWhen the replica that answered the request first saw the issue. Each replica tracks this on its own, so two replicas can report different since values for the same issue, and a replica restart resets it.

Source prefixes​

The source field determines which Health page tab surfaces an issue:

SourceTabExamples
upstream:<name>MCP, when <name> is a configured MCP server; Upstreams otherwiseupstream:openai-prod (Upstreams), upstream:github-mcp (MCP)
storage, readiness, service:<key>, collector:<what>, job:<name>Servicesstorage, service:okta, job:discovery-sync
runtime:*Runtimeruntime:sensor
everything elseGatewaypolicy_engine, policy:compile, audit:dropped, gateway:error_rate, gateway:overhead_p95

The Providers tab shows no issues of its own — provider status pages are informational, and a provider's upstream-facing problems surface as upstream:<name> issues on the Upstreams or MCP tab instead.

Thresholds​

MetricThresholdSummary field
Gateway error rateAbove 5%thresholds.error_rate_pct
Gateway P95 proxy overheadAbove 250 msthresholds.overhead_p95_ms

Both thresholds, and the audit:dropped rule, are evaluated over the last 15 minutes of traffic across every replica. With no traffic in that window, neither threshold raises an issue. See Overhead and end-to-end latency and Gateway errors for what each metric counts.

Endpoints​

EndpointAuthBacks
GET /api/v1/health/summaryAny admin UI role, including viewerThe Health page.
GET /api/v1/health/servicesAny admin UI role, including viewerThe Health page's Services tab. See below.
GET /api/v1/health/productivityAdminProductivity processing history.
GET /api/v1/health/productivity/failuresAdminPR failure history for a selected interval.
GET /api/v1/health/productivity/operationsAdminManual source and finalization failures, with hourly counts and PR drilldown.
GET /api/v1/health/gatewayAny admin UI role, including viewerThe Gateway tab of the Health page.
GET /api/v1/health/upstreamsAny admin UI role, including viewerThe Health page's Upstreams, MCP and Providers tabs. The MCP tab filters upstreams[] to type: "mcp"; the Providers tab reads providers[]. See below.
PUT /api/v1/health/upstreams/{name}/criticalityAdminSetting an upstream's criticality.
GET /api/v1/statusSigned in, or public when the public status page is enabledThe public status page (/status) and the developer portal's status indicator. Fields vary by caller — see below.

GET /api/v1/health/summary​

curl "$YOUR_WORKSPACE_URL/api/v1/health/summary" \
-H "Authorization: Bearer $ADMIN_TOKEN"
FieldMeaning
statusThe rolled-up status.
generated_atWhen the replica built this snapshot.
snapshot_age_secondsHow old the snapshot was when it was served.
issuesOpen issues, sorted by severity then source. Always an array; empty when nothing is wrong.
components[]One row per checked component: name, healthy, status (healthy, degraded, down, or unknown), required, and message. Storage, Readiness and Policy cache are required. A failing component's message is a fixed description; the underlying error, which can include hostnames or URLs, is written to the proxy logs instead.
proxyversion, mode, uptime_seconds, started_at.
replicasreporting is the number of replicas that recorded metrics in the last 3 minutes; ready is how many of those were ready. Before any replica has recorded metrics (for example, right after the first start), both counts describe the replica that answered the request.
thresholdsoverhead_p95_ms and error_rate_pct — see Thresholds.

GET /api/v1/health/gateway​

curl "$YOUR_WORKSPACE_URL/api/v1/health/gateway?window=24h" \
-H "Authorization: Bearer $ADMIN_TOKEN"

window is 1h (the default) or 24h; any other value returns 400 Bad Request. Counts and latencies cover every replica that recorded metrics in the window. Latency percentiles are computed from the combined distribution of all replicas, not averaged per replica. The endpoint returns 503 Service Unavailable when storage is disabled.

FieldMeaning
windowThe window the response covers: 1h or 24h.
generated_atWhen the response was built.
bucket_secondsWidth of each throughput.series point: 60 for 1h, 300 for 24h.
sessions.active_nowDeveloper sessions that are currently active.
sessions.unique_1h, sessions.unique_24hDeveloper sessions with activity in the last hour and the last 24 hours.
throughput.rpm_currentRequests per minute across all replicas in the most recent recorded minute. 0 when no replica recorded a minute in the last 3 minutes.
throughput.avg, min, max, p95, p99Requests per minute across all replicas, over the per-minute values in the window.
throughput.tokens_per_min_currentTokens per minute across all replicas in the most recent recorded minute. 0 when no replica recorded a minute in the last 3 minutes.
throughput.tokens_per_min_avgTokens per minute across all replicas, averaged over the per-minute values in the window.
throughput.series[]One point per bucket: ts, total_rpm, allowed_rpm, denied_rpm, escalated_rpm (averaged over the bucket's minutes), error_count (summed over the bucket), active_sessions, tokens_per_min, error_rate_pct, and overhead_avg_ms/overhead_min_ms/overhead_max_ms/overhead_p95_ms (overhead_min_ms and overhead_max_ms are estimated from latency histogram buckets, not exact). These back the Gateway tab's chart, whose title dropdown switches between active sessions, request throughput, token throughput, overhead latency, and error rate.
latency.overheadavg_ms, p95_ms, p99_ms of the time AIControls adds to an LLM request — see Overhead and end-to-end latency.
latency.end_to_endavg_ms, p95_ms, p99_ms of the full request time, including the upstream provider.
latency.mcpavg_ms, p95_ms, p99_ms of MCP tool calls.
latency.stagesP95 time spent in each request stage: identity_ms, content_scan_ms, policy_eval_ms, forward_ms.
errors.gateway_5xxGateway errors in the window.
errors.policy_eval_errorsPolicy evaluations that returned an error.
errors.content_scan_errorsContent scans that returned an error.
errors.fail_openRequests allowed because a check failed and was configured to fail open.
errors.error_rate_pctGateway errors plus policy evaluation errors, as a percentage of all requests in the window. See Gateway errors for which requests count. 0 when there were no requests. The gateway:error_rate rule uses the same calculation over the last 15 minutes.
policy_engine.enabledEnabled policies.
policy_engine.loadedPolicies compiled and loaded into the policy engine.
policy_engine.failed[]Names of policies that failed to compile.
policy_engine.storedPolicies in storage, enabled or not.
policy_engine.last_reload_atWhen the policy engine last reloaded policies. null before the first reload.
policy_engine.eval_p95_msP95 policy evaluation time. Same value as latency.stages.policy_eval_ms.
policy_engine.eval_errorsSame value as errors.policy_eval_errors.
policy_engine.sources[]Where enabled policies come from, for example local or kubernetes.
audit.write_backlogAudit events waiting to be written, summed over each replica's latest value.
audit.retry_backlogAudit events waiting to be retried after a storage error, summed over each replica's latest value.
audit.dropped_windowAudit events dropped in the window.
audit.dropped_15mAudit events dropped in the last 15 minutes. The audit:dropped rule uses this count.
audit.write_lag_p95_msP95 time between an event happening and its audit record being stored, over the last 5 to 10 minutes, on the replica that answered.
audit.last_error, audit.last_error_atWhether the replica that answered has had an audit write error, and when the most recent one happened. last_error is a fixed message; the full error is in that replica's proxy logs. Empty and null when there has been none since that replica started.
audit.events_retainedAudit events in storage. On PostgreSQL this is the database's row estimate. Refreshed at most once a minute.
audit.retention_daysHow many days audit events are kept. 0 means events are kept indefinitely.
hitl.oldest_pending_secondsAge of the oldest approval request still waiting for a decision. 0 when none are pending.
hitl.timeout_minutesThe default approval timeout.
hitl.expired_24hApproval requests that expired without a decision in the last 24 hours.
storage.driversqlite or postgres.
storage.ping_msRound-trip time of a storage ping from the replica that answered. -1 when the ping failed.
storage.size_bytesDatabase size. -1 when it could not be read. Refreshed at most once a minute.
storage.connections_open, storage.connections_maxOpen connections in the answering replica's pool, and the pool limit (0 means no limit). Refreshed at most once a minute.
storage.connections_in_use, storage.connections_idleConnections currently in use or idle in the answering replica's pool at the cached sample time. Refreshed at most once a minute.
storage.wait_countCumulative number of waits for a pool connection since the answering replica's pool was created. Refreshed at most once a minute.
storage.wait_duration_msCumulative time spent waiting for pool connections, in milliseconds, since the answering replica's pool was created. Refreshed at most once a minute.
replicas[]One row per replica that recorded metrics in the last 3 minutes: id, ready, db_ping_ms, memory_bytes, goroutines, gc_pause_p99_ms, decision_cache_hit_rate (null before any lookup), sampler_lease (true on the replica that runs fleet-wide sampling), and last_seen.

Pool statistics share the storage snapshot cache and can lag by up to one minute; frequent health polling does not refresh that cache sooner. Compare cumulative counters across distinct samples from the same replica. For shorter contention spikes, use the analytics Prometheus pool metrics, sampled once per second per replica (subject to your monitoring system's scrape interval).

Overhead and end-to-end latency​

  • Overhead is the time AIControls itself adds to a request: identity, content scanning, policy evaluation and request handling. It excludes the time spent waiting for the upstream provider, so a slow model does not raise it. The gateway:overhead_p95 rule uses overhead.
  • End-to-end is the full time from receiving the request to finishing the response, including the upstream provider. It shows what developers experience, but it moves with provider latency, so no health rule is based on it.

Gateway errors​

A gateway error is a 5xx response that AIControls produced itself, such as an internal error while handling the request. A 5xx that the upstream provider returned and AIControls passed through is not a gateway error, so a provider outage does not raise gateway:error_rate; it shows up on the Upstreams tab instead.

The error rate divides these errors by every response the LLM gateway served plus every MCP request. Each LLM gateway response counts once, whether or not it produced an audit event, so a request that AIControls rejects with a 5xx before it is audited still counts toward the rate. When every request fails this way, the rate is 100% and gateway:error_rate is raised. In a window with no LLM gateway responses, the rate uses the audited request count instead.

GET /api/v1/health/upstreams​

curl "$YOUR_WORKSPACE_URL/api/v1/health/upstreams?window=1h" \
-H "Authorization: Bearer $ADMIN_TOKEN"

window is 1h (the default) or 24h and sets the period for the summary and traffic fields. Any other value returns 400 Bad Request. Traffic, request counts, failovers and availability_24h are totals across every replica. probe, status and the route members' live status come from the replica that answers the request.

FieldMeaning
windowThe window applied: 1h or 24h.
generated_atWhen this response was built.
summary.critical_totalNumber of probed upstreams whose criticality is critical. Upstreams of type unknown have no live status, so they aren't counted.
summary.critical_healthyHow many of those are reachable.
summary.requestsRequests AIControls handled in the window.
summary.llm_requests, summary.mcp_requestsThe LLM and MCP share of requests.
summary.error_rate_pctUpstream errors as a percentage of upstream requests in the window.
summary.provider_latency_p95_msP95 upstream response time across all upstreams, in milliseconds.
summary.ttft_p95_msP95 time to first token for streamed LLM responses, in milliseconds.
upstreams[]One row per upstream, described below. The Upstreams tab shows type: "llm" rows (in its Providers table and under each route); the MCP tab shows type: "mcp" rows.
routes[]One row per route the router uses, including implicit routes, described below. The Upstreams tab shows routes with two or more members under Failover.
status_pages[]One row per provider status page, described below.
providers[]One row per LLM provider, described below. Backs the Providers tab.
failover_events[]Failovers in the last 24 hours, aggregated per minute across all replicas, newest first, at most 200 rows. Described below. Backs the Upstreams tab's Failover events view.

Each upstreams[] row:

FieldMeaning
nameThe upstream name.
typellm, mcp, or unknown for a name seen only in traffic that isn't a configured upstream, MCP server, or known provider. Every configured LLM upstream and MCP server is listed, even before it is probed or receives traffic; LLM upstreams come from the same source the gateway routes with (stored upstreams, or the configuration file when none is enabled). Unconfigured (shadow) MCP servers aren't listed. The admin UI shows unknown rows on neither the Upstreams nor the MCP tab.
statusThe upstream's live status.
criticalitycritical, non_critical or ignored — see Upstream criticality.
providerThe LLM provider this upstream uses, when applicable.
transportThe MCP transport (for example stdio or http), for MCP upstreams.
passthroughtrue for a passthrough LLM upstream. Passthrough upstreams aren't actively probed — their status is inherited from via_provider.
via_providerSet on a passthrough upstream: the provider name its status is read from. The admin UI renders this as "via <via_provider> provider".
probeLive probe results: p50_ms, p99_ms, error_rate_pct and last_checked_at. null for an upstream that isn't probed, including every passthrough upstream.
trafficReal traffic in the window: requests, errors, error_rate_pct, latency_p95_ms, and last_used_at. LLM traffic is keyed by the upstream name, else the provider; MCP tool calls are keyed by the configured MCP server name. Each attempt of a failed-over request counts toward the upstream it was sent to.
availability_24h[]48 half-hour slots covering the last 24 hours, oldest first, each with start and state. state is down when every probe in the slot failed, degraded when more than 5% failed, ok otherwise, and none when the slot has no probes.
issueThe open issue for this upstream (severity, message, since), or null. Always null for an ignored upstream.
routes[]Names of the model routes this provider is a member of. Omitted when none.

Each routes[] row:

FieldMeaning
nameThe route name.
strategyThe route's strategy: priority_failover for failover (shown in the admin UI as "Priority failover (sticky sessions)"), round_robin for round-robin ("Round-robin (sticky sessions)"), lowest_cost ("Lowest cost (sticky sessions)"), lowest_latency ("Lowest latency (sticky sessions)"), or weighted ("Weighted (sticky sessions)").
members[]Each member's name and live status, in member order.
active_memberThe member a new, non-sticky request is sent to first: the first reachable member in member order that isn't fallback-only, else the first reachable fallback-only member. Set only for priority_failover: other strategies start new sessions on any member, and the admin UI shows "Any member (round-robin)", "Any member (lowest cost)", "Any member (lowest latency)", or "Any member (weighted)". Failover happens per request, so a recent failover doesn't change it. Empty when no member is reachable.
healthy_membersHow many members are currently reachable.
trafficRoute-level traffic in the window, same shape as an upstreams[] row's traffic.
failovers_24hHow many times a request failed over from one member to another in the last 24 hours.
last_failoverThe most recent failover's at, from and to, or null when there was none in the last 24 hours.

Each status_pages[] row:

FieldMeaning
nameThe status page's display name.
statusoperational, degraded, outage or unknown.
detailThe component status as the provider reports it, for example partial_outage.
sinceWhen status last changed.

Each providers[] row:

FieldMeaning
nameThe provider name.
status_pageThe matching status_pages[] row, or null when this provider has no status page configured — shown in the admin UI as Not tracked.
statusThe provider's rolled-up status, based on the LLM upstreams that use it.
trafficCombined traffic in the window across every upstream that uses this provider: requests, errors, error_rate_pct, latency_p95_ms, last_used_at.
used_by[]Names of the upstreams that use this provider.

Each failover_events[] row:

FieldMeaning
atThe time of the latest failover in this row's minute.
routeThe route the failover happened in.
from, toThe member failed away from, and the member failed over to.
reasonWhy the failover happened, when known. Omitted otherwise.
countHow many failovers this row represents. Greater than 1 when the same from → to transition with the same reason repeated within the same minute, on any replica.

Failover history is kept for 7 days.

PUT /api/v1/health/upstreams/{name}/criticality​

curl -X PUT "$YOUR_WORKSPACE_URL/api/v1/health/upstreams/openai-prod/criticality" \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"criticality": "non_critical"}'

The body's criticality is critical, non_critical or ignored. The response is the updated upstreams[] row, and the rolled-up status is re-evaluated before it returns.

ResponseWhen
200 OKThe criticality was saved.
400 Bad RequestThe body isn't a single JSON object or criticality isn't one of the three values.
403 ForbiddenThe caller isn't an admin.
404 Not FoundNo configured LLM upstream, MCP server or probed upstream has that name. Upstreams of type unknown (seen only in traffic) can't be given a criticality.

Each change is recorded in the configuration audit log as upstream.configuration_updated.

GET /api/v1/status​

What a caller receives depends on who it is:

  • Public caller — not signed in.
  • Developer — a developer portal session or a developer token (sess_, pat_ or aic_), or any caller with the developer role.
  • Admin or viewer — an admin UI session with the admin or viewer role.
FieldPublic callerDeveloperAdmin or viewer
statusYesYesYes
generated_atYesYesYes
proxy.uptime_secondsYesYesYes
upstreamsWhen upstreams are shownYesYes
proxy.version, proxy.mode, proxy.policy_countNoNoYes
issuesNoNoYes
load.*NoNoYes. Deprecated: the counts are kept for API compatibility only, and load.budget_warnings is always 0. Read business activity from the Dashboard instead.

The public_status_show_upstreams setting controls upstreams for public callers only. It defaults to ui.publicViews.status.showUpstreams in the configuration file, which defaults to true; a value saved through the admin API overrides the file. Signed-in callers always receive upstreams. upstreams is omitted when there are none to list. When the public status page is disabled, public callers receive 404 Not Found. A change to either setting applies at once on the replica that saved it and within about 15 seconds on other replicas.

Upstream status values​

Each entry in upstreams carries its own status, independent of the rolled-up status:

StatusMeaning
reachableResponding normally.
degradedResponding, but with elevated latency or error rate.
unreachableNot responding.
unknownNot yet checked.

GET /api/v1/health/services​

curl "$YOUR_WORKSPACE_URL/api/v1/health/services" \
-H "Authorization: Bearer $ADMIN_TOKEN"
FieldMeaning
generated_atWhen the replica built this response.
services[]One row per service, in the fixed order below: key, name, status (see Service status values), required, configured (false for a service not set up on this deployment; the admin UI hides these rows by default behind a Show N not configured toggle, and shows required as "—" for them), alwaysVisible (present and true only for a not_configured row the admin UI shows regardless, such as the Workload Trust row), detail (a short summary with no raw upstream errors or URL credentials; admins find the raw error in the proxy logs), last_checked_at (omitted when never checked), and link (the admin UI page that configures the service; empty when there is none).
notifications[]One row per notification channel and kind that delivered in the last 24 hours: channel, kind, sent_24h, failed_24h, last_success_at, last_failure_at, and last_error (the error class of the most recent failure; empty unless the caller is an admin).
notifications_errorSet, and notifications empty, when delivery records could not be read or the read timed out. Omitted otherwise.
jobs[]One row per background job: job, status (see Job status values), holder (the replica that last ran it), last_run_at, last_duration_ms, last_error (the error class of the last failed run; empty unless the caller is an admin), next_run_at, and interval_seconds (0 when the interval is unknown).
jobs_errorSet, and jobs empty, when job runs could not be read or the read timed out. The same failure raises a warning issue from source service:job_runs. Omitted otherwise.

services, notifications and jobs are always arrays. Job and notification rows are read from shared storage, so every replica returns the same rows, except that a job's running status is known only to the replica running it: that replica reports running, and the others report the job's last completed run. Service rows reflect the replica that answered the request.

Services​

A required service that is degraded or down raises a degraded issue; an optional one raises a warning. Services that are not_configured or unknown raise nothing.

KeyNameRequired
storageStorageYes
policy_enforcementPolicy enforcementYes
policy_source_kubernetesKubernetes policy source. With several sources, one row per source, keyed policy_source_kubernetes_<n>.Yes
oidcOIDC issuerNo
okta_syncOkta syncNo
promptguardPromptGuard. Required when it is fail-closed (failOpen: false), because an outage then blocks content-scanned traffic.When fail-closed
llm_judgeLLM Judge. Reports degraded when most of its recent calls fail, and unknown when it made no calls recently.Yes
report_sinkPolicyReport sink. The detail names the state and, when the cluster serves no policy-report API, which CRDs to install; the full reason is on GET /api/v1/audit/report-sink/status.Yes
otel_exportOpenTelemetry exportNo
discoveryWorkload discoveryNo
postureRuntime postureNo
workload_trustWorkload Trust. Appears only when Workload Trust is unavailable, in place of discovery and posture.No
intelligenceSession intelligenceNo
runtime_sensorRuntime sensor continuity. One row per cluster, keyed runtime_sensor_<cluster> when there are several. The row is healthy with the time the current unbroken run began, down with the time of the outage and its reason, or unknown with never recorded when no healthy sensor probe exists yet. An outage degrades the overall status, because workload readiness rule R6 fails closed while it lasts. The row is not_configured when runtime controls aren't running. Demo mode simulates a healthy sensor.Yes

The discovery and posture rows are part of Workload Trust, which is available only in self-managed installations. On a Nirmata-hosted deployment, services omits both rows. In their place, a single workload_trust row reports not_configured and states why in its detail. The row has configured: false and alwaysVisible: true. The Services tab shows alwaysVisible rows even when it hides other not_configured rows, so this row explains the missing rows instead of leaving a gap. The row raises no issue. GET /api/v1/discovery/status returns enabled: false with reasonCode: "hosted_deployment".

If a deployment that held workload registrations or Workload Blueprints switches to hosted, AIControls keeps that data, hides it, and logs the warning workload trust: hidden on this deployment at startup with the number of each. The data reappears if you return the deployment to self-managed.

Service status values​

StatusMeaning
healthyWorking normally.
degradedWorking, but with errors — for example a policy source serving its last-known-good policies, or a Judge whose recent calls mostly fail.
downNot working.
unknownConfigured, but not yet checked, with no recent activity to judge by, or its status check did not answer in time — for example runtime posture before it has observed any workload. A check that runs past its time limit reports unknown with the detail status check timed out.
not_configuredNot set up on this deployment.

Error classes​

last_error on job and notification rows never carries the raw error, which can include hosts, addresses, usernames or response bodies. It is one of these fixed classes:

ClassMeaning
HTTP <code>The remote endpoint answered with that HTTP status code.
timed outThe operation hit a deadline.
canceledThe operation was canceled.
connection refusedNothing accepted the connection.
connection resetThe remote end dropped the connection.
host not foundThe host name did not resolve.
TLS errorThe TLS handshake or certificate check failed.
panickedThe job or delivery panicked.
failed (details in server logs)Any other failure.

The full error is in the proxy logs.

Job status values​

StatusMeaningIssue
okThe last run succeeded and the job is on schedule.None
runningThe replica that answered the request is running the job now.None
failingThe last run failed. Takes precedence over running and stale. The issue message is last run failed; admins read the error class from last_error and the full error in the proxy logs.degraded
staleThe last run started more than three intervals ago. A job whose interval is unknown (interval_seconds is 0) is never stale.warning
neverThe job is scheduled but has not run yet.None

Productivity processing history​

GET /api/v1/health/productivity?window=1h|24h is administrator-only. It reads retained operational samples and never starts collection, enqueues jobs, or calls a model. The endpoint enforces a bounded query window. See Monitor productivity processing.

FieldMeaning
generatedAt, from, to, bucketSecondsUTC response time, requested execution-time range, and chart bucket width (60 or 3600 seconds).
historyStartedAtEarliest retained queue/budget sample, or null before the first sample.
failureHistoryStartedAtEarliest retained immutable failure-event boundary, or null before recording starts. This boundary is separate from queue/budget sampling history.
telemetryStatecurrent, stale (latest sample older than 150 seconds), or unavailable. This describes telemetry, not classification quality.
missingMinutesMinutes in the window without a queue/cost sample, including the current minute if it has not yet been sampled.
currentLatest retained queue and daily-budget snapshot in the window, or null. Includes sampledAt, pending/running/completed/failed counts, schedule-ready count, wait age, last completed-job timestamp, UTC budgetDay, and accountedUSD.
completed, failed, failureRatePctRecorded terminal job settlements in the window; rate is failed / (completed + failed) × 100, or null with no outcomes.
seriesBucketed outcome counts plus last sampled pending/running/budget gauges. Missing values are null; sampledMinutes exposes partial buckets.
series[].at, from, toBucket timestamp and its bounded execution-time interval [from, to), suitable for the failure-history query. The active minute's to can be later than generatedAt; its counts are still changing.
series[].failureCategoriesCounts for all eight supported failure categories when a bucket has a recorded minute row, including explicit zero counts. null when no minute row was recorded; missing telemetry is not zero activity. Hourly buckets sum only retained recorded minutes.
failuresRecorded failed settlements by fixed safe category; no source text or provider response bodies.
enabled, automatic, dailyBudgetUSDEffective assessment switches and configured daily cap.

The budget gauge combines reserved and charged cost using the current assessment accounting rules. It does not claim invoice precision or reconstruct earlier periods. Counters are written atomically with fenced job settlement, and queue gauges represent the shared store once rather than being summed per replica.

GET /api/v1/health/productivity/failures​

Returns retained terminal failures from automatic PR assessments. Administrator access is required. Reading this endpoint does not retry a PR, fetch source, or call a model.

Query parameterMeaning
from, toRequired RFC3339 timestamps, with optional fractional seconds. Selects execution time in [from, to), with to after from and an interval of at most 24 hours plus one minute.
categoryOptional: source_unavailable, invalid_citation, invalid_json, provider, interrupted, other, incomplete_source, or invalid_classification. Omit for all categories.
repositoryOptional exact owner/repository filter, case-insensitive, at most 250 bytes. Filters this list only; processing charts remain workspace-wide.
limitPage size from 1 to 100. Omitted or 0 uses 25.
offsetZero-based row offset, from 0 to 100000. Defaults to 0. Narrow the interval, repository, or category when results exceed this paging limit.

Invalid parameters return 400 Bad Request; callers without administrator access receive 403 Forbidden. Unavailable failure-history storage returns 503 Service Unavailable. Responses disable caching.

Response fieldMeaning
from, to, category, repository, limit, offsetApplied query parameters, including the default page size.
maxOffsetLargest accepted offset, currently 100000.
generatedAtUTC response timestamp.
historyStartedAtEarliest retained failure-history boundary, or null before recording starts. History is retained for seven days.
completeWindowWhether the entire requested interval lies within retained history and ends no later than the response time.
totalNumber of retained events matching the filters, including events beyond the paging limit. This counts failed attempts, not distinct PRs.
itemsArray of matching events, newest first; ties use descending event ID. Empty when no retained events match.
items[].id, prID, repository, prNumber, titleEvent ID and associated PR identity. Repository and title reflect the current stored PR metadata.
items[].at, headSHA, queueVersionFailure timestamp and the attempt's revision and queue version.
items[].category, diagnosticCodeSafe failure category and diagnostic code. The code can be empty when unavailable.
items[].model, promptVersion, sourceVersionBounded processing metadata; empty when unavailable. Raw provider responses and source patches are not returned.

A retry or later success does not rewrite an earlier failure event. Events begin when failure recording is enabled; historical failures are not reconstructed. The chart's active minute can include later events than an earlier drill-down response, so counts at that boundary can differ.

GET /api/v1/health/productivity/operations​

Returns recorded manual source-retrieval and analysis-finalization failures. Administrator access is required. GET reads shared storage without retrieving GitHub source, queuing work, or calling a model. See Inspect manual operation failures.

Query parameterMeaning
from, toRequired RFC3339 timestamps with optional fractional seconds. Selects [from, to), with to after from and a maximum interval of 24 hours plus one minute.
stageOptional: source_preview, analysis_source, manual_save_source, review_source, or analysis_finalize. Omit for all stages.
diagnosticCodeOptional safe cause from the list below. Omit for all causes.
repositoryOptional exact case-insensitive owner/repository, at most 250 bytes. Applies to totals, series, distinct PRs, and event list.
limit, offsetPage size 1–100 (omitted or 0 defaults to 25); row offset 0–100000 (defaults to 0). Pagination affects only items.

Source codes are source_deferred, upstream_rate_limited, upstream_unauthorized, upstream_forbidden, upstream_not_found_or_inaccessible, upstream_error, source_timeout, source_canceled, source_network_error, source_response_too_large, source_malformed_response, source_unavailable, source_changed, incomplete_source, and source_ineligible. Finalization codes are publication_conflict, publication_rejected, settlement_unavailable, and storage_unavailable; unknown is also accepted.

Invalid parameters return 400; non-administrators receive 403; unavailable operation-history storage returns 503. Responses disable caching.

Response fieldMeaning
from, to, stage, diagnosticCode, repository, limit, offsetApplied filters and pagination.
generatedAt, maxOffset, bucketSecondsResponse time, maximum accepted offset (100000), and hourly bucket width (3600 seconds).
total, distinctPRsMatching recorded failures and distinct associated PRs across the full filtered interval. Repeated operations can fail for the same PR.
coverage, completeWindowAlways recorded_failures_only and false. Successful attempts and every provider/validation failure are not collected here, so this stream has no failure-rate denominator.
firstObservedAt, retainedSinceFirst successfully recorded manual failure (or null) and the current seven-day retention cutoff. First observation survives pruning and does not prove uninterrupted instrumentation coverage.
series[]Hourly at, clipped [from, to) interval, total, and a diagnosticCodes count map, under the same filters as the event list. Empty maps mean no recorded failures; they do not establish healthy coverage.
items[]Matching events, newest timestamp first with descending ID as tiebreaker.
items[].id, prID, repository, prNumber, title, headSHA, atServer correlation ID, PR identity/current metadata, imported attempt revision, and event time.
items[].stage, diagnosticCode, dispatchState, elapsedMSFailure stage/cause, not_dispatched, dispatched, or unknown, and elapsed milliseconds. Source stages are always not_dispatched. Dispatch status alone does not establish billing or successful publication.
items[].requestID, retryAt, upstreamStatus, upstreamRequestIDOptional analysis request association, suggested retry timestamp, HTTP status, and GitHub request ID. Unknown or unsafe metadata is omitted.

Events are retained for seven days, removed with deleted source PRs, and never reconstructed for older releases. Provider/output-validation errors remain in PR request history. An operation response reports eventRecorded: false if writing its event failed; its correlation ID remains available in safe server logs. No raw upstream body, credential, provider output, or source patch is stored in this stream.

Analytics API execution deadlines​

Dashboard and analytics JSON reads have a default 30-second execution deadline. This includes waiting for a database connection. When the deadline expires, query cancellation propagates through the request and the API returns HTTP 504 with an error message. A required analytics read that fails before the deadline returns HTTP 503, rather than presenting incomplete totals as a successful response. Successful response formats are unchanged.

The deadline applies to the selected cost, budget overview/effective/preview, stats, metrics, adoption, insights, activity, security, intelligence, identity-list, session-list, audit-list, and baseline-alert GET endpoints, including developer-scoped insights. It does not apply to LLM or MCP forwarding, streaming responses, exports, backups, or mutations. Gateway error and latency metrics describe forwarded traffic; they do not measure these analytics API responses.

Self-hosted administrators can configure the analytics deadline. An earlier caller deadline takes precedence.

The web UI treats a 504, and a request the browser gives up on after two minutes, as a final answer: it does not retry. Pages that handle load errors, such as the Insights overview and the Gateway activity list, show an error state with a Retry button instead of a zero. Most analytics views that read 7 to 30 day windows (attribution, adoption, contributions, intelligence and Insights) refresh every five minutes, and every fifteen after a deadline error; a few views, such as the security dashboard, keep their own refresh interval. The Insights overview loads its figures in three stages and marks any one that fails with Could not load and its own Retry button.

A 504 identifies an execution deadline, not a diagnosis of insufficient hardware. Inspect database query duration, connection waits, and CPU throttling before increasing the deadline. Increasing it allows expensive work to occupy resources for longer.