From 8191adbc61263403944fb06c3ffc90cfd63dbcee Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Thu, 20 Aug 2026 22:33:06 -0700 Subject: [PATCH 1/2] Add regression test: HomeRoute must keep polling past the stall state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stall message ("Myra is taking longer than usual") should never be the end of the line — a backend that becomes ready after the 45s stall threshold fires must still auto-navigate with no click required. --- apps/web/test/home-page.test.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/apps/web/test/home-page.test.tsx b/apps/web/test/home-page.test.tsx index 78885fc34..caa54bc15 100644 --- a/apps/web/test/home-page.test.tsx +++ b/apps/web/test/home-page.test.tsx @@ -354,6 +354,29 @@ describe("the wait right after connecting a provider", () => { ); expect(retry).not.toBeUndefined(); }); + + test("auto-navigates once Myra becomes ready even after the stall message fires, with no click", async () => { + // Myra doesn't answer until well past the stall threshold — the slow + // message must not be the end of the line. Polling keeps going + // underneath it, and the land happens on its own once she's ready. + benchWhereMyraArrivesAfter(6); + const navigated: string[] = []; + await renderHome({ retryMs: 10, stallAfterMs: 40, navigated }); + for (let i = 0; i < 40; i++) { + await settle(); + if ((container?.textContent ?? "").includes("longer than usual")) break; + } + expect(container?.textContent ?? "").toContain( + "Myra is taking longer than usual", + ); + + for (let i = 0; i < 60; i++) { + await settle(); + if (navigated.length > 0) break; + } + + expect(navigated).toEqual(["/w/chan_new"]); + }); }); describe('a failed memberships fetch never reads as "pick from the switcher"', () => { From 736addf17b2c03637fa3e8e196b61290be0c5afa Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Thu, 20 Aug 2026 22:34:21 -0700 Subject: [PATCH 2/2] HomeRoute: keep polling past the stall state, fix design nits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Design review on the CL-6462 land-in-chat wait surfaced four defects: - Critical: once the 45s stall message fired, waitAndRetry stopped scheduling retries entirely — a backend that became ready afterward never got noticed, and only "Try again" resumed anything. Retries now keep running underneath the slow message; the button stays as an explicit escape hatch, not the only way forward. - Same action, two verbs ("Retry" vs "Try again") on the identical startOver handler — unified on "Retry" to match every other retry action in the app (skills, plugins, insights, skill-detail pages). - The stall state isn't an error, but shared WarningCircle with the actual error state — swapped it for Clock. - setup-progress-note's "the rest of its agents" asserted an unspecified plural a first-time user (who has met exactly one agent) can't act on — reworded to drop the seed-count concept entirely. --- apps/web/src/pages/home-page.tsx | 10 ++++++---- apps/web/src/shell/setup-progress-note.tsx | 4 ++-- apps/web/test/home-page.test.tsx | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/apps/web/src/pages/home-page.tsx b/apps/web/src/pages/home-page.tsx index 6287c1c23..e1f6e0153 100644 --- a/apps/web/src/pages/home-page.tsx +++ b/apps/web/src/pages/home-page.tsx @@ -20,7 +20,7 @@ // implementation detail, and "0 of 5" told a waiting person nothing. import { Button, EmptyState, PageShell } from "@corbits/react-ui"; -import { WarningCircle } from "@corbits/icons"; +import { Clock, WarningCircle } from "@corbits/icons"; import { useEffect, useState } from "react"; import { listAllWorkbenches, WorkbenchLoadingState } from "@corbits/chat-ui"; @@ -75,8 +75,10 @@ export function HomeRoute({ if (cancelled) return; if ((attempt + 1) * retryMs >= stallAfterMs) { setState({ kind: "slow" }); - return; } + // Slow is a message, not a stop: retries keep going underneath it so + // a backend that recovers after the stall still lands on its own — + // "Retry" stays as an escape hatch, never the only way forward. retryTimer = setTimeout(() => setAttempt((count) => count + 1), retryMs); }; @@ -185,12 +187,12 @@ export function HomeRoute({ return ( } + icon={} title="Myra is taking longer than usual" description="She's still getting set up. Give it another moment, or try again." action={ } /> diff --git a/apps/web/src/shell/setup-progress-note.tsx b/apps/web/src/shell/setup-progress-note.tsx index 5c991c24a..4ac6f3830 100644 --- a/apps/web/src/shell/setup-progress-note.tsx +++ b/apps/web/src/shell/setup-progress-note.tsx @@ -78,8 +78,8 @@ export function SetupProgressNote() { return (

- Your workbench is still setting up the rest of its agents. Nothing to - wait for — keep going. + Your workbench is still setting up in the background. Nothing to wait + for — keep going.