Repository navigation
[codex] Add Cmd+Enter steer sends - #9
Merged
Merged
Conversation
SawyerHood
marked this pull request as ready for review
May 14, 2026 23:23
ymichael
added a commit
that referenced
this pull request
Oct 30, 2026
## Human comments ## What was wrong Several cache owners wrote a server reply or the thread-detail bootstrap straight into the React Query cache with `setQueryData` while a fetch of the same key could still be in flight. React Query writes fetch results without checking whether they're older than what's cached (query-core `query.ts`), so the older fetch landed last and put stale data back. Effects included: an environment or host status that stayed stale after opening a thread, a plugin settings form resetting its draft to the old value, a cancelled plugin install flipping back to running, new plugin update jobs dropping out of the list, an `idle` app update phase switching off the progress poll, and the AI service selection flickering back. These are items #2–#10 from the direct cache write audit (@thread:thr_fjr5x8dzaz). #1 (thread tabs) is fixed separately in #6611. ## What changed Two fixes, depending on whether the data has a version field: - **Environment and Host keep the newer copy by `updatedAt`** (#2, #3, #10). The bootstrap ingest (`thread-detail-cache-owner.ts`), the rename reply (`applyEnvironmentUpdateResult`), and the `useEnvironment`/`useHosts` fetches all compare `updatedAt`. The fetch-side check is what catches a fetch that started before the write and lands after it. To make it testable, those fetches now live in `environmentQueryOptions` and `hostsQueryOptions`. Host `status` comes from live daemon sessions and a disconnect doesn't change `updatedAt`, so on a tie the cached copy wins over the bootstrap. The bootstrap only fills an empty cache or replaces strictly older data. Rename replies and fetch results still win ties. - **`setQueryDataOverInFlightFetch`** (`cache-effect-utils.ts`) for data with no version (#4–#9): it writes the value, and if a fetch of the key is in flight it cancels that fetch (the cache keeps the written value) and refetches. With nothing in flight it's a plain write. Used by `applyPluginSettingsView`, `applyPluginInstallJob`, `applyPluginUpdateJob`, `hydrateAppUpdateStatus`, `hydrateSystemVersionCache` and `writeCachedAiServices`, so every caller gets the fix. Where the audit suggested an unconditional cancel-write-invalidate (#7) or a cancel before the write (#8, #9), this helper refetches only when a fetch was actually in flight. That avoids an extra request on every write. Forced version and app-update checks update the server's cache, so the trailing unforced refetch returns the forced result. No wire, CLI or plugin API changes. Not covered here: audit items #11 (plugin safe mode) and #12 (prompt history), both low risk. Also not covered: a lint rule restricting direct `setQueryData` calls to the helper, which would stop new call sites from bringing the race back. ## How you verified - New tests use real `QueryClient`/`QueryObserver` instances: start a fetch that resolves late with older data, do the write, let the fetch land, then check that the newer value survives (and, for the helper, that the trailing refetch runs). - `thread-detail-cache-owner.test.ts` (new): late environment and host-list fetches after a bootstrap, an older bootstrap over a newer cache, and the equal-`updatedAt` host status case. - `environment-workspace-cache-owner.test.ts`: a late environment fetch after a rename, and an older rename reply over a newer cache. - `in-flight-fetch-writes.test.ts` (new): one row per cache-owner write for #4–#9, plus helper tests for the no-fetch case (no extra request) and a fetch of an unobserved query. - With each source change reverted, every race test failed on the stale data and passed once the fix was restored. - `pnpm exec turbo run typecheck lint test --filter=@bb/app`: passed (647 files, 6515 tests; 0 lint errors, no new warnings). After rebasing onto `0472409243` I re-ran the three changed test files (21 tests passed). 🤖 Generated with [Claude Code](https://claude.com/claude-code) > AGENT GENERATED --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mode: "steer", preserving claim/delete handling and queue order.moderequired in the server contract so callers must explicitly choose"auto"or"steer".Validation
pnpm exec turbo run test --filter=@bb/server-contract -- contract.test.tsNODE_OPTIONS=--no-experimental-webstorage pnpm exec turbo run test --filter=@bb/app --forcepnpm exec turbo run test --filter=@bb/serverpnpm exec turbo run typecheck --filter=@bb/server-contract --filter=@bb/server --filter=@bb/app