You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Completion alert fires when a delegated task finishes, though the parent is about to continue #31087
A parent thread sends a "Thread completed" sound and notification when its last running delegated task finishes, then goes straight back to work. It never appears in Done at that moment, and this repeats through a long orchestration.
Diagnosis
Finishing the delegate and starting the parent's next run are separate steps, about 80 ms apart. In between, the thread has no active run or pending work and its latest run is completed, so createThreadNotificationGate notifies at once. #29146 removed the 2-second wait added by #24760 and accepted this trade-off. The sidebar keeps WORKING_EXIT_GRACE_MS, so the alert and the sidebar disagree.
Steps to reproduce
Set notifications to "Notifications with sound".
In a thread, start one async delegate_task and let the parent end its turn.
When the delegate finishes, an alert fires while the thread goes back to Working.
Version
0.1.7, on both the desktop client and the remote server. main has the same logic.
Environment
Desktop on macOS arm64, connected to a local server and a linked Linux server. Claude parent thread, Codex delegates.
Evidence
Times in UTC. Delegate marked finished 19:19:50.402, thread update published .410, next run dispatched .487, run requested .492. The thread really finished at 19:22:15. The same pattern came before 4 earlier wake-ups in that thread (18:26:35, 18:37:05, 18:52:11, 19:08:59). The alert itself isn't logged by the client.
The same gap happens without delegation: a background shell command the agent awaits with t3_background_wait. #31130 and #31357 only hold app-owned tasks, so they won't fix this case.
What happens
A Claude agent starts a command with run_in_background, calls t3_background_wait on it, and ends its turn. The sidebar correctly shows Waiting. When the command exits, the completion sound plays, and the wake run starts less than a second later. Every awaited command in a multi-step job produces one false alert.
Why
On v0.1.7 (322f6544df):
When Claude sends task_notification, clearPendingBackgroundTask deletes the finished task from the roster, along with its awaited flag. The wake run is requested only after that (apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts:8321-8326, removal at :5508).
In between, the shell has no work that holds completion and its latest run (the earlier one) is completed. That gives settled = status === "ready" && latestRun.status === "completed" (apps/web/src/components/ThreadNotificationCoordinator.tsx:264), and since fix(web): play completion sounds without delay #29146createThreadNotificationGate notifies at once.
Before #29146, the 2-second continuation grace covered this sub-second gap, so this is the same 0.1.7 regression described here. The difference is the fix: the hold has to be applied to awaited, provider-owned command/monitor entries in the Claude adapter roster, keeping the finished entry until its wake run exists. The delegated-task path in ProjectionStore doesn't cover it.
Evidence
Server trace, times in UTC:
11:20:20.981 t3_background_wait {taskIds: [<task 1>]} → run ends 11:20:21.9, sidebar Waiting
~11:21:23 command exits → completion sound plays
11:21:23.104 wake run starts ("Command … finished" notice)
11:22:04.692 t3_background_wait {taskIds: [<task 2>]} → run ends 11:22:07.1, Waiting
~11:24:00 command exits → completion sound plays again; next run 11:24:00.5
Environment
T3 Code 0.1.7 stable: Linux desktop (AppImage) against a local server, Claude provider (claude-opus-5-5), Settings → Thread notifications set to sound on.
Repro
Turn on sound for thread notifications.
In a Claude thread, have the agent run sleep 60; echo done with run_in_background, call t3_background_wait with that task ID, and end its turn.
Check the sidebar shows Waiting, then wait for the command to exit.
Related: #31346, #25585, #13625 (closed with "open a new issue" for native background work), and #15099 (the turn-end case, fixed by #24610).
Written by Claude Opus 5.5 (claude-opus-5-5) through Claude Code, via t3 triage.
Confirming the same symptom: completion notifications arrive even though the thread is still in the Working state and continues working. The alerts appear to be tied to individual turns rather than completion of the overall task.
Expected: a completion notification only when the thread's work is actually finished.
Still reproduces on 0.1.10-nightly.20261114.4682 (desktop app on macOS arm64, local server, commit 820f620e3d). This adds a third surface to the report: the in-app toast ("Thread completed" with "Open thread") fires too, not only the sound and the desktop notification. All three go through the same createThreadNotificationGate → present() path in ThreadNotificationCoordinator.
Setup: a Claude parent thread running a review loop. It delegates async delegate_task children (Claude and Codex), ends its turn, then continues when each child reports back. The user sees a toast each time a child finishes, while the parent goes straight back to Working.
Timings from one parent thread (UTC, from orchestration_v2_projection_runs / _subagents):
Child finished
Parent's next run requested
Gap
13:42:50.162
13:42:50.186
24 ms
14:28:47.844
14:28:47.856
12 ms
14:35:33.193
14:35:33.221
28 ms
Server trace for the 14:35:33 wake:
.150 Orchestrator.finalizeDelegatedCompletionDelivery
.151 AgentAwarenessRelay.publishThread
.188 EventSink.write (parent) / planDelegatedCompletionDelivery
.198 AgentAwarenessRelay.publishThread
.212 dispatch message.dispatch (parent) ← wake run begins
So the parent's shell is published at least once with a completed latest run and an empty background roster before the wake run exists. That matches the diagnosis above. #31130 and #31357 are both still open, so no current build has a fix.
Filed via T3 Code triage by Claude Opus 5.5 (claude-opus-5-5), Claude Code running in T3 Code.
Confirming this on a Pi thread with delegate_task children, where the gap is much wider than the Claude reports (0.5 to 0.7 s instead of 12 to 28 ms), so the false alert is reliably visible rather than a race you rarely catch.
Environment:0.1.10-nightly.20261113.4643. Linux x64, server on 127.0.0.1:3773, Linux desktop client showing OS desktop notifications (the new Notification path in ThreadNotificationCoordinator.present, not the in-app toast). Parent provider pi, model opencode-go/deepseek-v4.1-flash. All children are app-owned delegate_task subagents (116 in the local database, provider: pi, origin: app_owned), notification mode "notifications with sound".
Timings from orchestration_v2_projection_subagents.completed_at against the next orchestration_v2_projection_runs.requested_at for the same parent thread. Each parent has a completed run and an empty roster in between:
Parent thread
Child finished
Wake run requested
Gap
Stagger Theme Switch Animations
18:48:01.885
18:48:02.423
538 ms
Modern Site Scrollbar Styling
18:48:31.213
18:48:31.793
580 ms
Keep Close Button on Header Line
18:51:54.875
18:51:55.426
551 ms
Widen Suche Button
19:03:06.709
19:03:07.383
674 ms
Search Bar Clear Button Alignment
18:39:04.173
18:39:04.670
497 ms
In the same database a child that is still running has a subagent turn item with status running, which is what holds the roster and makes the sidebar show Waiting during the wait. Its transition to completed is what empties the roster (derivePendingBackgroundWork in packages/shared/src/orchestrationV2PendingBackgroundWork.ts), and only then does ThreadNotificationCoordinator.tsx:284 compute settled = completed && !monitorHoldsWakeCompletion(rawThread) as true. Since #29146 removed the 2 second continuation grace, createThreadNotificationGate notifies on that first observation.
Note that settled consults monitorHoldsWakeCompletion only, so a subagent-held settle is not filtered the way a monitor-held one is. Fixing the roster in ProjectionStore (as #31130 and #31357 do) should cover this case, but the wider Pi gap suggests the window is not purely a sub-millisecond dispatch race: for about half a second the parent genuinely reads as settled over the wire, so any client that samples state in that window alerts.
Both fix PRs on this path, #31130 and #31357, are still open and unmerged, so no current build covers it.
Filed via T3 Code triage by deepseek-v4.1-flash (opencode-go/deepseek-v4.1-flash), Pi running in T3 Code.
Activity
diwakar-s-maurya commentedon Nov 6, 2026
The same gap happens without delegation: a background shell command the agent awaits with
t3_background_wait. #31130 and #31357 only hold app-owned tasks, so they won't fix this case.What happens
A Claude agent starts a command with
run_in_background, callst3_background_waiton it, and ends its turn. The sidebar correctly shows Waiting. When the command exits, the completion sound plays, and the wake run starts less than a second later. Every awaited command in a multi-step job produces one false alert.Why
On v0.1.7 (
322f6544df):task_notification,clearPendingBackgroundTaskdeletes the finished task from the roster, along with itsawaitedflag. The wake run is requested only after that (apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts:8321-8326, removal at:5508).completed. That givessettled = status === "ready" && latestRun.status === "completed"(apps/web/src/components/ThreadNotificationCoordinator.tsx:264), and since fix(web): play completion sounds without delay #29146createThreadNotificationGatenotifies at once.Before #29146, the 2-second continuation grace covered this sub-second gap, so this is the same 0.1.7 regression described here. The difference is the fix: the hold has to be applied to awaited, provider-owned
command/monitorentries in the Claude adapter roster, keeping the finished entry until its wake run exists. The delegated-task path inProjectionStoredoesn't cover it.Evidence
Server trace, times in UTC:
Environment
T3 Code 0.1.7 stable: Linux desktop (AppImage) against a local server, Claude provider (
claude-opus-5-5), Settings → Thread notifications set to sound on.Repro
sleep 60; echo donewithrun_in_background, callt3_background_waitwith that task ID, and end its turn.Related: #31346, #25585, #13625 (closed with "open a new issue" for native background work), and #15099 (the turn-end case, fixed by #24610).
Written by Claude Opus 5.5 (
claude-opus-5-5) through Claude Code, viat3 triage.makeavish commentedon Nov 11, 2026
Confirming the same symptom: completion notifications arrive even though the thread is still in the Working state and continues working. The alerts appear to be tied to individual turns rather than completion of the overall task.
Expected: a completion notification only when the thread's work is actually finished.
ckafrouni commentedon Nov 14, 2026
Still reproduces on 0.1.10-nightly.20261114.4682 (desktop app on macOS arm64, local server, commit
820f620e3d). This adds a third surface to the report: the in-app toast ("Thread completed" with "Open thread") fires too, not only the sound and the desktop notification. All three go through the samecreateThreadNotificationGate→present()path inThreadNotificationCoordinator.Setup: a Claude parent thread running a review loop. It delegates async
delegate_taskchildren (Claude and Codex), ends its turn, then continues when each child reports back. The user sees a toast each time a child finishes, while the parent goes straight back to Working.Timings from one parent thread (UTC, from
orchestration_v2_projection_runs/_subagents):Server trace for the 14:35:33 wake:
So the parent's shell is published at least once with a completed latest run and an empty background roster before the wake run exists. That matches the diagnosis above. #31130 and #31357 are both still open, so no current build has a fix.
Filed via T3 Code triage by Claude Opus 5.5 (
claude-opus-5-5), Claude Code running in T3 Code.DontBlameMeDev commentedon Nov 14, 2026
Confirming this on a Pi thread with
delegate_taskchildren, where the gap is much wider than the Claude reports (0.5 to 0.7 s instead of 12 to 28 ms), so the false alert is reliably visible rather than a race you rarely catch.Environment:
0.1.10-nightly.20261113.4643. Linux x64, server on127.0.0.1:3773, Linux desktop client showing OS desktop notifications (thenew Notificationpath inThreadNotificationCoordinator.present, not the in-app toast). Parent providerpi, modelopencode-go/deepseek-v4.1-flash. All children are app-owneddelegate_tasksubagents (116 in the local database,provider: pi,origin: app_owned), notification mode "notifications with sound".Timings from
orchestration_v2_projection_subagents.completed_atagainst the nextorchestration_v2_projection_runs.requested_atfor the same parent thread. Each parent has acompletedrun and an empty roster in between:In the same database a child that is still running has a
subagentturn item with statusrunning, which is what holds the roster and makes the sidebar show Waiting during the wait. Its transition tocompletedis what empties the roster (derivePendingBackgroundWorkinpackages/shared/src/orchestrationV2PendingBackgroundWork.ts), and only then doesThreadNotificationCoordinator.tsx:284computesettled = completed && !monitorHoldsWakeCompletion(rawThread)as true. Since #29146 removed the 2 second continuation grace,createThreadNotificationGatenotifies on that first observation.Note that
settledconsultsmonitorHoldsWakeCompletiononly, so a subagent-held settle is not filtered the way a monitor-held one is. Fixing the roster inProjectionStore(as #31130 and #31357 do) should cover this case, but the wider Pi gap suggests the window is not purely a sub-millisecond dispatch race: for about half a second the parent genuinely reads as settled over the wire, so any client that samples state in that window alerts.Both fix PRs on this path, #31130 and #31357, are still open and unmerged, so no current build covers it.
Filed via T3 Code triage by deepseek-v4.1-flash (
opencode-go/deepseek-v4.1-flash), Pi running in T3 Code.