ADR-0034: Non-destructive memory budgeting — inject-time cap, no LLM compaction

Status

Accepted (pending Phase 2 implementation)

Tags

digital-worker, memory, learning, ai, cost, prompt-assembly

Decision

The compact-memory budget (MVP: ≤20 role-agent memories, ≤3,000 characters injected) is enforced as an inject-time selection, not a storage rewrite. At context-assembly time, active memories are ranked (org-wide first, then by usage/recency via last_used_at/use_count), and only what fits the budget is injected. Memories that don’t fit stay stored and untouched; nothing is summarized, merged, or deleted to make room. There is no digital_worker:memory_compact LLM call in Phase 2. When a role-agent is over budget, the panel surfaces an admin nudge (“N memories not injected — consider pruning”). LLM-driven merge/summarization is explicitly deferred to a later phase.

Why

The budget is fundamentally a constraint on what enters the prompt, not on what is stored — storage is cheap, prompts are bounded. Solving it at inject time puts the fix where the constraint actually lives and keeps the write path fast, deterministic, and free. The spec’s original “compaction” framing implied an LLM that merges low-value memories into a summary and supersedes the originals. We deliberately rejected that for MVP because it is lossy (a summary can silently drop the one nuance that mattered — “ask for the floor and printer model”), it spends a gated LLM call on the write path, and it makes saves non-deterministic. At MVP scale (20 × 3,000 chars) the cap is rarely hit, so an LLM summarizer would be paying a real cost to optimize a problem we may not have yet. The reason to record this is to stop a future reader from “fixing” the obvious-looking gap by bolting on a summarizer. Inject-time capping is the intended behavior, and it is forward-compatible: once production shows which memories genuinely go stale, LLM compaction can be added later with real signal — whereas shipping the lossy summarizer first is hard to walk back. Rejected alternatives:
  • LLM merge into a summary, supersede originals. Lossy, costs gated calls on writes, non-deterministic. Deferred to a later phase, not MVP.
  • Hard cap that stops auto-saving when full. Non-destructive, but the agent silently stops learning until a human prunes. Rejected — capping at inject time lets learning continue while keeping the prompt bounded.

Consequences

  • dw_agent_memories gains last_used_at (and optionally use_count), bumped when a memory is injected, so ranking drops genuinely-unused memories rather than merely-old ones.
  • Over-budget role-agents accumulate stored-but-uninjected memories; the panel must make this visible so admins curate.
  • No prompt-time LLM cost for memory management; the only memory-related gated calls are detection/classification.

Rules for agents

  • Enforce the memory budget by ranking and capping at context-assembly time; never rewrite, merge, or delete stored memory to fit the budget.
  • Do not add a memory_compact LLM call in Phase 2.
  • Bump last_used_at when a memory is injected so the ranking reflects real usage.