What happened

GET /camera/{id}/snapshot read {id} off the path, then never used it again. It unconditionally shelled out to rpicam-still and streamed back a brand-new live frame at a hardcoded 1280x720 — for any id, camera or not.

This is the exact route ServerNodeManager.readCameraSnapshot() calls to fetch a peer-owned camera’s frame for a cross-server vision LLM (krill#860/#861). So a capture on host A would publish snapshot=A, wake an LLM on host B, and the LLM’s fetch of “the frame that woke it” would return a freshly-captured frame B instead — silently, since both are valid JPEGs. Two Camera nodes on the same host also returned identical bytes, because the id that distinguished them was discarded before it could matter.

Root cause

The route predates the feature that made it load-bearing. It shipped with the original Camera node (krill@1c66f6f23, 2026-03-30) as a “capture me a frame right now” endpoint for the UI, well before any node published meta.snapshot or before a peer route existed at all — at the time, ignoring {id} in favor of “whatever camera is attached to this Pi” was harmless because there was exactly one camera and no published state to prefer. krill#842 later taught the camera processor to publish captured frames onto meta.snapshot.value, and krill#860/#861 wired an LLM to fetch that exact path across hosts — but nobody revisited this route to make it serve what it now had to serve.

Fix

Prevention