Round-3 remediation — durable RMM memory (Postgres) + cache-hit request-id so cache-served responses are auditable

2026-08-09

memorygovernancerouterapi

LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: [ "POST /v1/memory/entries", "GET /v1/memory/entries", "GET /v1/governance/artifacts/{request_id}", "none", ] sdk_methods_updated: ["none — no wire-shape change"] mcp_tools_updated: ["br_memory_store/list/query now durable across tasks (no schema change)"] ---

What We Built

Two Round-3 defects, both found by the stochastic review and both now fixed and revert-tested.

  1. RMM memory is durable and shared across tasks. Every memory surface

(POST /v1/memory/entries, MCP br_memory_store, dashboard, and completions auto-injection) was reading/writing a per-task ephemeral SQLite file — so on the 2-task ECS fleet a write handled by one task was invisible to a read routed to the other (store returned ok+id, list returned total:0 for the owner), and every redeploy wiped it. The durable PostgresRmmStore existed in the tree but was wired nowhere and had three bugs. This wave adds migration v68 (rmm_core_memory + rmm_archival_memory, FORCE RLS, tenant-scoped), fixes the store (RLS-scoped queries, snapshot-scoped delete-reconcile that never clobbers a concurrent task's inserts, awaited flush on close), adds a single withRmm() accessor (EFS → Postgres → ephemeral+warn), and repoints every RMM call site — including removing the injector's fs.existsSync → return null guard so memory_facts is finally non-zero after a store.

  1. Cache-served responses are auditable. A prompt-cache hit wrote a correct, cache_hit-tagged

completion_audit row — but under a fresh randomUUID(), while traceContextMiddleware re-asserts the canonical req_ id on the response header _after_ next() returns. So the row the caller could look up by and the row that was written were different ids, and GET /v1/governance/artifacts/{id} 404'd for the id the client held. Fix: the cache-hit path now reuses c.get("requestId") (the canonical id) instead of minting an orphan. Two one-line changes; the artifact assembler already handled lineage-less rows and needed no change.

Why It Matters

Round 3 pinpointed both precisely by triangulation: cost-owner saw the cache-hit $0 ledger row while compliance-officer saw its artifact 404 (one half-landed fix); agent-consumer, claim-auditor, and the auditor all saw memory writes vanish on read-back — a defect so pervasive it undercut tenant-security's isolation proof. These are the two highest-leverage Round-4 fixes.

How It Works

Memory: withRmm(tenantId, fn, {readOnly}) resolves the backend once, runs the unchanged sync RMM logic inside a per-request Postgres load→operate→flush cycle with set_config('app.current_tenant') for RLS; reads skip the flush to keep the completions hot path cheap. Cache-hit: reuse the id the request already owns.

The Numbers

  • Migration v68. Memory suite 122 passing; both revert-tests fail against pre-fix behavior and pass after (quoted in the review ledger).
  • pnpm tsgo clean on the combined tree.

Competitive Edge

The review found these; the platform fixed them and re-measures. Durable, tenant-isolated agent memory that survives task recycling — and cache responses that still land in the evidence chain — is exactly the "prove what happened" thesis holding under its own audit.

Lockstep Checklist

  • [x] API Routes: memory + prompt-cache middleware updated; no route add/remove/method change.
  • [x] TS SDK / Python SDK: no wire-shape change — none needed.
  • [x] MCP Schemas: br_memory_* behavior fixed (durable); no schema change.
  • [x] Master Record: no new capability; defects tracked in docs/reviews/2026-08-08/ledger.json.

Known follow-up: src/api/routes/agentic-completions.ts RMM handle escapes into the streaming agent-run loop and is left on the ephemeral path with a TODO(memory-persistence) — a durability gap on that one write path, tracked for a dedicated fix. Remaining Round-4 clusters (cost-truthfulness, router explain/health, platform-sre alerting, dashboard nav/CORS) are architected and queued.