Skip to content

chore: sync upstream/develop through v3.3.5#18

Merged
jphein merged 66 commits into
mainfrom
chore/sync-develop-2026-05-10
May 11, 2026
Merged

chore: sync upstream/develop through v3.3.5#18
jphein merged 66 commits into
mainfrom
chore/sync-develop-2026-05-10

Conversation

@jphein

@jphein jphein commented May 11, 2026

Copy link
Copy Markdown
Collaborator

Summary

Sync fork main with upstream/develop tip after MemPalace v3.3.5 release (2026-05-10). Brings in integrity/recovery/correctness fixes — including our co-authored MemPalace#1377.

What's pulled in from upstream

Conflict resolutions (8 files)

File Resolution
CLAUDE.md, README.md kept ours (fork-only inventory + badges; version line + badges bumped to 3.3.5)
mempalace/version.py, pyproject.toml took upstream v3.3.5
tests/conftest.py took upstream's _kg_by_path-aware cache reset (current mcp_server no longer has _recovery_collection_cache); env scrubbing for PALACE_DAEMON_URL/STRICT/API_KEY preserved
mempalace/hooks_cli.py kept daemon-strict short-circuit (rows 33/34) + project_wing semantics (row 5); adopted upstream's _spawn_mine wrapper (MemPalace#1415 per-target PID guard)
mempalace/miner.py combined upstream's _name_matches token-bounded routing (MemPalace#1004) with fork's keyword-candidate list in Priority 2
tests/test_miner.py kept fork's expanded chunking-constants imports (row 17)

Verification

  • Rows 33/34 daemon-strict gating verified in mcp_server.handle_request and cli.cmd_{status,search,mine} — daemon routing intact
  • .claude-plugin/.mcp.json (row 30 daemon-routed config) untouched by upstream — no auto-merge regression
  • scripts/check-docs.sh — clean (21 fork hashes resolve, 113 PR refs match, YAML→FORK_CHANGELOG.md parity)

Test plan

  • python -m pytest tests/ -q1828 passed, 1 skipped, 106 deselected (up from 1591 at 2026-05-07 sync — +237 tests)
  • bash scripts/check-docs.sh → clean
  • Copilot review of conflict resolutions
  • Smoke against live disks.jphe.in:8085 daemon after merge

🤖 Generated with Claude Code

bensig and others added 30 commits April 20, 2026 11:46
release: v3.3.3 — sync develop → main for tag cut
Bumps every version source from 3.3.3 to 3.3.4:
- pyproject.toml
- mempalace/version.py (canonical)
- .claude-plugin/plugin.json
- .claude-plugin/marketplace.json
- .codex-plugin/plugin.json
- README.md badge

