Skip to content

[codex] Make Electric-backed UI cache-first - #4785

Merged
Kitenite merged 3 commits into
mainfrom
harsh-watchmaker
May 20, 2026
Merged

Kitenite merged 3 commits into
mainfrom
harsh-watchmaker

Conversation

@Kitenite

@Kitenite Kitenite commented May 20, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Render cached Electric/TanStack DB rows before collection readiness flags on v2 workspace, automations, and settings surfaces.
  • Use isReady only to decide loading vs empty/not-found when no row exists yet.
  • Remove the resource monitor metadata readiness gate so metrics can render with fallback names and cached metadata enrichment.

Why

During an Electric outage or slow shape hydration, useLiveQuery can still expose persisted rows while isReady is false. UI code that blanked or skeletoned on readiness alone could hide valid cached data, which matched the blank workspace/settings reports during the 1.9.9 upgrade window.

Validation

  • bun test apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/resourceConsumptionPolicy.test.ts
  • bun run --cwd apps/desktop typecheck
  • bun run lint
  • git diff --check

Open in Stage

Summary by cubic

Make the Electric-backed UI cache-first so cached rows render immediately instead of blank states when isReady is false, and remove metadata gating from the Resource Monitor. Document the cache-first useLiveQuery policy in AGENTS.md.

  • Bug Fixes
    • Render cached rows before readiness across v2 workspace layout, automations (list/detail), and settings (account, API keys, members/invitations, teams, hosts, projects, organization, v2 project). Show loading only when not ready and no cached rows; show empty/not-found only after readiness.
    • Resource Monitor: drop v2 metadata readiness gate; start polling only when the popover opens; keep label enrichment from cached project/workspace data; update policy and tests.
    • useCurrentPlan: treat subscriptions as loaded when cached and return isReady accordingly.
    • Host/workspace readiness: useWorkspaceHostUrl, useRemoteHostStatus, and v2 workspace layout now gate on “not ready AND no row,” preventing blank UIs.
    • Refined empty-state gating on projects/hosts and automations pages to avoid premature “No items” messages.

Written for commit 6154036. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed loading state display across multiple pages, including automations, account settings, API keys, hosts, members, organization, projects, and teams.
    • Improved "not found" messaging when requested data is unavailable.
    • Resolved UI timing issues during initial data synchronization to prevent premature empty-state display.
    • Enhanced loading skeletons to display correctly while data is being fetched.
  • Documentation

    • Added guidelines for proper data-loading patterns with real-time database queries.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: fa293159-b224-419a-976f-463584b8027f

📥 Commits

Reviewing files that changed from the base of the PR and between e14a38e and 6154036.

📒 Files selected for processing (6)
  • AGENTS.md
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/hosts/$hostId/components/HostSettings/HostSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/organization/components/OrganizationSettings/OrganizationSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx

📝 Walkthrough

Walkthrough

This PR systematically refactors loading guards across hooks and settings pages to use LiveQuery isReady together with data-presence checks, preventing premature empty/not-found UI when cached rows exist. It also removes metadata-readiness short-circuits and simplifies polling logic.

Changes

Live Query Readiness and Loading State Refactoring

