Skip to content

mempalace_update_drawer silently ignores a case-only wing rename and returns success #2395

Description

@GregB1536

Observed on: 3.8.0, backend sqlite_exact, MCP over HTTP (docker image python:3.13-slim + pip install mempalace==3.8.0).

mempalace_update_drawer ignores a wing change that differs only by case, and reports success anyway. The response echoes the old wing, and the row is not touched — filed_at is unchanged. A caller that trusts success: true concludes the drawer moved when it did not.

Reproduction

Same drawer, same call, only the target string differs.

add_drawer(wing="ZZTestCaseRename", room="scratch", content="...")
  -> {"success": true, "drawer_id": "drawer_ZZTestCaseRename_scratch_f627c5ad...", "wing": "ZZTestCaseRename"}

# 1. case-only change -> IGNORED, but reported as success
update_drawer(drawer_id="drawer_ZZTestCaseRename_scratch_f627c5ad...",
              wing="zztestcaserename", room="scratch")
  -> {"success": true, "wing": "ZZTestCaseRename"}     # <-- the OLD value

# 2. control: same drawer, target differs by more than case -> works
update_drawer(drawer_id="drawer_ZZTestCaseRename_scratch_f627c5ad...",
              wing="zz-test-case-rename", room="scratch")
  -> {"success": true, "wing": "zz-test-case-rename"}  # <-- changed

Confirmed against the store, not just the response: for a real case-only attempt on a
pre-existing drawer, select count(*) from documents where wing = 'AI-infrastructure' COLLATE BINARY
was unchanged afterwards, and the rows' filed_at still held their original timestamp.

Why it matters

Case-duplicate wings (AI-infrastructure vs ai-infrastructure, Projects vs projects) arise
naturally — different sessions capitalise differently — and they split wing-scoped retrieval, so a
list_drawers(wing=...) or wing-filtered search silently sees only part of the topic. Consolidating
them is the obvious fix, and it is exactly the operation that cannot be performed.

The failure is quiet in the way that matters: a bulk consolidation reports every call as successful.
In our run, 41 of 46 drawers moved (their wings differed by more than case) and 5 did not, with no
error on any of them. The distinction is invisible from the tool responses alone.

Note list_drawers(wing=...) is case-sensitive — AI-INFRASTRUCTURE returns 0 while
ai-infrastructure returns 10 — so listing does discriminate. It is only the update that does not.

Expected

Either the case-only rename is applied, or it fails loudly. Silently returning success: true with
the old value is the problematic part; a caller has no way to detect it short of re-reading the
store with a binary collation.

Workaround

Rewriting $.wing inside metadata_json directly, with the server stopped, does work — wing is a
generated column, so the index it backs recomputes. That is obviously not something a client should
have to do.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2mediumarea/mcpMCP server and toolsbugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions