Skip to content

fix(web,mobile): resume a blocked goal from the goal line - #112

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
fix/goal-resume-while-working
Nov 12, 2026
Merged

ScriptedAlchemy merged 4 commits into
mainfrom
fix/goal-resume-while-working

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Nov 12, 2026 •

Copy link
Copy Markdown
Owner

Why

Let users resume a blocked, paused, or limited goal from web and mobile, including while another turn is working. Previously the web goal line exposed only Clear during work, and the mobile working timer hid the goal action.

What changed

Web and mobile show Resume when idle and Resume after turn during active work. Both clients always send /goal resume with the queue intent. This starts immediately when idle and waits behind any work that starts before the command arrives. Mobile preserves its working timer and saves changed composer modes before resuming. User documentation points to the action.

Active Claude goals do not offer Resume. Their server behavior is unchanged.

Verification

  • vp run check:changed passed formatting, lint, knip, affected typechecks, adjacent tests, and React compiler checks.
  • All mobile unit and React suites passed. There were 304 files and 3,474 tests.
  • Regression cases failed before the idle dispatch and mobile mode fixes, then passed afterward. Failed mode saves also prevent continuation.
  • The earlier busy-action repair was reproduced and checked on Android and iOS. Both displayed the action and a queued message. Those captures predate the final idle-intent and mode fixes.
  • On iOS, selected Supervised while the server still had Full access. Resume saved Supervised and Replay displayed a file-change approval. After Allow once, the turn completed.
  • Earlier web and native Replay runs completed sequentially. The enriched transcript includes the actual /goal resume messages. Replay has no native goal driver, so this proves client dispatch and Replay queue order only.
  • Two synthetic Codex orchestration cases pin that queued goal set and Resume leave stopRequested: false until explicit promotion.

The runtime fixture used isolated state, a blocked-goal projection, and the free Replay provider. It proves client controls, dispatch, and Replay queue order. It does not exercise Codex goal semantics or native goal-stop policy. The final idle race has client regression and server test proof, without a provider-native runtime reproduction. The final shared continuation ran on iOS. Android did not re-run the final idle path. Browser snapshots timed out, so web visual inspection remains incomplete. Native Mac Computer Use is unavailable.

Evidence

Assets are in an unpublished evidence release. Repository write access is required to view draft assets.

Android before Android after
Working timer without Resume Working timer with Resume after turn

iOS working timer with a queued goal resume

Android interaction video. Runtime run-order transcript.

The final changed-file gate also passed 66 adjacent tests and five affected package typechecks after the server policy assertions. Independent Opus 5.5 review found no confirmed bugs in the final client repairs. It identified evidence limits, now stated above.

Original work used Opus 5.5 through Claude Code. Follow-up mobile repair and validation used GPT-6.1-Sol through Codex in T3 Code.

Web hid Resume while the agent worked, leaving only Clear. Resume now shows
whenever the goal is paused or blocked; while working it queues /goal resume
behind the current turn instead of stopping it. Mobile's goal row gains the
same Resume action.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: d2d0adc

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Web runtime check (dev server on isolated worktree state, free Replay provider, blocked goal written as a projection fixture):

  • Idle: the goal line reads Goal blocked · 557k tokens · 58m 38s with Resume · Clear.
  • Working: during a Replay turn the button read Resume after turn. After clicking it, the runs were:
run 1  "go"            completed
run 2  "go again"      completed 01:05:47.930Z   (not stopped)
run 3  "/goal resume"  completed 01:05:53.433Z   (ran after run 2)

Mobile not verified at runtime: the dev client installed on an iOS simulator, but agent-device open failed with DEVICE_IN_USE, naming the same session, even after device_open reconnected. Typecheck and lint pass for the mobile change.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Mobile runtime check (iPhone 17 simulator, iOS 27.0, dev client paired with the same isolated backend and fixture):

  • The goal row reads Goal blocked | Resume (accessibility: "Resume goal").
  • Tapping Resume dispatched /goal resume. The server recorded it as run 4, completed.

This replaces the earlier note that mobile was unverified. The first simulator had a stale agent-device claim (DEVICE_IN_USE), so I used a second simulator.

@ScriptedAlchemy

Copy link
Copy Markdown
Owner Author

Shipping verdict for PR112: PASS+NOTES

Head d2d0adc68e54b174809866cc17d1dff88174ca98. I verified this independently and did not write any of this code.

