Skip to content

[Bug]: Regenerate title never updates the UI — thread stays stuck on the old title while the server commits the rename #7328

Description

@AntoineArt

Before submitting

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

Area

apps/web

Steps to reproduce

  1. Open any thread that already has a generated title.
  2. Right-click the thread in the sidebar (or use the thread's menu) → Regenerate title.
  3. Watch the thread title and the context menu afterwards.

Text generation provider is healthy throughout (cursor / grok-4.5, probe status: "ready"); automatic first-turn title generation works on the same setup.

Expected behavior

The title updates in place once the server finishes the regeneration, and the pending state clears.

Actual behavior

The UI never reflects the result. The thread keeps showing the previous title in the dimmed "regenerating" style, and from then on the menu entry is permanently Regenerating… / disabled. I have never once seen this action visibly change a title, across several versions and on Linux, macOS and Windows.

The confusing part: the server side actually works. The regeneration completes and the new title is persisted — the client simply never applies it.

Evidence from my local event store (~/.t3/userdata/state.sqlite):

  • 4 client-issued thread.meta-updated events with regenerateTitle: true.
  • Each one is answered 7–19 s later by a server thread.meta-updated carrying a new title and titleRegeneration: null.
  • projection_threads holds those new titles today, and no row has a non-null title_regeneration_request_id.
request server completion delay
2026-08-10T08:13:44Z, previousTitle "Changelog t3code 0.32 nightly" title "T3 Code Nightly Changelog Tracking", titleRegeneration: null 7 s
2026-08-10T09:41:57Z new title written, titleRegeneration: null 15 s
2026-08-10T13:50:22Z new title written, titleRegeneration: null 9 s
2026-08-12T08:44:10Z new title written, titleRegeneration: null 19 s

(three titles redacted — client project names)

So the completing event exists, is persisted, and clears titleRegeneration — but the client keeps its pending flag.

Second-order effect, which is what makes it look completely dead: once that flag is stuck, further clicks send nothing at all. I clicked Regenerate title while tailing the logs; the websocket was live (ws.rpc.server.reportClientActivity a few seconds earlier), yet there was no orchestration.command.thread.meta.update span and no new event in the store. That matches the client handler in the shipped bundle:

case `regenerate-title`: { if (m) return; let t = await x({... regenerateTitle:!0}); ... }
// m = a.titleRegeneration != null

a bare return with no toast, no logging, no recovery — and the menu is built with label: e.isRegeneratingTitle ? "Regenerating…" : "Regenerate title", disabled: e.isRegeneratingTitle. There is no timeout or reconciliation against the server projection either, so the action stays inert for that thread indefinitely.

Not the same as #5359: there, text generation itself fails because the provider is unhealthy. Here generation succeeds and the rename is committed server-side; the defect is that the client never consumes the completion.

Impact

Major degradation or frequent failure

Version or commit

Nightly channel, currently 0.0.34-nightly. Unchanged across 0.0.32 → 0.0.33 → 0.0.34; I have never seen this action work on any version.

The traces and the bundle snippet below were captured against server runtime 0.0.33-nightly.20260810.1056 (the runtime process still active during the capture, while the desktop shell was already on the 0.0.34 nightly line) — so the client/server pair in this capture was drifted, but the behaviour is identical on a matched pair.

Environment

Linux (Arch, Hyprland), desktop AppImage on the nightly channel (0.0.34-nightly); also reproduced on the macOS and Windows desktop builds. Providers: claudeAgent (Claude Max, ready), cursor (ready). textGenerationModelSelection: { instanceId: "cursor", model: "grok-4.5" }.

Logs or stack traces

# Regeneration requests (client) — event store
sqlite3 state.sqlite "select occurred_at, substr(payload_json,1,120) from orchestration_events
  where payload_json like '%\"regenerateTitle\":true%' and actor_kind='client' order by sequence desc;"

2026-08-12T08:44:10.759Z|{"threadId":"f0e66a62-...","regenerateTitle":true,"previousTitle":"<redacted>","titleRegeneration":{"requestId":"5c668f0b-f003-49de-be7b-ef9d6a8ab25d",...
2026-08-10T13:50:22.032Z|{"threadId":"c3382cba-...","regenerateTitle":true,"previousTitle":"<redacted>",...
2026-08-10T09:41:57.139Z|{"threadId":"a54c8a65-...","regenerateTitle":true,"previousTitle":"<redacted>",...
2026-08-10T08:13:44.151Z|{"threadId":"fc00ee8c-...","regenerateTitle":true,"previousTitle":"Changelog t3code 0.32 nightly",...

# Matching server completion for the last one — the rename IS committed
2026-08-10T08:13:51.135Z|server|thread.meta-updated|
  {"threadId":"fc00ee8c-...","title":"T3 Code Nightly Changelog Tracking","titleRegeneration":null,...}

# No thread is left pending server-side
sqlite3 state.sqlite "select count(*) from projection_threads where title_regeneration_request_id is not null;"
0

# A fresh click produces no command at all (server trace, click at ~15:15Z)
grep '"orchestration.command.thread.meta.update"' server.trace.ndjson   # last hit 15:05:56Z, unrelated branch update
grep 'regenerateThreadTitle\|processThreadTitleRegenerationSafely' server.trace.ndjson   # no hits

Workaround

None found for the stuck menu entry. The rename is not lost — it is committed server-side, so the new title exists in the projection and should surface on a client reload.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions