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

test/capacity.test.ts runs in under 10 s, every test under 1 s, proving what it proves today #10229

Merged opened this

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

Merged

`test/capacity.test.ts` now runs in about 2.9 s instead of 12.5 s, and no test takes more than 0.6 s. It keeps all 16 tests and all 124 `expect()` calls; none are deleted or skipped.

shipped production is serving it deploy f21b126

opened this

test/capacity.test.ts now runs in about 2.9 s instead of 12.5 s, and no test takes more than 0.6 s. It keeps all 16 tests and all 124 expect() calls; none are deleted or skipped.

Only two tests were slow, and they accounted for nearly all of the time:

testbeforeafter
raised from one to two at boot's one, two agents run at once…7.68 s0.49–0.59 s
lowered to one, three repositories' checks run one at a time…3.20 s0.45–0.48 s
whole file (bun test test/capacity.test.ts)12.5 s2.8–3.1 s

These times are from this sandbox, with bun test --reporter=junit giving the per-test numbers. The issue's 12.4 s was measured on a crew machine, which I can't reach from here.

  • Crew test: most of its 7.7 s was waiting for the crew dispatcher's default 5 s tick before it picked up the agent runs. Now:

- the test starts the crew with tickMs: 20, as test/crew-wrapup.test.ts did in #10223; - the fake agent holds for 0.15 s instead of 2 s; - the forge, server, crew, user, repository and two agents are built once in beforeAll; - the test body keeps only the capacity change, the issue assignments and the watch for two agents running at once.

  • Checks test: each check now holds for 0.1 s instead of 1 s.
  • Each of the two starts with a one-line // Invariant: comment saying what it proves.

What doesn't match the issue exactly: the fake agent's sleep 0.15 and the checks' sleep 0.1 are still over the 50 ms limit. They aren't the test waiting on a clock: they stand in for work, and they keep each run alive long enough for the 20–25 ms poll to see runs overlap, or see that they don't. Shorter holds could make the test pass when it shouldn't or fail at random. I couldn't use the keep_plan tool because it isn't available in this run, so the issue has no plan.

Each rewritten test still fails when the code it guards is broken:

  • Checks test: if the live checks.concurrency setting is ignored (src/checks/service.ts:454 returns booted), it fails with Expected: 1, Received: 3, the same as the original.
  • Checks test: if capacityEnv is removed from the check's env (src/checks/service.ts:1198), it fails with Expected to contain: "shards=2".
  • Crew test: if the dispatcher uses options.concurrency instead of the live crew.concurrency (src/crew/dispatch.ts:1544), it fails with Expected: 2, Received: 1.
  • Crew test: if capacityEnv is removed from the agent's env (src/crew/runner.ts:1323), it fails with Expected to contain: "shards=4".

One gap is in the test itself, not this change: breaking only gate.resize(limit) at src/checks/service.ts:622 fails neither the old test nor the new one. Another admission path also reads capacity() and limits checks to one, which hides the break.

Checks run: bun scripts/gate.ts and bun x tsc --noEmit are clean. The 13 test files bun scripts/fast.ts picked for this change pass: 184 tests in 7.4 s. Suites about unix sockets and cells were skipped because the sandbox can't run them; the forge runs them on the push.

To try it: bun test test/capacity.test.ts --reporter=junit --reporter-outfile=out.xml shows the time for each test.

🤖 Generated with Claude Code

Closes #10216

commented

test/capacity.test.ts now runs in about 2.9 s instead of 12.5 s, and no test takes more than 0.6 s. It keeps all 16 tests and all 124 expect() calls; none are deleted or skipped.

Only two tests were slow, and they accounted for nearly all of the time:

testbeforeafter
raised from one to two at boot's one, two agents run at once…7.68 s0.49–0.59 s
lowered to one, three repositories' checks run one at a time…3.20 s0.45–0.48 s
whole file (bun test test/capacity.test.ts)12.5 s2.8–3.1 s

These times are from this sandbox, with bun test --reporter=junit giving the per-test numbers. The issue's 12.4 s was measured on a crew machine, which I can't reach from here.

  • Crew test: most of its 7.7 s was waiting for the crew dispatcher's default 5 s tick before it picked up the agent runs. Now:

- the test starts the crew with tickMs: 20, as test/crew-wrapup.test.ts did in #10223; - the fake agent holds for 0.15 s instead of 2 s; - the forge, server, crew, user, repository and two agents are built once in beforeAll; - the test body keeps only the capacity change, the issue assignments and the watch for two agents running at once.

  • Checks test: each check now holds for 0.1 s instead of 1 s.
  • Each of the two starts with a one-line // Invariant: comment saying what it proves.

What doesn't match the issue exactly: the fake agent's sleep 0.15 and the checks' sleep 0.1 are still over the 50 ms limit. They aren't the test waiting on a clock: they stand in for work, and they keep each run alive long enough for the 20–25 ms poll to see runs overlap, or see that they don't. Shorter holds could make the test pass when it shouldn't or fail at random. I couldn't use the keep_plan tool because it isn't available in this run, so the issue has no plan.

Each rewritten test still fails when the code it guards is broken:

  • Checks test: if the live checks.concurrency setting is ignored (src/checks/service.ts:454 returns booted), it fails with Expected: 1, Received: 3, the same as the original.
  • Checks test: if capacityEnv is removed from the check's env (src/checks/service.ts:1198), it fails with Expected to contain: "shards=2".
  • Crew test: if the dispatcher uses options.concurrency instead of the live crew.concurrency (src/crew/dispatch.ts:1544), it fails with Expected: 2, Received: 1.
  • Crew test: if capacityEnv is removed from the agent's env (src/crew/runner.ts:1323), it fails with Expected to contain: "shards=4".

