Direct answer

Use a device shadow only for state that can be reconciled between a desired value and an observed device value. Store desired and reported documents separately, version every change, timestamp observations, and expose uncertainty. Do not turn commands, event history, or assumptions about an offline device into shadow state. Reconciliation must be idempotent, bounded, and safe when messages arrive late or out of order.

Scope and non-scope

A shadow provides a platform representation of selected device state while the device is disconnected or slow. It does not prove physical truth, replace telemetry history, or guarantee that desired state was applied. A shadow may say the last reported valve position was closed; it cannot claim the valve is currently closed after hours without contact.

Choose shadowed properties carefully

A property belongs in desired state when an authorized actor can set a target and the device can eventually report whether it applied that target. Sampling interval, display brightness, or an operating mode may fit. One-shot actions such as reboot, dispense, unlock, or “run calibration now” are commands with identifiers, expiry, and outcomes, not durable desired values that may replay indefinitely.

Reported state should contain device-observed values needed for reconciliation, not every telemetry sample. Include device timestamp where trustworthy, platform receive time, firmware or schema version, and a monotonically comparable document or property version. Keep historical changes in an event or time-series store.

State and version model

Represent at least desired value and version, reported value and version, last contact, and reconciliation status. Status should distinguish pending, applied, rejected, expired, superseded, and unknown. A delta is a convenience derived from authoritative documents; it should not become a third source of truth.

Use optimistic concurrency when services update desired state. A caller supplies the version it read, and conflicting updates are rejected or merged through explicit domain rules. The device acknowledges the desired version it processed. Never infer success merely because reported value happens to equal desired value; it may have been set locally or correspond to an older request.

Reconciliation flow

  1. An authorized service reads the current desired version and submits a conditional update.
  2. The platform persists the update before publishing a notification.
  3. The device receives the newest applicable version and checks compatibility, safety, and expiry.
  4. It persists intent if needed, applies the change, then reports the processed desired version and observed result.
  5. The platform updates reconciliation status only when the report satisfies version and identity checks.
  6. On reconnect, the device and platform compare versions and choose the newest valid desired document.
  7. Superseded or incompatible requests remain auditable but are not replayed.

Decide whether configuration is atomic as one document or independently versioned by property. Atomic documents simplify consistency but can cause unrelated writers to conflict. Property-level updates increase merge complexity. Choose from domain invariants rather than framework convenience.

Failure modes

Out-of-order reported messages can make a device appear to revert. A desired reboot flag can reboot forever after every reconnect. Two services writing an unversioned document can silently overwrite each other. A platform can show “synced” while the device reported before physical actuation completed. Clock skew can make a newer observation look old. Retaining shadow updates on a broad MQTT topic can leak state across tenants if ACLs are weak.

An offline shadow also tempts applications to treat cached state as live. Every read response should expose freshness and connectivity so callers can decide whether stale information is acceptable.

Implementation checklist

  • Every shadow property is reconcilable state, not an event or command.
  • Desired and reported documents have explicit versions.
  • Writers use conditional updates or defined merge rules.
  • Device reports the desired version it actually processed.
  • Pending, applied, rejected, expired, superseded, and unknown are distinguishable.
  • Freshness and last-contact context accompanies shadow reads.
  • Reconnect and out-of-order tests prove deterministic convergence.
  • History and audit records live outside the current-state document.

Review evidence

Keep a property catalog that states owner, type, desired writer, reporting source, safety impact, freshness expectation, and merge rule. For every new property, demonstrate offline update, competing writers, duplicate notification, out-of-order report, device reboot, platform restore, and unsupported desired value. Preserve document versions and decisions from these tests.

Audit callers that read shadows. They should consume freshness and reconciliation status rather than only the cached value. Sample production conflicts, long-pending changes, rejected versions, and updates overwritten before application. If operators routinely force a reported value to clear a discrepancy, the model is hiding a workflow problem. Remove unused properties and writers; a shadow that accumulates abandoned state becomes an ungoverned control interface with unclear authority.

Primary sources

The IETF YANG-Push specification, RFC 8641 provides useful normative concepts for datastore updates, change notifications, and subscription state, although a product shadow is not YANG-specific. MQTT transport behavior comes from the OASIS MQTT 5.0 specification. The product must document its own concurrency, persistence, and reconciliation semantics.