The `full test (windows-latest, *)` lane ran the entire unit suite (~740+
files) in one job whose wall-clock crept against the 20m cap and intermittently
CANCELLED (false-negative gate, observed on PR #1207). Prior tactical fixes
#869 (15→20m bump) and #1051 (handle-leak) deferred the cliff structurally.
Shard the unit suite across 3 parallel runners per OS/node leg so per-job
wall-clock is O(total/3) and stays under the cap as the suite grows.
- scripts/run-tests.cjs: add `--shard <i>/<n>` — a deterministic, balanced
round-robin partition (fileIndex % n === i-1) over the SORTED selected file
list. parseShardArg strictly validates i∈1..n, n≥1, integer-only; n=1 is a
pure no-op. The 28K Windows argv chunking is preserved within each shard. A
legitimately-empty shard (n > file count) exits 0; a selection empty BEFORE
sharding still hits the discovery hard error. Composes with --suite and is
order-independent (sorted before partition). Exports selectShard/parseShardArg.
- .github/workflows/test.yml: test-full becomes the 3 legs × 3 shards = 9-job
cross-product (explicit include rows — a base shard dim does not cross-product
with include legs, and a nested matrix.leg.os is unresolvable by the H1
shell-policy linter). Unit suite runs sharded; integration/security run once
per leg (shard 1). The Required tests fan-in is unchanged: it already needs
test-full and checks the matrix-aggregate result, so a failed/cancelled shard
fails the gate; the branch-protection check name is preserved.
- tests: partition/CLI + pure selectShard contract (completeness, disjointness,
balance, determinism, boundaries, fast-check property) + parseShardArg
validation, in run-tests-harness.test.cjs; a DEFECT.GENERATIVE-FIX parity
guard (per-row shard values 1..N, every leg runs all shards, N == --shard /N
denominator) + Required-tests name/needs pin, in ci-test-scope.test.cjs.
Closes#1212
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>