Files
atelier/domains/edge/iot.md
T
Jon Chery 20992883ff docs(P01): complete edge domain phase — v0.4
---ci---
project: atelier
phase: 1
milestone: v0.4
status: complete
phase_role: execution
phase_tag: v0.3.1
requirements:
  covered: [ATELIER-92, ATELIER-93, ATELIER-94, ATELIER-95, ATELIER-96]
  partial: []
---/ci---
2026-08-05 15:51:03 +00:00

12 KiB
Raw Blame History

IoT — Derived Rules

Derives from domains/edge/first-principles.md. Applies P3 (Resources are Constrained and Declared) primarily, with P5 (command idempotency), P7 (partial degradation when devices drop), P9 (device identity and provisioning), and P10 (telemetry from devices). Cross-links domains/security/secrets for device credentials and domains/messaging/queues for the MQTT QoS parallels to delivery semantics.

What IoT at the Edge Is (P3 Resources are Constrained and Declared)

  • IoT at the edge is the engineering discipline of operating constrained devices — sensors, actuators, gateways, microcontrollers — as first-class participants in a distributed system. The distinguishing constraint is per-device resource bounds (P3): a battery-powered sensor has kilobytes of RAM, a constrained protocol, and a multi-year sleep budget. These constraints are declared per device class, never assumed infinite.
  • The boundary is per D-061: edge owns the constrained-device reality; performance owns the generic unbounded-growth-is-a-bug principle (performance/P4 Resource Bounds); concurrency owns in-process primitives. IoT is an edge concern because its defining traits are constrained resources (P3), geographic distribution as a fleet (P8), partition-prone operation (P2), and device-scoped identity (P9) — concerns that only arise at the network edge.
  • See domains/edge/offline-first.md for the partition-survival discipline that constrained devices depend on, and domains/edge/sync.md for the reconciliation of device state across partitions.

Device Resource Classes (P3, C8 Economy)

  • A device resource class declares the bounds for a class of devices: CPU (MHz, cores), memory (KB/MB), power (battery mAh, duty-cycle budget), bandwidth (bytes/sec, latency budget), and storage (KB/MB). Every device in the fleet is assigned to a class; every operation is budgeted against its class.
  • An undeclared budget is a defect (P3 violation): a sensor that sends telemetry every second without a duty-cycle budget exhausts its battery in days, not years. The budget is the correctness bound (C1) and the economy bound (C8).
  • A device class implies a protocol choice: a class-0 device (constrained sensor, KB RAM) speaks CoAP; a class-1 device (gateway, MB RAM) speaks MQTT; a class-2 device (edge compute node, GB RAM) speaks HTTP. The protocol follows the constraint, not the reverse.
Class RAM Power Protocol Typical role
0 (constrained sensor) < 10 KB Battery, multi-year CoAP, LoRaWAN Telemetry only, no inbound commands
1 (actuator, gateway) 10 KB 1 MB Battery or wired, weeks-months MQTT, CoAP Telemetry + commands, queue-and-forward
2 (edge compute) > 1 MB Wired, continuous HTTP, MQTT Local aggregation, gateway, edge inference

Constrained Protocols — MQTT and CoAP (P3, P5)

  • MQTT is the canonical pub/sub protocol for constrained devices. It is lightweight (2-byte header), broker-backed, and provides QoS levels (0, 1, 2) that map to delivery semantics. MQTT is the cross-process analog of message-queue delivery — see domains/messaging/queues for the general queue/delivery-semantics discipline; the cross-link is one-directional outward (edge → messaging) per D-062 and D-026 extended.
  • CoAP is the REST analog for constrained devices: UDP-based, low-overhead, with confirmable (CON) and non-confirmable (NON) message types. CoAP fits class-0 devices where TCP is too heavy.
  • A blocking synchronous call on a constrained device with no timeout is the blocking-call-on-constrained-device chaos anti-pattern: it blocks the node, has no timeout (= hang), and retries are unsafe without idempotency (P3 + P5 breach). Every device operation must be async with a timeout, and every retried operation must be idempotent.
