---
title: "Fleet readiness for an AI observer"
method: GET
path: "/api/fleet/observation/health"
tags: ["Observation"]
---

# Fleet readiness for an AI observer

`GET /api/fleet/observation/health`

## Request

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

Returns the fleet readiness aggregate projected for an Observe Only token:
per-node domain cells, the findings behind them, state and severity counts,
and a staleness flag. Findings are capped at 50, worst first. The `control`
domain is withheld from this surface and named in `domainsOmitted`. The
aggregate is cached for up to 15 seconds and shared across callers, so
`generatedAt` and each cell's `evidenceAgeMs` describe the age of the
evidence, not of the request. Dismissals applied in the Fleet Readiness view
are not read here, because reading them would mutate dismissal state. This is
one of the five paths an Observe Only token may reach. Requires `node:read`
permission.

## Response `200`

Fleet readiness wrapped in the observation envelope.

- object
  - `schemaVersion` 1, required
  - `generatedAt` integer, required: Epoch ms of the evidence behind the answer.
  - `data` ObservationFleetHealthData, required
    - `stale` boolean, required: True when the cache served an expired aggregate after a failed refresh.
    - `domains` ReadinessDomainKey[], required
    - `domainsOmitted` ReadinessDomainKey[], required: Domains withheld from the observation surface. Today this is only `control`.
    - `summary` object, required
      - `nodes` object, required: Nodes whose worst domain state is each value.
        - `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
    - `nodes` ObservationFleetNode[], required
      - `id` integer, required
      - `name` string, required
      - `transport` 'local' | 'pilot' | 'proxy' | 'unreachable', required
      - `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).
      - `reachability` object, required
        - `status` 'online' | 'offline' | 'unknown', required
        - `contactAt` integer, nullable, required: Epoch ms of the last contact this hub can vouch for.
        - `probedLive` boolean, required
        - `latencyMs` integer, nullable, required
      - `cells` object, required: Keys are the subset of `domains` that apply to this node. A missing key means the domain does not apply, never that it is healthy.
      - `stackCount` integer, nullable, required
    - `findings` ObservationFleetFinding[], required: Worst severity first, capped at 50 rows.
      - `id` string, required
      - `domain` 'connectivity' | 'workloads' | 'updates' | 'recovery' | 'security' | 'control', required: One of the six readiness domains, in column order.
      - `nodeId` integer, required
      - `stack` string, nullable, required
      - `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
    - `findingsTruncated` boolean, required: True when more than 50 findings exist.

## Other responses

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

## Changes

- **2026-11-01** `bef9c9739469`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/studio-saelix/apis/sencho-api/changes/api/fleet/observation/health/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)
