Thing lifecycle — five states¶
Every device (a thing) that a factory onboards moves through a five-state lifecycle defined by ADR-0026 and made concrete on the wire by the DDI-1 contract §5. Understanding these states — and the transitions between them — is the mental model behind every endpoint in the API reference and every error bucket in the error catalog.
Diagram source: _static/diagrams/factory-lifecycle.mmd (mermaid stateDiagram-v2),
regenerable with the repo mmdc pattern — see Contributing.
The five states¶
ROLLEDOFF¶
The device has rolled off the factory line with bootstrap firmware and a
factory-burned attestation token (plus the platform trust-anchor set) — but no
platform identity yet. On first boot it calls POST /ddi/v1/identify (DDI-1 §3.1) with
the attestation token. A recognized identity advances the thing toward PROVISIONED; an
unrecognized serial returns DDI-1-403-NOT-RECOGNIZED, and a blacklisted identity returns
DDI-1-403-IDENTITY-BLACKLISTED (jumping straight to the terminal ANNIHILATED view).
PROVISIONED¶
The device has completed POST /ddi/v1/provision (DDI-1 §3.2) and now holds a signed
X.509 device certificate + CA chain. It switches from attestation-token auth to
mTLS, opens its MQTT 5.0 connection on port 8883, subscribes to shared-attribute
pushes and commands, and publishes its initial client-attribute snapshot. The attestation
token is invalidated platform-side. The thing is enrolled but not yet carrying production
workload.
ACTIVATED¶
The cloud-side state after OS / software install completes (delivered via the OTA update surface, DDI-1 §3.5). From the device’s perspective this is simply normal operation: telemetry, events, heartbeat, and logs flow per DDI-1 §4. This is the steady state a healthy fleet device spends almost all of its life in.
DEACTIVATED¶
The device’s certificate has been revoked. Its next mTLS attempt fails with a TLS
alert certificate_revoked (DDI-1-403-CERT-REVOKED). Firmware should halt cloud
communication after N consecutive cert failures and back off. A DEACTIVATED thing is
not terminal — the cloud can re-issue a certificate via POST /ddi/v1/rotate and
re-activate the device, returning it to ACTIVATED (the re-activation edge in the
diagram above).
ANNIHILATED¶
The terminal state. The identity has been blacklisted (ADR-0026).
POST /ddi/v1/identify returns DDI-1-403-IDENTITY-BLACKLISTED and firmware MUST stop
retrying — log and halt. A thing can be annihilated from any non-terminal state; once
annihilated it never returns.
State transitions at a glance¶
From |
To |
Trigger |
Wire call (DDI-1) |
|---|---|---|---|
(burn) |
|
factory burn |
— |
|
|
identify + provision |
§3.1 + §3.2 |
|
|
activate (OS/software install delivered) |
§3.5 (OTA) |
|
|
deactivate (cert revoked) |
cert revocation |
|
|
re-activate (cert re-issued) |
§3.3 (rotate) |
|
|
annihilate (blacklist) |
§3.1 returns 403 (terminal) |
Where errors map to states¶
The lifecycle is also the spine of the error catalog: the thing-state-machine
bucket (bucket 4) covers illegal-transition and wrong-state errors (for example,
attempting to activate a thing that is still ROLLEDOFF), and the identity / blacklist
bucket covers the ANNIHILATED terminal-identity errors. See the
error catalog for the full mapping of each THM-* code to the state it
guards. The state-change feed that reports these transitions to your backend is documented
in the API reference under /api/v1/state-changes.
Trust anchors ride the ACTIVATE edge¶
Every ACTIVATE (both first-time from PROVISIONED and re-activation from DEACTIVATED)
carries the platform trust-anchor envelope to your provision-role backend. See
Trust-anchor delivery for the envelope contract and the
verb/leg matrix.