Issue #1553: perf: avoid loading all facts for active-task projection/injection
Status: WIP scaffold PR only — implementation pending.
Source Issue
- Issue: #1553
- URL: https://github.com/markus-lassfolk/openclaw-hybrid-memory/issues/1553
- State: OPEN (snapshot: 2026-05-21)
- Priority label: priority:high
- Labels: enhancement, priority:high, issue/stage/enriching
Acceptance Criteria / Issue Body
Summary
Active-task projection/injection appears to load all active facts and then filter to project/task facts in memory. With a large facts database, this causes unnecessary SQLite work, JS allocation churn, and memory pressure during every prompt build.
Evidence / suspected code path
The active-task path appears to do a broad fetch before filtering:
const facts = factsDb
.getAll({ scopeFilter })
.filter((fact) => fact.category === TASK_LEDGER_CATEGORY)
.slice(0, factLimit);
On Maeve, the gateway logs reported:
memory-hybrid: injecting 100 active task(s) from category:project facts (87 stale)
The facts.db file is ~421 MB and active fact volume is high. Reading all facts on prompt build is therefore expensive even if only a small subset is needed.
Impact
- Prompt build performs unnecessary DB reads and allocations.
- Stale/duplicate active-task rows amplify the cost.
- In high-concurrency periods, this can add memory churn and latency.
- It likely interacts badly with the separate duplicate SQLite-handle/native-RSS issue.
Acceptance criteria
- Active-task selection should query only
category='project'/ task-ledger rows at the SQL level. - Query should select only relevant columns/keys for task reconstruction.
- Query should apply candidate limits and terminal-status/staleness filters as early as possible.
- Prompt injection should not require hydrating the entire facts table.
- Add timing/row-count logs around active-task selection:
- SQL rows scanned/fetched
- active candidates
- stale skipped
- duplicates collapsed
- injected count
- elapsed ms
Suggested fix direction
- Add
FactsDB.getProjectFacts()orgetFactsByCategory(category, options)with indexes. - Ensure category/key/entity indexes exist and are used.
- Build active-task rows from latest facts per entity/key rather than all fact history.
- Consider a materialized active-task table/view updated by
active_task_checkpoint.
Stewardship Notes
This placeholder document exists to create a draft PR branch for Issue Stewardship tracking. The implementation work remains pending and should replace or extend this scaffold with the actual fix and verification evidence.