Dates the CHANGELOG section and adds entries for the bug fixes that
landed this cycle (MemPalace#1135, MemPalace#1191, MemPalace#1230, MemPalace#1231) plus expands the MemPalace#1194
entry to credit the lookup-side recovery path from MemPalace#1197.

Pre-tag verification:
- 1441 passed, 1 skipped (full suite minus benchmarks, all platforms)
- ruff check + format clean
- 44/44 in test_version_consistency + test_readme_claims (6-file sync)
- JPH invariant: pyproject.toml + .claude-plugin/plugin.json both
  reference mempalace-mcp
- Wheel build + fresh-venv install: mempalace --version reports 3.3.4,
  mempalace-mcp --help works (catches the v3.3.2-class regression)
Agent-Logs-Url: https://github.com/MemPalace/mempalace/sessions/01a1089d-da46-4dc8-85e8-d7e50763dd58

Co-authored-by: igorls <4753812+igorls@users.noreply.github.com>
The fix landed this cycle and is documented under 3.3.4. The 3.3.0
Bug Fixes block is shipped history and shouldn't grow new entries
retroactively.
…entry

The PR documenting the fix is MemPalace#1232; referencing it from inside its
own changelog entry is circular.
…MemPalace#1288

Three fixes landed on develop after the initial release-prep cut and
were brought in via the develop merge. Document them in the 3.3.4
Bug Fixes section so the release notes reflect what users will
actually receive.

- MemPalace#1287 - HNSW divergence floor scales with hnsw:sync_threshold
  (resolves a silent-fallback regression introduced by the
  interaction between MemPalace#1191 and MemPalace#1227 in this release)
- MemPalace#1262 - ChromaBackend get_or_create_collection split, fixing the
  stop-hook SIGSEGV class on legacy palaces with mismatched stored
  metadata (MemPalace#1089)
- MemPalace#1288 / MemPalace#1254 - repair --mode max-seq-id heuristic now decodes
  BLOB-typed embeddings.seq_id, restoring the un-poison path added
  in MemPalace#1135 for palaces where chromadb 1.5.x writes seq_ids natively
The release was originally cut on 2026-04-27 but did not tag that day.
Three additional bug fixes have been folded in since then (MemPalace#1262,
MemPalace#1287, MemPalace#1288) and the actual tag will happen on 2026-04-30. Update
the header date to match.
…MCP server companion

The same try/except split that MemPalace#1262 applied at the backend layer
(ChromaBackend.get_collection) was needed at the parallel call site
in mcp_server._get_collection(create=True), which carries the same
metadata payload directly to chromadb's Python client. Both reopen
paths in mempalace now bypass get_or_create_collection on existing
collections, closing the SIGSEGV class for both tool_add_drawer
and tool_diary_write (the Stop hook's path).
Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 5 to 6.
- [Release notes](https://github.com/actions/configure-pages/releases)
- [Commits](actions/configure-pages@v5...v6)

---
updated-dependencies:
- dependency-name: actions/configure-pages
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…nt (MemPalace#1315)

After a bulk CLI mine, ChromaDB's HNSW segment metadata can be unflushed
  for ~30-60s. Wing-scoped MCP search hits "Internal error: Error finding id"
  during that window, and the existing inode/mtime cache invalidation isn't
  enough — tool_search routes via search_memories -> palace.get_collection
  -> _DEFAULT_BACKEND._client, which has its own per-palace cache.

  This wraps tool_search with a single retry that drops both the MCP-local
  cache and _DEFAULT_BACKEND._clients/_freshness for the palace, sleeps 2s,
  retries once, and tags successful retries with index_recovered=True.

  Does not address tool_check_duplicate or other index-touching tools, nor
  the underlying flush window — options 1-3 from MemPalace#1315 (auto-flush after
  mine, fail-fast detection, SQLite-only fallback) are still on the table
  for a complete fix.

  Refs MemPalace#1315
Substring checks in path/filename routing caused systemic misrouting
in large monorepos — e.g., "views" ⊂ "interviews" sent every file
under views/ to the interviews room. Switch to separator-bounded
token matching (-, _, ., /) via a _name_matches helper, applied to
priority 1 (path parts) and priority 2 (filename).
The Stop hook spawns mining subprocesses via subprocess.Popen and then
returns. On Windows the parent stays blocked at session end because the
child inherits stdout/stderr handles and the OS waits for them to
release before the parent can exit — the user-visible symptom is the
"running stop hooks... 3/3" spinner hanging for minutes (MemPalace#1268).

Add _detached_popen_kwargs() helper that returns the right detach knobs
per platform:
- POSIX: start_new_session=True, stdin=DEVNULL, close_fds=True
- Windows: creationflags=DETACHED_PROCESS|CREATE_NEW_PROCESS_GROUP|
  CREATE_BREAKAWAY_FROM_JOB, stdin=DEVNULL, close_fds=True

Apply to all three fire-and-forget Popen sites in hooks_cli:
_spawn_mine, _ingest_transcript, _desktop_toast. Leave _mine_sync's
subprocess.run alone — that path is intentionally synchronous (the
precompact hook must wait for the mine to finish).

Note: the issue body references mempalace-stop.js, which does not exist
in this repo (the plugin ships shell wrappers calling Python). The
mechanism described — child holds parent open via inherited handles —
is universal, so this fix targets the equivalent symptom in our Python
hook path. Will follow up on the upstream JS file with the reporter.
When a `mempalace mine` collided with another writer (live mcp_server,
another mine, anything taking mine_palace_lock), the operator saw a
generic "another `mempalace mine` is already running" message and the
CLI exited 0 — making the contention invisible to nohup or scripts
checking $?. The reporter ran a `nohup mempalace mine ... & disown`
and got a 200-byte log with only the auto-defaults warning, no clue
that an MCP server was holding the store.

palace.py: the lock file now records the holder's PID + first three
argv tokens on acquire. A failed acquire reads the file and surfaces
"palace <path> is held by PID N (mempalace mcp_server); wait for it
to finish or stop the holder before retrying" in the
MineAlreadyRunning message. Open mode changes from "w" to "a+" so the
prior holder's identity survives long enough to be read.

miner.mine() now lets MineAlreadyRunning propagate. cmd_mine catches
it, prints the holder-aware message to stderr, and exits non-zero so
shell wrappers detect the contention.

Note: this is a behavior change for in-process callers that depended
on miner.mine() silently swallowing MineAlreadyRunning. The silent
swallow was the bug.

Closes MemPalace#1264
Windows CI surfaced two bugs introduced by the holder-identity write:

1. msvcrt.locking(LK_NBLCK, 1) locks 1 byte at the *current* file
   position. Switching to "a+" mode put the position at end-of-file,
   so two contenders locked different bytes and silently both
   acquired (the test asserts saw [(ok, 1), (ok, 2)] instead of
   ok+busy).

2. With the byte-range lock active on Windows, the locked byte is
   read-blocked for other processes. A contender trying to read the
   holder identity from byte 0 would hit PermissionError.

Switch to "r+" mode (after touch-create) and explicitly seek(0) before
both lock and unlock. Then reserve byte 0 as a pure lock sentinel and
write the holder identity from byte 1 onward. _read_lock_holder reads
from byte 1+, so it never touches the locked byte.

Also bound file growth across re-acquires: truncate to
sentinel + len(ident) before writing so the file body stays the size
of the current holder, never accumulating across runs.

Linux fcntl.flock locks the whole file independent of byte position,
so the seek(0) is harmless on POSIX. The shape works on both.
os.path.expanduser("~") reads HOME on POSIX but USERPROFILE on Windows;
the lock-body bound test was monkeypatching HOME only, so on
test-windows the lock file landed in the runner's real ~/.mempalace
and the tmp_path glob found nothing.

Patch USERPROFILE in addition to HOME, and read the body as bytes so
the byte-0 sentinel doesn't trip a UTF-8 decode warning. Assertion
shifts from line-count to size-bound (still detects unbounded growth
across re-acquires).
The v3.3.4 release prep landed on main but was never merged back into
develop, leaving every version-bearing file one release behind. Bumps
pyproject.toml, mempalace/version.py, both plugin manifests, the
marketplace entry, the README badge, and the lockfile to 3.3.4 to match
the tagged release.
End-user installs now lead with `uv tool install mempalace`, with
`pip install mempalace` kept as a fallback. Dev/contributor docs lead
with `uv sync --extra dev` and `uv run` for tests/benchmarks/lint, with
the equivalent pip recipe kept inline. The shipped `/mempalace:init`
skill instructions (mempalace/instructions/init.md) try `uv tool install`
first when uv is on PATH, then fall back through the pip variants.

Adds a .python-version pin at 3.12 because the lockfile's
onnxruntime==1.24.3 only ships wheels for Python >=3.11; without the
pin, `uv sync` on a host where uv prefers 3.10 fails with no source
distribution available, which would make the documented command a
footgun. pyproject's `requires-python = ">=3.9"` is unchanged — pip
users on 3.9/3.10 are unaffected.

Files updated: README.md, CONTRIBUTING.md, CLAUDE.md, the gemini-cli
guide and example, the .claude-plugin / .codex-plugin READMEs, the
mempalace SKILL, the openclaw SKILL, tools/save.md, the three
benchmarks docs, and the corresponding website mirrors.
…h-windows

fix(hooks): detach Popen children so hook exits cleanly on Windows (MemPalace#1268)
…older-diagnostics

fix(mine): identify lock holder + exit non-zero on contention (MemPalace#1264)
- mempalace/instructions/init.md: only skip Step 4 when `mempalace
  --version` succeeds. `pip show` / `uv tool list` reporting an install
  is not enough -- if the package lives in an unactivated venv, Step 5
  (`mempalace init ...`) fails with command-not-found. Treat that case
  as not-installed and re-install via Step 3 into a PATH-visible
  location.
- .codex-plugin/README.md: switch the git-install recipe from `uv sync`
  to `uv tool install --editable .` so the bundled `plugin.json`
  (which invokes `mempalace-mcp` by bare name) can launch the MCP
  server. Plain `uv sync` only puts the script in `.venv/bin/`, which
  Codex won't find unless the venv is activated first.
…emPalace#1206)

The hook PID guard used a single global ``~/.mempalace/hook_state/mine.pid``
file, which failed two ways:

1. ``_mine_already_running`` read-then-spawn was a TOCTOU race. Two
   near-simultaneous Stop hook fires both passed the existence/liveness
   check before either wrote — so both ended up calling
   ``_spawn_mine``.

2. ``_spawn_mine`` unconditionally overwrote the global PID file with
   the new child's PID. The first PID was lost, orphaning the first
   child. The user-visible result in MemPalace#1212 was two concurrent
   ``mempalace mine`` processes running against the same source, both
   driving HNSW inserts in parallel — exactly the corruption pattern
   the guard was meant to prevent. MemPalace#1206 reported the same shape from
   the perspective of the user (two mines hung on a 350MB folder).

Replace the global file with per-target slots under
``~/.mempalace/hook_state/mine_pids/``, keyed by sha256 of the mine
sub-arguments (everything after ``mine``). The slot is claimed via
``O_CREAT | O_EXCL`` so the claim is atomic — two simultaneous fires
can never both pass.  Stale slots (PID exists but is dead) are
reclaimed transparently. Different targets (e.g. project mine vs
transcript ingest, or two different MEMPAL_DIRs) get independent
slots and run in parallel.

The mine subprocess receives its slot path via
``MEMPALACE_MINE_PID_FILE`` env var; ``miner._cleanup_mine_pid_file``
reads that var on exit and removes the slot if it points at our PID,
so orphaned slots from crashed mines don't accumulate.

Also routes ``_ingest_transcript`` through ``_spawn_mine`` so the
transcript ingest path now participates in the same dedup — repeated
Stop fires for the same transcript no longer stack parallel mines.

Closes MemPalace#1212
Closes MemPalace#1206
PEP 604 union syntax (Path | None) requires Python 3.10+. The project
still supports 3.9 (per pyproject target-version and CI matrix), and
this annotation lives in a function signature so it is evaluated at
module load time — failing with "unsupported operand type(s) for |"
on test-linux 3.9.

The other ``int | None`` annotation in this file is inside a function
body, where Python skips runtime evaluation of local annotations, so
it does not trip 3.9.
…pid-guard

fix(hooks): per-target PID guard with atomic claim (MemPalace#1212, MemPalace#1206)
igorls and others added 23 commits May 9, 2026 01:31
…entity-1317

docs: clarify contributor git identity setup
fix(miner): use token-boundary matching in detect_room
…try-on-hnsw-flush

fix(mcp): retry tool_search once on Chroma "Error finding   id" transient (MemPalace#1315)
test_palace_locks.py and test_chroma_collection_lock.py spawned child
processes with the ``fork`` start method on POSIX. Under Python 3.13
this deadlocks reliably enough to hang the Linux 3.13 and macOS CI jobs
indefinitely while Linux 3.9 / 3.11 / Windows complete normally.

Root cause: by the time these tests run, the pytest parent process is
multi-threaded — chromadb and onnxruntime both spawn background threads
on import. ``fork`` snapshots the parent's address space into the
child without those threads, so any lock another thread held at fork
time stays locked in the child forever. Python 3.13 widened the window
where Python's own internal threads can be holding locks (hence the new
DeprecationWarning that fired ten times in our local 3.13 run).

macOS hits a related but distinct issue: Apple's CoreFoundation
explicitly forbids fork-without-exec; once anything in the parent has
loaded a CF-using library (ONNX, anything via Objective-C bridges) a
forked child will silently hang the moment it touches the same
library.

Switching to ``spawn`` re-imports modules in the child (~0.5s overhead
per Process — measurable but bounded), which is the standard fix for
both classes of bug. Lock-file semantics are unchanged: ``spawn``
inherits ``os.environ`` (including monkeypatched ``HOME``), which is
all these tests need from the parent.

Locally on Python 3.13: all 14 lock tests pass in 6.58s.
…sing-spawn

fix(tests): use spawn instead of fork for lock-test subprocesses
Several tests opened sqlite3 connections without try/finally or
context-manager cleanup, relying on a flat conn.close() after the
work. Any assertion failure or exception between connect and close
leaked the connection until GC, producing
``ResourceWarning: unclosed database`` in CI logs.

On Python 3.13 / macOS the ResourceWarning isn't just noise: a
leaked connection can hold a SQLite advisory lock long enough for
later test setup to block on it, which appears to be the cause of
recent intermittent CI hangs on those two runners.

Wrap each affected ``conn = sqlite3.connect(...)`` block in
``contextlib.closing(...)`` so cleanup runs on the failure path too.
Mirrors the try/finally pattern already used in production code
(searcher.py, repair.py, backends/chroma.py).

No behavior change — same operations, same assertions, just
deterministic cleanup. All 162 affected tests pass locally.
…eanup

chore(tests): wrap sqlite3 connections in contextlib.closing
Bumps version 3.3.4 → 3.3.5 across pyproject.toml, version.py, plugin
manifests, README badge, and uv.lock. Flips CHANGELOG.md from
``[3.3.5] — unreleased`` to ``[3.3.5] — 2026-05-09`` and adds entries
for the four PRs that landed after the bug-fix block was authored:

- Bug Fixes: MemPalace#1396 (tool_search retry on transient HNSW flush)
- Documentation: MemPalace#1385 (CONTRIBUTING git-identity guidance, closes MemPalace#1317)
- Internal: MemPalace#1431 (test multiprocessing fork → spawn)
- Internal: MemPalace#1430 (test sqlite connection lifecycle via contextlib.closing)

The four open issues remaining on the v3.3.5 milestone (MemPalace#1266, MemPalace#1253,
MemPalace#1092, MemPalace#1082) have been moved to v3.4 — they form the concurrent-writer
/ HNSW corruption cluster that needs deeper work than this cycle could
absorb.
…etimes

# Conflicts:
#	tests/test_palace_locks.py
…imes

fix(kg): accept ISO datetimes for temporal inputs
The 3.3.4 release shipped 2026-05-01 (per GitHub release v3.3.4) but
its CHANGELOG header was never flipped from ``unreleased`` to the
release date. Backfill while we're already touching CHANGELOG for
the 3.3.5 cut.
# Conflicts:
#	.claude-plugin/marketplace.json
#	.claude-plugin/plugin.json
#	.codex-plugin/plugin.json
#	CHANGELOG.md
#	README.md
#	mempalace/version.py
#	pyproject.toml
#	uv.lock
Copilot review on PR MemPalace#1434 caught that the existing 3.3.5 entry
described the validator as it was authored under MemPalace#1167 — accepting
``YYYY``/``YYYY-MM``/``YYYY-MM-DD`` and rejecting ISO datetimes — but
PR MemPalace#1417 (closes MemPalace#1374) merged into develop on 2026-05-10 and
inverted that: ``sanitize_iso_temporal()`` now rejects partial dates
and accepts canonical UTC datetimes (``YYYY-MM-DDTHH:MM:SSZ`` /
``+00:00``). ``sanitize_iso_date()`` is kept as a backwards-compat
wrapper.

Update the bullet to describe the *shipped* behavior, name both
functions, list both accepted and rejected forms, and call out the
3.3.4 → 3.3.5 behavior change for partial-date inputs that now error.
Reference both MemPalace#1167 (original) and MemPalace#1374/MemPalace#1417 (the expansion).
…k-to-develop

chore(release): sync main back to develop after v3.3.5
Sync fork main with upstream/develop tip after MemPalace v3.3.5 release
(2026-05-10). Brings in integrity/recovery/correctness fixes shipped in
v3.3.5 — including our co-authored MemPalace#1377 (retry _get_collection once on
transient failure) which extracted the surgical retry from MemPalace#1286.

Notable upstream additions pulled in:
- MemPalace#1310 — repair --mode from-sqlite for HNSW-corrupt palaces
- MemPalace#1396 — tool_search retry on HNSW-flush transient
- MemPalace#1214/MemPalace#1167/MemPalace#1417 — KG temporal validation (breaking: partial dates
  like "2026"/"2026-05" rejected)
- MemPalace#1215 — atomic EntityRegistry.save()
- MemPalace#1105/MemPalace#1160 — cross-process correctness on Windows + multi-tenant
  KG cache
- MemPalace#1004 — detect_room token-boundary matching
- MemPalace#1421 — gitignore-aware drawer prune
- MemPalace#1107 — paginated closet_llm col.get
- MemPalace#1415/MemPalace#1413/MemPalace#1412 — per-target PID guard atomic claim + Popen detach
  on Windows + mine-contention exit codes

Conflict resolutions:
- CLAUDE.md, README.md — kept fork (fork-only inventory + badges)
- mempalace/version.py, pyproject.toml — took upstream v3.3.5
- tests/conftest.py — took upstream's _kg_by_path-aware cache reset
  (mcp_server no longer has _recovery_collection_cache); env scrubbing
  for PALACE_DAEMON_URL/STRICT/API_KEY preserved
- mempalace/hooks_cli.py — kept daemon-strict short-circuit (rows
  33/34) and project_wing semantics (row 5); adopted upstream's
  _spawn_mine wrapper (MemPalace#1415 per-target PID guard)
- mempalace/miner.py — combined upstream's _name_matches token-bounded
  routing (MemPalace#1004) with fork's keyword-candidate list in Priority 2
- tests/test_miner.py — kept fork's expanded chunking-constants imports
  (row 17)

Rows 33/34 daemon-strict gating verified intact in mcp_server.py
(handle_request chokepoint) and cli.py (cmd_status / cmd_search /
cmd_mine). Daemon-routed .claude-plugin/.mcp.json (row 30) untouched
by upstream — no auto-merge regression.

Test suite: 1828 passed, 1 skipped, 106 deselected (up from 1591 at
2026-05-07 sync — +237 tests from upstream's repair/PID-guard/sync
additions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 11, 2026 00:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR syncs the fork’s main branch with upstream develop through the MemPalace v3.3.5 release, bringing in multiple correctness/integrity fixes plus new functionality (notably gitignore-aware drawer pruning) and associated documentation/test updates.

Changes:

  • Adds the new mempalace sync capability end-to-end (core sync_palace, CLI command, MCP tool + docs) with extensive test coverage.
  • Strengthens multi-process correctness: per-target mine PID slots, improved lock-holder diagnostics, and safer multiprocessing test strategy (spawn).
  • Updates KG temporal validation to a stricter ISO “date or canonical UTC datetime” model and adjusts MCP/knowledge-graph behavior + tests accordingly.

Reviewed changes

Copilot reviewed 51 out of 52 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
website/reference/mcp-tools.md Documents the new mempalace_sync MCP tool and updates tool count.
website/reference/contributing.md Updates contributor workflow examples to prefer uv.
website/reference/benchmarks.md Updates benchmark setup instructions to prefer uv.
website/guide/getting-started.md Updates installation guidance to recommend uv tool install.
website/guide/gemini-cli.md Updates Gemini CLI setup to use uv workflows.
uv.lock Bumps locked editable package version to 3.3.5.
tools/save.md Updates install instructions to recommend uv tool install.
tests/test_sync.py Adds comprehensive tests for gitignore-aware sync/prune behavior and surfaces.
tests/test_sources.py Improves sqlite connection cleanup in tests via closing().
tests/test_searcher.py Adds CLI rendering safety test for None documents.
tests/test_repair.py Improves sqlite connection cleanup in tests via closing().
tests/test_palace_locks.py Switches lock tests to spawn and adds holder-identity regression coverage.
tests/test_palace_graph_tunnels.py Adds coverage for shared wing normalization behavior.
tests/test_miner.py Adds token-boundary routing tests and updates PID-slot cleanup tests.
tests/test_mcp_server.py Adds retry-on-transient-search tests, KG datetime tests, and vector-disabled duplicate check test.
tests/test_knowledge_graph.py Adds datetime compatibility + context manager/close cleanup tests.
tests/test_hooks_cli.py Expands coverage for per-target PID guard and detached spawn behavior.
tests/test_config.py Adds sanitize_iso_temporal test coverage and backward-compat wrapper assertions.
tests/test_cli.py Adds CLI regression test ensuring lock contention exits non-zero with holder PID.
tests/test_chroma_collection_lock.py Switches multiprocessing start method to spawn for reliability.
tests/test_backends.py Improves sqlite connection cleanup in tests via closing().
tests/conftest.py Updates MCP cache reset fixture to avoid importing mcp_server and to clear _kg_by_path.
README.md Updates version/upstream badges to 3.3.5.
pyproject.toml Bumps project version to 3.3.5.
mempalace/version.py Bumps runtime version constant to 3.3.5.
mempalace/sync.py Introduces sync_palace implementation (gitignore-aware prune + reporting + closet purge).
mempalace/palace.py Enhances per-palace lock with holder identity recording and improved diagnostics.
mempalace/palace_graph.py Uses shared normalize_wing_name and trims empty/whitespace wings.
mempalace/miner.py Adds token-boundary _name_matches routing and changes lock contention behavior to raise.
mempalace/mcp_server.py Adds transient HNSW-flush retry, KG temporal validation update, and new tool_sync.
mempalace/knowledge_graph.py Implements safe date/datetime temporal comparisons, validation, and context manager support.
mempalace/instructions/init.md Updates install/run instructions to validate mempalace on PATH and prefer uv tool.
mempalace/hooks_cli.py Implements per-target PID slots + detached Popen behavior for background mines.
mempalace/entity_detector.py Updates output schema docstring to include topics.
integrations/openclaw/SKILL.md Updates installation instructions to recommend uv tool install.
examples/gemini_cli_setup.md Updates setup doc to recommend uv and use uv run.
CONTRIBUTING.md Updates contributor guidance to prefer uv and adds git identity checks.
CLAUDE.md Updates fork metadata/version sync notes.
CHANGELOG.md Updates v3.3.5 section with upstream changes and internal/test notes.
benchmarks/README.md Updates benchmark setup instructions to prefer uv.
benchmarks/HYBRID_MODE.md Updates benchmark setup instructions to prefer uv.
benchmarks/BENCHMARKS.md Updates benchmark setup instructions to prefer uv and uv run.
.python-version Pins local dev Python version to 3.12.
.github/workflows/deploy-docs.yml Updates GitHub Pages action version to actions/configure-pages@v6.
.codex-plugin/README.md Updates plugin install docs to recommend uv tool install --editable.
.codex-plugin/plugin.json Bumps plugin version to 3.3.5.
.claude-plugin/skills/mempalace/SKILL.md Updates install instructions to recommend uv tool install.
.claude-plugin/README.md Updates post-install wording to reflect uv/pip install flow.
.claude-plugin/plugin.json Bumps plugin version to 3.3.5.
.claude-plugin/marketplace.json Bumps marketplace version to 3.3.5.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread mempalace/palace.py
try:
ident = f"{os.getpid()} {' '.join(sys.argv[:3])}".strip()
lock_file.seek(_LOCK_SENTINEL_BYTES)
lock_file.truncate(_LOCK_SENTINEL_BYTES + len(ident.encode("utf-8")))
Comment thread mempalace/hooks_cli.py
Comment on lines +359 to +365
pid_file = _pid_file_for_cmd(cmd)
pid_file.parent.mkdir(parents=True, exist_ok=True)
try:
fd = os.open(str(pid_file), os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
os.close(fd)
return pid_file
except FileExistsError:
Comment thread CHANGELOG.md
---

## [3.3.5] — unreleased
## [3.3.5] — 2026-05-09
@jphein jphein merged commit a7ba201 into main May 11, 2026
11 checks passed
@jphein jphein deleted the chore/sync-develop-2026-05-10 branch May 11, 2026 01:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.