#21610: fix(context-pruning): pi-extensions never built + null lastTouch skips prune after restart
agents
size: XS
Cluster:
Session Pruning Enhancements
## 3 bugs found & fixed via live debugging on Raspberry Pi 4
---
### Bug 1 (build): `pi-extensions/` never built — pruning never ran in production
`resolvePiExtensionPath()` resolves to `<root>/pi-extensions/<id>.js` but `tsdown.config.ts` had no entry for these files. Both `context-pruning` and `compaction-safeguard` were silently never loaded.
**Fix:** Add tsdown entry → `pi-extensions/`. Add to `.gitignore` (build artifact). Fix `.gitignore` pattern to `/pi-extensions` (was incorrectly also ignoring `src/agents/pi-extensions/`).
---
### Bug 2 (logic): `!lastTouch` falsy check skips pruning after restart
After restart, `readLastCacheTtlTimestamp` returns `null` (correctly skips zero-timestamp entries). But `extension.ts` used `!lastTouch` which is `true` for both `null` and `0` → pruning skipped indefinitely after every restart.
```ts
// Before
if (!lastTouch || ttlMs <= 0) return undefined; // null treated same as 0
// After
if (ttlMs <= 0) return undefined;
if (lastTouch !== null && Date.now() - lastTouch < ttlMs) return undefined; // null = cold cache → prune immediately
```
---
### Bug 3 (estimate): `CHARS_PER_TOKEN_ESTIMATE = 4` causes pruner to under-fire
Pruner computes `charWindow = contextTokens × CHARS_PER_TOKEN`. With `= 4`, charWindow is overestimated → fill ratio underestimated → pruner stops too early.
Empirical measurement from a real session (code/JSON/shell tool results):
- `~384k chars / ~158k tokens ≈ 2.44 chars/token`
With `= 4`: ratio = `384k / 800k = 48%` → below `hardClearRatio=0.5` → no hard-clear
With `= 2.5`: ratio = `384k / 500k = 77%` → above `hardClearRatio=0.5` → hard-clear runs ✅
Note: prose ≈ 4 chars/token, but tool results (code, JSON, shell) tokenize more efficiently at ~2.5.
---
## How it was found
Debugged live on a Raspberry Pi 4 running OpenClaw 2026.2.18 — noticed context pruning never reducing context size even after extended idle. Traced through session JSONL entries, extension loader, pruner source, and Anthropic token usage data.
Most Similar PRs
#14879: fix: persist session metadata to sessions.json after context pruning
by skylarkoo7 · 2026-02-12
72.6%
#14913: fix: update context pruning to notify session metadata after prunin...
by ScreenTechnicals · 2026-02-12
72.5%
#10997: fix: enable cache-ttl pruning on first load after restart
by anotb · 2026-02-07
68.6%
#5057: fix: add per-tool-result hard cap to prevent context overflow
by hanxiao · 2026-01-31
67.7%
#10465: Context pruning: strip image blocks instead of skipping
by quentintou · 2026-02-06
66.6%
#19878: fix: Handle compaction when fallback model has smaller context window
by gaurav10gg · 2026-02-18
66.3%
#23648: fix: detect truncated file paths from partial JSON streaming
by davidemanuelDEV · 2026-02-22
64.4%
#5360: fix(compaction): add emergency pruning for context overflow
by sgwannabe · 2026-01-31
63.8%
#9620: fix: increase auto-compaction reserve buffer to 40k tokens
by Arlo83963 · 2026-02-05
63.3%
#17730: feat: per-tool softTrim overrides for context pruning
by IrriVisionTechnologies · 2026-02-16
63.3%