The save hook uses SESSION_ID in file paths (state_dir/).
A crafted session_id value like '../../etc/cron.d/evil' could write
state files outside the intended directory.
Strip everything except [a-zA-Z0-9_-] from SESSION_ID, defaulting
to 'unknown' if empty after sanitization.
Finding: #4 (HIGH — path traversal via SESSION_ID)
Includes test infrastructure from PR #131.
92 tests pass.
- Tighten chromadb dependency from >=0.4.0,<1 to >=0.5.0,<0.7
(the collection API changed significantly across majors; this
pins to the tested range)
- Add optional 'spellcheck' extras for the undeclared autocorrect
dependency used in spellcheck.py
- Add PEP 561 py.typed marker for type checker support
Findings: #10 (HIGH — chromadb range too wide), #30 (LOW — undeclared
autocorrect), #32 (LOW — missing py.typed)
Includes test infrastructure from PR #131.
92 tests pass.
- Enable WAL journal mode in _conn() for better concurrent read
performance and reduced SQLITE_BUSY risk
- Add LIMIT 100 to entity-filtered timeline query (was unbounded,
while global timeline already had LIMIT 100)
Findings: #8 (HIGH — no WAL mode), #22 (LOW — inconsistent limits)
Includes test infrastructure from PR #131.
92 tests pass.
- Remove palace_path from _no_palace() error response (prevents
leaking filesystem paths to the LLM)
- Replace str(e) with generic 'Internal tool error' in MCP dispatch
catch block (full error is still logged server-side via stderr)
- Replace sys.exit(1) with return in searcher.search() CLI function
(prevents process termination if called from library context)
- Remove unused sys import from searcher.py
Findings: #12 (HIGH), #5 (MEDIUM), #15 (LOW)
Includes test infrastructure from PR #131.
92 tests pass.
Prevents OOM when the palace grows large. The following unbounded
metadata fetches now have a safety cap:
- tool_status: col.get(include=['metadatas'], limit=10000)
- tool_list_wings: same
- tool_list_rooms: same (including wing-filtered variant)
- tool_get_taxonomy: same
- Layer1.generate: col.get(include=['documents','metadatas'], limit=10000)
Layer2 already had a limit parameter — no change needed.
Finding: #3 (CRITICAL — unbounded data fetching causes OOM)
Includes test infrastructure from PR #131.
92 tests pass.
- Replace len(text)//3 token heuristic with word-based estimate (~1.3 tokens/word)
- Old heuristic inflated compression ratios by ~3-5x
- Update docstrings: "compression" → "lossy summarization"
- Update module docstring to clarify AAAK is NOT lossless
- compression_stats() now returns honest field names and a note
- CLI output labels ratios as lossy
Fixes#43
detect_room() now matches folder path parts against room keywords,
not just the room name. Fixes docs/ files routing to general instead
of documentation room — "docs" wasn't a substring of "documentation"
but is now matched via the persisted keywords list.
Found during end-to-end testing after merging #108 keyword persistence.
- Switch CI install step from `pip install -r requirements.txt` to
`pip install -e ".[dev]"` since requirements.txt was removed
- Add noqa: E402 to intentionally-late imports in conftest.py
(HOME must be isolated before mempalace imports)
- Remove unused KnowledgeGraph import in test_knowledge_graph.py
- Apply ruff formatting to test files
Replace the ─ (U+2500) separator character with - in convo_miner.py.
Windows terminals using cp1252 encoding raise UnicodeEncodeError when
printing this character unless PYTHONUTF8=1 is set explicitly.
Fixes crash on Windows: UnicodeEncodeError: 'charmap' codec can't encode
character '\u2500'
Pass yes flag through to detect_rooms_local so init --yes
skips both entity detection AND room approval prompts.
Agents and CI can now run init without interactive input.
Fixes#8
- Add `mempalace repair` command to rebuild vector index from SQLite
when HNSW files are corrupted after crash/interrupt (fixes#74, #72, #96)
- Fix split command passing dir as positional instead of --source
flag to split_mega_files (fixes#63)
- Handle Claude privacy export format (array of conversation objects
with chat_messages inside each) in normalize.py (fixes#63)
- Persist room keywords in mempalace.yaml so mine can match files
in docs/ to room "documentation" (fixes#108)
- hooks/mempal_save_hook.sh: pass $TRANSCRIPT_PATH as sys.argv
instead of interpolating into python -c string (fixes#110)
- normalize.py: accept type "user" in addition to "human" for
Claude Code JSONL sessions (fixes#111)
- convo_miner.py: skip tool-results/, memory/ dirs and .meta.json
files when scanning for conversations (fixes#111)
- pyproject.toml: pin chromadb>=0.4.0,<1 to avoid crashing 1.x
builds on macOS ARM64 (fixes#100)
The community caught real problems within hours of launch. Addressing them
directly:
- Added prominent "A Note from Milla & Ben" section at top owning the issues
- Fixed AAAK section: removed "lossless" claim, removed bogus token example,
honest about lossy nature and 84.2% regression on LongMemEval
- Headline benchmark table: clearly labeled as "raw mode" (the 96.6% number)
- Removed misleading "100%" headline (still real but rerank pipeline not
in public scripts yet — addressing)
- Removed misleading "+34% palace boost" headline (it's metadata filtering,
real but not a novel mechanism)
- Marked Contradiction Detection as "experimental, not yet wired into KG ops"
- Closet legend now notes plain-text summaries in v3.0.0, AAAK closets coming
- Intro pillars rewritten honestly — raw verbatim is the win, AAAK is
experimental compression layer
Thank you to @panuhorsmalahti (#43), @lhl (#27), @gizmax (#39) and everyone
who filed issues in the first 48 hours. Brutal honest criticism is exactly
what makes open source work.