feat(search): add since/before date window to mempalace_search and CLI search (#463)#2000
Open
mvalentsev wants to merge 1 commit into
Open
feat(search): add since/before date window to mempalace_search and CLI search (#463)#2000mvalentsev wants to merge 1 commit into
mvalentsev wants to merge 1 commit into
Conversation
…ace#463) Co-Authored-By: Matthew Clapp <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Fixes #463
Adds an optional
[since, before)date window to both search surfaces, filtered on each drawer'sfiled_at(thecreated_atshown in results):mempalace_searchacceptssinceandbefore(ISO date or datetime;sinceinclusive,beforeexclusive).mempalace searchgains--since/--before.Semantics are shared with the
list_drawersfilter from #1128 through a new side-effect-freemempalace/date_window.pymodule (the #1128 helpers moved there;mcp_serverkeeps them under the old private names, so the existinglist_drawersbehavior and tests are untouched). Comparison is wall-clock and timezone-naive,Z/offset inputs are normalized, and drawers with a missing or unparseablefiled_atare excluded while a bound is active, so a date-filtered result never silently includes rows of unknown age.Design notes:
$gte/$lt(verified on the locked 1.5.7), so the window cannot be a server-sidewhereclause. It is applied as a post-filter on every candidate path: the vector scored loop,candidate_strategy="union"lexical merge, and the BM25-only sqlite path used when vector search is disabled.n_results * 3tomax(min(n_results * 15, 500), n_results), the same ceiling the degraded-filter path already uses. When the widened pool still comes back full, the response carriesdate_filter_pool_truncated: trueinstead of passing a thin result off as complete; the BM25 path sets the same flag when its candidate page hitsmax_candidates.Z/offset suffixes); the Python check stays authoritative, mirroring how wing/room are double-checked there.since/beforerather than the issue'safter:list_drawersalready shippedsince/beforewith these exact semantics in feat: add since/before date filter to list_drawers and search #1128, and one vocabulary across the read tools seemed more valuable than a second name for the same bound. Relative forms (--last 7d) and a--betweenshorthand from the issue discussion are intentionally left for a follow-up; they layer cleanly on top of this window.total_before_filterreflects the post-filtered count, so the truncation flag can under-report there; union mode's lexical fetch keeps itsn_results * 3size (widening it under a window is a possible follow-up, the merge itself already respects the window); abeforeat the calendar ceiling (9999-12-31) skips the SQL narrowing instead of overflowing pastdatetime.max; and a storedfiled_atwith leading whitespace would pass the Python filter but not the SQL prefilter (no in-tree writer produces one).How to test
Automated (all green locally, ruff 0.15.14 clean):
New coverage: 20 unit tests for the shared parser/window, 26 searcher tests (window/boundaries/invalid/inverted, undated and aware
filed_at, pool widening recall, truncation flags on both paths, legacyfiled_atspellings and the calendar-ceiling sentinel on the sqlite path, union side door, CLI ordering and errors), 6 MCP-surface tests (schema, threading, filters echo, clean error shapes).Manual, against a real palace:
MCP: call
mempalace_searchwith{"query": "budget meeting", "since": "2026-04-01"}over JSON-RPC; the tool schema now declares both properties, results stay within the window,filtersechoes it, and an invalid or inverted window returns a structured error instead of-32000/-32602.Checklist
python -m pytest tests/ -v)ruff check .)