#19923: feat: track held messages during compaction gate and split verification payload
app: web-ui
gateway
agents
size: XL
Cluster:
Context Management Enhancements
## Problem
When a session compacts, messages arriving during the window each get a static 'context compacted' reply but are never surfaced. After the user types 'ok', neither the user nor the agent knows what came in. The verification payload also mixed agent internals (freeze rules, do-not-touch lists) into the user-visible message.
## Changes
**`src/config/sessions/types.ts`**
- Add `compactionHeldMessages?: Array<{body, timestamp, senderId?}>` to `SessionEntry`
**`src/auto-reply/reply/get-reply-run.ts`**
Three-part change to the post-compaction gate:
1. **Accumulate held messages** — Non-'ok' messages during the gate are appended to `compactionHeldMessages` in the session store before returning the verification reply.
2. **User-facing message** (clean, no agent internals):
- What was happening (next actions + active tasks from `.context-transfer.json`)
- `[Q1] body` / `[Q2] body` for held messages
- _"What should I do? Type 'ok' to resume."_
3. **Agent system context** (injected invisibly via `extraSystemPrompt` on the 'ok' turn):
- `[POST-COMPACTION FREEZE PROTOCOL]` header
- Freeze rules, next actions, do-not-touch list, queued messages with labels
- Discard instructions for unaddressed items
On 'ok', both `compactionPendingVerification` and `compactionHeldMessages` are cleared from the store.
## Testing
- Build: `pnpm build` ✅
- Tests: 32/32 pass (`post-compaction-audit`, `post-compaction-context`, `sessions`) ✅
Closes #88
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Large feature PR that adds several interrelated capabilities across the compaction, cron, directive handling, and agent runner subsystems.
**Core feature — post-compaction verification gate:** After compaction, messages are now held in `compactionHeldMessages` until the user types 'ok'. The verification message shows context from `.context-transfer.json` (next actions, active tasks, pending decisions) and labels held messages as `[Q1]`, `[Q2]`, etc. Agent-internal freeze instructions are injected via `extraSystemPrompt` on the 'ok' turn, cleanly separating user-visible from agent-visible content.
**Supporting additions:**
- Context extraction during compaction via a Sonnet API call, writing structured `.context-transfer.json`
- Session lock retry logic in `agent-runner.ts` and `queue/drain.ts` with backoff and max-retry limits
- New `shellGate` cron payload kind that gates agent turns on shell command output
- `"silent"` delivery mode for cron jobs
- Model-switch context guard with auto-compaction in directive handling
- `/model --force` flag to bypass context guard
- Pre-prompt hook infrastructure (`prePromptHook` config + `pre-prompt-hook.ts`)
- `restartNotify` gateway config to suppress post-restart pings
- Proactive DM handoff after memory flush
- `FORK-RUNBOOK.md` deployment guide
**Issues found:**
- The `shellGate` cron tool documentation uses `{{stdout}}` as the template placeholder, but the runtime in `timer.ts` substitutes `{{output}}` — agents following the docs will get un-substituted placeholders in their prompts
- `compactionHeldMessages` grows without bound during the verification gate; automated messages (cron, sub-agents) could inflate the session store if the user doesn't respond promptly
<h3>Confidence Score: 3/5</h3>
- Large feature PR with one confirmed logic bug (placeholder mismatch) and an unbounded growth concern; core compaction gate and lock retry logic appears sound.
- Score of 3 reflects the breadth of the change (38 files, ~1700 lines added) and one confirmed logic bug in the shellGate template placeholder. The core verification gate, session lock retry, and directive handling logic are well-structured with appropriate fallbacks. The placeholder mismatch is a definite runtime bug that will affect any shellGate cron job created using the tool documentation.
- `src/agents/tools/cron-tool.ts` (placeholder mismatch with `src/cron/service/timer.ts`), `src/auto-reply/reply/get-reply-run.ts` (unbounded held message array)
<sub>Last reviewed commit: c07f0e6</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
**Context used:**
- Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8))
- Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13))
<!-- /greptile_comment -->
Most Similar PRs
#20081: feat: post-compaction triage UX — fuzzy ok + stage-2 gate + Discord...
by PrivacySmurf · 2026-02-18
89.6%
#10273: fix(agents): detect and auto-compact mid-run context overflow
by terryops · 2026-02-06
84.2%
#18997: fix: improve context overflow error messages and docs
by realhoratiobot · 2026-02-17
82.5%
#20038: (fix): Compaction: preserve recent context and sync session memory ...
by rodrigouroz · 2026-02-18
82.0%
#18663: feat: progressive compaction escalation and mechanical flush fallback
by Adamya05 · 2026-02-16
81.5%
#14887: feat(compaction): configurable auto-compaction notifications with o...
by seilk · 2026-02-12
81.5%
#8713: feat: gateway memory monitor, install linger, docs and failover
by quratus · 2026-02-04
80.4%
#11999: fix: add session-growth guard to prevent unbounded session store gr...
by reverendrewind · 2026-02-08
80.3%
#4042: agents: add proactive compaction before request
by freedomzt · 2026-01-29
80.3%
#10915: fix: prevent session bloat from oversized tool results and improve ...
by DukeDeSouth · 2026-02-07
80.0%