Layer / File(s) Summary
Core hook readiness logic
apps/desktop/src/renderer/hooks/host-service/useWorkspaceHostUrl/useWorkspaceHostUrl.ts, apps/desktop/src/renderer/hooks/useCurrentPlan.ts, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
Hooks now allow execution when data rows exist even if isReady is false. useCurrentPlan derives subscriptionsLoaded from readiness OR non-empty subscriptions; useWorkspaceHostUrl and useRemoteHostStatus gate loading only when no data is cached.
Resource consumption polling and metadata gates
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/ResourceConsumption.tsx, resourceConsumptionPolicy.ts, resourceConsumptionPolicy.test.ts
Removes v2 metadata-ready short-circuits; simplifies shouldQueryResourceMonitor to depend only on enabled and open (removes metadataReady input); updates dependency lists and tests to reflect cache-first rendering without metadata gates.
Dashboard automation pages
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/page.tsx, automations/page.tsx, apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx
Automation detail/list pages and v2-workspace layout use isReady + data-presence to delay not-found/empty UI; detail pages return null while loading, then show "not found" only when ready; list page refactors loading state flags.
Basic settings: account, API keys, hosts
apps/desktop/src/renderer/routes/_authenticated/settings/account/components/AccountSettings/AccountSettings.tsx, settings/api-keys/components/ApiKeysSettings/ApiKeysSettings.tsx, settings/hosts/$hostId/components/HostSettings/HostSettings.tsx, settings/hosts/page.tsx
Switch to isReady + data-length checks for skeleton vs empty-state gating; normalize nullable lists to arrays; defer empty/not-found UI until queries complete.
Settings: members, invitations, organization
apps/desktop/src/renderer/routes/_authenticated/settings/members/components/MembersSettings/MembersSettings.tsx, settings/members/components/PendingInvitations/PendingInvitations.tsx, settings/organization/components/OrganizationSettings/OrganizationSettings.tsx
Members, invitations, and organization settings use isReady and data-presence to choose between skeletons, empty states, and not-found UI; organization now shows explicit "not found" message once queries sync instead of returning null immediately.
Settings: teams, team-detail, projects, v2-project
apps/desktop/src/renderer/routes/_authenticated/settings/teams/components/TeamsSettings/TeamsSettings.tsx, settings/teams/$teamId/components/TeamDetailSettings/TeamDetailSettings.tsx, settings/projects/page.tsx, settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx
Derive combined readiness from multiple query states; gate empty/not-found rendering on isReady and data-presence; show "Project/Team not found" messages only after queries sync.
Documentation: LiveQuery cache-first guideline
AGENTS.md
Added guideline for TanStack DB/Electric useLiveQuery: render persisted data immediately and use isReady only to determine UI when no data exists; write/seeding side effects are exempted from the cache-first rule.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 The query bounds, the data flows,
When cache has rows, the UI shows;
No more "not found" too early shown—
Let readiness bring truth when known!
Each hook and page now waits its turn,
Then shows the state it learns.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.76% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: making Electric-backed UI cache-first by rendering cached data before readiness flags.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, rationale, and validation steps. It exceeds the template requirements with detailed context about the Electric outage scenario.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch harsh-watchmaker

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@capy-ai

capy-ai Bot commented May 20, 2026

Copy link
Copy Markdown

Capy auto-review is paused for this organization because the monthly auto-review limit has been reached. Increase the limit or turn it off in billing settings to resume automatic reviews.

@ghost

ghost commented May 20, 2026 •

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 5 individual chapters for you:

Title
1 Document cache-first policy for live queries
2 Update core hooks for cache-first behavior
3 Refine workspace and automation loading states
4 Apply cache-first rendering to settings pages
5 Remove metadata readiness gate from Resource Monitor
Open in Stage

Chapters generated by Stage for commit 6154036 on May 20, 2026 9:05pm UTC.

@coderabbitai coderabbitai 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/page.tsx (1)

84-86: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the “Automation not found.” text selectable.

The error state at Line 84 renders plain text but misses the required select-text cursor-text classes.

Suggested fix
-		<div className="flex h-full w-full items-center justify-center text-sm text-muted-foreground">
+		<div className="flex h-full w-full items-center justify-center text-sm text-muted-foreground select-text cursor-text">
 			Automation not found.
 		</div>

