Skip to content

Deduplicate cold-load network requests - #2672

Open
ymichael wants to merge 3 commits into
mainfrom
bb/profile-network-with-dev-browser-thr_2fun4nxmap
Open

Deduplicate cold-load network requests#2672
ymichael wants to merge 3 commits into
mainfrom
bb/profile-network-with-dev-browser-thr_2fun4nxmap

Conversation

@ymichael

Copy link
Copy Markdown
Collaborator

Human comments

What was wrong

Cold app loads had multiple owners for the same system-config and plugin-list resources, while pending-interaction query options accidentally overwrote the shared QueryClient freshness default with undefined. The plugin frontend loader also interpreted a failed shared query as an authoritative empty installation set, and overlapping initial-connection atom refreshes repeated local daemon discovery.

What changed

The app now has one shared QueryClient for React and non-React owners, with stable shared query options for system config and the installed-plugin list. Plugin frontend reconciliation reuses that query and preserves active frontends when inventory loading fails. Pending interactions inherit the app freshness default unless callers provide an override, while stale remounts still revalidate. The redundant local-daemon connection refresh was removed, cache writers use the raw installed-plugin array shape, and narrow regressions cover each ownership and failure boundary.

There are no wire, daemon protocol, CLI, guide, or public Plugin SDK changes.

Review requested from @slopcop.

How you verified

The regressions failed before the fixes and pass afterward. Browser verification used the copied production repro database and confirmed one cold request each for system config, plugins, thread include, interactions, daemon status, and workspace targets. Hosts and sidebar retain their intentional initial-connect race-closing revalidation.

  • pnpm exec turbo run test --filter=@bb/app --force: 443 files passed; 3,510 tests passed and 3 skipped
  • pnpm exec turbo run typecheck --filter=@bb/app --force: passed
  • pnpm exec turbo run build --filter=@bb/app --force: passed
  • pnpm exec turbo run lint --filter=@bb/app --force: 0 errors
  • Touched-file oxfmt --check and git diff --check: passed

Fixes: none

AGENT GENERATED

ymichael and others added 3 commits August 28, 2026 14:26
## What was wrong

PR #2616 removed the `host.list_branches` command from the host daemon
contract and its dispatch table, but one call to it stayed behind in
`host-branches-dispatch.test.ts`. `main` is red: `tsc` reports TS2820 for the
unknown command type, and the test itself throws
`onlineRpcHandlers[command.type] is not a function`.

## What changed

- `apps/host-daemon/test/command/host-branches-dispatch.test.ts` dispatches
  `host.inspect_git_source` with `remoteRefresh: "blocking"`, like the other
  tests in the same describe block. A blocking refresh keeps the promise
  pending until the fetch ends, which is what this test waits for.

## How you verified

- `pnpm exec turbo run typecheck test --filter=@bb/host-daemon` passes, 45
  test files. The repaired test runs instead of throwing.

> AGENT GENERATED

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@bb-slop-cop bb-slop-cop Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 SLOP COP 🚨 · review

I am reviewing this pull request now. I will check security, code quality, architecture, performance, and the main user path.

const options = systemConfigQueryOptions();
const config = await appQueryClient.fetchQuery({
...options,
staleTime: refresh ? 0 : options.staleTime,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 slopcop/review — One config event can start two requests.

The atom starts this fetch when its WebSocket listener updates the refresh tick.

The realtime cache owner handles the same event and invalidates this query.

If the atom listener runs first, the invalidation cancels this request and starts another request.

My QueryClient reproduction recorded three calls and one abort. The initial load used one call. One refresh used two calls.

Please use one refresh owner, or prevent the later invalidation from canceling an active request.

Add a test with both consumers active. Test both listener orders. Expect one request after config-changed.

queryClient: QueryClient = appQueryClient,
): Promise<PluginFrontendCandidate[]> {
const plugins = await queryClient.fetchQuery(
pluginListQueryOptions({ enabled: true }),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 slopcop/review — A restored page can use an old plugin list.

The persisted pageshow path calls this function without cache invalidation.

This query stays fresh for 30 seconds. A short page freeze can hide plugin installation, removal, or state changes.

Please force a fresh inventory request after a persisted pageshow event.

Add a test with recent cached data and changed server data. The restore must request and apply the new list.

@bb-slop-cop bb-slop-cop Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 SLOP COP 🚨 · review

This PR gives early app startup and React one shared QueryClient.

It joins matching system config and plugin inventory requests. It also fixes the pending-interaction freshness policy.

I found two event paths that still need work.

  1. A config-changed event can start two config requests. The second refresh cancels the first request.
  2. A persisted page restore can reuse the plugin inventory for 30 seconds. The page can miss plugin changes during the freeze.

I found no confirmed security defect. The product has no supported same-page server or user transition.

The focused app suite passed all 88 tests. All GitHub CI checks passed.

I could not complete browser QA. The checkout-specific dev server stayed in the plugin SDK type build for 20 minutes.

Please add one test for each event sequence. The inline comments give the exact cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants