Skip to content

ci(oracles): run the framework self-oracle and the e2e fixed seed as two jobs each - #38

Merged
KyleAMathews merged 2 commits into
mainfrom
ci/shard-slow-jobs
Nov 12, 2026
Merged

KyleAMathews merged 2 commits into
mainfrom
ci/shard-slow-jobs

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

The workflow's critical path grew from about 8 minutes to 14 to 20 minutes in CI over the last three merges. The maintainer's limit is 10 minutes. This change splits the two slowest jobs, the framework self-oracle and the end-to-end oracle's fixed seed, into two parallel jobs each. Vitest 5's self-oracle job splits the same way. No test is dropped: a check proves that the shards together run exactly the tests that one job ran before.

Where the time went

CI job times on main and on pull requests, in minutes:

commit framework self-oracle e2e fixed seed fast gap oracles
49f3bd1 era (2026-11-11) 8:12 5:21 3:39
d38af38 (#35, units) 10:26 5:29 4:39
7dc3639 (#36) 14:41, rerun 11:44 9:01 6:22
9c18836 (#37 pull request) 13:50 10:44 4:35
908b1f9 (#37 on main) 15:12 19:54 7:55

The same code gives different CI times. #36 did not touch the framework's code or the self-oracle, and a rerun of its self-oracle job took 11:44 against 14:41. The fast gap job took 7:55 on 908b1f9 against 4:35 on its pull request. So part of the growth is runner variance. To separate real cost from variance, I measured each suite locally, under the e2e lock, at each commit:

The shards

packages/oracles/scripts/pr-shards.mjs names two partitions:

  • oracle-framework: the first shard takes the determinism units, except the slowest (61 s). The second shard takes the rest. The measured costs are 322 s and 266 s.
  • oracle-gaps-fixed-seed: the first shard takes the five fixed-seed units that cost most at 908b1f9. The second shard takes the rest. The measured costs are 168 s and 157 s.

node scripts/pr-shards.mjs check lists each suite's tests with vitest list, and the Test job runs it. It fails in these cases:

  • a selected test is in no shard or in two shards
  • another test is in a shard
  • the shards select a different set than the old job's -t "fixed seed"
  • a named exception no longer exists

A new test goes to the rest shard, so the shards' balance can drift, but CI never leaves a test out.

vitest list -t "<pattern>" selects 149 and 150 framework tests, 299 in all. It selects 5 and 26 e2e units, 31 in all, the same as -t "fixed seed". The check rejected three wrong partitions. In the first, the old pattern selected a test that the shards do not. In the second, two shards overlap. The third names a missing exception.

Measured shard times

Locally, at a load average of about 4, each shard ran as the workflow runs it:

shard local time
framework 1/2 287 s
framework 2/2 240 s
e2e fixed seed 1/2 150 s
e2e fixed seed 2/2 145 s

CI took 1.0 to 1.5 times the local time for the self-oracle and 1.7 to 2.5 times for the e2e. With about 20 s of setup, the framework shards would take 5 to 7.5 minutes. The e2e shards would take 4.5 to 6.5 minutes. The real numbers come from this pull request's run.

The first CI run, and a Vitest 5 defect it found

The first run (43170624412) passed every job, with these times:

job time
Framework self-oracle 1/2 6:00
Framework self-oracle 2/2 6:12
e2e fixed seed 1/2 6:02
e2e fixed seed 2/2 5:14
Gap report oracles 6:42
Vitest 5 framework 1 6:46
Vitest 5 framework 2 9:50

The second Vitest 5 framework job ran all 299 tests, not its 150. Vitest 5 joins a suite's name and a test's name with >. The pattern's separator accepted a space or >. In a Vitest 5 name, the space before > matched, and the rest shard's negative lookahead then passed on > determinism: ….

The check missed this. It counted a shard as an owner only when the shard selected both joins. The fix has two parts:

  • A space followed by > is no separator now.
  • The check now counts a shard that selects either join as an owner. It requires exactly one owner, and that owner must select both joins. With the old separator, this check reports framework tests "in shards 1, 2".

A probe file holds every listed test name with an empty body. Under Vitest 4.1.12 and 5.1.0 alike, the patterns select 149 and 150 framework tests and 5 and 26 fixed-seed units. scripts/e2e-shards.mjs gets the same check and separator.

The run after the fix

The second run (43172279755) passed every job. Its critical path was 8:35, the first framework shard:

job time
Framework self-oracle 1/2 8:35
Framework self-oracle 2/2 5:11
e2e fixed seed 1/2 4:08
e2e fixed seed 2/2 7:37
Gap report oracles 8:14
Vitest 5 framework 1 6:52
Vitest 5 framework 2 (150 tests) 4:27

Runner variance is large. The same shard took 6:00 in the first run and 8:35 in the second. The fast gap job, which this change leaves as it is, took 6:42 and then 8:14. So on a slow runner it is now as long as the longest shard.

The workflow gains three jobs: one framework shard, one e2e shard, and one Vitest 5 framework shard. Each matrix job passes its shard through an environment variable.

This pull request and its description were written by Isaac.

…two jobs each

The framework self-oracle (299 tests since #35) and the end-to-end
oracle's fixed-seed units each set the workflow's critical path at about
10 to 15 minutes in CI. Each now runs as two jobs, and Vitest 5's
self-oracle job as two too. scripts/pr-shards.mjs names the shards: one
by a pattern over test names, the other the rest. Its check, which the
Test job runs, lists each suite's tests and fails unless the shards
together select exactly the tests one job selected before (for the e2e,
the tests that -t "fixed seed" selects).

Locally, at load average 4, the shards take 287 s and 240 s (framework,
589 s as one job at load 10) and 150 s and 145 s (e2e, 325 s as one).

Co-authored-by: Isaac <no-reply@databricks.com>
@changeset-bot

changeset-bot Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b28da9d

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 33005c9d-914d-46e8-9dd0-b1b55b23816a
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@pkg-pr-new

pkg-pr-new Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/TanStack/oracles/@tanstack/eslint-plugin-oracles@38
npm i https://pkg.pr.new/TanStack/oracles/@tanstack/oracles@38

commit: b28da9d

Vitest 5 joins a suite's name and a test's with ` > `. The pattern's
separator accepted a space or ` > `, so in a Vitest 5 name the space
before `> ` matched, and the rest shard's negative lookahead then passed
on `> determinism: …`: the second Vitest 5 framework job ran all 299
tests (570 s). A space followed by `> ` is now no separator. The check
missed it because it required a shard to select both joins; it now takes
any shard that selects either join as an owner and requires exactly one
owner that selects both, which reports the old separator. A probe of
every listed name under Vitest 4.1.12 and 5.1.0 selects 149 and 150
framework tests and 5 and 26 fixed-seed units under both.

Co-authored-by: Isaac <no-reply@databricks.com>
@KyleAMathews
KyleAMathews merged commit daa3a00 into main Nov 12, 2026
16 checks passed
@KyleAMathews
KyleAMathews deleted the ci/shard-slow-jobs branch November 12, 2026 07:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant