Public: anyone can read this; the crew can change it.

The proposal tests in crew-proposal and upstream-forge wait for the proposal, not a fixed 1.5 s #9090

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

mason/forge:mason/9083-the-proposal-tests-in-crew-proposal-and → main 3 commits fork 1 thread · 1 unresolved

  • Merged. mason/9083-the-proposal-tests-in-crew-proposal-and was merged into main as e908ae0.

Review

Sign in to review this change.
2 files changed +23 −4
test/crew-proposal.test.ts +16 −3
@@ -94,6 +94,8 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Wrote note
9494 concurrency: 1,
9595 budgetUsd: 2,
9696 runTimeoutMs: 60_000,
97 // A queued run starts on the next tick, not up to 5 s later.
98 tickMs: 50,
9799 });
98100 const a = await createUser(app.db, {
99101 origin: "seed",
@@ -266,8 +268,15 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Wrote note
266268 await Bun.sleep(20);
267269 }
268270 await press("v");
269 await Bun.sleep(1500);
270 await settleApp(tui);
271 // A writer's `v` opens the conflict blocks: wait for them to be drawn.
272 // A reader's `v` is ignored and draws nothing to wait for; what a
273 // reader may not do is asserted on the keys that follow.
274 const writer = user.id === alice.id;
275 while (writer && !tui.screen.toText().includes("conflict block in")) {
276 if (Date.now() > end) throw new Error(`v never opened the conflict blocks:\n${tui.screen.toText()}`);
277 await settleApp(tui);
278 await Bun.sleep(20);
279 }
271280 for (const key of keys) await press(key);
outdated

This negative check runs immediately after press("v") and proves nothing about a later draw. Wait for a positive signal that v was handled by a reader, then assert the blocks are absent; or remove it.

272281 while (until !== undefined && !until(tui.screen.toText())) {
273282 if (Date.now() > end + 30_000) throw new Error(tui.screen.toText());
@@ -376,7 +385,11 @@ echo '{"type":"result","subtype":"success","is_error":false,"result":"Wrote note
376385 issueId: pull.id,
377386 reason: "comment",
378387 });
379 app.db.query("UPDATE run SET state = 'running' WHERE id = ?1").run(run.id);
388 // A live run holds its lease; without a heartbeat the crew's next tick
389 // takes it for one a restart interrupted and queues it again for real.
390 app.db
391 .query("UPDATE run SET state = 'running', heartbeat_at = strftime('%Y-%m-%dT%H:%M:%fZ','now') WHERE id = ?1")
392 .run(run.id);
380393 const before = agentRuns();
381394 const refused = await proposeResolution(app, alice, repo, current());
382395 expect(refused.ok).toBe(false);
test/upstream-forge.test.ts +7 −1
@@ -266,7 +266,13 @@ describe("a child forge proposes to its parent forge", () => {
266266 const screen = await chainScreen(child, kid, ctx);
267267 expect(screen.keys.map((k: any) => k.keys?.[0] ?? k[0])).toContain("p");
268268 screen.key({ key: "p" } as any);
269 await Bun.sleep(1500);
269 // Wait for what the lines below read: the press's toast and its event.
270 const deadline = Date.now() + 10_000;
271 while (toasts.length === 0 || heard.length === 0) {
272 if (Date.now() > deadline)
273 throw new Error(`after p: ${toasts.length === 0 ? "no toast" : "no forge.proposal event"} within 10 s (toasts: ${JSON.stringify(toasts)})`);
274 await Bun.sleep(10);
275 }
270276 off();
271277 expect(toasts.join("\n")).toContain("Proposed to the parent forge as #");
272278 // One event, tied to the forge's repository so only its readers hear it.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs