@@ -50,6 +50,24 @@ function median(nums) {
5050 return sorted . length % 2 ? sorted [ mid ] : ( sorted [ mid - 1 ] + sorted [ mid ] ) / 2 ;
5151}
5252
53+ // Stable per-package offset (derived from the package dir) so each package's heaviest file - which
54+ // LPT always drops into bin 0 - maps to a DIFFERENT shard. Without it, a serial multi-package job
55+ // (`turbo --concurrency=1 --filter "@internal/*"`) stacks every package's heaviest file into shard 1.
56+ // It's a rotation of the bin->shard mapping, so coverage stays exact (each file runs once).
57+ function packageOffset ( specs , count ) {
58+ if ( specs . length === 0 ) return 0 ;
59+ const rel = path . relative ( REPO_ROOT , specs [ 0 ] . moduleId ) ;
60+ const key = rel . split ( path . sep ) . slice ( 0 , 2 ) . join ( "/" ) ;
61+ // FNV-1a - spreads similar sibling package names (e.g. internal-packages/*) far better than a
62+ // simple polynomial hash mod count, which collided run-engine + schedule-engine onto one shard.
63+ let h = 2166136261 ;
64+ for ( let i = 0 ; i < key . length ; i ++ ) {
65+ h ^= key . charCodeAt ( i ) ;
66+ h = Math . imul ( h , 16777619 ) ;
67+ }
68+ return ( h >>> 0 ) % count ;
69+ }
70+
5371/**
5472 * Duration-weighted interpretation of `--shard=i/N`. Instead of vitest's default file-count split,
5573 * this greedily bin-packs test files by recorded duration (test-timings.json at the repo root;
@@ -103,7 +121,8 @@ class DurationShardingSequencer {
103121 lightest . specs . push ( spec ) ;
104122 }
105123
106- return bins [ shard . index - 1 ] . specs ;
124+ const offset = packageOffset ( specs , shard . count ) ;
125+ return bins [ ( shard . index - 1 + offset ) % shard . count ] . specs ;
107126 }
108127}
109128
0 commit comments