Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

commit f953ea526b412323648cd36109ba6b93545da69f
parent 7daa86515342c77a155a31d73011626fd700eaee
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 03:06:38 -0400

hub: /ask waits for a live-chat refetch in flight; the front page stays ready through it (review low 1) — subsSettled = data || (errored && (progressive || !isFetching)); e2e: /ask after a front-page live-chat failure is not ready while its own mount refetches it

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

Diffstat:
Mcommon/components/SearchDataContext.tsx | 12+++++++++++-
Mexport/e2e-hub/federated-search.spec.ts | 32++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/common/components/SearchDataContext.tsx b/common/components/SearchDataContext.tsx @@ -447,11 +447,21 @@ export function MultiSiteDataProvider({ // refetches, so `isError` would take the archive (and its videos) out of // the search for the length of a live-chat Retry. With the count, the // archive stays ready through it, still noted as missing its live chat. + // + // That holds for the PROGRESSIVE front page only. The count lives in the + // shared query client, so it also survives into a later refetch the front + // page never asked for: /ask's own mount (an errored query with no data is + // refetched when a new observer mounts), a scope toggle off and on, a + // whole-archive Retry. /ask grounds in what it was given, so it waits for + // such a refetch to settle rather than answer without live chat that is + // about to arrive. const posts = postsQueries[i]; const postsSettled = !!posts && (posts.isSuccess || posts.isError); const subs = subsQueries[i]; const subsErrored = !!subs && subs.data === undefined && subs.errorUpdateCount > 0; - const subsSettled = !!subs && (subs.data !== undefined || subsErrored); + const subsSettled = + !!subs && + (subs.data !== undefined || (subsErrored && (progressive || !subs.isFetching))); if ( m?.isSuccess && pages.length === m.data.pageCount && diff --git a/export/e2e-hub/federated-search.spec.ts b/export/e2e-hub/federated-search.spec.ts @@ -582,6 +582,38 @@ test.describe("hub federated search — scope, per-archive state, attribution", expect(mocks.b.requests.slice(asked)).toEqual(["/subs/manifest.json"]); }); + test("/ask is not ready while it refetches a live chat that failed on the front page", async ({ + page, + }) => { + // Origin B's live chat failed on the front page: its archive is ready + // there, noted as missing its live chat. + const mocks = await setup(page); + mocks.b.subs = "error"; + await page.goto("/"); + await expect(chip(page, B).getByTestId("hub-scope-live-chat")).toHaveText( + LIVE_CHAT_MISSING, + ); + + // To /ask in the same page life (the same query client): its own mount + // asks for the failed live chat again. Held, /ask is not ready — a question + // now would miss live chat that may be about to arrive. + mocks.b.subs = "hold"; + await page + .getByRole("banner") + .getByRole("link", { name: "Ask AI", exact: true }) + .click(); + await page.waitForURL(/\/ask\/?$/); + await expect.poll(() => mocks.b.heldSubs.length).toBe(1); + await page.waitForTimeout(1_000); + await expect(page.getByPlaceholder("Loading transcripts…")).toBeVisible(); + + // It answers: /ask is ready, over both archives and B's live chat. + for (const r of mocks.b.heldSubs.splice(0)) await fulfillJson(r, SUBS_OK); + await expect( + page.getByPlaceholder(/^Ask about the transcripts/), + ).toBeVisible(); + }); + test("/ask with every archive switched off says so and cannot ask; with one back on, it asks", async ({ page, }) => {