Archilyzer · Source

archilyzer

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

commit 49e71c0fb4a0cd9b3e698651c523218c1d414948
parent d7b3026ee81cbb8f0eeea09d8fda846861bf223d
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue,  8 Sep 2026 08:36:51 -0400

export: the sweep-Stop test holds batch 2 open itself instead of racing a timer

"corpus sweep: Stop aborts mid-sweep and keeps the partial report" delayed every
sweep response by a wall-clock 500 ms and then had to get its Stop click in
before that timer expired. On a loaded box it does not, batch 2 lands, and the
closing `toHaveCount(0)` on batch 2's finding fails. The delay was the test's
own scaffolding, not a property of the thing under test.

The route now awaits a deferred promise for any batch after the first, and the
line immediately after the Stop click resolves it. Batch 2 is therefore still in
flight when Stop is pressed, by construction rather than by timing, and its
response arrives afterwards — so the assertions still prove that a stopped sweep
discards the batch it did not wait for. Batch 1 answers immediately; the
assertions at the end of the test are unchanged.

Measured from a worktree at this tree, one worker, behind the e2e queue:
`playwright test theme.spec.ts theme-family.spec.ts ask-chat.spec.ts --repeat-each 10`
— **250 passed, 0 failed, 8.4 min**; "Stop aborts mid-sweep" is 10 of those.
(Invoked as `node ../scripts/queue-lock.mjs --ports EXPORT_E2E_PORT:3020 -- pnpm
exec playwright test …`, because `pnpm e2e --` inserts a literal `--` that
Playwright reads as end-of-flags and `--repeat-each` then becomes a filename
filter.)

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

Diffstat:
Mexport/e2e/ask-chat.spec.ts | 17+++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/export/e2e/ask-chat.spec.ts b/export/e2e/ask-chat.spec.ts @@ -965,7 +965,16 @@ test.describe("ask chat", () => { await page.addInitScript(() => localStorage.setItem("ytdlp-tb:ai:sweepchunk", "2"), ); - // Delay each sweep response so batch 2 is still in flight when we click Stop. + // Batch 2 must still be in flight when Stop is clicked. A wall-clock delay + // made that a race the test loses on a loaded box (the 500 ms timer expires + // before Playwright gets round to the click, batch 2 lands, and the final + // assertion sees its finding). The test holds the response open itself + // instead: batch 2's route awaits this latch, and only the line after the + // Stop click releases it. No timing assumption left to lose. + let releaseBatch2 = () => {}; + const batch2Gate = new Promise<void>((resolve) => { + releaseBatch2 = resolve; + }); await page.route("https://api.anthropic.com/**", async (route) => { if (route.request().method() === "OPTIONS") { await route.fulfill({ status: 204, headers: CORS }); @@ -982,7 +991,6 @@ test.describe("ask chat", () => { const isToolResult = Array.isArray(lastUser?.content); const text = typeof lastUser?.content === "string" ? lastUser.content : ""; if (Array.isArray(body.tools) && /running report/.test(system)) { - await new Promise((r) => setTimeout(r, 500)); if (isToolResult) { await route.fulfill({ status: 200, @@ -992,6 +1000,8 @@ test.describe("ask chat", () => { return; } const b = /Batch (\d+) of/.exec(text)?.[1] ?? "1"; + // Batch 1 answers at once; every later batch waits for the test. + if (b !== "1") await batch2Gate; await route.fulfill({ status: 200, headers: { ...CORS, "content-type": "application/json" }, @@ -1025,6 +1035,9 @@ test.describe("ask chat", () => { // Stop the sweep from the pinned panel while batch 2 is still running. await page.getByRole("button", { name: "Stop the sweep" }).click(); + // Stop has been asked for; let batch 2's response go. The sweep must + // discard it, which is the thing under test. + releaseBatch2(); // The sweep message resolves to a "stopped" line, and the partial report // (batch 1 only) survives — batch 2 never landed.