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:
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.