# ADR-0004: Read-only SQL-over-SSH as the peer query contract; no debug API ## Status Accepted (2026-07-08). Supersedes the earlier sketch of a bespoke query service. ## Context Beyond the 5 Hz broadcast, a peer (or an engineer on the bench) sometimes needs to *ask* a drone a richer question: "show me your detections in the last minute near this position". Inventing a service for this means a new port, a new protocol, an auth layer, and a second code path that only runs during debugging — the classic "works on the bench, untested in flight" trap. ## Options | Option | Pros | Cons | | --- | --- | --- | | A — Custom query microservice + REST API | Flexible | New port/protocol/auth to secure; a debug-only path that never flies | | B — Read-only DuckDB SQL over an SSH forced command | Reuses SSH trust + the query language already on both ends; identical path on bench and in flight | SQL must be gated to read-only | ## Decision Peer data access is **read-only DuckDB SQL executed through an SSH forced command**. SQL is already the query language on both ends ([ADR-0002](ADR-0002-one-storage-format.md)), and SSH already carries the trust model ([ADR-0005](ADR-0005-wireguard-beneath-ssh.md)), so no new service, port, or protocol is invented. A **SQL gate** rejects anything that writes (`COPY`, `INSERT`, `ATTACH`, pragmas). There is **no separate debug API**: an engineer debugging on the ground runs the identical query through the identical wrapper, permissions, and output format a peer drone would use. ## Consequences - One access path is designed for flight and bench — "what you test is what flies". - The statement gate in the PoC (`simulator/explorer/server.py`, covered by `simulator/tests/test_sql_gate.py`) is a **first layer**: keyword allow/deny over HTTP for the explorer. Production still needs the remaining layers in [04 — Swarm sync](../04-swarm-sync.md) (forced-command key, read-only OS user, engine hardening, resource caps) and a real SQL parser rather than keywords alone. - The explorer and the prototype's live mode are *stand-in consumers* of the same read-only contract over HTTP today; the proposed flight path is SQL-over-SSH ([`../04-swarm-sync.md`](../04-swarm-sync.md)). - Design principles 7 and 8 in [`../../README.md`](../../README.md) restate this.