# 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 built, secured, and tested — "what you test is what flies". - The SQL gate is safety-critical and is covered by unit tests (`simulator/tests/test_sql_gate.py`). - The explorer and the prototype's live mode are *just another read-only consumer* of this same contract ([`../04-swarm-sync.md`](../04-swarm-sync.md)). - Design principles 7 and 8 in [`../../README.md`](../../README.md) restate this.