## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The board UI keeps company data fresh through `LiveUpdatesProvider`, which listens on a WebSocket and invalidates queries for each event > - The provider closes the socket while the tab is hidden, and events are not replayed, so it invalidates every active query when the socket opens and when the tab returns > - Some of those queries have no live events at all: instance settings, plugin UI contributions, and the person's workspace and sidebar preferences > - Reconciling them adds requests to every tab return and to the first socket open, on a server that is already saturated > - This pull request excludes those reads from the reconcile and gives them a 5-minute stale time > - The benefit is four fewer requests on each tab return and on the first socket open, with no change to company data freshness ## Linked Issues or Issue Description **What existing behavior does this improve?** The burst of requests when a board UI tab regains focus, and the second wave right after page load. **Subsystem affected** Board UI live updates (`ui/src/context/LiveUpdatesProvider.tsx`) and query defaults (`ui/src/main.tsx`, new `ui/src/lib/live-reconcile.ts`). **Current behavior** On a local instance, returning to a hidden Mine tab sends 27 API requests. Those include `instance/settings/experimental`, `workspace-preferences/me`, `plugins/ui-contributions` and `sidebar-preferences/me`. Live events never touch these. The same four re-fire when the socket first opens after load. **Proposed behavior** The socket reconcile skips those four reads. Their stale time is 5 minutes, so a window-focus refetch runs at most every 5 minutes. Their own mutations still invalidate them at once. **Reason and benefit** Each tab return costs four fewer requests. On staging, about 25 requests re-fire together on focus, and every one delays the visible rows. ## What Changed - New `ui/src/lib/live-reconcile.ts`: `LIVE_EVENT_FREE_QUERY_KEYS` (instance settings, general and experimental settings, plugin UI contributions, workspace preferences, sidebar preferences), `isLiveReconciledQuery`, and `applyLiveEventFreeQueryDefaults`. - `LiveUpdatesProvider` passes `isLiveReconciledQuery` as the predicate on its invalidate-all paths: tab return, disconnected polling, socket open, `live.resync`, and the transcript recovery that runs after a resync. The first healthy open still also skips session and health. - `main.tsx` applies the 5-minute stale time to those keys with `setQueryDefaults`. No observer sets its own stale time for them. - Not changed, and why: - `auth/get-session` and `health` keep focus refetch and reconnect handling for sign-out and reconnect detection. - `cli-auth/me` (board access) keeps the reconcile because it detects revoked access. - The company list keeps the reconcile because live events invalidate it. - Company data (agents, chats, projects, approvals, labels, join requests, live runs and others) keeps the reconcile. The socket is closed while hidden, so the reconcile is how missed events arrive. Keeping the socket open while hidden is a larger change and is not in this pull request. - Tests: new `live-reconcile.test.ts` covers the scope and the stale-time defaults. The hidden-tab test in `LiveUpdatesProvider.hook.test.tsx` expects the predicate. ## Verification - `ui`: `npx vitest run src/lib/live-reconcile.test.ts src/context/LiveUpdatesProvider src/lib/query-client.test.ts src/lib/persisted-query-cache.test.ts` passes (283 tests). - `pnpm verify` asks for broader CI coverage because `main.tsx` is outside the resolved test graphs. Required CI provides it. - Manual, on a local instance with the Mine page: hide the tab for 45 s, then show it, and count `/api/` resource entries. `master` sends 27 requests and this branch sends 23. The four reads above are absent; every company read is still present. ## Risks - The reconcile was also how other tabs picked up changes to these reads. A change made in another tab or browser now reaches this tab on its next focus after 5 minutes, or on reload; before, it was the next focus after 30 s. This covers an administrator changing an instance or experimental setting or installing a plugin, and the same person changing their workspace or sidebar preferences in another tab (for example the coordinator or classic shell, or sidebar order). Changes made in the same tab still apply at once. - Low risk otherwise. Only the reconcile predicate and the stale time change. ## Model Used - Claude Opus 5.5 (`claude-opus-5-5`), Anthropic, via Claude Code with tool use (shell, file edits, browser). 1M-token context window. Extended thinking was off. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@paperclipai/ui
Published static assets for the Paperclip board UI.
What gets published
The npm package contains the production build under dist/. It does not ship the UI source tree or workspace-only dependencies.
Storybook
Storybook config, stories, and fixtures live under ui/storybook/.
pnpm --filter @paperclipai/ui storybook
pnpm --filter @paperclipai/ui build-storybook
Typical use
Install the package, then serve or copy the built files from node_modules/@paperclipai/ui/dist.
Editor dependency identity
Keep the root and workspace overrides for @codemirror/state,
@codemirror/view, and @lezer/common aligned. CodeMirror requires shared
extension identity, while Lezer parsers and syntax highlighters require shared
NodeProp IDs. Multiple Lezer copies can crash code-block highlighting with
tags is not iterable. src/lib/codemirror-single-instance.test.ts checks the
installed dependency graph and highlights sample code through the editor's real
language dependencies. GitHub Actions owns regeneration of pnpm-lock.yaml.