fix(desktop,db): unbreak chat in local-first workspaces and clean up no-credential UX
Closed
KI
1mo ago+6781+6781+0123456789012345678901234567890123456789-14-14-01234567890123456789
Summary
- Drop the
chat_sessions.v2_workspace_id→v2_workspacesFK (migration 0064): since workspaces went local-first (#5731) they have no cloud mirror row, sochat.createSessionfailed its insert for every newly created workspace and chat was unusable there. - Stop the chat pane's error loop: the 4fps
getSnapshotpoll retried runtime creation (including macOS keychain reads) four times a second while flipping between the loading spinner and the error banner — it now holds a steady error state and backs off to 5s until it recovers. - Replace the raw "No model provider credentials available" error with a neutral setup callout and an Open Model Settings button.
Why / Context
Reported symptom: sending a chat message in a v2 workspace surfaced Failed query: insert into "chat_sessions" … and the pane kept "reloading". Root causes were the stale cloud FK (the referenced v2_workspaces row is never created anymore) and the snapshot poll treating every failed background retry as a fresh load.
How It Works
v2WorkspaceIdstays on the cloudchat_sessionsrow as a plain uuid — it still scopes the Electric-synced session list per workspace; it just no longer requires a cloud workspace row. LosingonDelete: set nullonly leaves orphaned session rows that the UI already never shows (the selector filters by live workspace id).useWorkspaceChatDisplay:isConversationLoadingusesisPendingonly, andrefetchIntervalreturns 5s while the query is errored (auto-recovers to 4fps on success).ChatInputFooterrecognizes the missing-credentials error and renders the actionable banner; all other errors keep the existing destructive banner.
Manual QA Checklist (all done via CDP against the dev desktop, workspace 0830f756)
- Before fix: reproduced the exact failed insert in the chat pane; 0 rows landed in
chat_sessions - After applying 0064 to an isolated Neon branch: same interaction creates the session row with the local-only workspace id, no error
- Session round-trips through Electric into the session selector after a full renderer reload
- Errored snapshot poll: measured ~2
getSnapshotcalls per 5s window (was 4/s), steady banner, no spinner flicker - Setup banner renders for the credentials error; button navigates to
#/settings/models - Full chat turn with working credentials (dev sandbox host-service can't see keychain credentials; failure point is past the fixed code paths)
Testing
bun run typecheck(packages/db, packages/trpc, apps/desktop)bun run lintbun test apps/desktop/.../v2-workspace(117 pass)- Migration verified: constraint name in generated SQL matches
pg_constrainton a production-derived branch; applied cleanly viabun run db:migrate
Risks / Rollout
- Risk: low — FK drop is forward-only but non-destructive; no data rewritten.
- Rollout: apply migration with the normal API/DB deploy; fixes existing desktop builds without a release (per cloud-before-desktop ordering).
- Rollback: re-adding the FK would fail on rows referencing local-only workspaces; revert the renderer commit independently if needed.
Follow-ups
- Settings → Models can show Anthropic "Active" while the runtime rejects the same credential (expired OAuth failing refresh): presence check and
hasUsableRuntimeEnvdisagree. Separately, the credential resolver only probes legacy keychain services (claude-cli), not modern Claude Code's"Claude Code-credentials". - Chat local-first (host-service
chat_sessions) remains Phase B ofplans/remove-cloud-project-model.md.
Summary by cubic
Fixes chat in local-first workspaces by removing the stale chat_sessions.v2_workspace_id FK and stabilizing the chat pane’s error behavior. Adds a simple model setup callout with an “Open Model Settings” button and backs off polling on errors.
-
Bug Fixes
- Dropped
chat_sessions → v2_workspacesFK; keptv2_workspace_idas a plain uuid so session inserts work for local-only workspaces. - Backed off snapshot polling to 5s while errored and stopped flipping between spinner and error; loading now uses a stable pending state.
- Replaced the raw missing-credentials error with a neutral setup banner and quick access to model settings.
- Dropped
-
Migration
- Run migration
0064_drop_chat_sessions_v2_workspace_fkto drop the FK (forward-only, non-destructive).
- Run migration