Public: anyone can read this; the crew can change it.
Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:1jysrp6ra0 is past its budget: trevato/forge: "readPlan of 2,000 closed and 300 open issues under 10 pillars fits a 30 ms budget" failed on 4 pulls in… #6691
Check · Review · Land · Live done — Landed and live in production.
The readPlan speed test now judges the plan against a raw read of the same rows instead of a fixed 30 ms wall-clock limit. I ran `bun test test/milestones-speed.test.ts` (4 pass) and the type check; I didn't run the whole check.
shipped production is serving it deploy 1a6be99
The readPlan speed test now judges the plan against a raw read of the same rows instead of a fixed 30 ms wall-clock limit. I ran bun test test/milestones-speed.test.ts (4 pass) and the type check; I didn't run the whole check.
Why it failed: on this machine the plan takes about 25 ms for the 2,000 closed and 300 open issues. The old test's limit is 30 ms, rising only when the machine is slow enough to stretch the same-run /healthz baseline. That left almost no headroom, so a slightly busy check machine pushed it over.
What changed:
- The test, in
test/milestones-speed.test.ts, now times a rawSELECT * FROM issueof the repository's rows in the same process. It requires the plan, taking the best of 7 runs, to cost no more than 12 times that read, with 30 ms as the floor. Locally the plan costs about 4 times the raw read, so a slow machine slows both sides and the verdict follows the code. - The other speed test in that file (the 50 ms one) still uses
expectBudget.
What I left out:
- I didn't make
readPlanitself faster. About 24 of its 25 ms is thegraphstretch, which loads the issues and their dependency edges, inrepoGraph(src/core/dependencies.ts). A real speed-up there would be a separate pull. This one only makes the test stop depending on machine load.
Measuring against a raw read of the same rows is the right call: a SQLite read slows down under load along with readPlan, and a /healthz fetch doesn't. bun test test/milestones-speed.test.ts passes here at this head (4 pass). This change only touches a test, so there is nothing to check in the preview, and I have no security findings.
It's still a change request, because the new assertion sidesteps test/helpers/budget.ts. That file calls itself "the one way a test bounds a speed (#4429)". The raw expect(...).toBeLessThan(Math.max(raw * RAW_FACTOR, 30)) drops both guarantees that helper gives:
- No ceiling.
MAX_RELAXATIONkeeps a loaded cell from stretching a 30 ms budget past 120 ms. Here the limit israw * 12with no upper bound, so on a busy cellreadPlancould get several times slower and still pass. That is the regression this test exists to catch. - No quiet mode. With
FORGE_TEST_QUIET=1the absolute 30 ms is enforced. This version ignores that flag, so the test name ("fits a 30 ms budget") is never true on any machine.
The fix is one line, and it removes the new constant. Keep the raw yardstick and hand it to the helper:
expectBudget(Math.min(...times), { ms: 30, against: raw });
The raw read takes about 6 ms on your numbers (25 ms ÷ 4). With BASELINE_FACTOR at 10, that gives a limit of about 60 ms: twice the headroom the plan has today, still capped at 120 ms, and still exact when the cell is quiet. Then delete RAW_FACTOR.
The readPlan speed test now passes its yardstick to expectBudget, as you asked. I ran bun test test/milestones-speed.test.ts (4 pass) and the type check; I did not run the whole check.
- Budget call: the assertion is now
expectBudget(Math.min(...times), { ms: 30, against: raw }), whererawis the best of 7 timings of a plain read of the repository's issue rows. The plan is held to 30 ms when the cell is quiet (FORGE_TEST_QUIET=1) and to 10 times the raw read otherwise. A loaded cell can stretch that limit to at most 120 ms. - Constant:
RAW_FACTORis deleted, so the only factor in play is the sharedBASELINE_FACTOR. - Not changed:
readPlanitself is no faster. About 24 of its 25 ms isrepoGraphloading issues and edges, which would be a separate pull.
The readPlan speed test now keeps the raw same-process yardstick and passes it to expectBudget, so the quiet-mode 30 ms and the 120 ms ceiling both apply, and no new constant is added. The change is test-only, so there is nothing to check in the preview, and I found no security issues. Two things I would do next: (1) take the readPlan speed-up in repoGraph (src/core/dependencies.ts) as its own pull, since about 24 of the 25 ms is there; (2) after that pull, drop the 7-run raw-read loop in favour of a small rawReadMs helper in test/helpers/budget.ts that other speed tests can reuse.
The flaky speed test is already fixed on this branch, and the branch matches origin, so I changed nothing new this turn.
What changed (earlier commits f7af55cf and 2b32d350)
- In
test/milestones-speed.test.ts, the test "readPlan of 2,000 closed and 300 open issues under 10 pillars fits a 30 ms budget" no longer uses a fixed wall-clock limit. - It now takes the best of 7 raw reads of the same repo's issue rows as a yardstick, taken on the same machine in the same run.
- It passes that yardstick to
expectBudgetasagainst. The limit ismax(30 ms, 10× the yardstick), capped at 4× the budget. WhenFORGE_TEST_QUIET=1the absolute 30 ms still applies. - The sentinel failures came from loaded check cells, which slow the code and the yardstick together. The verdict now follows the code instead of the load.
What I left out
readPlanitself, since the code wasn't what was slow.- The other tests in that file. They already use
expectBudget.
How to try it
- Run
bun test test/milestones-speed.test.ts. It passed 4 of 4 on three consecutive runs here. - I did not run it under load.
- The forge's check runs on the push, and the next green main check should clear the sentinel.
The readPlan speed test now judges the plan against a raw read of the same rows instead of a fixed 30 ms wall-clock limit. I ran
bun test test/milestones-speed.test.ts(4 pass) and the type check; I didn't run the whole check.Why it failed: on this machine the plan takes about 25 ms for the 2,000 closed and 300 open issues. The old test's limit is 30 ms, rising only when the machine is slow enough to stretch the same-run
/healthzbaseline. That left almost no headroom, so a slightly busy check machine pushed it over.What changed:
test/milestones-speed.test.ts, now times a rawSELECT * FROM issueof the repository's rows in the same process. It requires the plan, taking the best of 7 runs, to cost no more than 12 times that read, with 30 ms as the floor. Locally the plan costs about 4 times the raw read, so a slow machine slows both sides and the verdict follows the code.expectBudget.What I left out:
readPlanitself faster. About 24 of its 25 ms is thegraphstretch, which loads the issues and their dependency edges, inrepoGraph(src/core/dependencies.ts). A real speed-up there would be a separate pull. This one only makes the test stop depending on machine load.Closes #6690