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

A test boots the flow-label dispatcher: labelling a held issue `flow` starts its run, that issue only, paid by whoever last assigned it #7520

Merged opened this

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

Merged

This adds `test/flow-label-dispatch.test.ts`, which imports `src/crew/flow_label.ts` directly and runs it two ways: in-process, and cold in a fresh `bun` process. The tests found no fault in the dispatcher, so it is unchanged. The cold check is the one that would have caught 0.7.283.

shipped production is serving it deploy 40e21c3

opened this

This adds test/flow-label-dispatch.test.ts, which imports src/crew/flow_label.ts directly and runs it two ways: in-process, and cold in a fresh bun process. The tests found no fault in the dispatcher, so it is unchanged. The cold check is the one that would have caught 0.7.283.

In-process tests (the module is the file's first import, so an error while loading it fails the file). "Flow only" is on, with the agent bot on the crew:

  • Held issue: labelling a held issue flow and calling dispatchFlowLabelled starts exactly one run for it. A second held issue next to it starts nothing. Labelling again, or running the sweep, still leaves one run.
  • Who pays: the run's run.queued event is charged to alice, who assigned the issue. When a guest is the last to assign, the label starts nothing; when alice assigns after the guest, the run starts and alice pays. So it is the last assigner who counts.
  • Nothing to start: labelling an issue with no assignee, one assigned to a person, one already labelled flow that has run, or a closed one starts nothing and throws nothing.

Cold-boot test (test/helpers/flow-label-boot.ts): a fresh bun process loads the app and the HTTP server's modules the way src/main.ts does at boot, then has the owner label a held issue through setIssueLabels. That reaches the dispatcher through the same lazy require() in src/actions/issues.ts that production uses. The test asserts the process exits 0 and that the issue now has one run.

Checks that the tests bite:

  • Adding await Bun.sleep(1) at the top of flow_label.ts fails the cold-boot test with Bun's error from the 0.7.283 boot-proof log: require() async module … is unsupported.
  • Dropping the assigner in the dispatcher fails both payer tests.
  • With flow_label.ts restored, all 4 tests pass, as do the 13 files scripts/fast.ts named (167 tests). tsc is clean.

The 0.7.283 failure doesn't happen today: on Bun 1.3.14 (the image's version), loading the dispatcher cold succeeds both on main and on #7436's base, e7df551. #7436 reported test/flow-only-dispatch.test.ts failing when run on its own; at both commits it passes 2/2 here. The top-level await in src/release/launch.ts sits inside if (import.meta.main), and Bun allows require() of a module like that when it isn't the entry point.

Not done: I didn't replace the lazy require() with import(). That was #7436's change and it is parked; this test is what would show that change is needed.

🤖 Generated with Claude Code

Closes #7512

commented

This adds test/flow-label-dispatch.test.ts, which imports src/crew/flow_label.ts directly and runs it two ways: in-process, and cold in a fresh bun process. The tests found no fault in the dispatcher, so it is unchanged. The cold check is the one that would have caught 0.7.283.

In-process tests (the module is the file's first import, so an error while loading it fails the file). "Flow only" is on, with the agent bot on the crew:

  • Held issue: labelling a held issue flow and calling dispatchFlowLabelled starts exactly one run for it. A second held issue next to it starts nothing. Labelling again, or running the sweep, still leaves one run.
  • Who pays: the run's run.queued event is charged to alice, who assigned the issue. When a guest is the last to assign, the label starts nothing; when alice assigns after the guest, the run starts and alice pays. So it is the last assigner who counts.
  • Nothing to start: labelling an issue with no assignee, one assigned to a person, one already labelled flow that has run, or a closed one starts nothing and throws nothing.

Cold-boot test (test/helpers/flow-label-boot.ts): a fresh bun process loads the app and the HTTP server's modules the way src/main.ts does at boot, then has the owner label a held issue through setIssueLabels. That reaches the dispatcher through the same lazy require() in src/actions/issues.ts that production uses. The test asserts the process exits 0 and that the issue now has one run.

Checks that the tests bite:

  • Adding await Bun.sleep(1) at the top of flow_label.ts fails the cold-boot test with Bun's error from the 0.7.283 boot-proof log: require() async module … is unsupported.
  • Dropping the assigner in the dispatcher fails both payer tests.
  • With flow_label.ts restored, all 4 tests pass, as do the 13 files scripts/fast.ts named (167 tests). tsc is clean.

The 0.7.283 failure doesn't happen today: on Bun 1.3.14 (the image's version), loading the dispatcher cold succeeds both on main and on #7436's base, e7df551. #7436 reported test/flow-only-dispatch.test.ts failing when run on its own; at both commits it passes 2/2 here. The top-level await in src/release/launch.ts sits inside if (import.meta.main), and Bun allows require() of a module like that when it isn't the entry point.

Not done: I didn't replace the lazy require() with import(). That was #7436's change and it is parked; this test is what would show that change is needed.

🤖 Generated with Claude Code

Approved

Test-only change, no runtime surface, so there is no new door, input or output to gate. It covers the flow-label dispatcher in-process (held issue starts one run, that issue only, last assigner pays; unassigned, person-assigned, already-flow and closed issues start nothing) and cold in a fresh process the way main.ts boots. No dependency is added, the new test files use the repository pattern, and the pull reports mutation checks showing the tests fail when the dispatcher is broken. It guards the 0.7.283 boot failure, which fits pipeline-first.

Two things I would do next:

  1. Tighten the cold-boot test's 30_000 ms timeout to fit the per-test time budget (#1242) once that lands, and check that the spawn stays well under a second. Assert the child's exit code and stderr in one expect rather than awaiting child.exited twice.
  2. If the lazy require() in actions/issues.ts is later replaced by import() (#7436), keep the cold test as the guard and drop the comment that ties it to the parked change.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs