Split out of #839, which merged as a variance fix (#861). This is the lever that moves the floor.
The problem
dotnet test overlaps collections but runs tests within a collection serially. The shared integration collection is one collection holding 95 classes and 1,024 of 1,815 tests — 316.1s of test work that cannot overlap itself.
That 316s serial block is the suite's wall-clock floor. Measured on the #861 run: 331.5s total wall clock, of which the shared collection occupied 316.1s end to end. #861 stops the block landing at the end of the timeline (the 434s outlier); it cannot shrink the block.
Everything else — 142 classes, 852.4s of test work — already runs in parallel across 12 cores and fits inside the block's shadow. Splitting the shared collection is the only change that lowers the floor.
First task: measure, do not split
#839's own lesson applies. Its stated premise (per-class container startup) was already solved before anyone looked. Before designing a split, establish:
- What state the 95 classes actually share. The default account, base reference data (grades, roles, packed-unit conversions),
Simulation:* config, and any advisory-lock assumptions. The shared fixture exists because they share something; find out what, per class, before assuming two classes are separable.
- Which classes are already isolated in practice — those that never write, or write only rows nobody else reads. Those are the candidates.
- What the floor would become at 2, 3, and 4 collections of the resulting groups. A split that produces two 158s blocks halves the floor; one that produces 300s + 16s does nothing.
Constraints
Explicitly not this issue
Test deletion and higher worker counts. #775 decision 1 argues against deletion; #776 landed coverage to answer "what is untested", which is never "what is redundant".
Known remaining cost, for whoever sizes this
The parallel work is lumpy: six classes hold 374s of the 852s. OtlpSubprocessExporterTests 80.5s for 11 tests, ProcessRoleGuardTests 71.7s, SeedCommandTests 61.0s, OneShotVerbMinimalConfigTests 58.7s. These repeatedly launch the app as a subprocess. Lowering the collection floor below roughly that height makes this the next floor, so measure both before committing to a split width.
Refs #839
Split out of #839, which merged as a variance fix (#861). This is the lever that moves the floor.
The problem
dotnet testoverlaps collections but runs tests within a collection serially. The sharedintegrationcollection is one collection holding 95 classes and 1,024 of 1,815 tests — 316.1s of test work that cannot overlap itself.That 316s serial block is the suite's wall-clock floor. Measured on the #861 run: 331.5s total wall clock, of which the shared collection occupied 316.1s end to end. #861 stops the block landing at the end of the timeline (the 434s outlier); it cannot shrink the block.
Everything else — 142 classes, 852.4s of test work — already runs in parallel across 12 cores and fits inside the block's shadow. Splitting the shared collection is the only change that lowers the floor.
First task: measure, do not split
#839's own lesson applies. Its stated premise (per-class container startup) was already solved before anyone looked. Before designing a split, establish:
Simulation:*config, and any advisory-lock assumptions. The shared fixture exists because they share something; find out what, per class, before assuming two classes are separable.Constraints
AGENTS.mdrequires real Postgres via Testcontainers, never SQLite.Versionconcurrency-token races, Write guard trusts OriginalValue as DB provenance; detached Update/Remove can bypass the tenant theft check #562's detached tenant writes, and Sales: the Orders list cannot show which orders are unpaid #769's paging defects are only observable against real SQL — a split must not make two racing tests share a database they previously had alone.StealLossConnectionReleaseTestsalready keeps a dedicated factory and one-slot pool; do not fold it back in.Explicitly not this issue
Test deletion and higher worker counts. #775 decision 1 argues against deletion; #776 landed coverage to answer "what is untested", which is never "what is redundant".
Known remaining cost, for whoever sizes this
The parallel work is lumpy: six classes hold 374s of the 852s.
OtlpSubprocessExporterTests80.5s for 11 tests,ProcessRoleGuardTests71.7s,SeedCommandTests61.0s,OneShotVerbMinimalConfigTests58.7s. These repeatedly launch the app as a subprocess. Lowering the collection floor below roughly that height makes this the next floor, so measure both before committing to a split width.Refs #839