# $defs.AgentCompat.description
The agent-compatibility nudge inside [`HeartbeatAck`]: HQ tells a deployed
gateway whether its build predates the oldest supported agent version.
Advisory only — HQ never rejects an outdated agent, it just says so; the
agent logs an upgrade nudge and surfaces it in `mf status`.

# $defs.AgentCompat.properties.minSupported.description
The oldest agent build HQ fully supports.

# $defs.AgentCompat.properties.reported.description
The version this agent reported on the beat.

# $defs.ApiError.description
The error envelope every device-API error response carries. Wire-additive
over the original `{ error: string }` prose: `error` stays exactly where
deployed agents expect it, and the machine-readable siblings are new.

# $defs.ApiError.properties.code.description
Stable machine-readable cause — see [`ApiErrorCode`].

# $defs.ApiError.properties.error.description
Human-readable prose (the original, pre-envelope field).

# $defs.ApiError.properties.param.description
The offending input field (dotted zod path) on 400s.

# $defs.ApiError.properties.requestId.description
Minted per response and logged at HQ, so a support report and a
Workers log line correlate on one id. Absent on responses emitted
before HQ's request pipeline (e.g. the demo floor's middleware 403).

# $defs.ApiError.properties.retryAfterSecs.description
On 429s: seconds until the throttle budget refreshes (mirrors the
`retry-after` header in the body, which is what the agent reads).

# $defs.ApiErrorCode.description
The stable machine-readable code registry for device-API error responses
(`ApiError.code`). APPEND-ONLY: a published slug never changes meaning —
deployed agents branch on these instead of prose or overloaded HTTP
statuses. HQ's `lib/fleet/api-error.ts` derives its registry from this enum
(via the generated contract), so the two can never drift.

# $defs.ApiErrorCode.oneOf[].description
The request body was not JSON at all (400).

# $defs.ApiErrorCode.oneOf[].description
The JSON body failed schema validation — `ApiError.param` names the
offending field (400), and a per-item scan rejection carries this code.

# $defs.ApiErrorCode.oneOf[].description
The claim code was rejected — burned, stale, or unknown (404).

# $defs.ApiErrorCode.oneOf[].description
Missing/invalid device token (401) — revoked or rotated at HQ.

# $defs.ApiErrorCode.oneOf[].description
The token's device does not match the body's `gatewayId` (403).

# $defs.ApiErrorCode.oneOf[].description
The addressed record does not exist (404).

# $defs.ApiErrorCode.oneOf[].description
A command ack replay: HQ already recorded a terminal outcome (404,
same status as `not_found` for wire compat — the code disambiguates).

# $defs.ApiErrorCode.oneOf[].description
Per-device/IP throttle tripped (429) — `ApiError.retryAfterSecs` says
when the budget refreshes.

# $defs.ApiErrorCode.oneOf[].description
Unexpected HQ fault (500) — opaque; correlate via `ApiError.requestId`.

# $defs.ApiErrorCode.oneOf[].description
The public read-only demo floor refused a write (403) — not an agent
fault; nothing to retry.

# $defs.ClaimRequest.description
The agent's identity claim: presented once at first power-on to redeem a
single-use claim code for a long-lived device token. HQ stores only the HASH
of the issued token — the plaintext appears once, in the claim result.

# $defs.ClaimRequest.properties.agentVersion.description
The agent build that is claiming, for support + compatibility checks.

# $defs.ClaimRequest.properties.claimCode.description
The claim code printed on the unit / shown in HQ. Single-use.

