Record route-lifetime streaming overruns and maximum operation costs, require canonical reveal/resource convergence at every connected checkpoint, and keep recenter semantics independent of the production wall-clock budget. Co-authored-by: Erik Nilsson <erikn@users.noreply.github.com>
510 lines
18 KiB
C#
510 lines
18 KiB
C#
namespace AcDream.App.Tests.Diagnostics;
|
|
|
|
public sealed class ConnectedR6SoakContractTests
|
|
{
|
|
private static readonly string[] ExpectedCheckpointNames =
|
|
[
|
|
"caul-baseline",
|
|
"sawato-baseline",
|
|
"rynthid",
|
|
"aerlinthe",
|
|
"sawato-return",
|
|
"holtburg",
|
|
"caul-return",
|
|
"sawato-plateau",
|
|
"caul-plateau",
|
|
];
|
|
|
|
[Fact]
|
|
public void RouteContainsExactlyNineOrderedCheckpointBarriers()
|
|
{
|
|
string routePath = Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"connected-r6-soak.route.txt");
|
|
string[] checkpoints = File.ReadAllLines(routePath)
|
|
.Select(static line => line.Trim())
|
|
.Where(static line => line.StartsWith(
|
|
"checkpoint ",
|
|
StringComparison.Ordinal))
|
|
.Select(static line => line["checkpoint ".Length..])
|
|
.ToArray();
|
|
|
|
Assert.Equal(ExpectedCheckpointNames, checkpoints);
|
|
|
|
string[] teleports = File.ReadAllLines(routePath)
|
|
.Select(static line => line.Trim())
|
|
.Where(static line => line.StartsWith(
|
|
"command /teleloc ",
|
|
StringComparison.Ordinal))
|
|
.ToArray();
|
|
Assert.Equal(9, teleports.Length);
|
|
Assert.All(teleports, static line => Assert.EndsWith(
|
|
" 1 0 0 0",
|
|
line,
|
|
StringComparison.Ordinal));
|
|
|
|
string[] screenshots = File.ReadAllLines(routePath)
|
|
.Select(static line => line.Trim())
|
|
.Where(static line => line.StartsWith(
|
|
"screenshot ",
|
|
StringComparison.Ordinal))
|
|
.Select(static line => line.Split(' ', StringSplitOptions.RemoveEmptyEntries)[1])
|
|
.ToArray();
|
|
Assert.Equal(ExpectedCheckpointNames, screenshots);
|
|
}
|
|
|
|
[Fact]
|
|
public void DenseTownRoutePinsArwicViewAndScreenshot()
|
|
{
|
|
string[] route = File.ReadAllLines(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"connected-dense-town.route.txt"))
|
|
.Select(static line => line.Trim())
|
|
.Where(static line => line.Length > 0 && !line.StartsWith('#'))
|
|
.ToArray();
|
|
|
|
AssertAppearsInOrder(
|
|
string.Join('\n', route),
|
|
"command /telepoi Arwic",
|
|
"wait materialized 1 60000",
|
|
"input down MovementTurnRight",
|
|
"sleep 6000",
|
|
"input up MovementTurnRight",
|
|
"screenshot arwic-dense 10000",
|
|
"checkpoint arwic-dense");
|
|
}
|
|
|
|
[Fact]
|
|
public void PerformanceRoutesPinNoonBeforeTheirFirstTeleport()
|
|
{
|
|
foreach (string routeName in new[]
|
|
{
|
|
"connected-r6-soak.route.txt",
|
|
"connected-dense-town.route.txt",
|
|
})
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
routeName));
|
|
int firstTeleport = source.IndexOf("command /tele", StringComparison.Ordinal);
|
|
Assert.True(firstTeleport > 0, $"{routeName} has no teleport command.");
|
|
string preTeleport = source[..firstTeleport];
|
|
Assert.Equal(
|
|
3,
|
|
CountOccurrences(
|
|
preTeleport,
|
|
"input press AcdreamCycleTimeOfDay"));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ReferenceConfigurationDefinesLocalAuthorityAndScreenshotRule()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"docs",
|
|
"research",
|
|
"2026-07-24-performance-reference-configuration.json"));
|
|
using System.Text.Json.JsonDocument document =
|
|
System.Text.Json.JsonDocument.Parse(source);
|
|
System.Text.Json.JsonElement root = document.RootElement;
|
|
|
|
Assert.Equal(
|
|
"performance-gate",
|
|
root.GetProperty("displayPaths")
|
|
.GetProperty("authoritativeLocal")
|
|
.GetProperty("authority")
|
|
.GetString());
|
|
Assert.Equal(
|
|
"diagnostic-only",
|
|
root.GetProperty("displayPaths")
|
|
.GetProperty("diagnosticRdp")
|
|
.GetProperty("authority")
|
|
.GetString());
|
|
Assert.Equal(
|
|
2,
|
|
root.GetProperty("screenshotComparison")
|
|
.GetProperty("channelTolerance")
|
|
.GetInt32());
|
|
Assert.Equal(
|
|
0.001,
|
|
root.GetProperty("screenshotComparison")
|
|
.GetProperty("maxDifferentPixelFraction")
|
|
.GetDouble());
|
|
}
|
|
|
|
[Fact]
|
|
public void GateConsumesCanonicalTimelineWithoutWeakeningResidencyFormulas()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"$expectedCheckpointNames = @(",
|
|
"'caul-baseline'",
|
|
"'sawato-baseline'",
|
|
"'rynthid'",
|
|
"'aerlinthe'",
|
|
"'sawato-return'",
|
|
"'holtburg'",
|
|
"'caul-return'",
|
|
"'sawato-plateau'",
|
|
"'caul-plateau'");
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"$canonicalCheckpoints = @(Read-CanonicalCheckpoints)",
|
|
"Add-CanonicalCheckpointFailures $process",
|
|
"Add-RelativeGateFailures");
|
|
Assert.Contains("CanonicalCheckpoints = @($canonicalCheckpoints)", source);
|
|
Assert.Contains("CheckpointTimeline = $checkpointTimeline", source);
|
|
Assert.Contains(
|
|
"Join-Path $artifactDir \"checkpoint-$expectedName.json\"",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"missing render-world synchronization fields",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"canonical cache '$field' grew",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"if ($workloadChanged) { $warnings.Add($message) }",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
|
|
string[] zeroFields =
|
|
[
|
|
"pendingLiveTeardowns",
|
|
"pendingLandblockRetirements",
|
|
"stagedMeshUploads",
|
|
"stagedMeshBytes",
|
|
"compositeWarmupPending",
|
|
];
|
|
foreach (string field in zeroFields)
|
|
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
|
|
|
string[] revealFields =
|
|
[
|
|
"materialized",
|
|
"completed",
|
|
"worldViewportObserved",
|
|
"cancelled",
|
|
"invariantFailureCount",
|
|
"isReady",
|
|
];
|
|
foreach (string field in revealFields)
|
|
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
|
|
|
string[] streamingZeroFields =
|
|
[
|
|
"deferredCompletions",
|
|
"deferredAdoptedCpuBytes",
|
|
"pendingPublications",
|
|
"pendingRetirements",
|
|
"workerCompletionBacklog",
|
|
"destinationBacklog",
|
|
"controlBacklog",
|
|
"unloadBacklog",
|
|
"nearBacklog",
|
|
"farBacklog",
|
|
];
|
|
foreach (string field in streamingZeroFields)
|
|
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
|
|
|
string[] streamingEvidenceFields =
|
|
[
|
|
"lifetimeFrameOverrunCount",
|
|
"lifetimeOversizedProgressCount",
|
|
"maximumFrameMilliseconds",
|
|
"maximumFrameStage",
|
|
"maximumOperationMilliseconds",
|
|
"maximumOperationStage",
|
|
];
|
|
foreach (string field in streamingEvidenceFields)
|
|
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
|
|
|
|
Assert.Equal(1, CountOccurrences(
|
|
source,
|
|
"$privateLimit = [Math]::Max(192.0, $pair.First.PrivateMiB * 0.20)"));
|
|
Assert.Equal(1, CountOccurrences(
|
|
source,
|
|
"$workingLimit = [Math]::Max(192.0, $pair.First.WorkingSetMiB * 0.20)"));
|
|
Assert.Equal(1, CountOccurrences(
|
|
source,
|
|
"$updateLimit = $pair.First.UpdateP95Ms * 1.5 + 0.5"));
|
|
Assert.Equal(1, CountOccurrences(
|
|
source,
|
|
"$allocLimit = $pair.First.AllocP50Kb * 1.5 + 16.0"));
|
|
}
|
|
|
|
[Fact]
|
|
public void UncappedRenderDefaultsToCappedAndIsGatedByAParameter()
|
|
{
|
|
// 2026-07-24 measurement-tooling review: the soak unconditionally
|
|
// forced ACDREAM_UNCAPPED_RENDER=1 with no capped mode, while the
|
|
// sibling lifecycle gate script exposes both. Pin the fix so it
|
|
// cannot silently regress back to an unconditional '1'.
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains("[switch]$Uncapped", source, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"$env:ACDREAM_UNCAPPED_RENDER = if ($Uncapped) { '1' } else { $null }",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain(
|
|
"$env:ACDREAM_UNCAPPED_RENDER = '1'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void StationaryDwellSamplesAfterTheLivenessDeadline()
|
|
{
|
|
// LiveEntityLivenessController.DestructionTimeoutSeconds is 25s; the
|
|
// stationary sample must dwell past it or a prior destination's
|
|
// records can masquerade as retained memory in the return gate.
|
|
// The script previously slept only 12s despite the comment already
|
|
// citing the 25s deadline.
|
|
string script = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
string route = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"connected-r6-soak.route.txt"));
|
|
|
|
AssertAppearsInOrder(
|
|
script,
|
|
"LiveEntityLivenessController's 25-second authoritative absence",
|
|
"$checkpointPattern =",
|
|
"Wait-ForLogPattern $process $stdoutLog $checkpointPattern",
|
|
"$stationaryProfiles = Get-FrameProfiles $stdoutLog",
|
|
"Capture-Sample $process $destination.Name 'stationary'");
|
|
Assert.Equal(9, CountOccurrences(route, "sleep 27000"));
|
|
Assert.Equal(9, CountOccurrences(route, "sleep 3000"));
|
|
}
|
|
|
|
[Fact]
|
|
public void LaunchConfigurationIsDisclosedToTheArtifactDirectoryBeforeLaunch()
|
|
{
|
|
// 2026-07-24 measurement-tooling review: a prior audit could only
|
|
// observe ACDREAM_DUMP_MOVE_TRUTH because no other ACDREAM_* launch
|
|
// flag the script sets was ever recorded anywhere machine-readable.
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"Get-ChildItem Env: | Where-Object { $_.Name -like 'ACDREAM_*' }",
|
|
"Join-Path $artifactDir 'env-disclosure.json'",
|
|
"try {");
|
|
Assert.Contains(
|
|
"EnvDisclosure = Join-Path $artifactDir 'env-disclosure.json'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"$sensitive = $_.Name -match '(?i)(PASS|PASSWORD|TOKEN|SECRET|KEY)'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"Value = if ($sensitive) { '<redacted>' } else { $_.Value }",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
// ACDREAM_DUMP_MOVE_TRUTH stays SET (the exercise gate greps its
|
|
// output) — it is now disclosed, not removed.
|
|
Assert.Contains("$env:ACDREAM_DUMP_MOVE_TRUTH = '1'", source, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void BaselineIdentityComesFromTheMeasuredBinaryRatherThanOnlyTheCheckout()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"$sourceCommit = (& git -C $Repository rev-parse HEAD).Trim()",
|
|
"[Diagnostics.FileVersionInfo]::GetVersionInfo($exe).ProductVersion",
|
|
"$binaryCommitMatch = [regex]::Match(",
|
|
"$commit = if ($null -ne $binaryCommit) { $binaryCommit } else { $sourceCommit }",
|
|
"$binaryMatchesSource = $null -ne $binaryCommit -and $binaryCommit -eq $sourceCommit");
|
|
Assert.Contains(
|
|
"status --short --untracked-files=no",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains("BinaryProductVersion = $binaryProductVersion", source);
|
|
Assert.Contains("BinaryCommit = $binaryCommit", source);
|
|
Assert.Contains("BinaryMatchesSource = $binaryMatchesSource", source);
|
|
Assert.Contains("TrackedSourceStatus = @($sourceStatus)", source);
|
|
Assert.Contains(
|
|
"measured binary commit $binaryCommit differs from checked-out source commit $sourceCommit",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void SoakExportsAndSummarizesFrameHistory()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains(
|
|
"$env:ACDREAM_FRAME_HISTORY = $frameHistory",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"& dotnet $cliDll summarize-frame-history",
|
|
"$frameHistory",
|
|
"$checkpointTimeline",
|
|
"$markerLog",
|
|
"$frameSummary");
|
|
Assert.Contains("FrameHistory = $frameHistory", source, StringComparison.Ordinal);
|
|
Assert.Contains("FrameSummary = $frameSummary", source, StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void ContentionCaptureIsExplicitAndIncludesStackEvents()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains("[switch]$CaptureContention", source, StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"'Microsoft-Windows-DotNETRuntime:0x4000:5'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"ContentionTrace = if ($CaptureContention) { $contentionTrace } else { $null }",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void RuntimeCountersCaptureProcessWideAllocationByDefault()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains("[switch]$SkipRuntimeCounters", source, StringComparison.Ordinal);
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"if (-not $SkipRuntimeCounters) {",
|
|
"'--counters', 'System.Runtime'",
|
|
"'--refresh-interval', '1'",
|
|
"'--format', 'csv'",
|
|
"'--output', $runtimeCounters");
|
|
Assert.Contains(
|
|
"RuntimeCounters = if (-not $SkipRuntimeCounters) { $runtimeCounters } else { $null }",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"Wait-ForLogPattern $process $stdoutLog 'live: in world'",
|
|
"if (-not $SkipRuntimeCounters) {",
|
|
"Start-Process -FilePath 'dotnet-counters'",
|
|
"if ($CaptureContention) {",
|
|
"Start-Process -FilePath 'dotnet-trace'");
|
|
}
|
|
|
|
[Fact]
|
|
public void LoginGateDoesNotRequireTheOptionalFirstPositionRecenterDiagnostic()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains(
|
|
"Wait-ForLogPattern $process $stdoutLog 'live: in world'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.DoesNotContain(
|
|
"Wait-ForLogPattern $process $stdoutLog 'live: first player position'",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
Assert.Contains(
|
|
"route materialization below is the deterministic world-ready barrier.",
|
|
source,
|
|
StringComparison.Ordinal);
|
|
}
|
|
|
|
[Fact]
|
|
public void DenseTownModeUsesTheDedicatedOneCheckpointRoute()
|
|
{
|
|
string source = File.ReadAllText(Path.Combine(
|
|
FindRepoRoot(),
|
|
"tools",
|
|
"run-connected-r6-soak.ps1"));
|
|
|
|
Assert.Contains("[switch]$DenseTown", source, StringComparison.Ordinal);
|
|
AssertAppearsInOrder(
|
|
source,
|
|
"if ($DenseTown) {",
|
|
"Name = 'Arwic dense'",
|
|
"$expectedCheckpointNames = @('arwic-dense')",
|
|
"$routeFileName = 'connected-dense-town.route.txt'",
|
|
"$runName = 'connected-dense-town'");
|
|
Assert.Contains("if (-not $DenseTown) {", source, StringComparison.Ordinal);
|
|
}
|
|
|
|
private static int CountOccurrences(string source, string value)
|
|
{
|
|
int count = 0;
|
|
int cursor = 0;
|
|
while ((cursor = source.IndexOf(value, cursor, StringComparison.Ordinal)) >= 0)
|
|
{
|
|
count++;
|
|
cursor += value.Length;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
private static void AssertAppearsInOrder(string source, params string[] values)
|
|
{
|
|
int cursor = -1;
|
|
foreach (string value in values)
|
|
{
|
|
int next = source.IndexOf(value, cursor + 1, StringComparison.Ordinal);
|
|
Assert.True(next >= 0, $"Missing expected source fragment: {value}");
|
|
Assert.True(next > cursor, $"Out-of-order source fragment: {value}");
|
|
cursor = next;
|
|
}
|
|
}
|
|
|
|
private static string FindRepoRoot()
|
|
{
|
|
DirectoryInfo? directory = new(AppContext.BaseDirectory);
|
|
while (directory is not null)
|
|
{
|
|
if (File.Exists(Path.Combine(directory.FullName, "AcDream.slnx")))
|
|
return directory.FullName;
|
|
directory = directory.Parent;
|
|
}
|
|
|
|
throw new DirectoryNotFoundException("Could not find AcDream.slnx.");
|
|
}
|
|
}
|