danielmiessler / danielmiessler/LifeOS

Memory reviewer: the consolidation target is only an instruction, so the hot layer stays pinned at the cap and the prompt grows until runs time out

Open
#2,072 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
19k
Forks
2.5k
Avg merge
8d 17h
Merged PRs (30d)
1

Description

Two related gaps in `LIFEOS/TOOLS/MemoryReviewer.ts`, both measured on a live install over 237 reviewer runs that left a `prompt.user.md` on disk.

## 1. The consolidation target is never enforced

`buildReviewerUserPrompt` tells the model `≥80% FULL, CONSOLIDATE BEFORE ADDING` from 39 entries (`renderCurrentMemory`), and the prompt body repeats `CONSOLIDATE FIRST`. Neither is validated. The only limit the code actually enforces is `≤48`.

The model does what is enforced. On this install the last four successful runs returned **47, 47, 48 and 48 entries** with both actors sitting at 48/48. It swaps one-for-one at the cap and never merges. That state held for **eleven days**, including after #1905 was addressed locally, so the erosion guard was no longer the blocker: the door was open and nothing walked through it.

This matters because the file already contains the counter-example. The corrective-retry comment says a re-prompt carrying the exact validator error *"fixes what prompt-side warnings alone demonstrably did not"* (2026-08-03 incident, entry size). Same lesson, different constraint.

## 2. The exchange block is bounded by count, never by bytes

`buildExchanges` caps each message at `MAX_MSG_CHARS = 2000` and returns `exchanges.slice(-maxExchanges)`. Nothing bounds the total, and the memory block in front of it is unbounded too, so the prompt can reach any size.

Failure rate against prompt size, same install, window starting when the timeout was raised to 300s:

| prompt.user.md | runs | failed | rate |
|---|---|---|---|
| 20-30 KB | 12 | 0 | 0% |
| 30-40 KB | 15 | 4 | 27% |
| 60-70 KB | 3 | 2 | 67% |

Overall **7 of 34 = 20.6%** of curation runs lost. In the largest failure the two memory blocks were **21,887 of 34,102 characters, 64% of the prompt**, both actors at 48/48 with the consolidation flag lit, which is also the most expensive reasoning path the reviewer has.

Raising the wall has been tried three times (120s → 240s → 300s, the last via #1907) and the rate did not move, because a bigger wall does not make the work smaller.

## Suggested shape

- **Validate the target under cap pressure.** When an actor is at or above the same 39 used by the prompt and by `isConsolidation`, reject an `op:"set"` that returns more than `max(36, prior - 3)` and let the existing corrective retry carry the message. A short step avoids asking for a twelve-entry merge in one pass, which is exactly when the 256-char cap breaks. The floor sits 3 below the trigger so the rule goes dormant once satisfied, and 6 above `CONSOLIDATION_FLOOR = 30` so it can never push toward erosion.
- **Budget the prompt by bytes, adaptively.** Give the exchange block whatever a total target leaves after the memory block, dropping oldest exchanges first and always keeping the two most recent. A fatter memory then costs exchanges instead of pushing the total past the wall.

Happy to send a PR if the shape is agreeable.

Contributor guide

No contributing guide indexed for this repository

Research direction

Read LIFEOS/TOOLS/MemoryReviewer.ts, starting with buildReviewerUserPrompt, renderCurrentMemory, buildExchanges, and the existing corrective-retry validation. Done means consolidation targets are rejected under cap pressure and the exchange budget adapts to keep the complete prompt bounded while retaining the two newest exchanges.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
ai
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.