Bug description
When a user disables auto-approve while a followup question countdown timer is actively running, the backend setTimeout in Task.ts can still fire and auto-commit a selection even though the user has already disabled auto-approve.
PR #11439 fixed the UI cleanup wiring (passing onFollowUpUnmount to ChatRow so FollowUpSuggest's cleanup sends cancelAutoApproval). However, the backend itself has no independent safeguards:
-
No hard-cancel on toggle-off: When autoApprovalEnabled is toggled off via the webview message handler, the pending setTimeout is not cancelled directly. Cancellation depends entirely on the React cleanup chain firing correctly.
-
No defensive gate in timeout callback: The setTimeout callback executes unconditionally — it does not re-check whether auto-approval is still enabled or whether the ask has been superseded by a newer message.
Scenarios not covered by UI-only fix
- Webview crashes or is disposed before React cleanup fires
- React render timing causes cleanup to run after the timeout fires
- Component unmount order differs from expected sequence
cancelAutoApproval message is lost or delayed in the postMessage channel
Expected behavior
The backend setTimeout callback should independently verify that auto-approval is still valid before committing a selection, regardless of whether the UI cancellation chain succeeded.
Proposed fix
- Hard-cancel in webviewMessageHandler: When
autoApprovalEnabled is toggled off, call cancelAutoApprovalTimeout() directly on the current task
- Defensive gate in timeout callback: Re-check
autoApprovalEnabled via getState() and verify the ask is not stale before auto-committing
- Backend regression tests: Cover explicit cancellation, defensive gate, superseded ask, and happy-path scenarios
Builds on top of #11439 (UI cleanup wiring).