Skip to content

[Bug]: A thread that woke from snooze cannot be snoozed again to the same wake time #14298

Description

@vitalyiegorov

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Steps to reproduce

  1. Snooze a thread with Next week.
  2. Let its session fail after the snooze. In my case two Claude threads ran turns that failed at once with "Claude usage limit reached". The thread comes back as Failed, as intended: a failure newer than the snooze raises its hand.
  3. Snooze it again with Next week.

Expected behavior

The thread leaves the inbox until the new wake time.

Actual behavior

The command is accepted, but the thread stays in the inbox as Failed. Snoozing again with the same option does the same every time. I did it six times in 12 minutes on one thread. It looks like the snooze hangs or does nothing, with no toast.

Cause

A re-snooze to the same wake time is treated as a duplicate, and the original snoozedAt is kept:

  • server: apps/server/src/orchestration/decider.ts, thread.snooze, the existingSnoozedAt branch
  • client optimistic twin: packages/client-runtime/src/state/threadCommands.ts, snoozedAt: thread.snoozedUntil === input.snoozedUntil ? (thread.snoozedAt ?? now) : now

The raised-hand check in threadRaisedHandWhileSnoozed (packages/client-runtime/src/state/threadSettled.ts) compares session.updatedAt and latestTurn.completedAt against that stale snoozedAt. The failure is still newer, so the thread never classifies as snoozed again until the user picks a different wake time. Presets such as Tomorrow and Next week resolve to fixed clock times, so repeating the same option is the normal case.

Suggested fix

Remove the same-wake-time branch in both places, so an explicit snooze always stamps snoozedAt now. Re-snoozing means "I saw it, not now", so it should reset the raised-hand baseline. Real retries are already deduplicated by commandId receipts, and a double-click only moves the stamp by milliseconds. This is a net deletion. Update the existing decider.snoozed.test.ts case ("re-emits idempotently for a duplicate snooze to the same wake time") to assert a fresh snoozedAt. I can open the PR.

Impact

Minor bug or occasional failure

Version or commit

t3@0.0.43-nightly.20260929.2428 (main d2c9281). The code is unchanged on current main.

Environment

Linux host running t3 serve as a service, macOS desktop client connected remotely, Claude provider. Not specific to remote connections: the server accepted every command.

Logs or stack traces

# orchestration_events for one thread (UTC)
17:30:47.626  thread.snoozed      client    snoozedUntil 2026-10-05T07:00Z  snoozedAt 17:30:47.626
17:45:45.170  thread.session-set  provider  status error  "Claude usage limit reached…"
17:58:01.695  thread.session-set  provider  status error  "Claude usage limit reached…"   <- raises hand
17:58:19.209  thread.snoozed      client    snoozedUntil 2026-10-05T07:00Z  snoozedAt 17:30:47.626  <- stale
17:58:33.557  thread.snoozed      client    …same…
17:58:52.528  thread.snoozed      client    …same…
18:03:21.077  thread.snoozed      client    …same…
18:04:53.764  thread.snoozed      client    …same…
18:10:21.969  thread.snoozed      client    …same…
# all receipts: accepted; projection_threads.snoozed_at stays 17:30:47.626

A second thread shows the same pattern (snoozed 17:30:40, error at 18:05:45, re-snoozes at 18:08 and 18:10 all keep 17:30:40).

Screenshots, recordings, or supporting files

Both threads after six "Next week" re-snoozes between 17:58 and 18:10. Every command was accepted, and both rows are still in the inbox as Failed:

Sidebar: two Claude threads stopped by a usage limit stay in the inbox as Failed after repeated re-snoozes

Workaround

Snooze with a different option, such as Tomorrow or 3 hours. That stamps a fresh snoozedAt and the snooze holds.

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions