Skip to content

perf(webclient,relay): fast first paint, resilient boot, relay liveness#864

Merged
arul28 merged 5 commits into
mainfrom
ade/codex-auth-login-button-fd3c9bbe
Jul 20, 2026
Merged

perf(webclient,relay): fast first paint, resilient boot, relay liveness#864
arul28 merged 5 commits into
mainfrom
ade/codex-auth-login-button-fd3c9bbe

Conversation

@arul28

@arul28 arul28 commented Jul 20, 2026

Copy link
Copy Markdown
Owner

ADE   Open in ADE  ·  ade/codex-auth-login-button-fd3c9bbe branch  ·  PR #864

Summary by CodeRabbit

  • New Features

    • Improved connection reliability with native WebSocket liveness checks, clearer reconnect behavior, and more informative connection errors.
    • Added safer tunnel handling for unavailable hosts, bridge validation failures, and oversized buffered data.
    • Added loading, sign-in, retry, and storage-unavailable states to the web client.
    • Improved saved-environment cleanup and privacy handling.
    • Added a loading splash screen and stronger caching and security settings.
  • Improvements

    • Machine directory results are limited to the 500 most recently seen machines.
    • Directory responses now expose authentication and database timing information.
    • Account machine publishing responds more consistently to relay status and endpoint changes.
    • Web client builds now validate entry files and size limits.

Greptile Summary

This PR improves web client startup and sync reliability across the account directory, relay, CLI host, browser client, and iOS client. The main changes are:

  • Faster web client first paint with a splash screen, lazy app loading, and entry-size validation.
  • Account directory list responses now expose timing information and cap results to the 500 most recent machines.
  • CLI host publishing now reacts faster to relay readiness and endpoint changes.
  • Relay and tunnel clients now use native liveness checks, bounded buffering, bridge validation, and clearer close codes.
  • Browser sync adds storage-unavailable states, account-owned environment cleanup, stale connection handling, and retry flows.
  • iOS sync recovery policy now centralizes reconnect, heartbeat silence, and close-code handling.

Confidence Score: 5/5

Safe to merge with low risk.

The changed paths include targeted coverage for directory listing, relay behavior, CLI publishing, browser sync/storage flows, and iOS recovery policy. The reviewed code keeps account/session gating, bounded buffering, sanitized close propagation, and retry/backoff handling explicit.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • The initial ADE splash is rendered immediately after DOMContentLoaded on the real webclient route.
  • On the same route, the ADE splash remains visible after some time while browser console resource requests report localhost connection refusals, indicating local network blocks in the sandbox.
  • The network log anchors the capture to the real Vite-served repository code rather than a mocked page.
  • A boot video and its poster frame were prepared to document the webclient boot sequence.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
apps/ade-cli/src/services/sync/syncTunnelClientService.ts Adds native control ping/pong, stricter bridge validation, bounded buffering, account eligibility gating, and relay reject handling.
apps/tunnel-relay/src/tunnelDo.ts Adds relay-side reject handling, bounded pre-pipe buffering, sanitized close propagation, and liveness-compatible control handling.
apps/desktop/src/renderer/webclient/sync/connection.ts Adds transport/auth timeouts, inbound stale detection, visibility reconnect handling, and relay close-code mapping.
apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx Improves boot flow, storage privacy pruning, account machine pairing states, retry flows, and app lazy loading.
apps/account-directory/src/directory.ts Adds Server-Timing for list responses and caps directory listings to the 500 most recently seen machines.
apps/ios/ADE/Services/SyncRecoveryPolicy.swift Adds reusable recovery policy helpers for transport probes, heartbeat silence, reconnects, and close-code messages.
apps/desktop/vite.webclient.config.ts Adds webclient-specific dev entry routing and Cloudflare Pages output handling.
apps/desktop/scripts/check-webclient-entry.mjs Introduces build-time validation for the generated web client entry graph and heavy chunk references.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
  participant Browser as Web Client
  participant Directory as Account Directory
  participant Host as ADE CLI Host
  participant Relay as Tunnel Relay
  participant Local as Local Sync Listener

  Browser->>Directory: GET account machines
  Directory-->>Browser: recent machines with Server-Timing
  Host->>Directory: publish machine endpoints
  Host->>Relay: claim machine and open control socket
  Relay-->>Host: open request with connection id
  Host->>Local: validate loopback listener
  alt bridge valid
    Host->>Relay: open signed pipe socket
    Relay-->>Browser: pair client socket with host pipe
    Browser->>Local: sync request frames via relay
    Local-->>Browser: sync response frames via relay
  else bridge invalid or host unavailable
    Host-->>Relay: reject connection id and close code
    Relay-->>Browser: close client with application code
  end
  Host->>Relay: native WebSocket ping
  Relay-->>Host: native pong
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
  participant Browser as Web Client
  participant Directory as Account Directory
  participant Host as ADE CLI Host
  participant Relay as Tunnel Relay
  participant Local as Local Sync Listener

  Browser->>Directory: GET account machines
  Directory-->>Browser: recent machines with Server-Timing
  Host->>Directory: publish machine endpoints
  Host->>Relay: claim machine and open control socket
  Relay-->>Host: open request with connection id
  Host->>Local: validate loopback listener
  alt bridge valid
    Host->>Relay: open signed pipe socket
    Relay-->>Browser: pair client socket with host pipe
    Browser->>Local: sync request frames via relay
    Local-->>Browser: sync response frames via relay
  else bridge invalid or host unavailable
    Host-->>Relay: reject connection id and close code
    Relay-->>Browser: close client with application code
  end
  Host->>Relay: native WebSocket ping
  Relay-->>Host: native pong
Loading

Reviews (3): Last reviewed commit: "fix(review): SPA-wide no-cache headers; ..." | Re-trigger Greptile

arul28 and others added 3 commits July 20, 2026 03:29
Web client (app.ade-app.dev):
- Fix rolldown chunk graph: entry no longer statically depends on the 4.2MB
  Monaco chunk or vendor-graph (which had absorbed react/react-dom); login
  screen entry graph drops from ~4.7MB raw JS + 646KB CSS to ~252KB, enforced
  by a new post-build assertion + size budget (check-webclient-entry.mjs).
- _headers: immutable caching for hashed /assets/*, no-cache HTML, and fold in
  the production CSP drift (Clerk avatar img-src hosts).
- webclient.html: inline CSS splash (no blank page while JS loads) and
  preconnects to the Clerk issuer + account-directory origins.
- Boot: sign-in button and machine directory render immediately; IndexedDB
  maintenance (account pruning, trust reset) no longer gates them, is batched
  into single transactions, handles onblocked with a bounded timeout and a
  retry affordance. Account-owned saved environments still never render
  before pruning completes.
- Connection: inbound-silence watchdog (75s) + visibility-resume staleness
  check; transport-open (8s) and hello (12s) deadlines replace the too-tight
  4s combined timeout; DPoP/account-token prep overlaps socket dialing;
  relay close codes map to accurate user-facing errors; pending commands
  reject immediately on transport loss instead of waiting 65s.

Relay (tunnel-relay DO + brain client):
- Brain control socket gains native WS ping/pong liveness (30s/10s) — protocol
  frames are edge-handled so a hibernated DO is not woken or billed; half-open
  sockets after sleep/NAT rebind now recover in seconds instead of minutes.
- Single reconnect state machine: the 1s account poll no longer bypasses
  jittered backoff (ends claim-POST storms).
- New {t:"reject"} control signaling: failed bridge validation/pipe/local
  dials close the waiting client immediately (4507) instead of pinning a
  tunnel slot until timeout; control.send failures close the client with 4501.
- Close codes and bounded reasons now survive both the DO pairing boundary
  and the brain pipe<->local bridge (was: always 4000).
- Idle sweep alarm only runs while data sockets exist (stops ~8.6k needless
  DO wakes/month per idle machine); early-frame buffer gains a 256KiB byte cap.
- Cached loopback bridge validation (<30s) moves off the tunnel-open critical
  path with concurrent revalidation.

Directory:
- Worker bounds machine listing (ORDER BY last_seen_at DESC LIMIT 500) and
  emits Server-Timing (auth/db) for measurable backend latency.
- Brain publisher publishes immediately (2s debounce) on relay-readiness
  transitions instead of waiting for the next 30s tick, so a Mac that just
  came online appears in the directory right away.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Blocker: remove the cached bridge-validation fast path — every relay
  tunnel open now serially revalidates the loopback listener before the
  authenticated local socket (with the private bridge-proof header) is
  constructed, closing a 30s window where a swapped listener could receive
  the bridge proof and buffered client hello. The probe is loopback (~ms),
  so the latency cost is negligible.
- Sign-out gates relay work synchronously (live isAccountSignedIn check,
  fail-closed) instead of waiting up to 1s for the lease poll.
- Superseded control sockets can no longer initiate tunnels (socket
  identity rechecked in the message handler and across openTunnel awaits).
- envStore: IndexedDB versionchange clears the cached handle and
  trust-reset promise so retry reopens instead of reusing a closed db.
- Entry checker requires >=1 local JS entry and rejects external scripts.
- Browser maps relay close 4507 (bridge rejected) to an accurate message.
- Prune result is an explicit {removedIds, environments} shape (removes
  the hidden-property array hack and casts).
- Host control parser narrowed to {t:"open"} (JSON ping/pong dead since
  native WS liveness); worker-side legacy ping support unchanged.
- OAuth-callback bootstrap poll slowed 16ms -> 150ms.

Gated for follow-up (documented, not applied): shared relay-protocol
constants module, connection lifecycle dedup, publisher scheduler
consolidation, manifest-based entry checker, large test-file splits.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- iOS: classify new relay close codes (4506 pre-pipe overflow, 4507 bridge
  rejected) in SyncService/SyncRecoveryPolicy so they retry like transport
  faults instead of falling through generic handling; 16 targeted tests.
- Docs: web-client, sync-and-multi-device, and ARCHITECTURE updated for the
  new boot sequence, caching headers, relay liveness/reject protocol, and
  event-driven directory publishing.
- CLI/TUI parity: reviewed, no drift (no new actions or shared types).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jul 20, 2026 4:29pm

@arul28

arul28 commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds directory timing instrumentation, relay-state publishing and tunnel protocol safeguards, transactional web-client storage, resilient sync connections, privacy-aware boot flows, build validation, and iOS socket close-error handling.

Changes

Directory timing instrumentation

Layer / File(s) Summary
List timing and validation
apps/account-directory/src/directory.ts, apps/account-directory/test/directory.test.ts
List responses now include auth and db timings, CORS exposes Server-Timing, and tests cover timing headers and the 500-machine limit.

Account machine relay publishing

Layer / File(s) Summary
Relay-state publishing and lifecycle
apps/ade-cli/src/services/account/accountMachinePublisherService.ts, apps/ade-cli/src/services/account/accountMachinePublisherService.test.ts
Relay readiness and endpoint signatures trigger coalesced publications on a dedicated polling interval, with signed-out and startup cases covered by tests.

Relay tunnel protocol

Layer / File(s) Summary
CLI control and tunnel lifecycle
apps/ade-cli/src/services/sync/syncTunnelClientService.ts, apps/ade-cli/src/services/sync/syncTunnelClientService.test.ts
Control messages now use native ping/pong liveness and structured rejection frames, while bridge validation, socket deadlines, teardown, and reconnect behavior are tightened.
Durable Object buffering and close propagation
apps/tunnel-relay/src/tunnelDo.ts, apps/tunnel-relay/test/relay.test.ts, apps/tunnel-relay/README.md
Relay sockets validate close metadata, handle reject messages, enforce frame and byte buffer limits, preserve close reasons, and avoid recurring alarms for control-only sockets.
iOS socket close recovery
apps/ios/ADE/Services/SyncRecoveryPolicy.swift, apps/ios/ADE/Services/SyncService.swift, apps/ios/ADETests/SyncRecoveryPolicyTests.swift
Socket close error construction is centralized and tested for relay and unknown application close codes.

Desktop web client

Layer / File(s) Summary
Transactional environment storage
apps/desktop/src/renderer/webclient/sync/envStore.ts, apps/desktop/src/renderer/webclient/sync/client.ts, apps/desktop/src/renderer/webclient/sync/*.test.ts
Storage operations become transactional, IndexedDB failures are typed and retryable, pruning returns surviving environments, and pending commands are rejected on connection close.
Sync connection deadlines and recovery
apps/desktop/src/renderer/webclient/sync/connection.ts, apps/desktop/src/renderer/webclient/sync/__tests__/sync.test.ts
Transport and authenticated-hello deadlines are separated, stale inbound connections are detected, visibility affects reconnect behavior, and authentication preparation begins before socket open.
Privacy-aware boot and picker states
apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx, apps/desktop/src/renderer/webclient/shell/MachinePicker.tsx, apps/desktop/src/renderer/webclient/shell/__tests__/WebClientRoot.test.tsx
Boot phases, directory loading, saved-environment privacy state, retries, and progress screens are coordinated through the web-client shell and covered by route-flow tests.
Web client build and entry validation
apps/desktop/package.json, apps/desktop/scripts/check-webclient-entry.mjs, apps/desktop/vite.webclient.config.ts, apps/desktop/src/renderer/webclient.html, apps/desktop/src/renderer/webclient/public/_headers
The build validates generated references and raw size, removes manual chunking, adds a loading entry screen, and updates security and caching headers.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • arul28/ADE#705: Overlaps on relay control-channel message parsing and ping/open behavior.
  • arul28/ADE#846: Overlaps on account-machine publishing and relay control reliability.

Suggested labels: desktop, ios, docs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.95% 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
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately summarizes the main webclient and relay performance/resilience changes.
✨ 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 ade/codex-auth-login-button-fd3c9bbe

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/webclient/public/_headers`:
- Around line 8-15: Update the _headers rules so the global /* block sets
Cache-Control: no-cache for all SPA fallback routes. Keep the /assets/* rule
after it with public, max-age=31536000, immutable so immutable assets override
the global directive, and remove the narrower / and /index.html rules.

In `@apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx`:
- Around line 448-455: Ensure the /account/callback bootstrap rejection path
clears accountProgressInterval before restoring the account state. Update the
async bootstrap flow and its catch handling so the interval is cleared whenever
bootstrap() rejects, while preserving the existing disposed guard and recovery
state updates in the catch block.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fa5edb57-cf3b-4858-91b6-13e78f0dcbae

📥 Commits

Reviewing files that changed from the base of the PR and between 1431720 and 22c169b.

⛔ Files ignored due to path filters (3)
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/README.md is excluded by !docs/**
  • docs/features/web-client/README.md is excluded by !docs/**
📒 Files selected for processing (25)
  • apps/account-directory/src/directory.ts
  • apps/account-directory/test/directory.test.ts
  • apps/ade-cli/src/services/account/accountMachinePublisherService.test.ts
  • apps/ade-cli/src/services/account/accountMachinePublisherService.ts
  • apps/ade-cli/src/services/sync/syncTunnelClientService.test.ts
  • apps/ade-cli/src/services/sync/syncTunnelClientService.ts
  • apps/desktop/package.json
  • apps/desktop/scripts/check-webclient-entry.mjs
  • apps/desktop/src/renderer/webclient.html
  • apps/desktop/src/renderer/webclient/public/_headers
  • apps/desktop/src/renderer/webclient/shell/MachinePicker.tsx
  • apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx
  • apps/desktop/src/renderer/webclient/shell/__tests__/WebClientRoot.test.tsx
  • apps/desktop/src/renderer/webclient/sync/__tests__/sync.test.ts
  • apps/desktop/src/renderer/webclient/sync/client.ts
  • apps/desktop/src/renderer/webclient/sync/connection.ts
  • apps/desktop/src/renderer/webclient/sync/envStore.test.ts
  • apps/desktop/src/renderer/webclient/sync/envStore.ts
  • apps/desktop/vite.webclient.config.ts
  • apps/ios/ADE/Services/SyncRecoveryPolicy.swift
  • apps/ios/ADE/Services/SyncService.swift
  • apps/ios/ADETests/SyncRecoveryPolicyTests.swift
  • apps/tunnel-relay/README.md
  • apps/tunnel-relay/src/tunnelDo.ts
  • apps/tunnel-relay/test/relay.test.ts
💤 Files with no reviewable changes (1)
  • apps/desktop/vite.webclient.config.ts

Comment on lines +8 to +15
/assets/*
Cache-Control: public, max-age=31536000, immutable

/
Cache-Control: no-cache

/index.html
Cache-Control: no-cache

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Apply no-cache to all SPA fallback routes.

Because this is a Single Page Application (SPA), deep links (e.g., /work or /pair) will route to and serve the index.html content via SPA fallback. However, Cloudflare Pages matches _headers rules based on the requested URL, not the file ultimately served. By restricting Cache-Control: no-cache to exactly / and /index.html, deep links will lack this directive. This can cause browsers to aggressively cache stale HTML on deep links, leading to blank screens when older referenced JavaScript chunks are removed in new deployments.

To fix this, apply Cache-Control: no-cache to the global /* block so it covers all HTML SPA routes, and allow the /assets/* block to override it for immutable, hashed assets. Cloudflare Pages naturally overrides headers when multiple rules match the same URL and define the same header, using a top-down approach where the last match wins.

🛠️ Proposed fix to ensure SPA fallback routes are not cached
 /*
   Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://img.clerk.com https://images.clerk.dev https://storage.googleapis.com/images.clerk.dev/; font-src 'self' data:; connect-src 'self' wss: https:; worker-src 'self' blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
   X-Content-Type-Options: nosniff
   Referrer-Policy: no-referrer
   X-Frame-Options: DENY
   Permissions-Policy: camera=(), microphone=(), geolocation=()
+  Cache-Control: no-cache
 
 /assets/*
   Cache-Control: public, max-age=31536000, immutable
-
-/
-  Cache-Control: no-cache
-
-/index.html
-  Cache-Control: no-cache
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/assets/*
Cache-Control: public, max-age=31536000, immutable
/
Cache-Control: no-cache
/index.html
Cache-Control: no-cache
/*
Content-Security-Policy: default-src 'self'; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https://img.clerk.com https://images.clerk.dev https://storage.googleapis.com/images.clerk.dev/; font-src 'self' data:; connect-src 'self' wss: https:; worker-src 'self' blob:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none'
X-Content-Type-Options: nosniff
Referrer-Policy: no-referrer
X-Frame-Options: DENY
Permissions-Policy: camera=(), microphone=(), geolocation=()
Cache-Control: no-cache
/assets/*
Cache-Control: public, max-age=31536000, immutable
🤖 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/webclient/public/_headers` around lines 8 - 15,
Update the _headers rules so the global /* block sets Cache-Control: no-cache
for all SPA fallback routes. Keep the /assets/* rule after it with public,
max-age=31536000, immutable so immutable assets override the global directive,
and remove the narrower / and /index.html rules.

Comment on lines +448 to 455
})().catch(() => {
if (disposed) return;
const accountSnapshot = accountClient.getSnapshot();
setAccount(accountSnapshot);
setDirectoryLoading(false);
setPhase({ kind: "machine-picker" });
void applyAccountPrivacy(accountSnapshot);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Leaked polling interval when bootstrap() rejects.

On the /account/callback path, accountProgressInterval is started before await accountClient.bootstrap(). If bootstrap() rejects, the async IIFE throws before the clearInterval at Line 440-443, and this .catch handler never clears it. The 150ms poller then keeps firing until unmount, repeatedly calling setAccount/setDirectoryLoading(true)/setPhase/beginPrivacyLoad — which also fights the setDirectoryLoading(false) set here.

🛡️ Proposed fix
     })().catch(() => {
       if (disposed) return;
+      if (accountProgressInterval != null) {
+        window.clearInterval(accountProgressInterval);
+        accountProgressInterval = null;
+      }
       const accountSnapshot = accountClient.getSnapshot();
       setAccount(accountSnapshot);
       setDirectoryLoading(false);
       setPhase({ kind: "machine-picker" });
       void applyAccountPrivacy(accountSnapshot);
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
})().catch(() => {
if (disposed) return;
const accountSnapshot = accountClient.getSnapshot();
setAccount(accountSnapshot);
setDirectoryLoading(false);
setPhase({ kind: "machine-picker" });
void applyAccountPrivacy(accountSnapshot);
});
})().catch(() => {
if (disposed) return;
if (accountProgressInterval != null) {
window.clearInterval(accountProgressInterval);
accountProgressInterval = null;
}
const accountSnapshot = accountClient.getSnapshot();
setAccount(accountSnapshot);
setDirectoryLoading(false);
setPhase({ kind: "machine-picker" });
void applyAccountPrivacy(accountSnapshot);
});
🤖 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/webclient/shell/WebClientRoot.tsx` around lines 448
- 455, Ensure the /account/callback bootstrap rejection path clears
accountProgressInterval before restoring the account state. Update the async
bootstrap flow and its catch handling so the interval is cleared whenever
bootstrap() rejects, while preserving the existing disposed guard and recovery
state updates in the catch block.

…button-fd3c9bbe

# Conflicts:
#	apps/ade-cli/src/services/account/accountMachinePublisherService.ts
#	apps/ade-cli/src/services/sync/syncTunnelClientService.test.ts
#	apps/ade-cli/src/services/sync/syncTunnelClientService.ts
#	apps/desktop/src/renderer/webclient/shell/WebClientRoot.tsx
#	apps/desktop/src/renderer/webclient/sync/connection.ts
#	apps/desktop/src/renderer/webclient/sync/envStore.ts
#	docs/features/sync-and-multi-device/README.md
#	docs/features/web-client/README.md
@arul28

arul28 commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 9ae26d3c8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

…tion

- _headers: Cache-Control: no-cache moves to the /* rule so SPA fallback
  deep links (/work, /open, /account/callback) get it too; the later
  /assets/* rule still overrides hashed assets to immutable.
- WebClientRoot: the 150ms callback bootstrap poller is cleared in the
  rejection path as well, so a failed bootstrap can no longer leave it
  fighting the settled machine-picker state until unmount.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@arul28

arul28 commented Jul 20, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: 843294cb5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@arul28
arul28 merged commit 3de144c into main Jul 20, 2026
34 checks passed
@arul28
arul28 deleted the ade/codex-auth-login-button-fd3c9bbe branch July 20, 2026 16:42
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