Repository navigation
Conversation
…fetch Loading /threads/<id> for a project thread unmounts the whole layout during the canonical redirect. The sidebar footer's plugin-list observers go with it, and TanStack Query cancels the in-flight list fetch. Boot's fetchQuery had joined that fetch, so it rejected with CancelledError and left the app with no plugin frontends. Hiding the tab mid-boot cancels it the same way. fetchFrontendCandidates now fetches again when the shared fetch is cancelled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When boot failed before any plugin record existed, the load-failed flag stayed false, so the sidebar and composer showed "No ... plugin is enabled" with no way to recover short of a reload. A failed boot or runtime load now sets the flag, so those surfaces show their failed state with Retry, and a successful live reconcile recomputes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AppLayoutContent replaced its whole tree with a Navigate element while redirecting /threads/<id> to the thread's project route, so every such load unmounted and remounted the sidebar, panels and route content, and briefly rendered nothing. The Navigate now renders inside the layout. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Human comments
What was wrong
Loading
/threads/<id>redirects to/projects/<project>/threads/<id>.AppLayoutContenthandled that redirect by returning<Navigate>in place of the whole layout. That unmounted every layout child, including the sidebar footer's["plugin-list", true]query observers. When those were the last observers on an in-flight plugin list fetch, TanStack Query cancelled the fetch and reverted it, and because the query had no data yet, the revert rejected withCancelledError. If plugin frontend boot had already joined that shared fetch throughfetchQuery, it got theCancelledErrorand boot failed. Boot is memoized, so the failure was permanent, and the failure never set the plugin frontend load-failed flag. The sidebar and composer therefore showed "No navigation/thread list/composer plugin is enabled" with no Retry until a page reload. The browser lifecyclecancelQueriesthat runs when the tab is hidden can cancel the same shared fetch.What changed
apps/app/src/lib/plugin-frontend.ts:fetchFrontendCandidatesfetches the plugin list again whenfetchQueryrejects with a cancellation, so boot and live reconcile survive an observer unmount or a tab-hide cancel. Other errors, including the existing 401/403 handling, are unchanged.apps/app/src/lib/plugin-frontend.tsandplugin-frontend-lazy.ts: a failed boot, or a failed plugin runtime load, sets the load-failed flag. The sidebar and composer then show their existing "couldn't load" state with Retry instead of "No … plugin is enabled". The flag is recalculated from plugin load status after each boot and live reconcile, so Retry clears it once plugins load.apps/app/src/components/layout/AppLayout.tsx: the canonical thread redirect renders<Navigate>inside the layout instead of replacing it, so the redirect no longer unmounts and remounts the app shell.How you verified
plugin-frontend-reload.test.ts: a shared plugin list fetch is cancelled mid-flight, once by its last observer unmounting and once bycancelQueries.plugin-frontend-boot.test.ts: a failed boot reports load-failed, and a later reconcile clears it.AppLayout.test.tsx: the layout mounts once across the redirect, where it mounted twice before.pnpm exec turbo run typecheck lint --filter=@bb/apppasses.vitest run src/lib/plugin-frontend src/components/layoutpasses (23 files, 195 tests).pnpm start:worktreeserver, loading/threads/<id>in headless Chrome with the plugin list response delayed 1.5s:plugin frontend boot failed: CancelledErrorand showed "No … plugin is enabled".🤖 Generated with Claude Code