diff --git a/src/room/state.rs b/src/room/state.rs index 4817732..c987eaf 100644 --- a/src/room/state.rs +++ b/src/room/state.rs @@ -157,6 +157,11 @@ const NO_ACTIVE_TURN_ERROR_CODE: i64 = -32002; /// clients can render "queue full" rather than generic turn serialization. const QUEUE_FULL_ERROR_CODE: i64 = -32003; +/// JSON-RPC error code returned when a mux-owned queue item no longer +/// exists. Kept distinct from invalid params so clients can distinguish +/// malformed input from a remove/submit race. +const QUEUE_ITEM_NOT_FOUND_ERROR_CODE: i64 = -32004; + /// Standard JSON-RPC invalid params code used when an amux control request /// is missing its text/session payload. const INVALID_PARAMS_ERROR_CODE: i64 = -32602; @@ -2033,7 +2038,7 @@ impl RoomInner { self.send_error_response( peer_id, req.id, - INVALID_PARAMS_ERROR_CODE, + QUEUE_ITEM_NOT_FOUND_ERROR_CODE, "queue item not found", ); return None; diff --git a/tests/server.rs b/tests/server.rs index 398f4cb..6de78ed 100644 --- a/tests/server.rs +++ b/tests/server.rs @@ -2816,6 +2816,30 @@ async fn amux_unqueue_prompt_removes_pending_item_and_replays_removal() { let _ = ws_c.send(ClientMsg::Close(None)).await; } +#[tokio::test] +async fn amux_unqueue_prompt_missing_item_uses_queue_not_found_error() { + let (addr, _) = spawn_server_with_mock_env(&[]).await; + let url = format!("ws://{addr}/acp?room=busy-fixes&peer_id=A"); + + let (mut ws, _) = tokio_tungstenite::connect_async(url).await.unwrap(); + let _ = ws_request(&mut ws, r#"{"jsonrpc":"2.0","id":1,"method":"initialize"}"#).await; + + let response = ws_request( + &mut ws, + r#"{"jsonrpc":"2.0","id":300,"method":"amux/unqueue_prompt","params":{"queueItemId":"q-missing"}}"#, + ) + .await; + + assert_eq!(response["id"], serde_json::json!(300)); + assert_eq!(response["error"]["code"], serde_json::json!(-32004)); + assert_eq!( + response["error"]["message"], + serde_json::json!("queue item not found") + ); + + let _ = ws.send(ClientMsg::Close(None)).await; +} + #[tokio::test] async fn amux_disconnected_queue_owner_persists_without_becoming_driver() { let (addr, _) = spawn_server_with_mock_env(&[("MOCK_ACP_PROMPT_DELAY_MS", "500")]).await;