Adding tests to any file re-assigns every shard, so a PR that changes only the test count can move two slow files into one bucket and push that bucket past the job ceiling. This happened on a PR branch, recovered on a re-run, and main has about five minutes of headroom, so it can happen again to whoever adds tests next.
Recording the measurements first. The conclusion is deliberately left open.
What was measured
1. The buckets are a function of the head, so a shard number is not a stable name for a piece of work.
.github/scripts/shard-tests.sh partitions *.bats by test count (greedy LPT). Derived with that script on each head, for the two slowest files:
| head |
test_remote_sync.bats |
test_sqlite_sync_jq_binary.bats |
4c448cb195aafd7991b373847797154403419fae (main) |
shard 2/4 |
shard 1/4 — split |
87d91e1a208b3d3c3a7725b6693b857bef104345 (a PR branch) |
shard 2/4 |
shard 2/4 — together |
The branch adds fifteen test cases to one file (test_roster_journal.bats, which lands in shard 3/4 on that head). That is the whole input change: nothing about the two files above is touched.
2. The bucket that got both of them exceeded the ceiling, and then did not.
|
duration |
outcome |
branch, bats (macos-latest 2/4), attempt 1 |
25m22s |
cancelled at the job ceiling |
branch, bats (macos-latest 2/4), attempt 2 |
23m37s |
success |
The cancelled attempt reported its last test ok twelve seconds before the cancellation, so it was still running normally when the ceiling arrived — not stuck.
3. main is already close to the ceiling.
macOS shards on main at 121d27bb9e7f1c2af8fb0813e90359209691b408's predecessor run:
11m05s 1/4
9m15s 2/4
20m02s 3/4 <- about five minutes of headroom
11m33s 4/4
And on the branch: 11m21s / 25m22s / 10m48s / 14m05s.
What follows, and what does not
- Not established: that the added cases are themselves expensive enough to matter. They are in a different shard, which finished in 10m48s. Their own runtime is not the cost.
- Established: the changed test count moved the partition, and the partition put the two slowest files together.
- Established: balancing by count does not bound duration. Nothing in the current scheme notices that one file takes twenty minutes and another takes twenty seconds.
So the trigger is any PR that changes how many tests exist — which is most of them.
Candidates, not a decision
Listing these separately because picking between them needs measurement this issue does not have:
- Weight the partition by recorded duration rather than by test count. Needs a source of timings and a decision about where they live.
- Pin the known slow files apart, as an explicit rule rather than as an accident of counting.
- Raise the job ceiling. Cheapest, and it does not stop the buckets from drifting further apart.
A useful first step for any of them is publishing per-shard durations alongside the file list each run, so the next occurrence is measurable rather than reconstructed.
Reproducing the derivation
bash .github/scripts/shard-tests.sh <n> 4 # on each head, for n in 1..4
Comparing shard numbers across heads without deriving the membership will mislead: the same number denotes different files on different commits.
Adding tests to any file re-assigns every shard, so a PR that changes only the test count can move two slow files into one bucket and push that bucket past the job ceiling. This happened on a PR branch, recovered on a re-run, and
mainhas about five minutes of headroom, so it can happen again to whoever adds tests next.Recording the measurements first. The conclusion is deliberately left open.
What was measured
1. The buckets are a function of the head, so a shard number is not a stable name for a piece of work.
.github/scripts/shard-tests.shpartitions*.batsby test count (greedy LPT). Derived with that script on each head, for the two slowest files:test_remote_sync.batstest_sqlite_sync_jq_binary.bats4c448cb195aafd7991b373847797154403419fae(main)87d91e1a208b3d3c3a7725b6693b857bef104345(a PR branch)The branch adds fifteen test cases to one file (
test_roster_journal.bats, which lands in shard 3/4 on that head). That is the whole input change: nothing about the two files above is touched.2. The bucket that got both of them exceeded the ceiling, and then did not.
bats (macos-latest 2/4), attempt 1bats (macos-latest 2/4), attempt 2The cancelled attempt reported its last test
oktwelve seconds before the cancellation, so it was still running normally when the ceiling arrived — not stuck.3.
mainis already close to the ceiling.macOS shards on
mainat121d27bb9e7f1c2af8fb0813e90359209691b408's predecessor run:And on the branch:
11m21s / 25m22s / 10m48s / 14m05s.What follows, and what does not
So the trigger is any PR that changes how many tests exist — which is most of them.
Candidates, not a decision
Listing these separately because picking between them needs measurement this issue does not have:
A useful first step for any of them is publishing per-shard durations alongside the file list each run, so the next occurrence is measurable rather than reconstructed.
Reproducing the derivation
Comparing shard numbers across heads without deriving the membership will mislead: the same number denotes different files on different commits.