From 268c2a66ad00e89bfaf00036476472304d8fd639 Mon Sep 17 00:00:00 2001 From: atlas Date: Tue, 2 Jun 2026 15:01:15 +0200 Subject: [PATCH] fix(#1087): use correct "cmd" tag in matrix wake signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hive_sh4re::Request uses #[serde(tag = "cmd")] so Wake serialises as {"cmd":"wake",...}. The wake.rs in hive-matrix-mcp was sending {"kind":"wake",...} — the harness could not deserialise the message and silently discarded every incoming matrix event. Also: drain the server's response line instead of just shutting the write half. Without the drain the server got ECONNRESET writing back, which logged a spurious error even though the wake itself was now processed. Root cause of the matrix notification blackhole reported in #1087. --- hive-matrix-mcp/src/wake.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/hive-matrix-mcp/src/wake.rs b/hive-matrix-mcp/src/wake.rs index 34e09dcd..5ce5b8e5 100644 --- a/hive-matrix-mcp/src/wake.rs +++ b/hive-matrix-mcp/src/wake.rs @@ -28,24 +28,37 @@ pub const WAKE_BODY_TRUNCATE: usize = 100; /// control socket at `socket`. Best-effort: returns Err on any plumbing /// failure; callers log + ignore so a wake delivery hiccup doesn't tear /// down the matrix sync loop. +/// +/// Wire format matches `hive_sh4re::Request` tagged with `"cmd"` per +/// `#[serde(tag = "cmd", rename_all = "snake_case")]`. Must be `"cmd"`, +/// not `"kind"` — the harness deserialises against the hive-sh4re type +/// and silently discards requests that don't match. pub async fn send_wake(socket: &Path, body: impl AsRef) -> Result<()> { + use tokio::io::AsyncBufReadExt; + let payload = serde_json::json!({ - "kind": "wake", + "cmd": "wake", "from": "matrix", "body": body.as_ref(), }); let line = format!("{}\n", serde_json::to_string(&payload)?); - let mut stream = UnixStream::connect(socket) + let stream = UnixStream::connect(socket) .await .with_context(|| format!("connect hyperhive socket {}", socket.display()))?; - stream + let (read, mut write) = stream.into_split(); + write .write_all(line.as_bytes()) .await .with_context(|| format!("write wake to {}", socket.display()))?; - stream + write .shutdown() .await .with_context(|| format!("shutdown write to {}", socket.display()))?; + // Drain the response line so the server doesn't get ECONNRESET on + // its write-back. We don't act on the response — best-effort wake. + let mut reader = tokio::io::BufReader::new(read); + let mut _resp = String::new(); + let _ = reader.read_line(&mut _resp).await; Ok(()) }