As per coding guidelines apps/desktop/**/*.{tsx,jsx}: Error text must be selectable by users with explicit select-text cursor-text classes; renderer sets user-select: none on body.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/`$automationId/page.tsx
around lines 84 - 86, The error message div rendering "Automation not found." is
not selectable because it lacks the required select-text and cursor-text
classes; update the JSX element whose className currently is "flex h-full w-full
items-center justify-center text-sm text-muted-foreground" (the div that
displays the error) to include "select-text cursor-text" so users can copy the
message.
apps/desktop/src/renderer/routes/_authenticated/settings/hosts/$hostId/components/HostSettings/HostSettings.tsx (1)

123-129: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the not-found message selectable.

Line 126 renders an error/not-found message without select-text cursor-text, so users can’t reliably select/copy it in the renderer.

Suggested fix
-		return (
-			<div className="p-6 text-sm text-muted-foreground">
+		return (
+			<div className="p-6 text-sm text-muted-foreground select-text cursor-text">
 				Host not found in this organization.
 			</div>
 		);

As per coding guidelines, "Error text must be selectable by users with explicit select-text cursor-text classes; renderer sets user-select: none on body".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/hosts/`$hostId/components/HostSettings/HostSettings.tsx
around lines 123 - 129, The "Host not found in this organization." message is
rendered when host is falsy (check in HostSettings component where it tests if
(!host) { if (!hostReady) return null; return (<div...>Host not found...</div>);
}) but lacks selectable styling; update that div to include the explicit classes
"select-text cursor-text" so the message becomes selectable and copyable in the
renderer while preserving existing padding and text classes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx`:
- Around line 218-219: The Mine empty-state is shown prematurely because
showMineEmptyState uses visible.length === 0 && scope === "mine" without
checking automationsReady; update the logic (wherever showMineEmptyState is
defined and the analogous checks around lines 336-340) to additionally require
automationsReady (or equivalently !showAutomationLoading) so the Mine
empty-state only renders when scope === "mine", visible.length === 0, and
automationsReady is true; adjust the variable showMineEmptyState and any
duplicated empty-state guards accordingly.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/organization/components/OrganizationSettings/OrganizationSettings.tsx`:
- Around line 242-248: The "Organization not found." message in
OrganizationSettings.tsx is not selectable due to global renderer styles; update
the JSX returned in the !organization branch by adding the CSS classes
"select-text cursor-text" to the <p> element that renders "Organization not
found." (locate the conditional branch in the OrganizationSettings component
where it returns the div/p when !organization and add those classes to the <p>).

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx:
- Around line 116-119: The error-state div inside the V2ProjectSettings
component rendering "Project not found." is missing the selectable classes;
update that JSX element (the div that returns "Project not found." in
V2ProjectSettings) to include the classes select-text and cursor-text so the
error text is selectable despite the renderer's global user-select: none.

---

