Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions docs/recovery/index-metadata-recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,14 @@ The data is recoverable — the `data_level0.bin`, `link_lists.bin`,
the quarantined dir. Only the `dimensionality` field is missing. We can
supply it externally.

### 1. Stop the mempalace MCP server / palace-daemon
### 1. Stop the mempalace MCP server

Two `PersistentClient` instances against the same palace deadlock on the
sqlite filelock. The recovery script needs exclusive access.

```bash
# If running mempalace MCP via Claude Code or similar, kill that process.
# If running palace-daemon:
sudo systemctl stop palace-daemon.service
# If running any other service that holds the palace open, stop it too.
```

### 2. Snapshot sqlite as a rollback
Expand Down Expand Up @@ -137,7 +136,7 @@ PYEOF
### 6. Restart the service + verify

```bash
sudo systemctl start palace-daemon.service # or your equivalent
# Restart your mempalace MCP server or equivalent service
sleep 10 # warmup window

# Confirm vector search is back (not BM25-only fallback):
Expand Down Expand Up @@ -191,12 +190,13 @@ rm "$PALACE/<UUID>/index_metadata.pickle.broken-backup"
bad state during its temp-collection refile pass
- MemPalace/mempalace#1493 — proposal to have the integrity gate auto-recover
this exact corruption shape rather than just quarantining
- jphein/palace-daemon `docs/recovery/chromadb-metadata-dict-patch.md` —
the same procedure written from a palace-daemon operator's perspective
(HTTP probes instead of CLI commands)
- jphein/palace-daemon `tests/test_chromadb_metadata_recovery.py` —
regression test that builds a real palace, corrupts the metadata,
applies the patch, asserts chromadb fully loads + queries the result
- [jphein/palace-daemon](https://github.com/jphein/palace-daemon) is an
external third-party service layer for mempalace (not shipped with this
project). Its `docs/recovery/chromadb-metadata-dict-patch.md` covers
the same procedure from an HTTP-service operator's perspective, and
`tests/test_chromadb_metadata_recovery.py` contains a regression test
that builds a real palace, corrupts the metadata, applies the patch,
and asserts chromadb fully loads + queries the result

## Tested on

Expand Down
6 changes: 3 additions & 3 deletions mempalace/palace_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,9 @@ def build_graph(col=None, config=None):
# Skip these silently rather than crash the whole graph
# build — a single None drawer shouldn't take down /stats
# or any caller of build_graph for the entire palace. Caught
# 2026-04-25 by palace-daemon's verify-routes.sh smoke test
# against the canonical 151K palace. Closes the same gap as
# upstream #999 / fork PR #1094 in a different read path.
# 2026-04-25 during smoke testing against a canonical 151K
# palace. Closes the same gap as upstream #999 / fork
# PR #1094 in a different read path.
if meta is None:
continue
room = meta.get("room", "")
Expand Down
9 changes: 4 additions & 5 deletions tests/test_palace_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@ def test_none_metadata_does_not_crash(self):
"""ChromaDB can return None for drawers without metadata (legacy
data, partial writes — upstream #1020 territory). build_graph
must skip None entries silently rather than crash the whole
graph build with AttributeError. Caught 2026-04-25 by
palace-daemon's verify-routes.sh smoke test against the
canonical 151K palace; /stats was 500-ing on a single None
drawer and taking out every consumer of build_graph for the
whole call path."""
graph build with AttributeError. Caught 2026-04-25 during
smoke testing against a canonical 151K palace; /stats was
500-ing on a single None drawer and taking out every consumer
of build_graph for the whole call path."""
col = _make_fake_collection(
[
{"room": "auth", "wing": "wing_code", "hall": "security", "date": "2026-01-01"},
Expand Down