Note
Grok responding on behalf of Julius.
Triage
Thanks @0pilatos0 for the detailed diagnosis and the database evidence! I confirmed this on current main (263097a8). The nightly you reported on (fed41fa8) is an ancestor of that commit, and nothing since has changed this path.
What happens
thread.archive only refuses a thread that's already archived. It cancels queued runs, then detaches every live provider session with detail Thread archived. and revokeMcpCredential: true. A run that is preparing, starting, or running is left in place. By comparison, settle rejects active work before it detaches, and delete cancels active runs first. Archive does neither.
The clients already treat archiving a live turn as off-limits. threadRuntimeCanArchive allows dropping queued work but not detaching a provider that's preparing, starting, or running, and the web and mobile archive actions are disabled in that state. The menu comment saying the server rejects the action is out of date.
A self-archive through t3_thread_organize (with action: "archive" and no threadId) always hits this. readWritableThread requires the caller to own an active run, then dispatches thread.archive on that same thread. For a single-thread session like Claude, detach releases the session, and failSubscribers pushes a ProviderAdapterEventStreamError with cause Thread archived.. RunExecutionService still sees the run as running, so it writes a failed terminal. ProviderFailure then swaps the cause for the generic "provider event stream closed unexpectedly" text, which matches all six rows you posted. The tool item stays running because the stream dies before the tool result comes back.
Shared multi-thread sessions (Codex, OpenCode) interrupt or unload rather than going through releaseEntry, so they may end up interrupted instead of failed. That's still untested.
Related
#14203 (closed) was about stopping an idle provider process on archive. That teardown is now what kills the live turn. Open PR #14907 is a different path: setup finishing and starting work after the thread is already archived.
Likely fix area
One option is to make thread.archive reject a thread with a preparing, starting, or running run, the way settle does. The agent would then get a clear error and the turn could finish, while queued work can still be cancelled. Deferring a self-archive until the turn ends would be a new workflow. A maintainer will decide on the fix direction.
Your workaround holds: archive the thread only after its turn is idle, either from the UI or from another thread. Archiving it from anywhere while the turn is still running goes through the same server path.