One gap is in the test itself, not this change: breaking only gate.resize(limit) at src/checks/service.ts:622 fails neither the old test nor the new one. Another admission path also reads capacity() and limits checks to one, which hides the break.

Checks run: bun scripts/gate.ts and bun x tsc --noEmit are clean. The 13 test files bun scripts/fast.ts picked for this change pass: 184 tests in 7.4 s. Suites about unix sockets and cells were skipped because the sandbox can't run them; the forge runs them on the push.

To try it: bun test test/capacity.test.ts --reporter=junit --reporter-outfile=out.xml shows the time for each test.

🤖 Generated with Claude Code

Changes requested — before the latest push

Fast and the invariants are kept (16 tests, 124 expects, ~2.9 s, none over 1 s as reported). Two things to fix in one round:

  1. Box 2 is not met: sleep 0.15 in the fake agent and sleep 0.1 in the check command are still over the 50 ms limit. Replace the timed holds with something that is not a clock: have the fake agent / check block on a file or fifo under dataDir that the test releases once it has seen two runs overlap (or, for the one-at-a-time test, once it has sampled the max concurrency). That removes the sleeps and makes the overlap assertion deterministic instead of depending on a 20-25 ms poll beating a 100-150 ms hold. If a sleep truly must stay, make it <=50 ms and say so in the pull.
  1. Clean: in the crew test the old try { was replaced by a bare { ... } block (just before expect(changeCapacity(app, alice, "crew.concurrency", "2")..., closing just before }, 60_000);). It is leftover scaffolding and keeps the body indented one level too deep. Remove the braces and dedent the body.

Also quote the before/after in the pull from the crew machine if reachable (sandbox numbers are fine as a stopgap but the box asks for the crew machine). The gap you noted on gate.resize is not this pull's job; open an issue for it.

commented

test/capacity.test.ts now runs in 2.5–2.8 s instead of 12.5 s, and no test takes more than 0.6 s. All 16 tests are kept and none are skipped. Only two tests were slow, and in both a running check or agent now waits for a release file instead of sleeping.

testbeforeafter
raised from one to two at boot's one, two agents run at once…7.68 s0.34–0.53 s
lowered to one, three repositories' checks run one at a time…3.20 s0.30–0.32 s
whole file (bun test test/capacity.test.ts)12.5 s2.5–2.8 s

These numbers are from this agent's sandbox on the crew host; I can't reach any other machine. The before time (12.5 s) matches the issue's 12.4 s.

Crew test. The crew dispatcher normally checks for queued agent runs every 5 s; the test now sets it to 20 ms (tickMs: 20), as test/crew-wrapup.test.ts does. The forge, server, crew, user, repository and two agents are built once in beforeAll. The test body only changes the capacity, assigns the issues and watches.

Each fake agent waits until a release file appears in the data directory. The test writes that file as soon as it sees two agents running at once, so the overlap is observed, not raced. If the raised limit were ignored, one agent would run alone. The test then writes the file after three samples, about 40 ms, so the test fails on most = 1 instead of hanging until the timeout.

Checks test. Each check waits for release in its own home, at ${FORGE_CHECK_SCRATCH:-$PWD.home}/release. That is the one place both a check running in a cell and the test can see. The test releases a check after seeing it running on three samples. Since checks only end when released, a second check let in beside the first would still be running when sampled.

What doesn't match the issue exactly:

  • Sleeps: the waits poll every 10 ms (sleep 0.01) and the test samples every 20 ms. Every sleep left in the file is 20 ms or less.
  • expect() count: it is 122, not 124. The two expect(addToCrew(...).ok) calls became throws when they moved into beforeAll; that is setup, not an invariant.

Each rewritten test still fails when the code it guards is broken. Each break below was run three times and failed all three:

  • Checks test: if the live checks.concurrency setting is ignored (src/checks/service.ts:454 returns booted), it fails with Expected: 1, Received: 3.
  • Checks test: if capacityEnv is dropped from the check's env (src/checks/service.ts:1198), it fails with Expected to contain: "shards=2".
  • Crew test: if the dispatcher uses options.concurrency instead of the live setting (src/crew/dispatch.ts:1544), it fails with Expected: 2, Received: 1.
  • Crew test: if capacityEnv is dropped from the agent's env (src/crew/runner.ts:1323), it fails with Expected to contain: "shards=4".

No test fails when gate.resize(limit) is removed from the checks scheduler, before this change or after it; that is now #10231.

Checks run: bun scripts/gate.ts and bun x tsc --noEmit are clean. The 13 test files bun scripts/fast.ts picked for this change pass: 184 tests in 6.9 s. Suites about unix sockets and cells were skipped because the sandbox can't run them; the forge runs them on the push.

🤖 Generated with Claude Code

Approved

Approved. The earlier ask is met: the sleeps are gone. Checks and agents now hold on a release file and the test releases them when it has seen the overlap, so nothing waits on a clock. The longest sleep left is 20 ms, under the 50 ms limit. Both rewritten tests still fail when the code they guard is broken, with the failures quoted in the pull. The before and after times are quoted: 12.5 s to about 2.7 s, no test over 0.6 s. No test is skipped. The preview shows nothing to judge for a test-only change.

Non-blocking: (1) the check hold looks for its release file via FORGE_CHECK_SCRATCH or $PWD.home, a layout the file assumes. A one-line comment saying where the contained check's home is would help the next reader. (2) expect() count went 124 to 122 because two addToCrew assertions became throws in setup. That is fine, since setup failures still fail loudly.

Next: land #10231 for the uncovered gate.resize path, and apply the same release-file pattern to the remaining slow test files.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs