From 676ee682ec4ac302c707cd2d116fb5cb55d91b21 Mon Sep 17 00:00:00 2001 From: Sathvik-1007 Date: Mon, 8 Jun 2026 20:49:33 +0530 Subject: [PATCH 1/2] fix(mcp): preserve room/wing casing on case-only update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LLM clients (Claude, Codex) often autocorrect acronyms in tool args (ps5→PS5). When the only difference is casing, treat it as a no-op to prevent silent room fragmentation. Genuinely different room/wing values still apply normally. Fixes #1621 --- mempalace/mcp_server.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mempalace/mcp_server.py b/mempalace/mcp_server.py index 734ac28..8e5ae6a 100644 --- a/mempalace/mcp_server.py +++ b/mempalace/mcp_server.py @@ -1696,14 +1696,22 @@ def tool_update_drawer(drawer_id: str, content: str = None, wing: str = None, ro new_meta = dict(old_meta) if wing is not None: try: - new_meta["wing"] = sanitize_name(wing, "wing") + wing = sanitize_name(wing, "wing") except ValueError as e: return {"success": False, "error": str(e)} + # Preserve existing casing when the caller passes a case-only + # variant (LLM clients often "autocorrect" acronyms like ps5→PS5). + if wing.lower() != (old_meta.get("wing") or "").lower(): + new_meta["wing"] = wing if room is not None: try: - new_meta["room"] = sanitize_name(room, "room") + room = sanitize_name(room, "room") except ValueError as e: return {"success": False, "error": str(e)} + # Preserve existing casing when the caller passes a case-only + # variant (LLM clients often "autocorrect" acronyms like ps5→PS5). + if room.lower() != (old_meta.get("room") or "").lower(): + new_meta["room"] = room _wal_log( "update_drawer", From d514787f956264be1451eb437b86e954b95ad715 Mon Sep 17 00:00:00 2001 From: Sathvik-1007 Date: Mon, 8 Jun 2026 21:12:34 +0530 Subject: [PATCH 2/2] fix(mcp): str-coerce metadata before case comparison Addresses review: old_meta values could be non-string after corruption or external writes. str() prevents AttributeError. --- mempalace/mcp_server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mempalace/mcp_server.py b/mempalace/mcp_server.py index 8e5ae6a..4714e7e 100644 --- a/mempalace/mcp_server.py +++ b/mempalace/mcp_server.py @@ -1701,7 +1701,7 @@ def tool_update_drawer(drawer_id: str, content: str = None, wing: str = None, ro return {"success": False, "error": str(e)} # Preserve existing casing when the caller passes a case-only # variant (LLM clients often "autocorrect" acronyms like ps5→PS5). - if wing.lower() != (old_meta.get("wing") or "").lower(): + if wing.lower() != str(old_meta.get("wing") or "").lower(): new_meta["wing"] = wing if room is not None: try: @@ -1710,7 +1710,7 @@ def tool_update_drawer(drawer_id: str, content: str = None, wing: str = None, ro return {"success": False, "error": str(e)} # Preserve existing casing when the caller passes a case-only # variant (LLM clients often "autocorrect" acronyms like ps5→PS5). - if room.lower() != (old_meta.get("room") or "").lower(): + if room.lower() != str(old_meta.get("room") or "").lower(): new_meta["room"] = room _wal_log(