#2395

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

OpenGregB1536opened 2mo ago

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

0

No activity yet.