// MQTT publish/subscribe payload with QoS levels (P5 idempotency,
// P3 constrained protocol).
// QoS 0 — at-most-once: fire-and-forget, no ack. For telemetry
// where a dropped sample is acceptable (P3 economy of the
// constrained link).
{
  "topic": "devices/sensor-7/temperature",
  "qos": 0,
  "payload": {
    "device": "sensor-7",
    "ts": 1700000000,
    "value": 21.4,
    "unit": "C"
  }
}

// QoS 1 — at-least-once: acked, may duplicate. The consumer must
// be idempotent (P5) — dedup by (device, ts) or an idempotency key.
{
  "topic": "devices/actuator-3/command",
  "qos": 1,
  "payload": {
    "device": "actuator-3",
    "idempotencyKey": "cmd-1700000000-1",
    "command": "set-point",
    "value": 22.0
  }
}

// QoS 2 — exactly-once: four-step handshake, no duplication. The
// heaviest QoS; use only where duplicates are intolerable AND the
// device has the budget for the handshake (class-1+ only, P3).
{
  "topic": "devices/actuator-3/irreversible-command",
  "qos": 2,
  "payload": {
    "device": "actuator-3",
    "idempotencyKey": "cmd-1700000000-2",
    "command": "calibrate"
  }
}
  • The QoS choice is a P5 (idempotency) and P3 (resource) decision: QoS 0 is cheapest (no ack) but lossy; QoS 1 requires consumer idempotency (P5); QoS 2 is exactly-once but costs a four-step handshake on a constrained link. The default for telemetry is QoS 0 or 1; the default for commands is QoS 1 with an idempotency key (P5); QoS 2 is reserved for irreversible commands where the device budget permits.

Device Identity and Provisioning (P9 Identity is Constrained at the Edge)

  • Every device holds a per-device identity: a unique device ID and a scoped credential (X.509 certificate, API token, or rotating key). No shared fleet credential — one compromise must not equal a fleet compromise (P9). The credential scope is minimal: a device can publish to devices/<its-id>/+ and subscribe to devices/<its-id>/commands, nothing else.
  • Provisioning is the act of assigning a device identity at enrollment time. The provisioning manifest declares the device, its class, its allowed topics, and its credential. The manifest is the P9 contract — a device operating outside its manifest scope is a violation.
  • A device that is provisioned with a shared fleet key (the shared-edge-device-credential anti-pattern) is a P9 violation: blast radius is unbounded. See domains/security/secrets for the general secret-hygiene discipline (per-identity credentials, rotation, minimal scope) that device provisioning builds on.
# Device provisioning manifest (P9 per-device identity + scoped
# credentials). The manifest is the contract; the device operates
# only within its declared scope.
device:
  id: sensor-7
  class: 0                    # P3 resource class
  model: temp-sensor-v2
  firmware: 1.4.2
identity:
  cert: "sha256-of-device-cert"
  credentialScope:
    publish:
      - "devices/sensor-7/temperature"
      - "devices/sensor-7/status"
    subscribe:
      - "devices/sensor-7/commands"
    # No wildcard, no fleet-wide topics (P9).
provisioning:
  enrolledAt: 2024-01-15T00:00:00Z
  rotatesEvery: 90d
  # Per-device credential; never shared (P9, domains/security/secrets).

Telemetry from Devices (P10 Edge Observability Survives Partition)

  • Device telemetry is local-first (P10): the device buffers telemetry on-node and forwards on reconnect. A fire-and-forget telemetry pipeline loses data when the link drops; a buffered pipeline survives. The buffer is bounded by the device class (P3): a class-0 sensor buffers minutes of telemetry, not hours.
  • Telemetry is observable in aggregate: the operator sees the fleet's behavior, not just per-device. A device that has not reported in its expected interval is itself a signal (a dead device, a partitioned device, a drained battery). See domains/observability/metrics for the generic structured-metrics discipline; edge owns the partition-survivable, local-first angle.
  • Telemetry must not be a secrets channel (P9 analog, see domains/observability/P6 No Secrets in Observability): device credentials, PII, and personally-identifying location must not enter telemetry payloads.

