Commit Graph

1767 Commits

Author SHA1 Message Date
Igor Lins e Silva 9a3afc9d64
Merge pull request #2220 from MemPalace/fix/windows-hybrid-search-empty-results
fix(tests): harden hybrid search against empty Windows Chroma reads
2026-08-11 11:47:26 -03:00
Igor Lins e Silva cb03ee61cb fix(tests): harden hybrid search against empty Windows Chroma reads
Windows CI intermittently returns zero hybrid hits right after a fast
seed write (same class as "Nothing found on disk" on tiny collections).
Close the palace client after seeding so the next open re-reads flushed
segments, retry search once if empty, and assert non-empty results with
a clear message instead of IndexError.
2026-08-11 11:20:09 -03:00
Igor Lins e Silva cb7ba7f573
Merge pull request #2218 from MemPalace/chore/sync-main-into-develop
chore: merge main into develop before 3.7.0 promotion
2026-08-11 09:26:33 -03:00
Igor Lins e Silva fd81cc55b3 chore: merge main into develop before 3.7.0 promotion 2026-08-11 09:26:21 -03:00
Igor Lins e Silva 1004572d53
Merge pull request #2217 from MemPalace/docs/changelog-370-release
docs(changelog): fold wave 1–3 notes into 3.7.0 for release
2026-08-11 09:25:31 -03:00
Igor Lins e Silva 7ba6c3a709 docs(changelog): fold wave 1–3 notes into 3.7.0 for release
Move Unreleased entries into the 3.7.0 section, add the Wave 2 headlines
(Hermes core, source adapters, stale-library MCP gate, date search,
openai-compat embeddings, integrity/encoding fixes), and set the release
date to 2026-08-11.
2026-08-11 09:25:14 -03:00
Igor Lins e Silva 1c6fad777d
Merge pull request #2159 from amorphous-dreams/fix/hnsw-defaults-followup
test(chroma): assert the HNSW defaults rather than a threshold arithmetic
2026-08-11 09:24:14 -03:00
Igor Lins e Silva cedbba0621
Merge pull request #597 from grtninja/codex/mx3-public-shim-example
docs: add MX3 public shim examples
2026-08-11 09:24:08 -03:00
Igor Lins e Silva df857ccbeb
Merge pull request #2163 from ATKabli/fix/rerank-label-dashless-model
fix: crash in --llm-rerank output for model names without a dash
2026-08-11 09:24:03 -03:00
Igor Lins e Silva b6eae9b0e5
Merge pull request #2191 from mbeacom/mbeacom-fix-numpy2-embedding-floats
test(backends): cover the _embed_texts fallback and empty-batch guard
2026-08-11 09:23:57 -03:00
Igor Lins e Silva 77b00d0ede
Merge pull request #2204 from rubicon/docs/document-mcp-idle-hours
docs: document MEMPALACE_MCP_IDLE_HOURS
2026-08-11 09:23:50 -03:00
Igor Lins e Silva 5253819f69
Merge pull request #555 from grtninja/codex/fix-541-contributing-discussions
docs: remove GitHub Discussions reference from contributing guide
2026-08-11 09:23:44 -03:00
Igor Lins e Silva 7ebde7d1a5
Merge pull request #2216 from MemPalace/fix/wave2-windows-lock-reap-home
fix(tests): isolate lock-reap home on Windows via USERPROFILE
2026-08-11 08:25:28 -03:00
Igor Lins e Silva cb9356e549 fix(tests): isolate lock-reap home on Windows via USERPROFILE
The #2200 reap tests only monkeypatched HOME. On Windows expanduser("~")
reads USERPROFILE, so the reaper scanned the real home and the suite
failed on test-windows after Wave 2. Share _isolate_home() that sets both.
2026-08-11 08:25:19 -03:00
Igor Lins e Silva eb8090eb84
Merge pull request #2215 from MemPalace/fix/wave2-ci-hermes-chroma-race
fix(hermes): stop second Chroma client racing the filing worker
2026-08-11 08:13:45 -03:00
Igor Lins e Silva 94a41ee217 fix(hermes): stop second Chroma client racing the filing worker
MemoryStack/Layer1 opened a second PersistentClient on the same palace
while the Hermes provider already held one for live filing. Concurrent
access corrupted local Chroma SQLite (disk I/O / Failed to get segments)
and failed CI on develop after #1915.

