SIGN IN SIGN UP

🐛 fix(hetero): stop AskUserQuestion cards from freezing after the producer times out (#19804)

* 🐛 fix(hetero): stop AskUserQuestion cards from freezing after the producer times out

The card's countdown started at mount while the producer's ask-user bridge
stops waiting at its own deadline (and its long-poll stops with it). Both
clocks are 10 minutes, but the producer's always starts first, so the card
auto-submitted option 1 into a producer that had just stopped listening. No
ACK could come back, and the card parked on `pending + resolving` with Submit
spinning and every button disabled — permanently.

- Countdown reads the producer's persisted deadline
  (`pluginState.heterogeneousIntervention.deadline`) instead of restarting on
  every remount.
- The timeout fallback answers inside the last 5 seconds, while the bridge is
  still listening, and never after a known producer deadline.
- A question past the producer's deadline is no longer offered as a card on
  any surface; its tool row states that it timed out.
- A submit the producer never acknowledges settles as answered after 30s and
  leaves the surface instead of being re-offered. The settle writes the
  `pluginIntervention` projection the card list reads, rather than waiting on
  the server echo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* 🐛 fix(hetero): expire intervention cards live and settle skips as skipped

Addresses Codex review on #19804.

- Pending cards past the producer's deadline were only dropped when a store
  update happened to re-run the selector. Provider-owned-option cards never
  auto-answer, so nothing wrote at expiry and an unanswerable card stayed on
  screen. Entries now carry the producer deadline, and `useDeadlineClock`
  re-renders consumers when the next one passes: the InterventionBar, the
  global approval island, and the assistant-turn-settled watcher.
- The inline tool row had the same gap: its "timed out" label only
  re-evaluated on render, so the row sat blank after the card left.
  `useIsTimedOutUnanswered` flips it at the deadline; an answer already in
  flight is never labelled as timed out.
- The no-ACK settle wrote `approved` for every action. A skip now settles as
  rejected + skipped and a cancel as rejected, matching the local desktop path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
A
Arvin Xu committed
878e802cebfc9da80ce7654a0405424a73748934
Parent: 11f36dd
Committed by GitHub <noreply@github.com> on 9/22/2026, 6:36:49 PM