Problem
The reflection pipeline is unidirectional: extract → store → decay → inject. There is no resolve → invalidate → suppress path.
Once a reflection item is written, it continues to be injected into every new session until maxAgeDays naturally expires (45 days for invariant items by default). When a problem is solved, the stale derived lessons about that problem keep being injected, occupying the injection budget and blocking relevant items.
Example:
- Session A: Rerank misconfiguration problem occurs → 6 derived lessons extracted
- Session B: Rerank is confirmed working
- Sessions C, D, E...: The 6 stale items continue to be injected on every new session, for up to 45 days
Proposed Solution: Option A — resolvedAt field + manual resolve tool
1. Add resolvedAt to ReflectionItemMetadata
interface ReflectionItemMetadata {
// ... existing fields ...
resolvedAt?: number; // Unix timestamp when marked resolved
resolvedBy?: string; // agentId that marked it resolved
resolutionNote?: string; // optional note
}
2. Add filterByResolved() in reflection recall
In reflection-recall.ts, after filterByMaxAge:
function filterByResolved(items: ReflectionItem[]): ReflectionItem[] {
return items.filter(item => item.metadata.resolvedAt === undefined);
}
This applies to all injection paths (derived-focus and inherited-rules) since they all consume the same recall output.
3. Add memory_reflection_resolve tool
memory_reflection_resolve({
query?: string, // BM25 match — resolves all matching items
id?: string, // Direct ID match — resolves one specific item
note?: string // Optional resolution note
})
Flow:
- If
id provided → directly resolve by ID
- If
query provided → bm25Search() for semantic match → resolve all results
- Set
resolvedAt = Date.now(), resolvedBy, optional note
- Return "resolved N items"
Why Option A over Option B/C?
| Option |
Effort |
Risk |
A — resolvedAt + tool |
Low |
Minimal — existing fields unchanged, new field is additive |
| B — Cross-pipeline suppression |
Medium |
Needs semantic similarity classification; high complexity for unclear accuracy |
C — Full status schema |
Medium-High |
Requires schema migration; most robust but overkill for the problem |
Option A requires no schema migration and solves the core issue.
Questions for Author
- Does the
resolvedAt field approach work for your use case?
- Should resolving an item automatically resolve all items with the same
strictKey?
- Should there be a
memory_reflection_list tool to let agents review their reflection items before resolving?
Related: #395
Problem
The reflection pipeline is unidirectional: extract → store → decay → inject. There is no resolve → invalidate → suppress path.
Once a reflection item is written, it continues to be injected into every new session until
maxAgeDaysnaturally expires (45 days for invariant items by default). When a problem is solved, the stale derived lessons about that problem keep being injected, occupying the injection budget and blocking relevant items.Example:
Proposed Solution: Option A —
resolvedAtfield + manual resolve tool1. Add
resolvedAttoReflectionItemMetadata2. Add
filterByResolved()in reflection recallIn
reflection-recall.ts, afterfilterByMaxAge:This applies to all injection paths (
derived-focusandinherited-rules) since they all consume the same recall output.3. Add
memory_reflection_resolvetoolFlow:
idprovided → directly resolve by IDqueryprovided →bm25Search()for semantic match → resolve all resultsresolvedAt = Date.now(),resolvedBy, optionalnoteWhy Option A over Option B/C?
resolvedAt+ toolstatusschemaOption A requires no schema migration and solves the core issue.
Questions for Author
resolvedAtfield approach work for your use case?strictKey?memory_reflection_listtool to let agents review their reflection items before resolving?Related: #395