Skip to content

Commit baf3f8d

Browse files
Programcodeclaude
andcommitted
Hold the fake Generate draft on screen long enough to inspect
On mobile, a full-page screenshot could outlast the one-second fake stream before the draft's ARIA snapshot. fake.streamDelay(ms) slows streamed chunks for one test; the next reset restores the default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent a6ee0c1 commit baf3f8d

4 files changed

Lines changed: 17 additions & 3 deletions

File tree

‎.claude/skills/verify-debatelab/SKILL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ It never touches `.verify/artifacts/` or `.verify/logs/`, and it is safe to run
174174

175175
- Live runs are slow: sparring and crossfire take several minutes each because the model must reason. Use `-g` to run one test while iterating.
176176
- Vite does not reload `tailwind.config.ts` on a running stack: new theme keys, variants and the `future` flags produce no CSS until `$H down && $H up`. Edits to `src/` and `src/index.css` apply on reload as usual.
177-
- The fake provider streams a structured answer in 24-character chunks 10 ms apart when the request asks to stream, so a Generate draft is on screen for about a second in fake mode. Short replies (a Crossfire turn) finish in well under that, so prove those with `expectStreamed` rather than by catching the draft.
177+
- The fake provider streams a structured answer in 24-character chunks 10 ms apart when the request asks to stream, so a Generate draft is on screen for about a second in fake mode; `fake.streamDelay(ms)` slows it for one test (the next reset restores it). Short replies (a Crossfire turn) finish in well under that, so prove those with `expectStreamed` rather than by catching the draft.
178178
- The fake provider rejects prompts it doesn't recognize. If a prompt change makes a feature fail with a provider error, update `e2e/full-stack/fake-openrouter.mjs`. Don't mock around it.
179179
- Once, the fake-provider container was SIGKILLed about 20 seconds after `up`, and the cause was never found. Doctor catches this, and `drive` refuses to run until you `down && up`.
180180
- Demo-code users are Pro with a daily limit of 999. To test quota or tier paths, change `user_settings` through `admin` inside the recipe, as `e2e/full-stack/case-generation.spec.ts` does.

‎.claude/skills/verify-debatelab/recipes/live-generation.spec.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Page, Response } from "@playwright/test";
2-
import { AI_TIMEOUT, expect, expectStreamed, readAIResponse, startDebate, test } from "./fixtures";
2+
import { AI_TIMEOUT, expect, expectStreamed, fake, readAIResponse, startDebate, test } from "./fixtures";
33

44
// Feature map: features/live-generation.md.
55
const motion = "This House would make public transport free at the point of use";
@@ -32,6 +32,8 @@ async function expectLiveStream(response: Response) {
3232
}
3333

3434
test("live-generate: a case fills in section by section while the model writes it", async ({ signedIn: page, evidence }) => {
35+
// Fake mode writes a case in about a second; slow it so the draft can be inspected.
36+
await fake.streamDelay(80);
3537
await startDebate(page, motion);
3638
await page.goto("/app/generate");
3739
await expect(page.getByRole("textbox", { name: "Motion / Topic *" })).toHaveValue(motion);

‎e2e/full-stack/fake-openrouter.mjs‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ if (upstream && !liveModel) throw new Error("LIVE_MODEL is required with UPSTREA
1919
const requests = [];
2020
let failures = [];
2121
let upstreamCalls = 0;
22+
// Delay between streamed chunks; a test can slow it to keep a draft on screen.
23+
let streamDelayMs;
2224

2325
const MARK = "FAKE-PROVIDER";
2426

@@ -217,7 +219,7 @@ async function streamJson(res, content) {
217219
res.writeHead(200, { "content-type": "text/event-stream", "cache-control": "no-cache" });
218220
for (let index = 0; index < content.length; index += STREAM_CHUNK_CHARS) {
219221
res.write(`data: ${JSON.stringify({ choices: [{ delta: { content: content.slice(index, index + STREAM_CHUNK_CHARS) } }] })}\n\n`);
220-
await new Promise((resolve) => setTimeout(resolve, STREAM_CHUNK_DELAY_MS));
222+
await new Promise((resolve) => setTimeout(resolve, streamDelayMs ?? STREAM_CHUNK_DELAY_MS));
221223
}
222224
res.write(`data: ${JSON.stringify({ choices: [{ delta: {}, finish_reason: "stop" }] })}\n\n`);
223225
res.write(`data: ${JSON.stringify({ choices: [], usage })}\n\n`);
@@ -307,6 +309,12 @@ createServer(async (req, res) => {
307309
if (url.pathname === "/__reset" && req.method === "POST") {
308310
requests.length = 0;
309311
failures = [];
312+
streamDelayMs = undefined;
313+
return json(res, 200, { ok: true });
314+
}
315+
if (url.pathname === "/__stream-delay" && req.method === "POST") {
316+
const { ms } = JSON.parse(await readBody(req) || "{}");
317+
streamDelayMs = typeof ms === "number" && ms >= 0 ? ms : undefined;
310318
return json(res, 200, { ok: true });
311319
}
312320
if (url.pathname === "/__fail" && req.method === "POST") {

‎e2e/full-stack/stack-core.ts‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ export const fake = {
3434
async fail(feature: string, status = 500, count = 1) {
3535
await fetch(`${fakeUrl}/__fail`, { method: "POST", body: JSON.stringify({ feature, status, count }) });
3636
},
37+
/** Milliseconds between streamed chunks (fake mode only) until the next reset. */
38+
async streamDelay(ms: number) {
39+
await fetch(`${fakeUrl}/__stream-delay`, { method: "POST", body: JSON.stringify({ ms }) });
40+
},
3741
};
3842

3943
export type DemoUser = { code: string; email: string; userId: () => Promise<string> };

0 commit comments

Comments
 (0)