fix(chat): invalidate deployment queries after a chat mutation - #6223
Conversation
PATCH /api/chat/manage/[id] calls performFullDeploy when the workflow has drifted from its active deployment, so editing a chat can mint a new deployment version. useUpdateChat invalidated only chatStatus and chatDetail, leaving the deployment panel showing the previous version and a stale "needs redeployment" indicator until the staleTime expired. Both mutations now route through invalidateDeploymentQueries, the shared helper the rest of the deployment surface uses. That also picks up deployedState, which useCreateChat's hand-rolled list had omitted even though performChatDeploy replaces the deployed workflow state. Tests cover both mutations and were verified to fail against the previous invalidation.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryLow Risk Overview
Adds Reviewed by Cursor Bugbot for commit e2dc391. Configure here. |
Greptile SummaryThis PR routes chat creation and update cache reconciliation through the shared deployment invalidation helper, ensuring deployment information, versions, deployed state, and chat status are refreshed after either mutation.
Confidence Score: 5/5The PR appears safe to merge, with the intended deployment cache refresh covered by both integration-level hook tests and direct helper key-coverage tests. The shared helper preserves every deployment query previously invalidated by these mutations, adds the missing deployed-state and update-related deployment keys, and retains update-chat detail invalidation.
|
| Filename | Overview |
|---|---|
| apps/sim/hooks/queries/chats.ts | Both chat mutations now use the shared, independently tested deployment invalidation boundary without dropping their prior cache invalidations. |
| apps/sim/hooks/queries/chats.test.tsx | New hook tests verify that create and update mutations invoke deployment invalidation for the affected workflow. |
Reviews (1): Last reviewed commit: "fix(chat): invalidate deployment queries..." | Re-trigger Greptile
renderHookWithClient created a React root per test but never tore it down, so trees stayed mounted with live QueryClient observers until worker teardown and async notifications could cross test boundaries. Audited every test in the repo using createRoot: 51 of 53 already unmount. The two that did not were both mine — voice.test.tsx here and chats.test.tsx from #6223 — so both are fixed and the pattern is now uniform.
* refactor(voice): load STT availability through React Query useSpeechToText fetched `/api/settings/voice` inside an effect and stored the result in useState behind a hand-rolled mountedRef guard: no cache, no dedupe across mounts, and no AbortSignal, so the response was fetched and parsed even after unmount. Two simultaneously mounted consumers issued two requests. It also bypassed hooks/queries/**, which is where every other server read in the app lives — and it escaped `check:react-query`, whose audit only covers useQuery/useMutation call sites. The value is server env read at request time, so it cannot change within a session; the new hook uses an infinite staleTime and a caller-controlled `enabled` so clients without the audio APIs never issue the request. Hydration is unchanged: SSR renders unavailable, and the first client render still resolves unavailable because `data` is undefined until the fetch settles. No initialData, deliberately — adding it would break that. mountedRef stays; it is still load-bearing for the streaming lifecycle. * test(queries): unmount rendered roots between tests renderHookWithClient created a React root per test but never tore it down, so trees stayed mounted with live QueryClient observers until worker teardown and async notifications could cross test boundaries. Audited every test in the repo using createRoot: 51 of 53 already unmount. The two that did not were both mine — voice.test.tsx here and chats.test.tsx from #6223 — so both are fixed and the pattern is now uniform. * fix(voice): let a failed STT probe recover on a later mount The app QueryClient sets retryOnMount: false and retry: 1, and refetchOnWindowFocus only refetches stale queries — which an infinite staleTime never becomes. So one transient failure cached the error for the life of the client and hid the mic until a full page reload. The effect this replaced refetched on every run, so retryOnMount: true restores parity: no refetch after success, a retry per mount after failure. Test asserts recovery under the app's real query defaults and fails without the override.
Summary
PATCH /api/chat/manage/[id]callsperformFullDeploywhen the workflow has drifted from its active deployment (route.ts:183-190), so editing a chat can mint a new deployment version.useUpdateChatinvalidated onlychatStatusandchatDetail, sodeploymentKeys.info/versions/deployedStatewent stale. The deployment panel kept showing the previous version and a stale "needs redeployment" indicator until the 30s/5minstaleTimeexpired or the window refocused.invalidateDeploymentQueries, the shared helper the rest of the deployment surface uses (useUndeployWorkflowfollows the same pattern).deployedState, whichuseCreateChat's hand-rolled list omitted even thoughperformChatDeployreplaces the deployed workflow state — so the deployed-state diff viewer could show stale content after deploying a chat.Failure scenario
Edit a chat's welcome message while the workflow draft has drifted → the PATCH redeploys to v4 → the deployment panel still shows v3 as latest, with the redeploy prompt still visible.
Type of Change
Testing
New
hooks/queries/chats.test.tsxcovers both mutations, following themcp.test.tsxrender-hook pattern. Verified to fail against the previous invalidation (revertinguseUpdateChatturns the test red). 115 tests pass acrosshooks/queries; typecheck and lint clean.Not exercised in a live browser — the assertion is on which query keys get invalidated.
Checklist