# $defs.ClaimRequest.properties.gatewayHardwareId.description
A stable per-gateway hardware id (e.g. the Pi's machine-id) so a re-claim
from the same box is recognizable.

# $defs.ClaimResult.description
HQ's response to a successful claim: the device's fleet id and the bearer
token the agent presents on every later call. The token is shown exactly
once (here); HQ keeps only its hash.

# $defs.ClaimResult.properties.deviceToken.description
Opaque bearer secret — sent as `Authorization: Bearer mf_dev_<token>`.

# $defs.ClaimResult.properties.heartbeatIntervalSecs.description
How often (seconds) the agent should heartbeat.

# $defs.Command.description
A command HQ wants the gateway to run. Adjacently tagged (`kind` + `payload`)
so the discriminant is type-checked and new commands are additive.

# $defs.Command.oneOf[].description
Encode + send a label to a bound printer.

# $defs.Command.oneOf[].description
Re-run discovery and report peripherals.

# $defs.CommandAck.description
The agent's acknowledgement of a command. Carries the `PrintResult` for a
print so HQ shows what was transmitted (honest wording: see `PrintResult`).
The agent sends this; HQ receives and deserializes it.

# $defs.CommandAck.properties.result.description
Present for an applied print; `None` for a rescan or a failure.

# $defs.CommandStatus.description
Outcome of applying a command, so HQ can drain the queue and surface results.

# $defs.CommandStatus.oneOf[].description
Dropped because it was past `expires_at`.

# $defs.DiscoveredPeripheral.description
A peripheral the gateway found on the LAN during discovery, reported so HQ
can surface it for adoption/binding.

# $defs.DiscoveredPeripheral.properties.model.description
Best-effort model string (from a probe / mDNS / USB descriptor).

# $defs.DiscoveredPeripheral.properties.serial.description
Serial number, if the peripheral reports one.

# $defs.Envelope.description
A command addressed to one device, with issue/expiry timestamps so a stale
command (the unit already moved on) can be dropped rather than misapplied.

# $defs.Envelope.properties.expiresAt.description
RFC3339 expiry; the agent drops the command after this instant.

# $defs.Heartbeat.description
Liveness + roster ping the agent POSTs on an interval. The freshness of
heartbeats is what flips a device online⇄offline in HQ.

# $defs.Heartbeat.properties.peripherals.description
Current reachability of each peripheral the gateway manages.

# $defs.Heartbeat.properties.seq.description
Monotonic per-agent sequence number, so HQ can detect gaps/restarts.
Stays well under 2^53, so it survives the JSON-number round-trip to HQ.

# $defs.HeartbeatAck.description
HQ's 2xx response to a heartbeat — the fleet's config channel back to the
agent. The agent parses this opportunistically: a body that doesn't parse
(an HQ predating this shape) is treated as legacy, never as a failed beat.

# $defs.HeartbeatAck.properties.agent.description
The upgrade nudge — see [`AgentCompat`].

# $defs.HeartbeatAck.properties.heartbeatIntervalSecs.description
The cadence HQ currently wants (seconds). Optional: pre-M8 HQ builds
omit it; the agent keeps its claim-time cadence when absent.

# $defs.HeartbeatAck.properties.lastSeen.description
When HQ recorded this beat (RFC3339). Nullable in HQ's fleet model,
hence optional on the wire.

# $defs.HeartbeatAck.properties.status.description
The device's fleet status as HQ records it (e.g. `online`). The
vocabulary is HQ-owned and advisory, so it stays an open string.

# $defs.PeripheralKind.description
What a discovered/managed peripheral is. A gateway adopts the printers and
scanners on its LAN; it is itself the gateway, so a peripheral is never that.

# $defs.PeripheralKind.oneOf[].description
A label printer (raw TCP-9100 / ZPL-II).

# $defs.PeripheralKind.oneOf[].description
A barcode/QR scanner (HID wedge or USB-CDC).

# $defs.PeripheralStatus.description
One peripheral's liveness as seen by the gateway this heartbeat.

# $defs.PeripheralStatus.properties.address.description
Network address (e.g. `192.0.2.10:9100`) or device path; `None` if a
peripheral known to HQ wasn't seen this cycle.

# $defs.PeripheralStatus.properties.reachable.description
Whether the gateway could reach it this cycle.

# $defs.PrintCommand.description
Payload for a `print` command. The agent encodes `label` to ZPL-II locally
and sends it to `target` over raw TCP-9100.

# $defs.PrintCommand.properties.target.description
The printer to send to (`host:port`), as bound in HQ.

# $defs.PrintResult.description
Outcome of a print operation — what was sent, in which dialect, where.
Serializes for `--output json`; Displays for human output.

# $defs.ScanEvent.description
A single decoded scan. `kind` is always derived from `value`, so the two can
never contradict; fields are public for read/serialization.

# $defs.ScanItemResult.description
One uploaded scan's verdict, in upload order (positional correlation is
guaranteed even when a malformed item's `clientId` could not be echoed).

# $defs.ScanItemResult.properties.clientId.description
The uploaded item's idempotency key, echoed back (best-effort for a
malformed item — may be empty; order still correlates).

# $defs.ScanItemResult.properties.code.description
Rejection cause from the [`ApiErrorCode`] registry; absent unless
`status` is `rejected`.

# $defs.ScanItemStatus.description
Per-item outcome of one uploaded scan in a batch (`ScanUploadResults`).

# $defs.ScanItemStatus.oneOf[].description
Already recorded (idempotent replay on `clientId`) — still durable.

# $defs.ScanItemStatus.oneOf[].description
NOT stored — see the item's `code`; the agent quarantines exactly this
line and keeps delivering the rest.

# $defs.ScanKind.description
A best-effort classification of a scanned value — a hint, not authoritative
symbology. Grows into real symbology detection when scanners report it.

# $defs.ScanKind.oneOf[].description
Anything else — note `MF-1` is text, not alphanumeric, so this is the
honest catch-all name.

# $defs.ScanReport.description
The scans captured in one invocation, with line accounting so dropped/blank
lines are visible rather than silently undercounted.

# $defs.ScanReport.properties.skipped.description
Lines that produced no scan (blank/whitespace-only): `read - count`.

# $defs.ScanUpload.description
A batch of captured scans the agent uploads (drained oldest-first from its
local store-and-forward buffer). The agent sends this; HQ receives it.

# $defs.ScanUploadResults.description
HQ's 2xx response to a scan upload: per-item verdicts IN UPLOAD ORDER plus
the batch's durable count (`recorded` + `duplicate` items). A poisoned item
never rejects its batch — the agent quarantines only `rejected` lines. Like
[`HeartbeatAck`], parsed opportunistically: an unparseable body is a legacy
HQ and the whole acked chunk counts as delivered (the pre-results behavior).

# $defs.ScanUploadResults.properties.recorded.description
Scans durably in the genealogy from this batch (new + duplicate).

# $defs.ScanUploadResults.properties.results.description
One verdict per uploaded scan, in upload order.

# $defs.UploadedScan.description
One captured scan queued for upload, carrying a client-generated id so HQ can
dedupe (at-least-once delivery → effectively-once into the genealogy).

# $defs.UploadedScan.properties.capturedAt.description
RFC3339 capture time (set on the gateway, before any network attempt).

# $defs.UploadedScan.properties.clientId.description
Gateway-unique id for this scan (idempotency key).

# $defs.UploadedScan.properties.stationId.description
The station the scan was captured at, if the device is bound to one.