How controls reach the device (edge v2)
- The edge worker commits a downlink intent in the transactional outbox.
- It stages
EdgeIngestControlRequestedV2on the MQTT downlink exchange (edge.ingest_control.requested.v1, domainedge). - The mqtt-broker consumes from
mqtt_broker_downlink_queueand publishes the JSON body to the device topic at QoS 1.
sync/ingest/ack and sync/ingest/request are device → cloud topics. They ingress on edge_ingress_exchange and are consumed by the edge worker — not delivered as MQTT downlinks.Shared envelope
Required device behavior (all kinds)
- ACK immediately on
sync/ingest/ackwith samecontrol_id. - Then execute kind-specific logic.
edge_pending_controls until ACK received.
pause_lineage
When sent:- Volume backpressure (staged rows exceed cap)
- Materialization circuit breaker
- Schema review pause alone (server stages while device keeps sending)
- Stop publishing batches for
source_table. - Buffer new journal rows durably (Omega:
state.db+ buffer store). - Record
server_watermark— last acceptedcommit_seq(rows) orbatch_seq(telemetry).
resume_lineage
When sent:- Backlog drained below resume threshold (auto sweep)
- After
reset-materializationwhen device had been pause-downlinked
- Drain buffer in commit_seq / batch_seq order starting at
server_watermark + 1. - Resume normal 5s flush loop.
- If local buffer was lost during pause → request bootstrap snapshot (secondary flow, when available).
url_grant
Secondary flow for large backfill or spill objects. Device actions:- ACK control.
- HTTP PUT zstd-compressed JSONL (
.jsonl.zst) topresigned_url(15 min TTL). - Publish finalize on
sync/ingest/requestwith matchingbatch_idandsegment_kind.
state_write
Cloud-originated desired state for cloud_authoritative tables (Pipeline B). When sent:- Operator calls
POST .../devices/{device_id}/edge/state-tables/{table_id}/rows - Edge worker upserts rows in the cloud state table, then stages a downlink
- ACK on
sync/ingest/ack. - Apply rows to the local SQLite table for the matching
source_table. - Persist the supplied
cloud_versionper primary key so the nextsync/rows/batchupload for those rows carrieslkcv.
Protocol diagram
url_grant, the device also publishes sync/ingest/request (finalize) after the HTTP PUT.
Omega implementation
Modulesqlite-replication subscribes to the control topic, handles pause/resume in state/store.go, ACKs via sync/ingest/ack, applies state_write rows into the local SQLite database, and records cloud_version so the next row-batch upload includes lkcv for the touched primary keys.
Verify in logs: