-
Notifications
You must be signed in to change notification settings - Fork 2
Description
Problem
When the user clicks "Pause & Outline Plan", Claude Code sometimes retries ExitPlanMode without writing a visible outline (~3-4 times out of 10). The user sees approval buttons again with no plan text.
Root Cause
The cooldown mechanism (check_discuss_cooldown) only blocks ExitPlanMode retries within a time window (30s, 60s, 90s, 120s). Once the window expires, ExitPlanMode goes through normally — even if no outline was written.
The _OUTLINE_PENDING set tracks that an outline is expected, and max_text_len_since_cooldown tracks how much text Claude wrote, but neither is checked when the cooldown expires. The code falls through to the normal 3-button flow.
Fix
A. Code guard (src/untether/runners/claude.py): Before checking the time-based cooldown, check if the session is in _OUTLINE_PENDING AND max_text_len_since_cooldown < 200. If so, auto-deny ExitPlanMode regardless of cooldown expiry.
B. Prompt strengthening (src/untether/telegram/commands/claude_control.py): Rewritten _DISCUSS_DENY_MESSAGE to open with "STOP. Do NOT call ExitPlanMode", add explicit "it does not matter what you already know", and warn about automatic rejection.
C. Escalation messages (src/untether/runners/claude.py): _DISCUSS_ESCALATION_MESSAGE now says "REJECTED" with clear reason; _OUTLINE_WAIT_MESSAGE warns further calls will be rejected.
Impact
- Only affects the failure case (no outline written after discuss click)
- Happy path (outline written, buttons shown, user clicks) unchanged
- Cooldown timing, synthetic buttons, session cleanup all unchanged