diff --git a/docs/events/projections/rebuilding.md b/docs/events/projections/rebuilding.md
index 279bdc2492..f39bc232c1 100644
--- a/docs/events/projections/rebuilding.md
+++ b/docs/events/projections/rebuilding.md
@@ -85,6 +85,20 @@ The effective cap is surfaced to monitoring tools through the store's usage desc
(`EventStoreUsage.MaxConcurrentRebuildsPerDatabase`), so tools like CritterWatch can size their own rebuild
orchestration to match.
+### Load-test evidence for the defaults
+
+The `max(1, MaxPoolSize / 8)` cap and the load/write governor default of 4 are confirmed by the
+`rebuildload` scenario in the `Marten.ScaleTesting` harness (marten#4884), which sweeps the three knobs
+against many partitioned tenants rebuilding concurrently and samples `pg_stat_activity` +
+`mt_event_progression` contention per configuration. The governing observation is that peak database
+connections track the outer cap directly — **peak connections ≈ min(cap, projections) + 1** — so the cap,
+not the inner slice workers, is the dominant connection driver, and the `MaxPoolSize / 8` fraction keeps peak
+usage comfortably inside pool headroom (e.g. peak 9 against a 100-connection pool at cap 12). Wall-clock gains
+flatten past a handful of concurrent cells (diminishing returns), and no `mt_event_progression` waiters appear
+across the swept caps, so raising the cap trades pool headroom for little rebuild speedup once past ~4.
+`EnableExtendedProgressionTracking` adds no measurable rebuild overhead at the scales tested. Re-run
+`rebuildload` at your production pool size and event volume before deviating from the defaults.
+
## Cancelling a Rebuild
`RebuildProjectionAsync` overloads accept a `CancellationToken`, including the per-tenant overload
diff --git a/src/Marten.ScaleTesting/Commands/RebuildLoadCommand.cs b/src/Marten.ScaleTesting/Commands/RebuildLoadCommand.cs
new file mode 100644
index 0000000000..ac28bf843c
--- /dev/null
+++ b/src/Marten.ScaleTesting/Commands/RebuildLoadCommand.cs
@@ -0,0 +1,422 @@
+using System.Diagnostics;
+using System.Text.Json;
+using JasperFx;
+using JasperFx.CommandLine;
+using JasperFx.Events;
+using JasperFx.Events.Projections;
+using Marten.Events;
+using Marten.ScaleTesting.Instrumentation;
+using Marten.Storage;
+using Npgsql;
+using Spectre.Console;
+
+namespace Marten.ScaleTesting.Commands;
+
+///
+/// rebuildload (marten#4884, epic jasperfx#486 WS6/WS3 closeout): load-test many tenant
+/// shards rebuilding concurrently, sweeping the three governor knobs so their shipped defaults can
+/// be confirmed — or a change recommended — from evidence.
+///
+/// For each configuration in the sweep the harness builds a fresh store with the governors applied
+/// (MaxConcurrentEventLoadsPerDatabase, MaxConcurrentBatchWritesPerDatabase,
+/// EnableExtendedProgressionTracking), then rebuilds every registered projection with the
+/// outer rebuild fan-out throttled to the swept cap value — a faithful replica of
+/// ProjectionHost.RebuildProjectionsWithCapAsync (jasperfx#463), whose shipped default is
+/// max(1, MaxPoolSize / 8). Throughout, pg_stat_activity and the
+/// mt_event_progression lock-wait sampler run, so each row of the comparison carries
+/// wall-clock, peak/idle connections and progression contention.
+///
+/// This is a MEASUREMENT tool: it never changes a shipped default. The recommendation it prints is
+/// advisory, to be weighed into rebuilding.md by a human.
+///
+[Description("marten#4884 (epic jasperfx#486 WS6/WS3): rebuild-load governor sweep. Rebuilds N projections × many partitioned tenants under a swept per-database rebuild cap + inner load/write governors, measuring wall-clock, peak/idle connections and mt_event_progression contention per configuration, then prints a tuning recommendation. Never changes a shipped default.", Name = "rebuildload")]
+public sealed class RebuildLoadCommand: JasperFxAsyncCommand
+{
+ private const string Schema = "scaletest_rebuildload";
+
+ public override async Task Execute(RebuildLoadInput input)
+ {
+ if (input.DatabasesFlag > 1)
+ {
+ AnsiConsole.MarkupLine(
+ "[yellow]--databases > 1 (sharded rebuild sweep) is a documented follow-up; running the governor sweep on a single database, which is where the tuning evidence lives.[/]");
+ }
+
+ var caps = ParseInts(input.CapsFlag);
+ var loadGovernors = ParseInts(input.LoadGovernorsFlag);
+ var writeGovernors = ParseInts(input.WriteGovernorsFlag);
+ var extendedModes = input.SweepExtendedProgressionFlag ? new[] { false, true } : new[] { false };
+
+ var projectionNames = Enumerable.Range(0, Math.Max(1, input.ProjectionsFlag))
+ .Select(i => $"RebuildRollup{i}")
+ .ToArray();
+ var tenants = Enumerable.Range(0, input.TenantsFlag).Select(i => $"tenant_{i:0000}").ToArray();
+
+ AnsiConsole.MarkupLine(
+ $"[blue]rebuildload: tenants=[yellow]{tenants.Length}[/] projections=[yellow]{projectionNames.Length}[/] " +
+ $"events/tenant=[yellow]{input.EventsPerTenantFlag}[/] caps=[yellow]{input.CapsFlag}[/] " +
+ $"load-gov=[yellow]{input.LoadGovernorsFlag}[/] write-gov=[yellow]{input.WriteGovernorsFlag}[/] " +
+ $"ext-progression-sweep=[yellow]{input.SweepExtendedProgressionFlag}[/][/]");
+
+ if (input.WipeFlag)
+ {
+ await WipeSchemaAsync().ConfigureAwait(false);
+ }
+
+ if (!input.SkipSeedFlag)
+ {
+ await SeedAsync(projectionNames, tenants, input).ConfigureAwait(false);
+ }
+
+ var poolMax = new NpgsqlConnectionStringBuilder(ConnectionSource.ConnectionString).MaxPoolSize;
+ var shippedDefaultCap = Math.Max(1, poolMax / 8);
+ AnsiConsole.MarkupLine(
+ $"[grey]Connection pool MaxPoolSize={poolMax} ⇒ shipped default rebuild cap = max(1, {poolMax}/8) = [yellow]{shippedDefaultCap}[/][/]");
+
+ var results = new List();
+
+ foreach (var extended in extendedModes)
+ foreach (var loadGovernor in loadGovernors)
+ foreach (var writeGovernor in writeGovernors)
+ foreach (var cap in caps)
+ {
+ var result = await RunConfigurationAsync(
+ projectionNames, tenants, input, cap, loadGovernor, writeGovernor, extended).ConfigureAwait(false);
+ results.Add(result);
+
+ AnsiConsole.MarkupLine(
+ $"[grey] cap={cap} load={loadGovernor} write={writeGovernor} ext={extended}: " +
+ $"{result.ElapsedSeconds:N1}s, peak conns {result.PeakConnections}, " +
+ $"max waiters {result.MaxProgressionWaiters}[/]");
+ }
+
+ RenderResults(results, shippedDefaultCap);
+ var recommendation = BuildRecommendation(results, shippedDefaultCap, input);
+ AnsiConsole.MarkupLine($"[bold green]Recommendation:[/] {recommendation}");
+
+ await WriteMetricsAsync(input, shippedDefaultCap, poolMax, results, recommendation).ConfigureAwait(false);
+
+ return true;
+ }
+
+ private static async Task RunConfigurationAsync(
+ string[] projectionNames, string[] tenants, RebuildLoadInput input,
+ int cap, int loadGovernor, int writeGovernor, bool extended)
+ {
+ var applicationName = $"scaletest-rebuildload-c{cap}-l{loadGovernor}-w{writeGovernor}-e{(extended ? 1 : 0)}";
+ var connectionString = new NpgsqlConnectionStringBuilder(ConnectionSource.ConnectionString)
+ {
+ ApplicationName = applicationName
+ }.ConnectionString;
+
+ using var store = Marten.DocumentStore.For(opts =>
+ {
+ opts.Connection(connectionString);
+ opts.DisableNpgsqlLogging = true;
+ opts.DatabaseSchemaName = Schema;
+ opts.Events.TenancyStyle = TenancyStyle.Conjoined;
+ opts.Events.UseTenantPartitionedEvents = true;
+ opts.Events.AppendMode = EventAppendMode.QuickWithServerTimestamps;
+ opts.Events.EnableExtendedProgressionTracking = extended;
+ opts.Policies.AllDocumentsAreMultiTenanted();
+ opts.Events.AddEventType();
+
+ // The two inner governors size the daemon's per-database load / write semaphores.
+ opts.Projections.MaxConcurrentEventLoadsPerDatabase = loadGovernor;
+ opts.Projections.MaxConcurrentBatchWritesPerDatabase = writeGovernor;
+ // Set the outer cap for descriptor fidelity; concurrency itself is enforced below by a
+ // SemaphoreSlim(cap) around the concurrent RebuildProjectionAsync calls — the same
+ // shape as ProjectionHost.RebuildProjectionsWithCapAsync (jasperfx#463).
+ opts.Projections.MaxConcurrentRebuildsPerDatabase = cap;
+
+ foreach (var name in projectionNames)
+ {
+ opts.Projections.Add(new DaemonLoadRollupProjection(name), ProjectionLifecycle.Async, name);
+ }
+ });
+
+ await store.Storage.ApplyAllConfiguredChangesToDatabaseAsync().ConfigureAwait(false);
+
+ using var cts = new CancellationTokenSource();
+ await using var connectionSampler = ConnectionSampler.Start(
+ ConnectionSource.ConnectionString, applicationName,
+ TimeSpan.FromSeconds(Math.Max(0.1, input.SampleSecondsFlag)), null, cts.Token);
+ await using var lockSampler = ProgressionLockSampler.Start(
+ connectionString, TimeSpan.FromSeconds(Math.Max(0.1, input.SampleSecondsFlag)), null, cts.Token);
+
+ var shardTimeout = TimeSpan.FromSeconds(input.ShardTimeoutSecondsFlag);
+ using var daemon = await store.BuildProjectionDaemonAsync().ConfigureAwait(false);
+
+ var stopwatch = Stopwatch.StartNew();
+
+ // Outer rebuild fan-out throttled to `cap` concurrent projection rebuilds — the exact
+ // mechanism jasperfx#463 caps in production.
+ using var gate = new SemaphoreSlim(Math.Max(1, cap));
+ var rebuilds = projectionNames.Select(async name =>
+ {
+ await gate.WaitAsync(cts.Token).ConfigureAwait(false);
+ try
+ {
+ await daemon.RebuildProjectionAsync(name, shardTimeout, cts.Token).ConfigureAwait(false);
+ }
+ finally
+ {
+ gate.Release();
+ }
+ }).ToArray();
+
+ await Task.WhenAll(rebuilds).ConfigureAwait(false);
+ stopwatch.Stop();
+
+ var connections = connectionSampler.Capture();
+ var lockWaits = await lockSampler.StopAsync().ConfigureAwait(false);
+
+ var totalEvents = (long)tenants.Length * input.EventsPerTenantFlag;
+
+ return new RebuildLoadResult(
+ cap, loadGovernor, writeGovernor, extended,
+ stopwatch.Elapsed.TotalSeconds,
+ totalEvents / Math.Max(0.001, stopwatch.Elapsed.TotalSeconds),
+ connections.MaxTotal,
+ connections.MeanTotal,
+ connections.MaxBusy,
+ lockWaits.MaxConcurrentWaiters,
+ lockWaits.MaxSingleWaitMs,
+ lockWaits.ObservedWaiterSeconds);
+ }
+
+ private static async Task SeedAsync(string[] projectionNames, string[] tenants, RebuildLoadInput input)
+ {
+ var expectedEvents = (long)tenants.Length * input.EventsPerTenantFlag;
+
+ using var store = Marten.DocumentStore.For(opts =>
+ {
+ opts.Connection(ConnectionSource.ConnectionString);
+ opts.DisableNpgsqlLogging = true;
+ opts.DatabaseSchemaName = Schema;
+ opts.Events.TenancyStyle = TenancyStyle.Conjoined;
+ opts.Events.UseTenantPartitionedEvents = true;
+ opts.Events.AppendMode = EventAppendMode.Quick;
+ opts.Policies.AllDocumentsAreMultiTenanted();
+ opts.Events.AddEventType();
+
+ // Projections registered (Async) so the schema matches what the rebuild configs expect,
+ // but seeding never runs them.
+ foreach (var name in projectionNames)
+ {
+ opts.Projections.Add(new DaemonLoadRollupProjection(name), ProjectionLifecycle.Async, name);
+ }
+ });
+
+ await store.Storage.ApplyAllConfiguredChangesToDatabaseAsync().ConfigureAwait(false);
+
+ var stats = await store.Advanced.FetchEventStoreStatistics().ConfigureAwait(false);
+ if (stats.EventCount >= expectedEvents)
+ {
+ AnsiConsole.MarkupLine(
+ $"[grey]Seed idempotent: {stats.EventCount:N0} events already present (≥ {expectedEvents:N0}); skipping.[/]");
+ return;
+ }
+
+ AnsiConsole.MarkupLine(
+ $"[grey]Registering {tenants.Length} tenants + seeding {expectedEvents:N0} events...[/]");
+ await store.Advanced.AddMartenManagedTenantsAsync(CancellationToken.None, tenants).ConfigureAwait(false);
+
+ var perStream = Math.Max(1, input.EventsPerTenantFlag / 20);
+ await Parallel.ForEachAsync(tenants,
+ new ParallelOptions { MaxDegreeOfParallelism = 8 },
+ async (tenant, ct) =>
+ {
+ var remaining = input.EventsPerTenantFlag;
+ var sequence = 0;
+ while (remaining > 0)
+ {
+ var batch = Math.Min(perStream, remaining);
+ await using var session = store.LightweightSession(tenant);
+ var events = Enumerable.Range(0, batch)
+ .Select(_ => new DaemonLoadEvent(tenant, ++sequence))
+ .Cast