Repository navigation
LocalGate: the tests.yml suites locally through Bobcat's Gate (Bobcat 1.0.0-rc.3) - #5726
Merged
Merged
Conversation
rc.2 dropped Bobcat's JasperFx dependency (bobcat#744) and moved the Critter Stack vocabulary DaemonTests uses (CritterStackSpec, CritterStackScenario, EventStores in Bobcat.CritterStack) to WolverineFx.Bobcat, so DaemonTests takes WolverineFx.Bobcat 6.51.2-alpha.1, built on the same JasperFx/JasperFx.Events 2.91.0 Marten builds against. The build project no longer needs its JasperFx 2.90.2 override. Part of #5725. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
./build.sh LocalGate inits once, preflights Postgres, builds src/Marten.slnx -c Release
once, then runs every test project as a unit through Bobcat.Supervisor's Gate: newest
TFM unless --framework all, longest first, one worker budget across all units.
- Each unit keeps its CI target's supervisor configuration, now shared through
configureSupervisor (opt-in Retry traits in a fresh process, stall report, heartbeat,
ledger-balanced lanes) and its committed worker count.
- Each unit gets its own lane databases, marten_testing_<project>_<tfm>_w{n}, through
marten_testing_database.
- Exclusive tracks keep suites that use fixed server-level names apart:
tenant-databases (Core, Daemon, MultiTenancy, Stress), shard-databases
(MultiTenancy, TenantPartitionedEvents) and default-database (EventSourcingTests'
hard-coded localhost:5432/marten_testing).
- The budget is half the cores, lowered to what the server's free connections hold
(about 40 per worker); a stock 100-connection Postgres ran out with 53300 under four
EventSourcingTests lanes. docker-compose.yml now sets max_connections=500.
- Opt-in: --gate-include postgis|timescaledb|multihost|stress, --gate-serializer
(Newtonsoft, SystemTextJson, split), --gate-database (the PG15 leg). Also
--gate-only, --gate-skip-build, --gate-worker-budget.
- BOBCAT_RUN_TAG is the prefix each unit publishes under (<tag>/<project>.<tfm>).
- Durations and folded test ledgers persist in .bobcat/ (ignored), since Init's
Clean() empties artifacts/.
CI is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 24, 2026
Merged
jeremydmiller
added a commit
to vpetrevski/marten
that referenced
this pull request
Oct 26, 2026
Moves BobcatVersion from 1.0.0-rc.3 to 1.0.0-rc.4, the candidate before Bobcat 1.0.0 (JasperFx/bobcat#568). rc.4 fixes the gate's default build passing -f to the whole solution (JasperFx/bobcat#774, found here in JasperFx#5726), so Marten's GateDeclaration.Build workaround can go in a follow-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
This was referenced Oct 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5725
Stoat plan node:
local-gates/marten-local-gate./build.sh LocalGateruns the logical suites of thetests.ymlmatrix on one machine through the local commit-and-push Gate in Bobcat.Supervisor 1.0.0-rc.3 (bobcat#729). CI is unchanged.What changed
Bobcat 1.0.0-rc.1 → 1.0.0-rc.3 (
Directory.Packages.props)Bobcat.CritterStackvocabulary DaemonTests uses (CritterStackSpec,CritterStackScenario,EventStores) moved to WolverineFx.Bobcat. DaemonTests now referencesWolverineFx.Bobcat6.51.2-alpha.1. That package is built on JasperFx/JasperFx.Events 2.91.0, the same version Marten builds against. It asks for Bobcat rc.2 and resolves rc.3.build/build.csprojdrops itsJasperFx2.90.2VersionOverride. Bobcat.Supervisor no longer needs it.The
LocalGatetarget (build/LocalGate.cs)LocalGatedepends onInitonce, preflights Postgres, and buildssrc/Marten.slnx -c Releaseonce, covering both TFMs. In CI, each job runscompile-project, whoseInit → Clean()wipesartifacts/test-ledgerand rewritesAssemblyInfo.cs. The gate no longer repeats that once per unit.--framework all. On a first run the units go in CI's job-time order, longest first. After that, Bobcat orders them by.bobcat/gate-durations.json. One worker budget covers every unit.runSupervisedused to build inline now live inconfigureSupervisor(build/SupervisedTests.cs), and the gate passes it through.Supervise(...). That covers the opt-in[Trait("Retry","N")]policy (fresh-process retries), the retry budget, the stall report, the heartbeat and ledger-balanced lanes. EventSourcing and Linq keep their 4 workers.--disable-test-retryand--test-workersstill apply.marten_testing_database, namedmarten_testing_<project>_<tfm>_w{n}. These never collide with each other, with CI-target lanes (marten_testing_w{n}) or with Weasel's lanes. Lane creation is serialized.tenant-databases: Core, Daemon, MultiTenancy and Stress all createtenant1..6/database1.shard-databases: MultiTenancy and TenantPartitionedEvents both usemarten_shard_*.default-database: EventSourcingTests'testing_projectionshard-codeslocalhost:5432/marten_testing. Stress also holds it.max_connectionscan hold, at about 40 per worker, and logs the change. The first full run on the stock 100-connection container failed with hundreds of53300: sorry, too many clients already. EventSourcingTests' four lanes alone peaked above 100.docker-compose.ymlnow setsmax_connections=500.--gate-worker-budgetoverrides the budget.--gate-include postgis|timescaledb|multihost|stress. Each one has a preflight. The MultiHost check logs in with the suite's credentials, so an unrelated container on 5440 fails it. The TimescaleDB check confirms the extension exists, because 5433 is also Wolverine's Postgres.--gate-serializer Newtonsoft|SystemTextJson|split, wheresplituses CI's net9/net10 pairing.--gate-database <conn>, used for the PG15 leg.--gate-only,--gate-skip-build,--gate-timescale-database.BOBCAT_RUN_TAGis the prefix, so each unit publishes as<tag>/<project>.<tfm>..bobcat/test-ledger/, becauseClean()emptiesartifacts/(.bobcat/is git-ignored).CLAUDE.mdcovers how to run the gate, each option and the measured wall-clock.Gate report (this 18-core machine, net10.0, Postgres 17)
Final run on a 500-connection server (budget 9), built from the repo's own
marten-postgresqlimage on port 5434 withmax_connections=500, matching the newdocker-compose.yml. I did not restart the shared 5432 container.End to end,
./build.sh LocalGatetook 7m48s, including Init and the solution build. DaemonTests sets the wall clock. The 7m43s wall clock compares with 13m11s for the units run one after the other.Run on the stock 100-connection
marten-postgresql-1on 5432 (the gate derived a budget of 2): 19/19 clean. Wall clock 11m27s against 14m10s one after the other; 11m30s end to end.The MultiHost leg was not run locally because port 5440 is held by an unrelated container. TimescaleDB, PostGIS and the PG15 leg were also not exercised.
One intermittent failure, not caused by this change
LinqTests.Acceptance.using_explicit_sql_in_select_clauses.using_explicit_sql_to_scalar_valuefailed in 2 of 7 LinqTests runs inside the gate and passed in the other 5. It passed 3 times on a clean master worktree (4 lanes twice, 1 lane once).The cause is in the test itself. It never saves its own users, so it passes only when no
Usernamed "Hank" is already in the sharedIntegrationContexttable. A probe on master showed that when a Hank does exist,ExplicitSql<string>("d.data -> 'FirstName'")returns the JSON-quoted"Hank", so the assertion fails. Whether it fails depends on which classes share its worker and the order they run in, not on the gate. I left it alone here.Follow-up (not done here)
tests.ymlinclude:matrix to a generatedbuild/gates.jsonand feed CI withfromJSON, so CI andLocalGateread one list.docs-prs.yml.🤖 Generated with Claude Code