Loki Mode v7.65.0
Immutable
release. Only release title and notes can be modified.
Memory subsystem hardening (wave-6 bug-hunt)
A dedicated hardening pass on the memory subsystem (storage.py, engine.py,
retrieval.py, consolidation.py, token_economics.py). The headline is a real
data-integrity fix; the rest is defensive robustness against corrupt or
hand-edited records. Reviewed by a 3-reviewer council (2 Opus + 1 Sonnet) to
unanimous approve. Full Python test suite: 1248 passed, 11 skipped.
Data-integrity (the real HIGH):
- Lost-update under concurrent writes:
storage._decay_semantic/
_decay_episodic/_decay_skillsandengine._update_index_with_episode/
_update_index_with_patternpreviously read a JSON state file under one lock
scope, mutated in memory, then wrote under a separate lock scope. A concurrent
save_pattern/store_episodelanding between the read and the write was
silently clobbered (dropped patterns, under-counted index totals). All sites
now hold ONE exclusive file lock across the full read-modify-write, mirroring
the already-correctsave_patterntemplate. This completes the v7.58.0
lost-update fix, which had been applied unevenly. Cross-process safe (fcntl
flock on the sidecar lock file).
Defensive robustness (corrupt / hand-edited records; no live writer emits these
values, schema validation enforces ranges):
- Null-field guards across every score/keyword path that does arithmetic or
.lower()on a raw record field:boost_on_retrieval,apply_decay,
calculate_importance(importance, phase, category),_score_result,
_keyword_search_semantic/_anti_patterns/_skills/_episodic,
optimize_context(confidence, usage_count), and the engine search /
update-pattern confidence + usage_count paths. An explicitnullfield no
longer crashes a query with TypeError / AttributeError. The guard preserves a
legitimate stored0.0(is-None check, not truthiness) where 0.0 is
meaningful (importance, confidence). - Path-traversal hardening:
engine.store_skillandstorage.save_episode
now sanitize the filename / validate the date component before building the
on-disk path, matchingsave_skill. A poisoned skill name or episode
timestamp (../../../tmp/evil) can no longer escape the memory root. _cleanup_stale_locksnow probes a stale lock with a non-blocking flock
before unlinking, so a long-running (>5min) live writer's lock is not removed
out from under it.
Correctness:
- consolidation: cluster-merge dedup now appends the saved pattern to the
in-memory set so two similar clusters in one run dedup correctly (no more
near-duplicate patterns); zettelkasten link-count is incremented only for
links that actually persisted. - retrieval Layer-2 progressive budget now trims topic summaries to the
remaining budget (mirroring Layer 3) instead of all-or-nothing admission. - retrieval topic-relevance ranking now reads the keys the writer actually
emits (id/summary), so the previously-inert layer-1 ranking works. - token_economics
optimize_contextis now strict-by-default (never exceeds
the stated budget); a previously-hardcoded 10% overage is now an explicit,
documented, opt-inslack_ratioparameter (default 0.0).
Test infrastructure:
- pytest.ini now collects hyphen-named Python test files
(python_files = test_*.py test-*.py). The repo had long carried hyphen-named
tests (e.g. test-memory-retrieval-bugs.py, test-memory-consolidation-merge.py)
that the defaulttest_*.py-only pattern silently skipped, so their
regression guards never ran underpytest tests/. They now do.