Wake-up L1 now scans the long-lived collection under the collection lock,
and filing holds that lock for the full upsert. Also rewrite the RFC 001
section-4.4 docstring to avoid the internal §N jargon guard.
2026-08-11 08:13:19 -03:00
Igor Lins e Silva 97be77c0e9
Merge pull request #2000 from mvalentsev/feat/search-date-filter-463
feat(search): add since/before date window to mempalace_search and CLI search (#463)
2026-08-11 07:55:59 -03:00
mvalentsev 5036e3c05e feat(search): add since/before date window to search surfaces (#463)
Co-Authored-By: Matthew Clapp <1807922+nautis@users.noreply.github.com>
2026-08-11 07:55:24 -03:00
Igor Lins e Silva 2174eb047c
Merge pull request #2200 from fxinfo24/fix/reap-orphaned-mine-locks
fix(palace): reap orphaned per-source-file mine locks
2026-08-11 07:54:52 -03:00
Offbeat-Breed 27212e5c62 fix(palace): reap orphaned per-source-file mine locks
_cleanup_mine_lock_file reclaims a lock correctly on the happy path (see
its own docstring for the flock-based rendezvous safety it already
handles) — but only for the specific lock a mine_lock context manager
just released. A process that dies before reaching its own finally
block (SIGKILL, force-quit, host crash) never runs that cleanup, and
nothing else in the codebase later revisits that lock file.

Found in the wild: one long-lived installation had 5,636 stale lock
files in ~/.mempalace/locks/, the oldest several months old, none held
by any live process (confirmed via lsof before cleanup). This is
distinct from the #1264 lock-holder-diagnostics fix (identifies who
holds a live lock) and the #1299 mcp_server embedding-function fix
(unrelated code path) — neither addresses orphan reclamation, and the
2026-07-10 outage postmortem comment in mcp_server.py's stdio loop
covers graceful client disconnection, not abrupt process death.

Adds reap_stale_mine_locks(), which reuses _cleanup_mine_lock_file
itself for the actual removal — same nonblocking-flock-reacquire safety
mechanism, same Windows/POSIX handling already tested in this file, no
duplicated locking logic. A lock is only ever removed after this
process re-acquires it, so anything genuinely held by a live process is
left untouched regardless of age. Wired into mine_lock() via a
throttled opportunistic call (_maybe_reap_stale_mine_locks, at most
once per 15 minutes) rather than a new background thread, scheduled
task, or CLI surface — it piggybacks on the natural cadence of mining
rather than adding new infrastructure.

mine_palace_*.lock (the newer per-palace lock added for the #974/#965
fan-out fix) is explicitly skipped — it has its own lifecycle and
holder-identity tracking and doesn't have this failure mode.

Tests: 6 new cases in test_palace_locks.py covering removal of a
genuinely stale+unheld lock, preservation of a young lock regardless of
hold state, the core safety property (a lock held by another process is
never removed even when backdated past the age threshold), skipping
mine_palace_*-prefixed locks, a missing-lock-dir no-op, and the
throttle itself. Full existing test_palace_locks.py suite (19 tests)
passes unchanged. Broader tests/ -k 'palace or mine' run clean (730
passed) aside from two pre-existing failures confirmed unrelated and
present on an unmodified checkout (test_hnsw_capacity.py SQLite WAL
signature caching, test_repair.py FTS5 shadow-table write restriction —
both environment/SQLite-build-specific, neither touches locking).
2026-08-11 07:54:23 -03:00
Igor Lins e Silva 7eaa3bc3de
Merge pull request #1915 from raman325/feat/hermes-provider-core
feat(integrations): Hermes memory provider core
2026-08-11 07:53:44 -03:00
Igor Lins e Silva f5a766a0de
Merge pull request #2068 from ggettert/feat/2062-mine-source-registry-dispatch
feat(mine): route explicit source adapters through the RFC 002 registry (#2062)
2026-08-11 07:53:35 -03:00
Igor Lins e Silva be27e7852e
Merge pull request #2081 from mvalentsev/fix/899-stale-library-detection
fix(mcp): refuse writes when the served library is no longer installed (#899)
2026-08-11 07:53:27 -03:00
Igor Lins e Silva b8c92f852f
Merge pull request #2211 from MohabMohie/fix/windows-mcp-fd-capture-fallback
fix: handle unavailable MCP stdout redirection on Windows
2026-08-11 07:53:20 -03:00
Igor Lins e Silva 174dc31647
Merge pull request #743 from MemPalace/docs/rfc-storage-backend-plugin-spec
docs: RFC 001 — storage backend plugin specification
2026-08-11 07:50:32 -03:00
Igor Lins e Silva aeac794c1a docs(rfc-001): fold §4.4 review nits; accept storage-backend spec
Close the last open items on #743 before merge:

- Conformance: document two isolation arms (cross-id for all backends;
  same-id/different-namespace for supports_namespace_isolation advertisers).
- No silent drop: non-advertising backends must raise UnsupportedCapabilityError
  when PalaceRef.namespace is set, rather than accept-and-ignore.
- Wire require_namespace_support() into chroma/sqlite_exact; add conformance test.
- Refresh implementation-status banner now that #1727/#1731/#1732/#1734 landed.
2026-08-11 07:50:09 -03:00
Igor Lins e Silva 4416dbdff0 docs(rfc-001): resolve review blockers; accept storage-backend spec
- §7.4: pin canonical NAMESPACE_MEMPALACE to qdrant's shipped UUID (bensig block)
- §2.1/§4.4: supports_namespace_isolation contract (cschnatz)
- §5/§1.5: minimal Embedder protocol normative; nameless→unknown (kostadis, bensig)
- §2.1/§10: backend-declared distance_metric; searcher.py added to cleanup
- §7.3: observable/serializable run_maintenance; no-op-kind omission
- §2.4/§8.2: multi-collection-per-palace; exact-vector lossless both ways
- §3.3/§4.2/§9: env + versioning clarifications (bensig)
- §10/§11/§13: reconcile with #1679; resolve §12 open questions; Status Draft→Accepted

Follow-ups tracked: #1724 (embedder identity), #1725 (maintenance hooks),
#1726 (searcher.py backend-neutrality).
2026-08-11 07:48:28 -03:00
Igor Lins e Silva 96715514b1 docs(rfc-001): flag mcp_server cache/reconnect for §10 cleanup
#757 landed mtime/inode cache invalidation and mempalace_reconnect
in mcp_server._get_client(). Both are Chroma-specific (stat of
chroma.sqlite3). They should migrate into ChromaBackend.get_collection
and ChromaBackend.close_palace during the §10 cleanup so the freshness
contract lives inside the backend, not in the caller.
2026-08-11 07:48:28 -03:00
Igor Lins e Silva bd3ea6bde4 docs(rfc-001): close four spec defects surfaced in review
Addresses the actual spec defects flagged in #743 review, ignoring
operator-UX asks that are not plugin-contract concerns.

- Goal #3: 'without data loss' → mirrors §8.2's capability-conditional
  lossless-vs-reembed framing. No more overpromise.
- §1.5: `server_embedder` is no longer an implicit escape hatch from
  identity/dimension rules. Such backends MUST expose an effective
  identity via `effective_embedder_identity()` and are bound by the
  same three-state check.
- §7.3: adds `maintenance_kinds: ClassVar[frozenset[str]]` advertisement
  mechanism. `run_maintenance(kind)` must raise
  UnsupportedMaintenanceKindError for unadvertised kinds. Benchmark
  harness reads this set rather than guessing kind names. Reserves
  `analyze`/`compact`/`reindex` as well-defined names.
- §1.2: adds `update()` as optional method with a default get+merge+
  upsert implementation. §2.1: `supports_update` redefined to gate
  atomic single-round-trip semantics (not mere capability), since the
  default impl already supports partial updates.

Operator asks explicitly NOT adopted (diplomatic shims, not contract
defects): `.to_dict()` compat on typed results, migration progress
reporting, `BaseBackend.repair()` separate from `run_maintenance`,
per-palace capability variance, identity recording on read-only ops.
2026-08-11 07:48:28 -03:00
Igor Lins e Silva ed79ccfa0c docs(rfc-001): strengthen embeddings contract and migration safety
Incorporates review feedback from skuznetsov (Postgres, #665) and
dekoza (Lance, #574) on issue #737:

- §1.5: split 'accepts embeddings=' (signature compliance) from
  'persists embeddings as-is' (correctness). Adds
  supports_embeddings_passthrough capability; the former is universal,
  the latter is required to label a migration lossless.
- §1.5: model identity check becomes a three-state machine
  (known_match / known_mismatch / unknown) so legacy palaces without
  recorded identity don't hard-fail on upgrade.
- §1.4: makes explicit that supports_contains_fast is the ONLY
  performance floor the spec promises; without it callers MUST assume
  O(n). $contains is a correctness requirement, not a performance one.
- §3.3: clarifies auto-detect is an upgrade-compat path only, never
  the selection mechanism for new palaces.
- §8.2: migrate CLI refuses to run against a target lacking
  supports_embeddings_passthrough unless --accept-re-embed is passed;
  migration record now captures lossless status and model identities.
2026-08-11 07:48:28 -03:00
Igor Lins e Silva f142458a31 docs: align capability token names in RFC 001
Copilot review flagged back-references in §1.4 and §6 that still used
the pre-skuznetsov-rename names (`$contains_fast`, `sync_capable`,
`change_feed`). Updated to the `supports_*` prefix used in the §2.1
capability table.
2026-08-11 07:48:28 -03:00
Igor Lins e Silva 2a2466c656 docs: draft RFC 001 — storage backend plugin specification (#737)
Formalizes the BaseCollection/BaseBackend contract introduced as a seam
in #413 into an interchangeability spec that third-party backends can
build to. Driven by six in-flight backend PRs (#574, #643, #665, #697,
#700, #381) each implementing the interface differently.

Key decisions captured: entry-point distribution, typed QueryResult/
GetResult replacing Chroma dict shape, daemon-first multi-palace model
via PalaceRef, required where-clause subset (incl. $contains),
mandatory embedder injection with model-identity validation, capability
tokens, shared pytest conformance suite, and a backend-neutral
migrate/verify CLI.
2026-08-11 07:48:27 -03:00
Igor Lins e Silva 9bc8cdddc6
Merge pull request #1671 from maximilize/feat/openai-compat-embeddings
feat(embedding): add OpenAI-compatible /v1/embeddings backend
2026-08-11 07:47:28 -03:00
Igor Lins e Silva d9a24c7000 fix(embedding): land openai-compat EF cleanly on develop
After rebasing #1671 onto current develop:
- Opt test_embedding_api out of conftest's stable EF mock so the
  get_embedding_function selection tests exercise the real factory.
- Move the CHANGELOG entry from released 3.7.0 Performance into
  Unreleased Features (rebase context had drifted).
2026-08-11 07:08:02 -03:00
maximilize f272c84514 fix(embedding): harden API error handling (PR #1671 review)
Address the gemini-code-assist review on #1671:

- Wrap `http.client.HTTPException` (BadStatusLine / IncompleteRead — common
  with local/overloaded servers) and `ValueError` (invalid/missing URL scheme;
  also subsumes `json.JSONDecodeError`) in `EmbeddingAPIError` instead of
  letting them crash the caller.
- Reject a non-dict top-level JSON response before calling `.get()` on it, so a
  JSON list/`null`/string yields a clear `EmbeddingAPIError` rather than an
  unhandled `AttributeError`.
- Add tests for all three cases.
2026-08-11 07:07:13 -03:00
maximilize d471a9e262 feat(embedding): add OpenAI-compatible /v1/embeddings backend
Add an `embedding_model: "openai-compat"` option that computes embeddings
via any OpenAI-compatible `/v1/embeddings` server (LM Studio, llama.cpp,
vLLM, Ollama's OpenAI shim, self-hosted) instead of a local ONNX model.

- New OpenAICompatEmbeddingFunction (stdlib urllib, no new dependency):
  batches requests, asks for `encoding_format: "float"` and a custom
  User-Agent (avoids Cloudflare 403, see #1570), validates the response
  (contiguous 0..n-1 indices + well-formed vectors) before use, and
  L2-normalizes for the cosine collection. Exposes `embed_query` (ChromaDB
  1.5 dispatches query embedding through it, not `__call__`). `name()`
  encodes the model id so switching it forces `mempalace repair
  rebuild-index`. Failures raise a module-specific `EmbeddingAPIError`.
- Endpoint settings resolved by MempalaceConfig as a single source of truth:
  `embedding_api_url` / `embedding_api_model` / `embedding_api_key`, each
  overridable via the matching `MEMPALACE_EMBEDDING_API_*` env var.
  Whitespace-only values are treated as unset; the EF cache key fingerprints
  the key so a token rotation is picked up.
- The miner/MCP `Device:` header reports `openai-compat (<url>)` instead of a
  misleading local accelerator label when this backend is active.
- Opt-in; default stays minilm. Mirrors the existing `openai-compat` LLM
  provider naming; stays local when the endpoint is on the machine/LAN.
- Tests: tests/test_embedding_api.py (no server / no network required).
- Docs: README requirement note, module docstring, CHANGELOG.

Refs #1559.
2026-08-11 07:07:13 -03:00
Igor Lins e Silva db9c917078
Merge pull request #2212 from mvalentsev/fix/2207-repair-backup-non-regular
fix(backups): stop a socket in the palace from aborting repair (#2207)
2026-08-11 07:06:39 -03:00
Igor Lins e Silva 3161cae8a6
Merge pull request #1330 from mvalentsev/fix/convo-miner-skip-subagents
fix(convo-miner): skip Claude Code subagent transcripts by default (#1217)
2026-08-11 07:06:32 -03:00
Igor Lins e Silva b4345e84a7
Merge pull request #1104 from arnoldwender/fix/encoding-non-ascii-sweep
fix(encoding): replace non-ASCII symbols in CLI output (#1034)
2026-08-11 07:06:24 -03:00
Igor Lins e Silva c38cbf726f
Merge pull request #2208 from arnoldwender/fix/encoding-repair-ambiguous-window
fix(encoding): require local evidence before repairing the ambiguous [ÂÃ] window (#2193)
2026-08-11 07:06:18 -03:00
Igor Lins e Silva ffb5559823
Merge pull request #2194 from arnoldwender/fix/repair-encoding-cli-stdio-utf8
fix(repair-encoding-cli): reconfigure stdio to UTF-8 like the other entry points
2026-08-11 07:06:11 -03:00
Igor Lins e Silva 05ae73f54f
Merge pull request #2098 from KeilerHirsch/fix/utf8-encoding-hardening
fix(encoding): pin encoding=utf-8 on dialect.py + config.py text opens
2026-08-11 07:06:03 -03:00
Igor Lins e Silva cd1c27247a
Merge pull request #2195 from KeilerHirsch/integration/spark-safety-current
fix(repair): hold writer lease across rebuild_index
2026-08-11 07:05:40 -03:00
Igor Lins e Silva a09ba417cd
Merge pull request #2135 from fatkobra/fix/2112-sweep-repeated-uuid
fix(sweep): collapse repeated message UUIDs before upsert
2026-08-11 07:05:36 -03:00
Igor Lins e Silva 3db1c5bf1b
Merge pull request #2038 from messelink/feat/pgvector-facet-counts
feat(pgvector): implement facet_counts server-side aggregation (#1868 contract)
2026-08-11 07:05:31 -03:00
Igor Lins e Silva 3f52734f85
Merge pull request #2192 from amorphous-dreams/fix/service-restores-palace-path-env
fix(service): restore MEMPALACE_PALACE_PATH after the call that stamped it
2026-08-11 07:05:26 -03:00
Igor Lins e Silva 5fa892eae0
Merge pull request #2178 from miky-mfw/codex/fix-codex-marketplace-install
fix(codex): make marketplace plugin installable
2026-08-11 07:05:22 -03:00
Igor Lins e Silva 441f4bbd39
Merge pull request #2203 from rubicon/fix/server-unit-survives-idle-exit
fix(deploy): survive the MCP idle watchdog exit in the systemd unit
2026-08-11 07:05:17 -03:00
Igor Lins e Silva fb0312f6c0
Merge pull request #2206 from bethaniamh/fix-wing-worktree
fix(hooks): derive wing from project, not the git-worktree dir
2026-08-11 07:05:12 -03:00
Igor Lins e Silva f44a95d545
Merge pull request #2199 from KeilerHirsch/fix/2197-markdown-emotion-marker
fix(extractor): ignore markdown emphasis as emotion
2026-08-11 07:05:07 -03:00