Repository navigation
Remembra 5.5.0 β production infrastructure
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.0What 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.