Skip to content

Commit a56e9fd

Browse files
tcconnallytcconnallyclaude
authored
release: v2.14.0 — bi-temporal valid-time axis + the concurrency/capacity hardening arc (#406)
Version bump 2.13.0 -> 2.14.0 (Cargo.toml/lock, README badge, server.json, CHANGELOG section cut for 2026-07-02). Co-authored-by: tcconnally <hermes@perseus.observer> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 2b28fc2 commit a56e9fd

5 files changed

Lines changed: 62 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
All notable changes to Perseus Vault (formerly Mimir/Mneme) are documented here. This project adheres to
44
[Semantic Versioning](https://semver.org/).
55

6-
## [Unreleased]
6+
## [2.14.0] - 2026-07-02
77

88
### Added
99
- Recall-first context injection (#366): `mimir_context` / `prepare` default
@@ -46,6 +46,62 @@ All notable changes to Perseus Vault (formerly Mimir/Mneme) are documented here.
4646
count 53 → 55.
4747

4848
### Fixed
49+
- Pool-exhaustion collapse under concurrency (#397): recall, insert, and
50+
auto-embed each drew a SECOND pooled connection while holding one, so at
51+
≥ pool-size concurrent requests every slot was held by a frame blocking on
52+
the nested draw — 32 clients vs pool 16 measured 174 req/s with 30-second
53+
stalls and failed writes; 64 clients wedged. `apply_recall_side_effects`,
54+
`find_near_duplicate`, and `store_embedding` now reuse the caller's held
55+
connection (`_with_conn` variants), including `mimir_embed`'s single-entity
56+
path; the same load now runs at ~4,200 req/s with zero errors. r2d2's
57+
checkout timeout is tunable via `MIMIR_POOL_TIMEOUT_MS`. A new
58+
`concurrency-gate` CI workflow pins the load test at 2× pool
59+
oversubscription plus the four concurrency hammer tests.
60+
- decay_tick write amplification (#399): every tick rewrote every
61+
non-archived row even when nothing changed — 412MB of WAL per tick on a
62+
45MB database at 100k entities. Writes are now skipped when the recomputed
63+
score is within epsilon of the stored value (archive and layer-boundary
64+
crossings always write), so steady-state ticks write ~zero rows;
65+
`entities_updated` now reports rows actually written.
66+
- `mimir_history` pagination (#403): the tool returned every full decrypted
67+
version body with no limit — a hot key with 10k versions produced a
68+
~10-15MB tool response. Now takes `limit` (default 20, newest-first,
69+
0 = count-only) and `offset`, and reports `total`/`returned`.
70+
- follow() cross-workspace efficacy clobber (#391) and lost updates (#385):
71+
the key-addressed UPDATE stamped one workspace's counts and
72+
`efficacy_status` onto every (category,key) row — other workspaces and
73+
archived rows included — and the unlocked read-modify-write lost
74+
increments under concurrent calls. follow() now resolves ONE live row
75+
(the deterministic get_entity pick) under the audited writer lock and pins
76+
its UPDATE to that id.
77+
- link/unlink pool starvation (#387): both resolved the source entity via
78+
`get_entity()`, drawing a second pooled connection while one was held —
79+
≥16 concurrent linkers hit 30s r2d2 timeouts with opaque `Error(None)`.
80+
Ids now resolve on the caller's own connection.
81+
- cohere error-path transaction leak (#388, corrected premise): the raw
82+
`BEGIN IMMEDIATE`/`COMMIT` pair had no rollback guard — any error between
83+
them returned the pooled connection with the transaction still open,
84+
permanently poisoning that slot ("cannot start a transaction within a
85+
transaction" on every subsequent checkout). cohere now uses the drop-safe
86+
transaction; errors roll back. (The filed links-clobber scenario could not
87+
occur — the pair-scan read already ran inside the writer transaction.)
88+
- remember() erased link graphs (#382): the MCP remember tool constructs
89+
entities with empty links and remember's full-row UPDATE wrote them
90+
wholesale — ANY re-remember of a linked entity deterministically erased
91+
its edges, and concurrent `mimir_link` calls could lose edges to the
92+
unguarded read-modify-write. link/unlink now run under the writer lock and
93+
remember UNIONS caller links with stored links (dedup by target;
94+
stored relationship/weight win; `mimir_unlink` is the only removal path).
95+
- invalidate_entity temporal-window corruption (#381): the fourth
96+
`entity_history` writer stamped `invalidated_at = now()` raw — an audited
97+
writer that legitimately set `recorded_at` ahead of the wall clock produced
98+
an INVERTED window, and a same-millisecond create+invalidate produced a
99+
zero-width window that `mimir_as_of` could never reconstruct. It now takes
100+
the writer lock and bumps `invalidated_at` strictly past `recorded_at`.
101+
- rekey-aad stale overwrite (#386): a `remember()` landing between rekey's
102+
read and its re-encrypted write was silently reverted to stale content
103+
under a valid ciphertext; the per-row write is now guarded on the
104+
ciphertext being unchanged.
49105
- Audited-writer TOCTOU (#379): the three audited temporal writers (the #371
50106
re-assert path in remember, the #373 `set_valid_to` close, the #377 status
51107
flip) read their preconditions on the bare pooled connection before opening

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "perseus-vault"
3-
version = "2.13.0"
3+
version = "2.14.0"
44
edition = "2021"
55
description = "Persistent memory engine for AI agents — MCP JSON-RPC stdio server (formerly Mneme/Mimir)"
66
repository = "https://github.com/Perseus-Computing-LLC/perseus-vault"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
88
[![Rust](https://img.shields.io/badge/rust-stable-orange.svg)](https://rust-lang.org)
9-
[![Version](https://img.shields.io/badge/version-2.13.0-green.svg)](https://github.com/Perseus-Computing-LLC/perseus-vault/releases)
9+
[![Version](https://img.shields.io/badge/version-2.14.0-green.svg)](https://github.com/Perseus-Computing-LLC/perseus-vault/releases)
1010
[![LangGraph](https://img.shields.io/badge/integrations-LangGraph-blue)](integrations/langgraph/)
1111
[![CrewAI](https://img.shields.io/badge/integrations-CrewAI-orange)](integrations/crewai/)
1212
[![AutoGen](https://img.shields.io/badge/integrations-AutoGen-purple)](integrations/autogen/)

server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
"name": "io.github.Perseus-Computing-LLC/mimir",
44
"title": "Perseus Vault (formerly Mimir/Mneme), persistent memory engine for AI agents",
55
"description": "Local-first MCP memory server: SQLite, FTS5 and vector search, AES-256-GCM. 55 tools, no cloud.",
6-
"version": "2.13.0",
6+
"version": "2.14.0",
77
"packages": [{
88
"registryType": "oci",
9-
"identifier": "ghcr.io/perseus-computing-llc/perseus-vault:2.13.0",
9+
"identifier": "ghcr.io/perseus-computing-llc/perseus-vault:2.14.0",
1010
"transport": {"type": "stdio"},
1111
"runtimeHint": "docker",
1212
"runtimeArguments": [

0 commit comments

Comments
 (0)