Command Idempotency (P5 Edge Operations are Idempotent)

  • Device commands are retried by nature (the network is partition-prone). Every command carries an idempotency key so a retried command does not double-apply (P5). A set-point command retried with the same idempotency key sets the point once, not twice; an open-valve command retried is safe because the valve is already open.
  • Irreversible commands (a calibration burn-in, a firmware flash) require stronger idempotency: the device tracks applied idempotency keys and refuses re-application. A retried irreversible command without idempotency tracking double-applies the effect (P5 violation, possibly a physical-side-effect bug).
  • The idempotency key is per-command, not per-device. A device that dedups by device ID alone will drop distinct commands issued in the same window. Use (device, command-id, ts-window) or a UUID per command.

Partial Degradation When Devices Drop (P7 Partial Degradation is Engineered)

  • A fleet degrades when devices drop (battery exhaustion, partition, hardware failure). The system must continue to operate with the remaining devices; a whole-system crash on one device's failure is a P7 violation. The degraded mode is documented: which aggregations are valid with N-1 devices, which alerts fire, which fallbacks engage.
  • A device that drops is not an incident by itself — fleets expect churn. The operator-facing signal is the aggregate health (X% of devices reporting, Y% partitioned for >Z minutes), not the per-device drop. Per-device drop alerts are noise; aggregate degradation alerts are signal (see domains/observability/metrics).
  • A command to a dropped device must time out (P5 — idempotent retry) and degrade (P7 — the fleet continues without that device). A command that blocks forever waiting for a dropped device is the blocking-call-on-constrained-device chaos anti-pattern (P3 + P5 breach).
  • MQTT QoS 0/1/2 maps to at-most-once / at-least-once / exactly-once delivery semantics — the same three-way tradeoff documented in domains/messaging/queues. The cross-link is one-directional outward (edge → messaging) per D-026 extended: edge owns the constrained-device protocol angle; messaging owns the generic cross-process delivery-semantics angle.
  • This link dangles until P2 (the messaging domain is authored in P2); it is verified bidirectional in P5 (ATELIER-114 per IDEATE-40). Acceptable per D-053 (vertical-slice integrity — P1 ships the edge domain self-consistent; the messaging cross-link resolves by the P6 ship).
  • The parallel: a constrained device's QoS 1 publish is the device-flavored instance of an at-least-once queue delivery — the consumer (the broker or the downstream service) must be idempotent (P5 here, messaging/P3 Consumers are Idempotent there). The idempotency discipline is the same; the protocol and failure model differ (constrained-device link vs broker-backed network).

What Violates IoT-at-the-Edge Discipline

Violation Principle
Undeclared device resource budget (assumes infinite battery/RAM) P3 Resources are Constrained and Declared
Shared fleet credential (one key for all devices) P9 Identity is Constrained at the Edge
Non-idempotent device command (retried command doubles the effect) P5 Edge Operations are Idempotent
Blocking synchronous call on a constrained device with no timeout P3, P5 (blocks the node; retry unsafe)
Fire-and-forget telemetry with no on-device buffer (lost on partition) P10 Edge Observability Survives Partition
Whole-system crash on one device's failure (no degradation contract) P7 Partial Degradation is Engineered
Device credential scope that includes fleet-wide topics (over-scoped) P9, domains/security/secrets
QoS 2 used on a class-0 device (no budget for the handshake) P3 Resources are Constrained and Declared
Per-device-drop alert (noise; aggregate degradation is the signal) P7, domains/observability/metrics
Telemetry payload that includes device credentials or PII P9, domains/observability/P6 No Secrets in Observability