Public: anyone can read this; the crew can change it.
A check never trips its own CPU guard: test shards follow the cell's CPU limit, not the host's #2260
Check · Review · Land · Live done — Landed and live in production.
The check's shard count now follows its cell's CPU limit, but I couldn't measure peak cores before and after. The sandbox can't run the check cell, so the pull has no run numbers. `tsc --noEmit` and `test/shards.test.ts` pass here. The full check hasn't run, and its log will show the new peak.
shipped production is serving it deploy fc82d1a
The check's shard count now follows its cell's CPU limit, but I couldn't measure peak cores before and after. The sandbox can't run the check cell, so the pull has no run numbers. tsc --noEmit and test/shards.test.ts pass here. The full check hasn't run, and its log will show the new peak.
- Env var:
src/checks/service.tsnow gives the checkFORGE_CELL_CPUS, the cell's CPU limit fromforge.json's check limits (16 today), alongside the other check env. - Shard count:
shardCountinscripts/shards.tstakes an optionalcellCpusargument. The count is min(limit − 1,SHARDS_MAX, memory bound, file count), and at least 1. With the var unset, empty or not a whole number from 1, it behaves as before.scripts/test-shards.tspassesprocess.env["FORGE_CELL_CPUS"]in. - Why one less than the limit: the runner process needs a core of its own, and the guard kills a check that uses more than its limit.
- Expected effect: on a host reporting 80 CPUs with a 16-CPU cell, the shards drop from
SHARDS_MAXto 15. That should leave the peak under 16 cores instead of the 16.1 the guard killed. - Tests: a new case in
test/shards.test.tscoversFORGE_CELL_CPUS=4giving 3 workers on an 80-CPU host, the file-count and memory caps, and unset, empty or garbage values leaving the count unchanged.
I did not touch the "two forges in one process" test (the low-disk failure #2248 fixes).
The shardCount logic is right and well tested: min(limit-1, SHARDS_MAX, memory, files), floored at 1, and unset, empty or garbage input leaves the count as before. The limit is read from the same resolveLimits("step", manifest.limits) the cell is started with, so the guard and the shard count agree. This is CI-only, with no page or terminal change, so I judged it by reading the code.
One miss against the tests rule: the wiring has no test. If the FORGE_CELL_CPUS line in src/checks/service.ts were deleted, or scripts/test-shards.ts stopped passing process.env["FORGE_CELL_CPUS"], every test would still pass. That wiring is the whole fix, because the pure function already existed. Fix first: add a test in the checks service suite that the env handed to a check step contains FORGE_CELL_CPUS equal to resolveLimits("step", limits).cpus. Cover the script side too, by extracting the env-to-count step or running the script with the variable set. Then the change cannot silently revert.
Smaller point: FORGE_CHECK_SHARDS still overrides the cell cap. That is reasonable as an explicit operator choice. Say so in the doc comment so nobody is surprised.
Both wiring points now have tests, and the doc comment says what you asked. tsc --noEmit, test/shards.test.ts and test/check-tiers.test.ts pass here. The full check hasn't run.
- Service side: a new test in
test/check-tiers.test.tscommits aforge.jsonwithcheck.limits.cpus: 3and a fast command that echoes$FORGE_CELL_CPUS. It opens a pull and asserts the check log showsresolveLimits("step", { cpus: 3 }).cpus. I commented out theFORGE_CELL_CPUSline insrc/checks/service.tsand the test failed; with the line restored it passes. - Script side: the env reading moved into
shardCountFromEnv(env, cpus, files, memory)inscripts/shards.ts. It readsFORGE_CHECK_SHARDSandFORGE_CELL_CPUS, andscripts/test-shards.tsnow calls it withprocess.env.test/shards.test.tscoversFORGE_CELL_CPUS=4giving 3 workers, no variable givingSHARDS_MAX, andFORGE_CHECK_SHARDSoverriding the cap. - Override doc: the
shardCountcomment now saysFORGE_CHECK_SHARDSis an explicit operator choice and wins over the cell cap.
The call in scripts/test-shards.ts is still one line that no test exercises. Dropping process.env from it would not fail a test. Running the whole script in a test would be too heavy for that one line, so I left it.
Peak cores before and after are still unmeasured, as in the first description. The check's own log will show the after number.
No page, phone or keyboard surface changes. This is check plumbing, so I judged it on the diff. The cell CPU limit reaches the check env, the shard count stays one below it, and an explicit FORGE_CHECK_SHARDS still wins. Unset or garbage values behave as before. Input is validated with a strict regex, and the service-side test would fail without the env line. Two things I would do next: (1) have a test cover the shardCountFromEnv call in scripts/test-shards.ts, so dropping process.env there fails something; the check log is the only evidence until then; (2) read the peak-core number from the first check log after landing and record it on #2257 to confirm the guard no longer trips.
The check's shard count now follows its cell's CPU limit, but I couldn't measure peak cores before and after. The sandbox can't run the check cell, so the pull has no run numbers.
tsc --noEmitandtest/shards.test.tspass here. The full check hasn't run, and its log will show the new peak.src/checks/service.tsnow gives the checkFORGE_CELL_CPUS, the cell's CPU limit fromforge.json's check limits (16 today), alongside the other check env.shardCountinscripts/shards.tstakes an optionalcellCpusargument. The count is min(limit − 1,SHARDS_MAX, memory bound, file count), and at least 1. With the var unset, empty or not a whole number from 1, it behaves as before.scripts/test-shards.tspassesprocess.env["FORGE_CELL_CPUS"]in.SHARDS_MAXto 15. That should leave the peak under 16 cores instead of the 16.1 the guard killed.test/shards.test.tscoversFORGE_CELL_CPUS=4giving 3 workers on an 80-CPU host, the file-count and memory caps, and unset, empty or garbage values leaving the count unchanged.I did not touch the "two forges in one process" test (the low-disk failure #2248 fixes).
Closes #2257