Outside diff comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/`$automationId/page.tsx:
- Around line 84-86: The error message div rendering "Automation not found." is
not selectable because it lacks the required select-text and cursor-text
classes; update the JSX element whose className currently is "flex h-full w-full
items-center justify-center text-sm text-muted-foreground" (the div that
displays the error) to include "select-text cursor-text" so users can copy the
message.

In
`@apps/desktop/src/renderer/routes/_authenticated/settings/hosts/`$hostId/components/HostSettings/HostSettings.tsx:
- Around line 123-129: The "Host not found in this organization." message is
rendered when host is falsy (check in HostSettings component where it tests if
(!host) { if (!hostReady) return null; return (<div...>Host not found...</div>);
}) but lacks selectable styling; update that div to include the explicit classes
"select-text cursor-text" so the message becomes selectable and copyable in the
renderer while preserving existing padding and text classes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f48a2030-0172-4c5e-8579-40f6227ccecd

📥 Commits

Reviewing files that changed from the base of the PR and between e344f27 and 2f32c9d.

📒 Files selected for processing (21)
  • apps/desktop/src/renderer/hooks/host-service/useWorkspaceHostUrl/useWorkspaceHostUrl.ts
  • apps/desktop/src/renderer/hooks/useCurrentPlan.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/$automationId/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/ResourceConsumption.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/resourceConsumptionPolicy.test.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/resourceConsumptionPolicy.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/hooks/useRemoteHostStatus/useRemoteHostStatus.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx
  • apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useDefaultV2TerminalPresets/useDefaultV2TerminalPresets.ts
  • apps/desktop/src/renderer/routes/_authenticated/settings/account/components/AccountSettings/AccountSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/api-keys/components/ApiKeysSettings/ApiKeysSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/hosts/$hostId/components/HostSettings/HostSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/hosts/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/members/components/MembersSettings/MembersSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/members/components/PendingInvitations/PendingInvitations.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/organization/components/OrganizationSettings/OrganizationSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/projects/page.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/teams/$teamId/components/TeamDetailSettings/TeamDetailSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/teams/components/TeamsSettings/TeamsSettings.tsx
  • apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx

@greptile-apps

greptile-apps Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates 21 Electric/TanStack DB-backed UI surfaces from a "block on isReady" pattern to a cache-first pattern, where persisted rows are rendered immediately and isReady is used only to disambiguate between "still loading" and "genuinely empty/not-found" when no cached row exists yet.

  • Workspace, automation, and settings surfaces replace isLoading/!isReady skeleton gates with !isReady && data.length === 0, surfacing cached rows instantly during Electric outages or slow shape hydration.
  • useCurrentPlan returns the resolved plan tier from cached subscription rows without waiting for Electric readiness, eliminating plan-tier flash for paid users.
  • ResourceConsumption drops the v2MetadataReady gate so metrics start polling as soon as the popover opens, rendering workspace/project names from whatever metadata is already in cache.

Confidence Score: 4/5

Safe to merge — the pattern change is consistent across all 21 files and the test suite validates the policy changes. One edge case in terminal preset initialization warrants a follow-up.

The vast majority of changes correctly apply the cache-first pattern: skeleton/null gates now check both readiness and cache emptiness, 'not found' states are properly deferred until Electric confirms readiness, and the resolveCurrentPlan path is correctly updated. The one concern is useDefaultV2TerminalPresets, where switching from presetsReady to presetsUsable = presetsReady || v2Presets.length > 0 lets the initialization effect fire while Electric is mid-sync. If the cached preset list is a partial snapshot, createDefaultV2TerminalPresetRows fills in 'missing' defaults with fresh UUIDs, and once terminalPresetsInitialized is written as true, the full server-side rows that arrive later stack on top as duplicates with no cleanup path.

apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useDefaultV2TerminalPresets/useDefaultV2TerminalPresets.ts deserves a second look around the presetsUsable guard change.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useDefaultV2TerminalPresets/useDefaultV2TerminalPresets.ts Switches from strict readiness gate to cache-first; risks premature initialization with partial preset snapshots creating duplicate entries.
apps/desktop/src/renderer/hooks/useCurrentPlan.ts Returns isReady: true when cached subscription rows exist; resolves plan tier from cache, eliminating skeleton flash for paid users.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/layout.tsx Guard updated to show blank only when workspace is absent from cache AND Electric isn't ready; correctly delegates to WorkspaceNotFoundState when ready.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/TopBar/components/ResourceConsumption/ResourceConsumption.tsx Removes v2MetadataReady gate entirely; metrics now render immediately with whatever project/workspace names are in cache, falling back to empty strings.
apps/desktop/src/renderer/routes/_authenticated/_dashboard/automations/page.tsx showAutomationLoading now requires both !automationsReady AND empty cache; cached rows render eagerly with correct scope-based empty states.
apps/desktop/src/renderer/routes/_authenticated/settings/organization/components/OrganizationSettings/OrganizationSettings.tsx Splits old combined loading/not-found early return into two distinct states; adds an explicit 'Organization not found' message when isReady is true but no org row exists.
apps/desktop/src/renderer/routes/_authenticated/settings/api-keys/components/ApiKeysSettings/ApiKeysSettings.tsx Replaces isLoading with !isReady && apiKeys.length === 0 skeleton gate; also simplifies empty-state check by switching to apiKeys = apiKeysData ?? [].

Sequence Diagram

sequenceDiagram
    participant UI as UI Component
    participant LQ as useLiveQuery
    participant Cache as Local Cache
    participant Electric as Electric Sync

    Note over UI,Electric: Old behavior (isReady-first)
    UI->>LQ: subscribe
    LQ->>Cache: query rows
    Cache-->>LQ: [] (empty, not ready)
    LQ-->>UI: "isReady=false, data=[]"
    UI-->>UI: render skeleton / null
    Electric-->>LQ: sync complete
    LQ-->>UI: "isReady=true, data=[rows]"
    UI-->>UI: render content

    Note over UI,Electric: New behavior (cache-first)
    UI->>LQ: subscribe
    LQ->>Cache: query rows
    Cache-->>LQ: [cachedRows] (partial, not ready)
    LQ-->>UI: "isReady=false, data=[cachedRows]"
    UI-->>UI: render cached content immediately
    Electric-->>LQ: sync complete
    LQ-->>UI: "isReady=true, data=[fullRows]"
    UI-->>UI: update with complete data
Loading
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useDefaultV2TerminalPresets/useDefaultV2TerminalPresets.ts:30-41
**Early preset initialization with partial Electric snapshot may create duplicates**

`presetsUsable` becomes `true` as soon as any preset rows appear in the local cache, even while Electric is mid-sync. If `createDefaultV2TerminalPresetRows` sees an incomplete `existingPresets` list and creates "missing" defaults (each with a fresh `crypto.randomUUID()`), it then writes `terminalPresetsInitialized = true`. When Electric finishes syncing, the server's copy of those same defaults also lands in the collection — both sets now coexist under different IDs. Because `terminalPresetsInitialized` is already `true`, the guard on line 39 prevents any cleanup run, leaving the user with duplicate default terminal presets that persist across sessions.

Reviews (1): Last reviewed commit: "Make Electric-backed UI cache-first" | Re-trigger Greptile

Comment on lines 30 to 41
const presetsUsable = presetsReady || v2Presets.length > 0;
const preferencesUsable = preferencesReady || preferenceRows.length > 0;

useEffect(() => {
if (
!hostUrl ||
!agentsFetched ||
!presetsReady ||
!preferencesReady ||
!presetsUsable ||
!preferencesUsable ||
preferences.terminalPresetsInitialized
) {
return;

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.

P2 Early preset initialization with partial Electric snapshot may create duplicates

presetsUsable becomes true as soon as any preset rows appear in the local cache, even while Electric is mid-sync. If createDefaultV2TerminalPresetRows sees an incomplete existingPresets list and creates "missing" defaults (each with a fresh crypto.randomUUID()), it then writes terminalPresetsInitialized = true. When Electric finishes syncing, the server's copy of those same defaults also lands in the collection — both sets now coexist under different IDs. Because terminalPresetsInitialized is already true, the guard on line 39 prevents any cleanup run, leaving the user with duplicate default terminal presets that persist across sessions.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/components/AgentHooks/hooks/useDefaultV2TerminalPresets/useDefaultV2TerminalPresets.ts
Line: 30-41

Comment:
**Early preset initialization with partial Electric snapshot may create duplicates**

`presetsUsable` becomes `true` as soon as any preset rows appear in the local cache, even while Electric is mid-sync. If `createDefaultV2TerminalPresetRows` sees an incomplete `existingPresets` list and creates "missing" defaults (each with a fresh `crypto.randomUUID()`), it then writes `terminalPresetsInitialized = true`. When Electric finishes syncing, the server's copy of those same defaults also lands in the collection — both sets now coexist under different IDs. Because `terminalPresetsInitialized` is already `true`, the guard on line 39 prevents any cleanup run, leaving the user with duplicate default terminal presets that persist across sessions.

How can I resolve this? If you propose a fix, please make it concise.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 21 files

Re-trigger cubic

@github-actions

github-actions Bot commented May 20, 2026 •

Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ✅ Neon database branch

Thank you for your contribution! 🎉

@Kitenite
Kitenite merged commit 2a368bf into main May 20, 2026
17 checks passed
@Kitenite
Kitenite deleted the harsh-watchmaker branch May 20, 2026 21:15
MocA-Love added a commit to MocA-Love/superset that referenced this pull request May 25, 2026

This branch was previously deployed

1 inactive deployment
preview — 61540361 Deployed May 20, 2026 by Kitenite via Deploy Docs #5616
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.

1 participant