Skip to content
Merged
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
8 changes: 7 additions & 1 deletion mempalace/palace.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,7 +507,13 @@ def resolve_backend_name(palace_path: str, explicit: Optional[str] = None) -> st
return selected


_MULTI_PROCESS_WRITER_BACKENDS = frozenset({"pgvector", "qdrant"})
# Fork: "postgres" (the #665-lineage backend behind palace-daemon) delegates
# all cross-process concurrency to the postgres server, exactly like
# "pgvector" — without it here, the daemon's embedded MCP server takes the
# process-lifetime writer lease and every `mempalace mine` subprocess the
# daemon spawns for /mine refuses with "palace is held by PID <daemon>"
# (production incident 2026-08-09, first post-v3.7.0 deploy).
_MULTI_PROCESS_WRITER_BACKENDS = frozenset({"pgvector", "qdrant", "postgres"})


def backend_requires_single_writer(backend_name: str) -> bool:
Expand Down
4 changes: 4 additions & 0 deletions tests/test_palace.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ def test_backend_writer_ownership_remains_conservative_for_unknown_backend():
assert backend_requires_single_writer("plugin_backend") is True
assert backend_requires_single_writer("qdrant") is False
assert backend_requires_single_writer("pgvector") is False
# Fork: postgres coordinates concurrent clients server-side; the daemon
# must NOT take the writer lease or its spawned /mine CLI subprocesses
# self-refuse ("palace is held by PID <daemon>", 2026-08-09 incident).
assert backend_requires_single_writer("postgres") is False


def _capture():
Expand Down
Loading