Title
Memory health permanently WARNs on memory-retrievals.jsonl: CortexHealth checks a stream MemoryRetriever never writes
Body
What happens
On a fresh 7.40.4 install, bun LIFEOS/TOOLS/MemoryHealthCheck.ts reports overall: warn with:
retrieval-missing: No retrieval evidence within 86400000ms freshness window.
The statusline renders this as 🧠 NEEDS ATTENTION · NO RETRIEVAL EVIDENCE WITHIN 86400000MS FRESHNESS… and it never clears, no matter how much retrieval actually happens. The <lifeos-ground> block is injected every turn, so retrieval is working; it just isn't recorded.
Why
The stream was designed but the writer was never built, and a health check was later added that assumes it exists.
ObservabilitySystem.md:55 still carries the original note: MemoryRetriever.getRelevantContext() (ISC-107..112; not yet populated as of 2026-05-23; infrastructure ready).
MemorySystem.md lists the stream as "Per-turn retrievals — written by MemoryRetriever".
- Release 7.40.4 (
be9e8ef) added CortexHealth.ts, which reads MEMORY/OBSERVABILITY/memory-retrievals.jsonl and WARNs when the latest row is missing or older than 24h. CortexContract.md:203 codifies it: "Retrieval evidence freshness | 24 hours | WARN when missing/stale".
git grep memory-retrievals over the whole tree returns only readers: CortexHealth.ts, MemoryStatus.ts, and three docs. MemoryRetriever.ts has never contained the string in any commit.
- No test references the stream, so a check shipping without its producer could not fail anywhere.
Fix
PR: #2094
Adds the writer to getRelevantContext(). Every uncached exit funnels through one finish() closure that appends a row shaped exactly as CortexHealth.validRetrievalRow requires: {ts, query_hash, returned_count, duration_ms} plus optional top_score.
Design choices worth a look:
- Empty-result paths are recorded. An empty retrieval is still evidence the retriever ran this turn, which is what the freshness check is asking about.
- Cache hits are not recorded. They do no ranking work; the stream is described as a "per-turn BM25 audit".
- The query is never persisted. It is the principal's prompt. The row carries a 16-hex sha256 prefix of the cache key, enough to correlate repeats.
- Writes are best-effort and swallowed. The retriever sits on every turn's critical path; a full disk must not turn into a thrown error.
Adds bun MemoryRetriever.ts test, following the self-test convention MemoryReviewer and seven other TOOLS already use. It runs the real hot-path entry point in a child process against a throwaway corpus and validates the rows with the real collectCortexEvidence / assessCortexEvidence. 12 assertions.
Updates the ObservabilitySystem.md:55 note from "not yet populated" to the landed behavior.
Verified
bun MemoryRetriever.ts test → PASS (12/12)
MemoryHealthCheck.ts on a live install: warn {critical:0, warn:1} → ok {critical:0, warn:0, ok:26}
- Existing CLI (
--help, positional query, corpus-missing error) unchanged
Diff footprint
LIFEOS/DOCUMENTATION/Observability/ObservabilitySystem.md | 2 +-
LIFEOS/TOOLS/MemoryRetriever.ts | 166 +++++++++++++--
Title
Memory health permanently WARNs on
memory-retrievals.jsonl: CortexHealth checks a stream MemoryRetriever never writesBody
What happens
On a fresh 7.40.4 install,
bun LIFEOS/TOOLS/MemoryHealthCheck.tsreportsoverall: warnwith:The statusline renders this as
🧠 NEEDS ATTENTION · NO RETRIEVAL EVIDENCE WITHIN 86400000MS FRESHNESS…and it never clears, no matter how much retrieval actually happens. The<lifeos-ground>block is injected every turn, so retrieval is working; it just isn't recorded.Why
The stream was designed but the writer was never built, and a health check was later added that assumes it exists.
ObservabilitySystem.md:55still carries the original note:MemoryRetriever.getRelevantContext()(ISC-107..112; not yet populated as of 2026-05-23; infrastructure ready).MemorySystem.mdlists the stream as "Per-turn retrievals — written by MemoryRetriever".be9e8ef) addedCortexHealth.ts, which readsMEMORY/OBSERVABILITY/memory-retrievals.jsonland WARNs when the latest row is missing or older than 24h.CortexContract.md:203codifies it: "Retrieval evidence freshness | 24 hours | WARN when missing/stale".git grep memory-retrievalsover the whole tree returns only readers:CortexHealth.ts,MemoryStatus.ts, and three docs.MemoryRetriever.tshas never contained the string in any commit.Fix
PR: #2094
Adds the writer to
getRelevantContext(). Every uncached exit funnels through onefinish()closure that appends a row shaped exactly asCortexHealth.validRetrievalRowrequires:{ts, query_hash, returned_count, duration_ms}plus optionaltop_score.Design choices worth a look:
Adds
bun MemoryRetriever.ts test, following the self-test conventionMemoryReviewerand seven other TOOLS already use. It runs the real hot-path entry point in a child process against a throwaway corpus and validates the rows with the realcollectCortexEvidence/assessCortexEvidence. 12 assertions.Updates the
ObservabilitySystem.md:55note from "not yet populated" to the landed behavior.Verified
bun MemoryRetriever.ts test→ PASS (12/12)MemoryHealthCheck.tson a live install:warn {critical:0, warn:1}→ok {critical:0, warn:0, ok:26}--help, positional query, corpus-missing error) unchangedDiff footprint