Scope. I read the full origin/main...HEAD diff against main cff49436fd: 11 files, +221/-88. Server production code is unchanged, and the queue policy the clients rely on is already on main. Relative to the previously reviewed cf4c6db0e2, d2d0adc changes only SteeringCompletion.integration.test.ts (0 non-test lines).

Code read.

  • The web and mobile goal-line Resume buttons both send /goal resume with dispatch mode queue. The client maps queue to queue_after_active with no delivery intent (packages/client-runtime/src/operations/commands.ts:768-790). The server picks a goal-stop target only when a delivery intent is present (apps/server/src/orchestration-v2/Orchestrator.ts:7058-7062). So the button never stops a running turn, and with no active run the send starts at once.
  • presentProviderGoal derives canResume from goal status only, so the action stays visible while the agent works. Mobile disables it without operate scope.
  • Mobile continueThread saves changed modes before starting the turn. If a save fails, it returns that failure and starts nothing. Tests cover both cases.
  • These two buttons are the only client code that sends /goal resume. Typing /goal resume keeps its documented stop behavior, and docs/user/composer.md describes both behaviors.

Focused tests at d2d0adc.

  • vp test run apps/mobile/src/features/threads/resume-thread.test.ts: 1 file, 8 passed.
  • vp test run apps/server/src/orchestration-v2/SteeringCompletion.integration.test.ts -t "goal": 14 passed, 31 skipped. These include "queues /goal ship it until promoted by stopping the running turn" and "queues /goal resume until promoted by stopping the running turn".
  • vp test run apps/web/src/components/chat/ThreadActivityBanners.browser.test.tsx: 2 passed. Both the working=false and working=true cases send "queue".
  • CI at the exact head: 13 passed, 0 failed, 3 skipped. The PR is mergeable and has no unresolved review threads.

Fresh web runtime at d2d0adc. I used the existing isolated PR112 servers (web 6295 and backend 14335, both running from the PR112 checkout), the free Replay Showcase model in Supervised mode, and the blocked-goal fixture thread. I clicked with real pointer input in T3's Browser panel and read persisted runs from the isolated validation database in read-only mode.

Run Trigger Requested Started Completed
15 Idle Resume 05:51:51.651Z 05:51:51.919Z 05:53:00.521Z
16 Resume after turn while run 15 waited on approval 05:52:14.903Z 05:53:04.171Z 05:53:17.726Z
  • The idle Resume started its turn within 268 ms, and the goal line switched to "Resume after turn".
  • The busy click persisted run 16 as queued behind the running run 15, and the UI showed "1 queued". The thread has no run_interrupt_request turn items. Run 16 started only after run 15 completed.
  • After both runs finished, the line read "Goal blocked · 557k tokens · 58m 38s" with Resume again. The checkout stayed clean at d2d0adc.

Native captures I inspected.

  • Android before the fix shows only "Working 0s". Android after the fix shows "Working 8s | Resume after turn".
  • iOS after the fix shows "Working 1s | Resume after turn".
  • The final iOS mode capture, taken at 7:22 PM local, shows a /goal resume turn waiting on file-change approval. The event-history export records the mode change to approval-required at 03:22:15.099Z, before run 14 started at 03:22:15.547Z.

Notes and limits.

  1. Replay has no native goal driver, so no runtime run, mine or earlier, reached the server's goal-stop branch. That branch has coverage from the synthetic Codex orchestration cases above, not from a native provider run. My runtime check proves the UI state, the dispatch mode, and the queue order.
  2. The Android captures validate 38ab59c2a3. The final shared continueThread path ran natively only on iOS at cf4c6db0e2, whose production code is identical to d2d0adc. I did not run a fresh native session.
  3. Mobile has no in-flight guard, so a double tap can queue a second /goal resume. The extra one waits instead of stopping work, and the user can see and remove it. Web guards against this with sendInFlightRef.
  4. On mobile, Resume after turn saves composer modes while the current turn is still running. Web does the same, because it saves modes before every send. Only Codex and OpenCode goals can resume, and both providers switch modes within the session.
  5. My first preview_snapshot call timed out after 15000 ms. I switched to DOM reads and coordinate clicks, which worked, so this run has no web screenshot. Nothing signs off the native desktop shell, and Mac Computer Use is unavailable.

Verified by Claude Opus 5.5 via Claude Agent in T3 Code.

@ScriptedAlchemy
ScriptedAlchemy merged commit bc1a4ae into main Nov 12, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant