diff --git a/.github/reviews/speed-up-local-test-runner.receipt.json b/.github/reviews/speed-up-local-test-runner.receipt.json new file mode 100644 index 0000000..317f742 --- /dev/null +++ b/.github/reviews/speed-up-local-test-runner.receipt.json @@ -0,0 +1,96 @@ +{ + "schema_version": 1, + "instance": "speed-up-local-test-runner", + "program": { + "id": "boatstack-reviewer", + "version": "1", + "fingerprint": "76680abd47f9e920ebfe807d3b3f226cbb48bd1a531b0a0a068cd27fd3e6f6e6" + }, + "policy": { + "prompt_path": ".github/codex/review-prompt.md", + "prompt_sha256": "66c4c7111f200de489f4fed0852b261e36cbd1e962c61320c1e4ea2dd2641986", + "schema_path": ".github/codex/review-output-schema.json", + "schema_sha256": "113b02c5cca93156692031c3dedd038e5c2b80cbc4a56337ce06e536110e3e6a", + "max_rounds": 16, + "stall_window": 3, + "weights": [ + 1000, + 100, + 10, + 1 + ] + }, + "base_ref": "origin/main", + "merge_base": "1cb20b6862d34831898037792c1eea06cfdd0122", + "head_commit": "b27992fb3c827ad22041e70f667082295ba36220", + "reviewed_tree": "d0705c1c64d482191bec8c9d5a957dec98979569", + "generation": 1, + "rounds": [ + { + "generation": 1, + "index": 1, + "candidate_fingerprint": "32fc0219bbe4164255b3fa328a515883b1377db4f032d9d27a015c9fdb2718e3", + "reviewed_tree": "d0705c1c64d482191bec8c9d5a957dec98979569", + "head_commit": "b27992fb3c827ad22041e70f667082295ba36220", + "merge_base": "1cb20b6862d34831898037792c1eea06cfdd0122", + "verdict": "patch is correct", + "measure": 0, + "finding_count": 0, + "priorities": [ + 0, + 0, + 0, + 0 + ], + "transition": "review.converge" + } + ], + "final_review": { + "findings": [], + "overall_correctness": "patch is correct", + "overall_explanation": "The patch changes only the local test runner (.github/scripts/run_go_tests.py, ci_shard.py), its unit tests, and adds a release note; no Boatstack kernel, control-program, or CI-workflow behavior changes. Reviewed to closure: (1) package attribution in read_test_packages depends on go test printing each package's -list block contiguously, which the go tool guarantees via per-package output buffering; a ? [no test files] block cannot split another package's names from its ok line. (2) Tests with the same name in multiple packages keep every owner and the shard scope is the union, so scoping cannot drop an owner that ./... would have run. (3) verified_package_scope fails closed: an enumerated test with no owning package or outside its shard scope refuses the run before any worker spawns, and both the rejecting and accepting directions have unit tests. (4) LPT weights are strictly positive (load_timings filters v\u003e0, default weight 1.0) and shard count is capped at len(names), so no shard can be empty; an empty regex additionally refuses. (5) Timings persistence goes to the user cache with atomic os.replace, degrades to count-balancing on missing or malformed data, and the runner is local-only so CI never touches it; the Windows CI path through read_test_names is byte-identical. (6) -count=1, the jobs cap, and process isolation are unchanged, so fresh execution and seam isolation invariants hold. Questions for model-level verification (not defects): none newly reachable; the runner state machine gains only a refusing pre-spawn gate, which cannot introduce a blocking state because refusal exits the run. Model-level verification before merge is not required.", + "overall_confidence_score": 0.85 + }, + "control_state": { + "mode": "converged", + "revision": 3 + }, + "kernel_receipts": [ + { + "schema_version": 3, + "id": "rcp-a2307a2aed0e2372749a7022830a74b324476865ce91018533379e28d56cbe6e", + "instance_id": "speed-up-local-test-runner", + "prescription_id": "prx-76a2977343c8aee6ee7bf0368087461caf9c2b457bfe8a55588b62d8fb58df57", + "program": { + "id": "boatstack-reviewer", + "version": "1", + "fingerprint": "76680abd47f9e920ebfe807d3b3f226cbb48bd1a531b0a0a068cd27fd3e6f6e6" + }, + "transition_id": "review.converge", + "prior_state_revision": 1, + "attempt_state_revision": 2, + "result_state_revision": 3, + "authority_fingerprint": "38a1c3289b7f87426b560c99da0f3734b2a379475db8a915ab55d82f9bbd3846", + "capabilities": [ + "review.submit" + ], + "effects": [ + { + "facet": "review.round", + "operation": "review.converge", + "fingerprint": "32fc0219bbe4164255b3fa328a515883b1377db4f032d9d27a015c9fdb2718e3" + } + ], + "prior_observation": "5611ccc070fff3754879649c3522b8280ad0243ba86b9b00ea2c0739e7fd4a41", + "result_observation": "6a7c27ba3f797fcb50d94824e5fe8068d2763b960dbdccdbbbf671db3e2ff487", + "verification": "satisfied", + "committed_at": "2026-08-21T04:25:28.501588Z" + } + ], + "honesty": { + "semantic_correctness": "not-evaluated", + "origin_authenticity": "not-proven" + }, + "sealed_at": "2026-08-21T04:26:27.391146Z", + "fingerprint": "d857c5f2ec72e78388ec491979890ee82f34ad5a7d627d7dbd6d270c506662e6" +} diff --git a/.github/scripts/ci_shard.py b/.github/scripts/ci_shard.py index 905e5a4..be5a90f 100644 --- a/.github/scripts/ci_shard.py +++ b/.github/scripts/ci_shard.py @@ -51,6 +51,10 @@ # beginning with "Test"; keep only those. TEST_NAME = re.compile(r"^Test[A-Za-z0-9_]*$") +# The per-package summary line that follows that package's test names. +# Packages without test files print "? [no test files]" instead. +PACKAGE_SUMMARY = re.compile(r"^ok\s+(\S+)") + def read_test_names(stream) -> list[str]: """Parse `go test -list` output from a stream into a sorted, de-duped list.""" @@ -62,6 +66,32 @@ def read_test_names(stream) -> list[str]: return sorted(names) +def read_test_packages(stream) -> dict[str, tuple[str, ...]]: + """Parse `go test -list` output into a test-name -> owning-packages mapping. + + `go test -list ./...` interleaves each package's test names with that + package's trailing "ok " summary line, so names are attributed + to the next summary line seen. A name can legitimately exist in more than + one package; every owner is kept (sorted, de-duped). Names never followed + by a package summary are dropped — callers that need completeness must + verify the mapping covers their enumeration and fail closed on a gap. + """ + owners: dict[str, set[str]] = {} + pending: list[str] = [] + for line in stream: + stripped = line.strip() + if TEST_NAME.match(stripped): + pending.append(stripped) + continue + summary = PACKAGE_SUMMARY.match(stripped) + if summary: + package = summary.group(1) + for name in pending: + owners.setdefault(name, set()).add(package) + pending = [] + return {name: tuple(sorted(packages)) for name, packages in owners.items()} + + def assign_shards(names: list[str], total: int, timings: dict[str, float]) -> list[list[str]]: """Partition `names` into `total` shards via LPT greedy on estimated cost. diff --git a/.github/scripts/run_go_tests.py b/.github/scripts/run_go_tests.py index 7f76400..3acc938 100644 --- a/.github/scripts/run_go_tests.py +++ b/.github/scripts/run_go_tests.py @@ -5,7 +5,9 @@ import argparse import io +import json import os +import re import subprocess import sys import tempfile @@ -21,6 +23,13 @@ RUNTIME = REPO / "boatstack" MAX_DEFAULT_JOBS = 10 +# Top-level test verdicts in `go test -v` output; subtests are indented and +# deliberately excluded — shards are balanced on top-level names only. +TOP_LEVEL_RESULT = re.compile(r"^--- (?:PASS|FAIL): (Test[A-Za-z0-9_]*) \((\d+(?:\.\d+)?)s\)") + +# `go test -v` narration that carries no failure signal. +VERBOSE_NOISE = re.compile(r"^(=== (?:RUN|PAUSE|CONT|NAME)\s|--- PASS: |PASS$)") + class RunnerError(RuntimeError): """A deterministic local-test precondition or worker failed.""" @@ -42,11 +51,16 @@ def default_jobs() -> int: return min(MAX_DEFAULT_JOBS, cpu_aware_jobs) +def default_timings_path() -> Path: + return Path.home() / ".cache" / "boatstack" / "test-timings.json" + + def list_top_level_tests( runtime: Path = RUNTIME, *, run: Callable[..., subprocess.CompletedProcess[str]] = subprocess.run, -) -> list[str]: +) -> tuple[list[str], dict[str, tuple[str, ...]]]: + """Enumerate top-level tests and the packages that own each of them.""" completed = run( ["go", "test", "-list", "^Test", "./..."], cwd=runtime, @@ -59,21 +73,58 @@ def list_top_level_tests( names = ci_shard.read_test_names(io.StringIO(completed.stdout)) if not names: raise RunnerError("test enumeration returned no top-level tests") - return names + packages_by_test = ci_shard.read_test_packages(io.StringIO(completed.stdout)) + return names, packages_by_test -def verified_partition(names: list[str], jobs: int) -> list[list[str]]: +def verified_partition( + names: list[str], jobs: int, timings: dict[str, float] | None = None +) -> list[list[str]]: if jobs < 1: raise RunnerError("--jobs must be at least 1") if not names: raise RunnerError("cannot partition an empty test set") - shards = ci_shard.assign_shards(names, min(jobs, len(names)), {}) + shards = ci_shard.assign_shards(names, min(jobs, len(names)), timings or {}) assigned = [name for shard in shards for name in shard] if sorted(assigned) != sorted(names) or len(assigned) != len(set(assigned)): raise RunnerError("shards do not partition the enumerated tests exactly") return shards +def verified_package_scope( + shards: list[list[str]], packages_by_test: dict[str, tuple[str, ...]] +) -> list[list[str]]: + """Compute each shard's owning-package list, refusing on any coverage gap. + + Every enumerated test must map to at least one package, and every owning + package of every test must be in that shard's scope — otherwise a scoped + `go test` invocation could silently skip an enumerated test. + """ + scopes: list[list[str]] = [] + for index, shard in enumerate(shards): + packages: set[str] = set() + for name in shard: + owners = packages_by_test.get(name, ()) + if not owners: + raise RunnerError( + f"test {name!r} has no owning package in the enumeration; " + "refusing to run a scoped shard that could skip it" + ) + packages.update(owners) + scope = sorted(packages) + missing = [ + name + for name in shard + if not set(packages_by_test[name]).issubset(packages) + ] + if missing: + raise RunnerError( + f"shard {index} scope does not cover tests: {', '.join(missing)}" + ) + scopes.append(scope) + return scopes + + def stop_processes(processes: Sequence[subprocess.Popen], timeout: float = 2.0) -> None: active = [process for process in processes if process.poll() is None] for process in active: @@ -98,18 +149,23 @@ def run_shards( runtime: Path = RUNTIME, *, popen: Callable[..., subprocess.Popen] = subprocess.Popen, + package_scopes: list[list[str]] | None = None, ) -> list[ShardResult]: workers: list[tuple[int, list[str], subprocess.Popen, object, float]] = [] + finished_at: dict[int, float] = {} try: for index, shard in enumerate(shards): regex = ci_shard.shard_regex(shard) if not regex: raise RunnerError(f"refusing to run empty shard {index}") + scope = package_scopes[index] if package_scopes else ["./..."] + if not scope: + raise RunnerError(f"refusing to run shard {index} with an empty package scope") output = tempfile.TemporaryFile(mode="w+t", encoding="utf-8") started = time.monotonic() try: process = popen( - ["go", "test", "-count=1", "-run", regex, "./..."], + ["go", "test", "-count=1", "-v", "-run", regex, *scope], cwd=runtime, stdout=output, stderr=subprocess.STDOUT, @@ -120,7 +176,13 @@ def run_shards( raise workers.append((index, shard, process, output, started)) - while any(process.poll() is None for _, _, process, _, _ in workers): + while True: + now = time.monotonic() + for index, _, process, _, _ in workers: + if index not in finished_at and process.poll() is not None: + finished_at[index] = now + if len(finished_at) == len(workers): + break time.sleep(0.05) except BaseException: stop_processes([process for _, _, process, _, _ in workers]) @@ -139,13 +201,64 @@ def run_shards( index=index, test_count=len(shard), returncode=process.returncode, - elapsed_seconds=time.monotonic() - started, + elapsed_seconds=finished_at.get(index, time.monotonic()) - started, output=value, ) ) return results +def parse_test_durations(output: str) -> dict[str, float]: + """Extract top-level per-test seconds from one shard's `go test -v` output.""" + durations: dict[str, float] = {} + for line in output.splitlines(): + match = TOP_LEVEL_RESULT.match(line) + if match: + durations[match.group(1)] = float(match.group(2)) + return durations + + +def load_timings(path: Path, names: list[str]) -> dict[str, float]: + """Read persisted per-test seconds, keeping only currently enumerated tests. + + Missing, malformed, or foreign entries degrade to nothing: LPT then weighs + those tests at 1.0, exactly the pre-timings behavior. + """ + try: + raw = json.loads(path.read_text(encoding="utf-8")) + except (OSError, ValueError): + return {} + if not isinstance(raw, dict): + return {} + current = set(names) + timings: dict[str, float] = {} + for key, value in raw.items(): + if key in current and isinstance(value, (int, float)) and value > 0: + timings[str(key)] = float(value) + return timings + + +def save_timings(path: Path, timings: dict[str, float]) -> None: + """Persist per-test seconds atomically; failure to persist never fails the run.""" + try: + path.parent.mkdir(parents=True, exist_ok=True) + with tempfile.NamedTemporaryFile( + mode="w", encoding="utf-8", dir=path.parent, delete=False + ) as handle: + json.dump(dict(sorted(timings.items())), handle, indent=1) + handle.write("\n") + staging = Path(handle.name) + os.replace(staging, path) + except OSError as error: + print(f"warning: could not persist test timings: {error}", file=sys.stderr) + + +def failure_display(output: str) -> str: + """Strip `go test -v` pass narration so a failed shard shows its signal.""" + kept = [line for line in output.splitlines() if not VERBOSE_NOISE.match(line)] + return "\n".join(kept) + + def positive_int(value: str) -> int: parsed = int(value) if parsed < 1: @@ -161,17 +274,26 @@ def main(argv: list[str] | None = None) -> int: default=default_jobs(), help=f"isolated test processes (default: about seven of ten CPUs, up to {MAX_DEFAULT_JOBS})", ) + parser.add_argument( + "--timings-file", + type=Path, + default=default_timings_path(), + help="per-test seconds persisted between runs to balance shards (never in the repo)", + ) args = parser.parse_args(argv) started = time.monotonic() try: - names = list_top_level_tests() - shards = verified_partition(names, args.jobs) + names, packages_by_test = list_top_level_tests() + timings = load_timings(args.timings_file, names) + shards = verified_partition(names, args.jobs, timings) + package_scopes = verified_package_scope(shards, packages_by_test) + balanced = f"{len(timings)} of {len(names)} tests have measured weights" print( - f"Running {len(names)} tests across {len(shards)} isolated shards.", + f"Running {len(names)} tests across {len(shards)} isolated shards ({balanced}).", flush=True, ) - results = run_shards(shards) + results = run_shards(shards, package_scopes=package_scopes) except KeyboardInterrupt: print("Interrupted; all local test shards were stopped.", file=sys.stderr) return 130 @@ -179,6 +301,11 @@ def main(argv: list[str] | None = None) -> int: print(f"ERROR: {error}", file=sys.stderr) return 2 + measured: dict[str, float] = dict(timings) + for result in results: + measured.update(parse_test_durations(result.output)) + save_timings(args.timings_file, {k: v for k, v in measured.items() if k in set(names)}) + failed = False for result in sorted(results, key=lambda item: item.index): label = "PASS" if result.returncode == 0 else "FAIL" @@ -189,7 +316,7 @@ def main(argv: list[str] | None = None) -> int: if result.returncode != 0: failed = True if result.output: - print(result.output.rstrip(), file=sys.stderr) + print(failure_display(result.output).rstrip(), file=sys.stderr) elapsed = time.monotonic() - started if failed: diff --git a/.github/tests/test_run_go_tests.py b/.github/tests/test_run_go_tests.py index cd8f993..207c6b7 100644 --- a/.github/tests/test_run_go_tests.py +++ b/.github/tests/test_run_go_tests.py @@ -1,7 +1,9 @@ from __future__ import annotations import io +import json import sys +import tempfile import unittest from pathlib import Path from unittest import mock @@ -82,6 +84,55 @@ def failed_run(*_args, **_kwargs): with self.assertRaisesRegex(run_go_tests.RunnerError, "compile failed"): run_go_tests.list_top_level_tests(run=failed_run) + # control-law: complete-local-test-partition. + def test_enumeration_maps_every_test_to_its_owning_package(self): + listing = ( + "TestAlpha\n" + "TestBeta\n" + "ok \texample.com/mod/first\t0.01s\n" + "? \texample.com/mod/none\t[no test files]\n" + "TestGamma\n" + "ok \texample.com/mod/second\t0.02s\n" + ) + + def listed_run(*_args, **_kwargs): + return Completed(0, stdout=listing) + + names, packages = run_go_tests.list_top_level_tests(run=listed_run) + self.assertEqual(names, ["TestAlpha", "TestBeta", "TestGamma"]) + self.assertEqual( + packages, + { + "TestAlpha": ("example.com/mod/first",), + "TestBeta": ("example.com/mod/first",), + "TestGamma": ("example.com/mod/second",), + }, + ) + + # control-law: complete-local-test-partition. + def test_scoped_shards_refuse_tests_without_an_owning_package(self): + shards = [["TestAlpha", "TestOrphan"]] + packages = {"TestAlpha": ("example.com/mod/first",)} + with self.assertRaisesRegex(run_go_tests.RunnerError, "TestOrphan"): + run_go_tests.verified_package_scope(shards, packages) + + # control-law: complete-local-test-partition. + def test_shard_scope_is_the_union_of_owning_packages(self): + shards = [["TestAlpha", "TestGamma"], ["TestBeta"]] + packages = { + "TestAlpha": ("example.com/mod/first",), + "TestBeta": ("example.com/mod/first", "example.com/mod/second"), + "TestGamma": ("example.com/mod/second",), + } + scopes = run_go_tests.verified_package_scope(shards, packages) + self.assertEqual( + scopes, + [ + ["example.com/mod/first", "example.com/mod/second"], + ["example.com/mod/first", "example.com/mod/second"], + ], + ) + # control-law: complete-local-test-partition. def test_every_partition_reaches_one_isolated_worker(self): commands = [] @@ -91,19 +142,34 @@ def launch(command, **kwargs): return ImmediateProcess(command, **kwargs) names = ["TestAlpha", "TestBeta", "TestGamma", "TestDelta"] + packages = {name: ("example.com/mod/only",) for name in names} shards = run_go_tests.verified_partition(names, 3) - results = run_go_tests.run_shards(shards, popen=launch) + scopes = run_go_tests.verified_package_scope(shards, packages) + results = run_go_tests.run_shards(shards, popen=launch, package_scopes=scopes) self.assertEqual(len(results), len(shards)) self.assertTrue(all(result.returncode == 0 for result in results)) selected = [] for command in commands: - self.assertEqual(command[:4], ["go", "test", "-count=1", "-run"]) - regex = command[4] + self.assertEqual(command[:5], ["go", "test", "-count=1", "-v", "-run"]) + regex = command[5] + self.assertEqual(command[6:], ["example.com/mod/only"]) for name in names: if name in regex: selected.append(name) self.assertEqual(sorted(selected), sorted(names)) + # control-law: complete-local-test-partition. + def test_unscoped_workers_still_sweep_every_package(self): + commands = [] + + def launch(command, **kwargs): + commands.append(command) + return ImmediateProcess(command, **kwargs) + + shards = run_go_tests.verified_partition(["TestAlpha", "TestBeta"], 1) + run_go_tests.run_shards(shards, popen=launch) + self.assertEqual(commands[0][6:], ["./..."]) + # control-law: complete-local-test-partition. def test_interrupt_stops_active_workers(self): first, second = ActiveProcess(), ActiveProcess() @@ -114,20 +180,85 @@ def test_interrupt_stops_active_workers(self): # control-law: complete-local-test-partition. def test_any_worker_failure_fails_the_aggregate_gate(self): names = ["TestAlpha", "TestBeta"] + packages = {name: ("example.com/mod/only",) for name in names} results = [ run_go_tests.ShardResult(0, 1, 0, 0.1, "ok"), run_go_tests.ShardResult(1, 1, 1, 0.1, "failed assertion"), ] with ( - mock.patch.object(run_go_tests, "list_top_level_tests", return_value=names), + tempfile.TemporaryDirectory() as scratch, + mock.patch.object( + run_go_tests, "list_top_level_tests", return_value=(names, packages) + ), mock.patch.object(run_go_tests, "run_shards", return_value=results), mock.patch("sys.stdout", new_callable=io.StringIO), mock.patch("sys.stderr", new_callable=io.StringIO) as stderr, ): - self.assertEqual(run_go_tests.main(["--jobs", "2"]), 1) + timings_file = str(Path(scratch) / "timings.json") + self.assertEqual( + run_go_tests.main(["--jobs", "2", "--timings-file", timings_file]), 1 + ) self.assertIn("failed assertion", stderr.getvalue()) +class MeasuredShardBalance(unittest.TestCase): + def test_per_test_durations_parse_top_level_results_only(self): + output = ( + "=== RUN TestAlpha\n" + "--- PASS: TestAlpha (2.50s)\n" + "=== RUN TestBeta\n" + " --- PASS: TestBeta/subtest (1.00s)\n" + "--- FAIL: TestBeta (4.25s)\n" + "ok \texample.com/mod/first\t6.75s\n" + ) + self.assertEqual( + run_go_tests.parse_test_durations(output), + {"TestAlpha": 2.5, "TestBeta": 4.25}, + ) + + def test_timings_roundtrip_and_foreign_entries_are_dropped(self): + with tempfile.TemporaryDirectory() as scratch: + path = Path(scratch) / "cache" / "timings.json" + run_go_tests.save_timings( + path, {"TestAlpha": 2.5, "TestRemoved": 9.0, "TestBad": -1.0} + ) + loaded = run_go_tests.load_timings(path, ["TestAlpha", "TestBeta"]) + self.assertEqual(loaded, {"TestAlpha": 2.5}) + + def test_missing_or_malformed_timings_degrade_to_count_balance(self): + with tempfile.TemporaryDirectory() as scratch: + missing = Path(scratch) / "absent.json" + self.assertEqual(run_go_tests.load_timings(missing, ["TestAlpha"]), {}) + malformed = Path(scratch) / "broken.json" + malformed.write_text("not json", encoding="utf-8") + self.assertEqual(run_go_tests.load_timings(malformed, ["TestAlpha"]), {}) + + def test_measured_weights_change_the_partition(self): + names = ["TestHeavy", "TestA", "TestB", "TestC"] + counted = run_go_tests.verified_partition(names, 2) + weighted = run_go_tests.verified_partition( + names, 2, {"TestHeavy": 100.0, "TestA": 1.0, "TestB": 1.0, "TestC": 1.0} + ) + self.assertEqual(weighted, ci_shard.assign_shards(names, 2, {"TestHeavy": 100.0})) + self.assertIn(["TestHeavy"], weighted) + self.assertNotEqual(counted, weighted) + + def test_failure_display_strips_pass_narration(self): + output = ( + "=== RUN TestAlpha\n" + "--- PASS: TestAlpha (0.10s)\n" + "=== RUN TestBeta\n" + " boundary_test.go:12: broken invariant\n" + "--- FAIL: TestBeta (0.20s)\n" + "FAIL\n" + ) + display = run_go_tests.failure_display(output) + self.assertIn("broken invariant", display) + self.assertIn("--- FAIL: TestBeta", display) + self.assertNotIn("--- PASS", display) + self.assertNotIn("=== RUN", display) + + class ExistingShardControllerContract(unittest.TestCase): def test_runner_reuses_the_reviewed_controller(self): names = [f"Test{index:03d}" for index in range(12)] diff --git a/release-notes/2026-08-21-faster-local-test-runner.md b/release-notes/2026-08-21-faster-local-test-runner.md new file mode 100644 index 0000000..26214f5 --- /dev/null +++ b/release-notes/2026-08-21-faster-local-test-runner.md @@ -0,0 +1,3 @@ +### Speed up the local Go test runner with package-scoped, timing-balanced shards + +`python3 .github/scripts/run_go_tests.py` now scopes each isolated shard to only the packages that own its tests instead of sweeping every package, balances shards with per-test durations persisted in the user cache (`~/.cache/boatstack/test-timings.json`, never the repository), and reports each shard's true elapsed time. The full local suite drops about 22% in wall-clock on a 10-core-performance machine while keeping fresh execution (`-count=1`), process isolation, the jobs cap, and the exact-partition refusal; a new coverage gate refuses any scoped run that could silently skip an enumerated test.