---
title: "Fleet readiness"
method: GET
path: "/api/fleet/readiness"
tags: ["Fleet"]
---

# Fleet readiness

`GET /api/fleet/readiness`

## Request

- Base URL: `https://localhost:1852`
- URL: `https://localhost:1852/api/fleet/readiness`
- Auth: HTTP bearer

Aggregates readiness across six domains (connectivity, workloads,
updates, recovery, security, control) into a fleet summary, a
prioritized findings list, and a per-node matrix. Each node and each
domain degrades independently: a node that does not answer keeps the
domains the control instance could establish and reports the rest as
unavailable or unknown with a reason, so one unreachable node neither
blanks the page nor erases another node's results. Nothing is scored,
and no state is reported as healthy unless it was actually established.
Requires `node:read` permission. The `control` domain is withheld from
callers that do not pass the administrative check, and is named in
`domainsOmitted`.

## Query parameters

- `domains` string
- `nodeIds` string

## Response `200`

Fleet readiness aggregate.

- FleetReadinessResponse
  - `generatedAt` integer, required: Epoch ms this response was assembled; the surface's "last checked" time.
  - `domains` ReadinessDomainKey[], required: Domains present in this response, in column order.
  - `domainsOmitted` ReadinessDomainKey[], required: Domains withheld from this caller. Today the only member is `control`, omitted unless the caller passes the same admin check `GET /api/fleet/sync-status` uses; the key never appears in a node's cells.
  - `summary` object, required
    - `nodes` object, required: Nodes whose worst domain state is each value, counted over the domains this response carries. A node counts once, so the values sum to `nodes.length`.
      - `attention` integer
      - `degraded` integer
      - `unavailable` integer
      - `unknown` integer
      - `healthy` integer
    - `findings` object, required: Findings across the fleet, by severity.
      - `attention` integer
      - `degraded` integer
      - `unavailable` integer
      - `unknown` integer
  - `findings` ReadinessFinding[], required: Worst severity first, then by `id`. When a node's Connectivity cell carries a finding and a gated domain went unread for that same reason (no answer, a timeout, or a route the node does not serve), the domain keeps its unavailable cell but adds no finding. This applies only when `connectivity` is in `domains`.
    - `id` string, required: Stable across refetches, so a client keys and de-duplicates on it.
    - `domain` 'connectivity' | 'workloads' | 'updates' | 'recovery' | 'security' | 'control', required: One of the six readiness domains, in column order.
    - `nodeId` integer, required
    - `stack` string, nullable, required: Stack name for a stack-scoped finding, null otherwise.
    - `code` 'node_unreachable' | 'pilot_disconnected' | 'contact_stale' | 'probe_timeout' | 'workloads_exited' | 'workloads_partial' | 'workloads_unknown' | 'status_evidence_degraded' | 'status_evidence_stale' | 'update_blocked' | 'update_review_required' | 'update_ready_with_warnings' | 'rollback_not_ready' | 'rollback_partial' | 'snapshot_failed' | 'stacks_unknown' | 'summary_truncated' | 'summary_stale' | 'posture_partial' | 'posture_action_needed' | 'scanner_unavailable' | 'scans_stale' | 'scans_never_completed' | 'control_paused' | 'control_degraded' | 'control_unknown' | 'capability_absent' | 'domain_error', required: A closed vocabulary naming why a cell is not healthy. Each code belongs to one domain and maps to fixed copy in the client, which renders a code it does not know as "this check reported something this build does not know" rather than as healthy. `capability_absent` and `domain_error` apply to any domain.
    - `severity` 'attention' | 'degraded' | 'unavailable' | 'unknown' | 'healthy', required: Ordered worst first. A node's overall state is the first of its cell states found in this list. A known problem outranks a not-knowable one: `unavailable` (no evidence at all) ranks above `unknown` (incomplete evidence).
    - `count` integer, required: How many items sit behind this row (stacks, containers, snapshots).
    - `verdict` object, nullable, required: The canonical verdict this row restates, tagged by the vocabulary it holds: `{ "kind": "update", "value": "ready" | "ready_with_warnings" | "review_required" | "blocked" | "unknown" }` or `{ "kind": "rollback", "value": "ready" | "partial" | "not_ready" }`. Null when no verdict applies.
    - `detail` string, nullable, required: Pass-through of the canonical explanation, with sensitive values redacted.
    - `target` ReadinessTarget, required: Where a finding sends the operator. `surface` discriminates the variant and names an existing navigation affordance rather than a URL: `stack` carries `nodeId` and `stackName`; `auto-updates`, `fleet-snapshots` and `settings-nodes` carry nothing else; `security` carries a `tab` segment; `node-details` carries a `nodeId`.
      - `surface` 'stack' | 'auto-updates' | 'fleet-snapshots' | 'security' | 'node-details' | 'settings-nodes', required
      - `nodeId` integer
      - `stackName` string
      - `tab` string, nullable: Security tab segment, or null for the Security overview.
  - `nodes` FleetReadinessNode[], required
    - `id` integer, required
    - `name` string, required
    - `type` 'local' | 'remote', required
    - `mode` 'proxy' | 'pilot_agent', required
    - `transport` 'local' | 'pilot' | 'proxy' | 'unreachable', required: Which transport the hub would use to reach this node.
    - `reachability` NodeReachability, required
      - `status` 'online' | 'offline' | 'unknown', required
      - `contactAt` integer, nullable, required: Epoch ms of the last contact this hub can vouch for.
      - `contactSource` 'local' | 'pilot_last_seen' | 'last_successful_contact', required
      - `note` string, required: How reachability was decided, as a closed set rather than free prose, so a client renders it without a fallback string.
      - `probedLive` boolean, required: True when this request itself reached the node.
      - `latencyMs` integer, nullable, required: Round-trip time of the probe that produced this row, or null when there was none.
    - `state` 'attention' | 'degraded' | 'unavailable' | 'unknown' | 'healthy', required: Ordered worst first. A node's overall state is the first of its cell states found in this list. A known problem outranks a not-knowable one: `unavailable` (no evidence at all) ranks above `unknown` (incomplete evidence).
    - `cells` object, required: Keys are the subset of `domains` on the response that apply to this node. The `control` domain applies only to nodes that receive policy sync (proxy-mode remotes with an API URL and token), so this instance's own node and Pilot-agent nodes carry no `control` cell: a missing key means the domain does not apply. A domain absent from `domains` is one this caller was not told about (`domainsOmitted`).
    - `stackCount` integer, nullable, required: Stacks known on this node, or null when it could not be read.

## Other responses

- `400`: Invalid domains or nodeIds filter.
- `401`: Authentication required. Provide a valid Bearer token.
- `403`: Insufficient permissions or license tier.
- `500`: Internal server error.

## Changes

- **2026-09-24** `d8373a6de800`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/studio-saelix/apis/sencho-api/changes/api/fleet/readiness/get.md)

---

[API](https://skmtc.dev/studio-saelix/apis/sencho-api.md) - [All operations](https://skmtc.dev/studio-saelix/apis/sencho-api/llms.txt) - [OpenAPI document](https://skmtc.dev/studio-saelix/apis/sencho-api/revisions/bb1a37e1ed3b?raw)
