Compaction drift: 'Resume directly, do not ask questions' trailer causes silent task switching
Summary
After /compact (auto or manual), the model can resume on a completely different task than what was active pre-compaction, with no signal to the user. In the worst case this has caused unauthorized production deploys (full repro below). The root cause is the combination of three signals in the compact prompt that bias the model toward picking any actionable continuation, plus a trailer that explicitly forbids verifying.
Repro
Long-running Claude Code session, model is mid-task on feature A. /compact fires. Resumed model:
- Receives the compact summary (lossy)
- Sees
Skills restored (frontend-slides, deck-gen, ...)notice — historically loaded skills, NOT current intent - Reaches Section 9 "Optional Next Step" of the compact prompt — last position, high attention
- Final trailer at
compact/prompt.ts:359:"Continue the conversation from where it left off without asking the user any further questions. Resume directly..."
Result: model picks a continuation from the highest-attention skill or summary fragment and proceeds. If that's frontend-slides when the actual work was infrastructure, the model ships an executive deck instead of fixing the bug.
Real-world impact (last 24h on my workspace)
- Incident 1: Mid-session on a Postgres migration.
/compactfires. Model resumes onfrontend-slidesskill, generates a 996-linestrategy.htmlexecutive deck, deploys it to production fly.io with auth bypass inmiddleware.ts. Twice. - Incident 2: Mid-session on frontend skill work.
/compactfires. Model resumes on the previous topic (was journaled), abandons current work.
Both happened with users who had session journaling/observability — the drift was only caught after the fact via git log.
Why the model can't self-correct
The trailer at compact/prompt.ts:359 says verbatim: "do not ask the user any further questions". So even when the model has uncertainty about which task to resume, the prompt forbids verification. The model commits to something and ships.
Suggested fix
Three options, in order of effort:
1. Soft (low effort): Make the trailer conditional on summary confidence. If Section 9 ("Optional Next Step") was empty or marked "ambiguous", drop the "do not ask questions" instruction.
2. Medium: Add a confidence field to the summary writer's output. Trailer becomes: "If [confidence:high], resume directly. Otherwise, briefly confirm the active task with the user."
3. Robust: Allow SessionStart hooks with matcher: "compact" to inject a "verification protocol" that overrides the trailer when present. This already partially works (hookSpecificOutput.additionalContext lands before first API call), but the trailer's "do not ask questions" instruction still wins because it's positionally last. Adding precedence rules — or letting hooks suppress the trailer — would close the loop.
I've prototyped option 3 locally as a SessionStart:compact hook (compact-rehydrate.sh) that injects multi-signal ground truth (last journal entry + journal age + recent file edits) and an explicit "ASK if signals diverge" protocol. It works, but feels like a workaround for a prompt-design issue.
Workaround for users hitting this today
{
"hooks": {
"SessionStart": [{
"matcher": "compact",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/compact-rehydrate.sh" }]
}]
}
}
Hook script reads the project's most recent ground-truth (journal, recent edits) and emits hookSpecificOutput.additionalContext with explicit "ASK if signals disagree" protocol. Happy to share if useful.
References
src/services/compact/prompt.ts:359— the "Resume directly" trailersrc/services/compact/prompt.ts:76— Section 9 "Optional Next Step" (high-attention last position)src/utils/hooks.ts:3867-3891—executeSessionStartHookswith source-based matcherssrc/utils/sessionStart.ts:140-172—additionalContextinjection mechanism
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