Skip to content

Remembra 5.5.0 β€” production infrastructure

Choose a tag to compare

@lacrous lacrous released this 27 Sep 14:22
· 66 commits to main since this release

Remembra 5.5.0 β€” production infrastructure.

This is the roadmap Β§17–§24 milestone the plan calls V5.1.0. It ships as
5.5.0 because V5.4.0 was released first, so the planned 5.1.0 is now a
downgrade of an already-published version. The roadmap carries a renumbering
banner so the shift is explicit; milestone intent is unchanged.


Install

npm install @hilbras/remembra@5.5.0
pip install hilbras-remembra==5.5.0

What is new

Rate limiting β€” a RateLimiter interface (check / consume / reset,
async) with a bounded in-process implementation, injected through
HttpOptions.rateLimiter. check decides without charging, so a caller can ask
whether it has budget without spending it.

Quotas β€” REMEMBRA_QUOTAS sets per-dimension policies across organization,
project, user, agent, API key, IP, endpoint, and provider, layered on top of the
base budget. Precedence is the declared dimension order, charging is
all-or-nothing, and a 429 now names the dimension that refused it without ever
naming a principal.

Health β€” /health/live, /health/ready, /health/storage, and
/health/provider. Liveness is public and reads process state only, so it stays
200 when storage is broken and reports draining once a shutdown begins.

Metrics β€” p50/p95/p99 over recorded histograms, the six series Β§21 named that
did not exist, and a hard bound on label cardinality.

Logging β€” every line carries requestId, operation, and durationMs
through an AsyncLocalStorage request context, so events from the service,
storage, provider, and job-queue layers correlate without threading anything by
hand.

Shutdown β€” a bounded, idempotent, honest sequence in both HTTP and MCP mode.


Eight defects found and fixed

This release opened with an audit, and the two with the most weight:

The rate limiter was an unbounded memory-exhaustion vector, reachable without
a credential.
A window was reclaimed only if its own key was checked again
after expiry, so any identity used once and abandoned lived for the process
lifetime β€” 50,000 abandoned keys retained 50,001 entries. The anonymous bucket is
charged before authentication and keyed by source address. Now capped at
10,000 with a deterministic sweep and least-recently-used eviction.

A concurrent burst bypassed the quota entirely. Decide and charge were
separated by an await, so 500 simultaneous requests against an organization
cap of 20 were all admitted. A rate limiter that can be defeated by sending
requests in parallel is not a rate limiter. Found by the stress matrix, fixed by
serializing decide-and-charge, pinned by three regression tests.

The other six: /health performed a full storage scan and a durable
recovery-state write on every unauthenticated call; /metrics was rate limited
against its own documentation, so a scraper lost observability during the storms
it exists to diagnose; seven metrics were declared and never written, so
dashboards on them rendered empty and looked like data loss; the retrieval debug
trace logged raw query text behind the wrong environment flag and
migration_start logged a storage path unconditionally; MCP mode installed no
signal handler at all, so SIGTERM killed it with no drain; and an injected
embedding adapter bypassed provider metrics entirely β€” the path V5.4 most wanted
working.

Two of the test's own premises were also wrong, and were corrected rather than
papered over: refused requests under concurrency turned out to be 429 from the
default budget rather than the concurrency cap, and a 14 KB payload that appeared
to lose data was the token rule of the default sensitive-data policy matching
hyphen-separated words β€” a shape judgement, not a size limit.


Release evidence

Gate Result
Build pass
Full suite 684 tests, 0 failures
Security matrix 142 tests, 0 failures
Recovery matrix 52 tests, 0 failures
Python SDK 28 tests, 0 failures
Documentation links 40 files, 0 broken
npm audit --omit=dev 0 vulnerabilities
Package dry run 249 files, 564.4 kB
Tenant benchmark pass (within documented ceilings)
Scale benchmark pass (within documented ceilings)
Node runtimes 18.20.8 and 24.21.0

Not claimed

No distributed quotas, no distributed workers, no shared-state runtime, and no
advanced retrieval engine. The rate limiter, quota ledger, webhook queue, and
idempotency ledger remain single-host and in-process. The interfaces added here
exist so a shared implementation can be added later without changing the
request path β€” adding one is later work and is not claimed.

Compatibility

Additive everywhere. Authentication still precedes rate-limit consumption, rate
identity is still an opaque digest (now enforced rather than merely
conventional), REMEMBRA_RATE_LIMIT and REMEMBRA_RATE_WINDOW_MS still
configure the base budget, /health returns the same shape and status codes, and
SEC-RL-001, SEC-RL-002, and SEC-LOG-001 pass unmodified.

Four new limits a deployment could notice are listed in
docs/v5.5.0-compatibility.md.