feat(render): implement Campaign AR and terrain fidelity

This commit is contained in:
Erik 2026-08-22 13:13:29 +02:00
parent 99cf26e00c
commit 7a5f96ede5
368 changed files with 50611 additions and 950 deletions

View file

@ -0,0 +1,567 @@
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace AcDream.App.Tests.Diagnostics;
public sealed class AtmosphericPerformanceMatrixContractTests
{
[Fact]
public void ScriptsParseWithoutLaunchingTheMatrix()
{
foreach (string script in new[]
{
ScriptPath(),
Path.Combine(FindRepoRoot(), "tools", "run-offline-pixel-gate.ps1"),
Path.Combine(FindRepoRoot(), "tools", "atmospheric-performance-matrix-common.ps1"),
})
AssertPowerShellParses(script);
}
private static void AssertPowerShellParses(string script)
{
var start = new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
start.ArgumentList.Add("-NoProfile");
start.ArgumentList.Add("-NonInteractive");
start.ArgumentList.Add("-Command");
string quotedScript = "'" + script.Replace("'", "''", StringComparison.Ordinal) + "'";
start.ArgumentList.Add(
$"[scriptblock]::Create((Get-Content -Raw -LiteralPath {quotedScript})) | Out-Null");
using Process process = Process.Start(start)
?? throw new InvalidOperationException("Could not start pwsh parser process.");
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
Assert.True(process.WaitForExit(30_000), "PowerShell parser did not exit.");
Assert.True(
process.ExitCode == 0,
$"PowerShell parser failed for {script} with exit code {process.ExitCode}.\n{stdout}\n{stderr}");
}
[Fact]
public void MatrixPinsAllRequiredRowsAndExplicitFramePacingModes()
{
string source = ReadScript();
Assert.Contains("[string]$FramePacing = 'both'", source, StringComparison.Ordinal);
Assert.Contains(
"[ValidateSet('capped', 'uncapped', 'both')]",
source,
StringComparison.Ordinal);
Assert.Contains(
"[string[]]$PresetSet = @('retail', 'low', 'medium', 'high', 'auto')",
source,
StringComparison.Ordinal);
Assert.Contains(
"[string[]]$ResolutionSet = @('1920x1080', '2560x1440', '3840x2160')",
source,
StringComparison.Ordinal);
Assert.Contains(
"$presets = @($PresetSet | ForEach-Object { $_.ToLowerInvariant() } | Select-Object -Unique)",
source,
StringComparison.Ordinal);
Assert.Contains(
"$resolutions = @($ResolutionSet | Select-Object -Unique)",
source,
StringComparison.Ordinal);
Assert.Contains("default { @('capped', 'uncapped') }", source, StringComparison.Ordinal);
Assert.Contains("if ($pacing -eq 'uncapped')", source, StringComparison.Ordinal);
Assert.Contains("$arguments += '-Uncapped'", source, StringComparison.Ordinal);
Assert.Contains(
"'-RequiredRenderPackSamples', '2048'",
source,
StringComparison.Ordinal);
Assert.Contains(
"'-RenderPackSampleTimeoutMs', '300000'",
source,
StringComparison.Ordinal);
Assert.Contains(
"ExplicitPresetPerformanceWindowResetAfterWarmup = $true",
source,
StringComparison.Ordinal);
Assert.Contains(
"AutomaticPerformanceWindowPolicy",
source,
StringComparison.Ordinal);
Assert.Contains("'-AllowSafeRenderPackFallback'", source, StringComparison.Ordinal);
AssertAppearsInOrder(
source,
"$rowDirectory = Assert-MatrixContainedPath $outputRoot (Join-Path $outputRoot $rowId)",
"'-Out', $rowDirectory",
"'-WarmupMs', \"$WarmupMs\"",
"'-DayGroup', \"$DayGroup\"",
"'-WorldDayFraction'",
"'-SkyPhaseSeconds'",
"'-MsaaSamples', '0'",
"'-RenderPackPreset', $preset",
"'-Resolution', $resolution",
"'-OrbitDistanceMeters'",
"'-SkipBuild'");
string pixelGate = File.ReadAllText(
Path.Combine(FindRepoRoot(), "tools", "run-offline-pixel-gate.ps1"));
Assert.Contains(
"$probeCommands.Add('sleep 2000')",
pixelGate,
StringComparison.Ordinal);
Assert.Contains(
"last completed swapchain image",
pixelGate,
StringComparison.Ordinal);
}
[Fact]
public void DeclaredCeilingsAreExactAndNewIncrementalMetricsAreRequired()
{
string source = ReadScript();
AssertPresetBudget(source, "low", "0.15", "0.50", "2.00", "3.00", "64L");
AssertPresetBudget(source, "medium", "0.25", "0.75", "3.25", "4.50", "128L");
AssertPresetBudget(source, "high", "0.35", "1.00", "4.50", "6.00", "256L");
foreach (string field in new[]
{
"IncrementalCpuMillisecondsP50",
"IncrementalCpuMillisecondsP95",
"IncrementalCpuMillisecondsP99",
"AbsoluteReceiverCpuMillisecondsP50",
"AbsoluteReceiverCpuMillisecondsP95",
"AbsoluteReceiverCpuMillisecondsP99",
"InclusiveGpuMillisecondsP50",
"InclusiveGpuMillisecondsP95",
"InclusiveGpuMillisecondsP99",
"ResidentGpuBytes",
})
{
Assert.Contains($"'{field}'", source, StringComparison.Ordinal);
}
Assert.DoesNotContain("'CpuMillisecondsP50'", source, StringComparison.Ordinal);
Assert.DoesNotContain("'CpuMillisecondsP99'", source, StringComparison.Ordinal);
Assert.DoesNotContain("'GpuMillisecondsP50'", source, StringComparison.Ordinal);
Assert.DoesNotContain("'GpuMillisecondsP99'", source, StringComparison.Ordinal);
Assert.Contains(
"$gpuBudgetApplies = $availability -eq 'Active' -and",
source,
StringComparison.Ordinal);
Assert.Contains("$budget = $budgets[$effectiveQuality]", source, StringComparison.Ordinal);
Assert.Contains(
"$cpuP50 -gt $budget.IncrementalCpuMillisecondsP50",
source,
StringComparison.Ordinal);
Assert.Contains(
"$cpuP99 -gt $budget.IncrementalCpuMillisecondsP99",
source,
StringComparison.Ordinal);
Assert.Contains(
"$residentGpuBytes -gt $budget.ResidentGpuBytes",
source,
StringComparison.Ordinal);
Assert.Contains(
"$gpuP50 -gt $budget.InclusiveGpuMillisecondsP50At1080p",
source,
StringComparison.Ordinal);
Assert.Contains(
"$gpuP99 -gt $budget.InclusiveGpuMillisecondsP99At1080p",
source,
StringComparison.Ordinal);
}
[Fact]
public void MetadataAndSummariesCarryTheRequiredEvidenceWithoutSecrets()
{
string source = ReadScript();
Assert.Contains(
"$screenshotLeaf = 'world-offline'",
source,
StringComparison.Ordinal);
foreach (string evidence in new[]
{
"CpuSampleCount",
"GpuSampleCount",
"ShadowCasterCount",
"CascadeDrawCount",
"DrawCalls",
"DispatchCalls",
})
{
Assert.Contains($"'{evidence}'", source, StringComparison.Ordinal);
}
Assert.Contains("atmospheric-performance-matrix.json", source, StringComparison.Ordinal);
Assert.Contains("atmospheric-performance-matrix.md", source, StringComparison.Ordinal);
Assert.Contains("DeclaredBudgets", source, StringComparison.Ordinal);
Assert.Contains("Rows = @($rows)", source, StringComparison.Ordinal);
Assert.Contains("Failures = @($matrixFailures)", source, StringComparison.Ordinal);
Assert.DoesNotContain("ACDREAM_TEST_USER", source, StringComparison.Ordinal);
Assert.DoesNotContain("ACDREAM_TEST_PASS", source, StringComparison.Ordinal);
Assert.DoesNotContain("Get-ChildItem Env:", source, StringComparison.Ordinal);
}
[Fact]
public void ExecutableMetadataOracleAcceptsCompleteShapeAndRejectsAdversarialEvidence()
{
string directory = Path.Combine(Path.GetTempPath(), $"acdream-matrix-{Guid.NewGuid():N}");
Directory.CreateDirectory(directory);
try
{
string metadataPath = Path.Combine(directory, "capture.metadata.json");
foreach (string preset in new[] { "low", "medium", "high" })
{
File.WriteAllText(metadataPath, CreateMetadata(preset));
JsonElement valid = RunMetadataOracle(metadataPath, preset);
Assert.True(valid.GetProperty("Passed").GetBoolean());
Assert.Equal(9498, valid.GetProperty("ShadowCasterCount").GetInt32());
}
JsonNode automatic = JsonNode.Parse(CreateMetadata("high"))!;
automatic["RenderPack"]!["PresetId"] = "auto";
automatic["RenderPack"]!["ActivationGeneration"] = 4;
File.WriteAllText(metadataPath, automatic.ToJsonString());
JsonElement validAutomatic = RunMetadataOracle(metadataPath, "auto");
Assert.True(validAutomatic.GetProperty("Passed").GetBoolean());
Assert.Equal(
"high",
validAutomatic.GetProperty("EffectiveQuality").GetString());
File.WriteAllText(metadataPath, CreateMetadata("high"));
JsonNode invalid = JsonNode.Parse(File.ReadAllText(metadataPath))!;
JsonNode pack = invalid["RenderPack"]!;
pack["ShadowCasterCount"] = 0;
pack["CascadeDrawCount"] = 3;
pack["CpuClassificationCalls"] = 1;
pack["RetainedGpuBytes"] = 99;
pack["Performance"]!["CpuSampleCount"] = 2047;
pack["Performance"]!["IncrementalCpuMillisecondsP95"] = -1.0;
pack["Passes"]![1]!["DrawCalls"] = 4;
File.WriteAllText(metadataPath, invalid.ToJsonString());
JsonElement rejected = RunMetadataOracle(metadataPath, "high");
Assert.False(rejected.GetProperty("Passed").GetBoolean());
string failures = rejected.GetProperty("Failures").ToString();
Assert.Contains("at least one shadow caster", failures, StringComparison.Ordinal);
Assert.Contains("exactly 4 cascades", failures, StringComparison.Ordinal);
Assert.Contains("zero CPU classifications", failures, StringComparison.Ordinal);
Assert.Contains("GPU bytes disagree", failures, StringComparison.Ordinal);
Assert.Contains("complete 2048-sample window", failures, StringComparison.Ordinal);
Assert.Contains("finite and non-negative", failures, StringComparison.Ordinal);
Assert.Contains("exactly 5 draws and zero dispatches", failures, StringComparison.Ordinal);
}
finally { Directory.Delete(directory, recursive: true); }
}
[Fact]
public void ExecutableMetadataOracleReportsOnlyStrictZeroWorkUnavailability()
{
string directory = Path.Combine(Path.GetTempPath(), $"acdream-matrix-{Guid.NewGuid():N}");
Directory.CreateDirectory(directory);
try
{
string metadataPath = Path.Combine(directory, "capture.metadata.json");
const string resourceReason =
"Directional shadow rendering failed: Render pack preset 'low' needs 67465216 resident GPU bytes after materializing its scene-dependent shadow command buffers; the active pack budget is 67108864 bytes.";
File.WriteAllText(metadataPath, CreateFallbackMetadata(resourceReason));
JsonElement resourceUnavailable = RunMetadataOracle(
metadataPath,
"low",
allowSafeFallback: true);
Assert.True(resourceUnavailable.GetProperty("Passed").GetBoolean());
Assert.Equal("Unavailable", resourceUnavailable.GetProperty("Outcome").GetString());
Assert.Equal(
"ResourceUnavailable",
resourceUnavailable.GetProperty("UnavailableClassification").GetString());
Assert.Equal(resourceReason, resourceUnavailable.GetProperty("FailureReason").GetString());
JsonElement automaticUnavailable = RunMetadataOracle(
metadataPath,
"auto",
allowSafeFallback: true);
Assert.True(automaticUnavailable.GetProperty("Passed").GetBoolean());
Assert.Equal(
"ResourceUnavailable",
automaticUnavailable.GetProperty("UnavailableClassification").GetString());
JsonElement notOptedIn = RunMetadataOracle(metadataPath, "low");
Assert.False(notOptedIn.GetProperty("Passed").GetBoolean());
Assert.Contains(
"not explicitly allowed",
notOptedIn.GetProperty("Failures").ToString(),
StringComparison.Ordinal);
const string capabilityReason =
"Preset 'low' requires unsupported capability 'MultiviewDirectionalShadowCascades'.";
File.WriteAllText(metadataPath, CreateFallbackMetadata(capabilityReason));
JsonElement capabilityUnavailable = RunMetadataOracle(
metadataPath,
"low",
allowSafeFallback: true);
Assert.True(capabilityUnavailable.GetProperty("Passed").GetBoolean());
Assert.Equal(
"CapabilityUnavailable",
capabilityUnavailable.GetProperty("UnavailableClassification").GetString());
const string performanceReason =
"Automatic quality disabled render pack 'acdream.atmospheric' because Low remained over its declared performance budget for 180 stable samples: GPU p99 24.234 ms (budget 3.000 ms), CPU p99 0.630 ms (budget 0.500 ms), resident GPU bytes 41648404 (budget 67108864).";
File.WriteAllText(metadataPath, CreateFallbackMetadata(performanceReason));
JsonElement performanceUnavailable = RunMetadataOracle(
metadataPath,
"auto",
allowSafeFallback: true);
Assert.True(performanceUnavailable.GetProperty("Passed").GetBoolean());
Assert.Equal(
"PerformanceUnavailable",
performanceUnavailable.GetProperty("UnavailableClassification").GetString());
JsonElement explicitLowCannotUseAutoPerformanceFallback = RunMetadataOracle(
metadataPath,
"low",
allowSafeFallback: true);
Assert.False(
explicitLowCannotUseAutoPerformanceFallback.GetProperty("Passed").GetBoolean());
const string forgedWithinBudget =
"Automatic quality disabled render pack 'acdream.atmospheric' because Low remained over its declared performance budget for 180 stable samples: GPU p99 2.000 ms (budget 3.000 ms), CPU p99 0.400 ms (budget 0.500 ms), resident GPU bytes 41648404 (budget 67108864).";
File.WriteAllText(metadataPath, CreateFallbackMetadata(forgedWithinBudget));
JsonElement forged = RunMetadataOracle(
metadataPath,
"auto",
allowSafeFallback: true);
Assert.False(forged.GetProperty("Passed").GetBoolean());
const string arbitraryFailure =
"Render pack 'acdream.atmospheric' could not be prepared: shader validation failed: unsupported binding.";
File.WriteAllText(metadataPath, CreateFallbackMetadata(arbitraryFailure));
JsonElement unexpected = RunMetadataOracle(metadataPath, "low", allowSafeFallback: true);
Assert.False(unexpected.GetProperty("Passed").GetBoolean());
Assert.Equal(
"UnexpectedFailure",
unexpected.GetProperty("UnavailableClassification").GetString());
Assert.Contains(
"not a strict resource/capability/Auto-performance unavailability",
unexpected.GetProperty("Failures").ToString(),
StringComparison.Ordinal);
JsonNode unsafeFallback = JsonNode.Parse(CreateFallbackMetadata(resourceReason))!;
unsafeFallback["RenderPack"]!["ShadowCasterCount"] = 1;
unsafeFallback["RenderPack"]!["Performance"]!["GpuSampleCount"] = 1;
File.WriteAllText(metadataPath, unsafeFallback.ToJsonString());
JsonElement rejectedWork = RunMetadataOracle(metadataPath, "low", allowSafeFallback: true);
Assert.False(rejectedWork.GetProperty("Passed").GetBoolean());
string failures = rejectedWork.GetProperty("Failures").ToString();
Assert.Contains("zero pack work and resources", failures, StringComparison.Ordinal);
Assert.Contains("zero GpuSampleCount", failures, StringComparison.Ordinal);
}
finally { Directory.Delete(directory, recursive: true); }
}
private static string CreateMetadata(string preset)
{
int cascades = preset switch { "low" => 2, "medium" => 3, _ => 4 };
const int shadowDraws = 5;
var passIds = new List<string> { "atmospheric-world-receiver" };
if (preset == "low")
passIds.Add("directional-shadow-multiview");
else for (int cascade = 0; cascade < cascades; cascade++)
passIds.Add($"directional-shadow-cascade-{cascade}");
passIds.AddRange([
"atmospheric-sun-occlusion", "atmospheric-sun-rays",
"atmospheric-volumetric-shafts", "atmospheric-bloom-downsample",
"atmospheric-bloom-blur-horizontal", "atmospheric-bloom-blur-vertical",
"atmospheric-filmic"]);
object[] passes = passIds.Select((id, index) => new
{
PassId = id,
GpuMilliseconds = 0.1,
DrawCalls = id.StartsWith("directional-", StringComparison.Ordinal) ? shadowDraws :
id is "atmospheric-world-receiver" or "atmospheric-volumetric-shafts" ? 0 : 1,
DispatchCalls = 0,
}).Cast<object>().ToArray();
var performance = new
{
CpuSampleCount = 2048,
AbsoluteReceiverCpuSampleCount = 2048,
GpuSampleCount = 2048,
IncrementalCpuMillisecondsP50 = 0.1,
IncrementalCpuMillisecondsP95 = 0.2,
IncrementalCpuMillisecondsP99 = 0.3,
AbsoluteReceiverCpuMillisecondsP50 = 1.0,
AbsoluteReceiverCpuMillisecondsP95 = 1.5,
AbsoluteReceiverCpuMillisecondsP99 = 2.0,
InclusiveGpuMillisecondsP50 = 2.0,
InclusiveGpuMillisecondsP95 = 3.0,
InclusiveGpuMillisecondsP99 = 4.0,
ResidentGpuBytes = 1000L,
TransientGpuBytes = 0L,
};
return JsonSerializer.Serialize(new
{
SchemaVersion = 1,
Width = 1920,
Height = 1080,
RenderPack = new
{
State = 2,
PackId = "acdream.atmospheric",
PackVersion = "1.0.0",
PresetId = preset,
EffectiveQuality = preset,
FailureReason = (string?)null,
ActivationGeneration = 1,
RetainedGpuBytes = 1000L,
TransientGpuBytes = 0L,
ImageCount = 1,
BufferCount = 1,
DrawCalls = (preset == "low" ? shadowDraws : shadowDraws * cascades) + 6,
DispatchCalls = 0,
ShadowCasterCount = 9498,
CascadeDrawCount = cascades,
CpuClassificationCalls = 0,
Passes = passes,
Performance = performance,
},
});
}
private static string CreateFallbackMetadata(string failureReason) => JsonSerializer.Serialize(new
{
SchemaVersion = 1,
Width = 1920,
Height = 1080,
RenderPack = new
{
State = 3,
PackId = "retail",
PackVersion = (string?)null,
PresetId = "off",
EffectiveQuality = "off",
FailureReason = failureReason,
ActivationGeneration = 2,
RetainedGpuBytes = 0L,
TransientGpuBytes = 0L,
ImageCount = 0,
BufferCount = 0,
DrawCalls = 0,
DispatchCalls = 0,
ShadowCasterCount = 0,
CascadeDrawCount = 0,
CpuClassificationCalls = 0,
Passes = Array.Empty<object>(),
Performance = new
{
CpuSampleCount = 0,
AbsoluteReceiverCpuSampleCount = 0,
GpuSampleCount = 0,
IncrementalCpuMillisecondsP50 = 0.0,
IncrementalCpuMillisecondsP95 = 0.0,
IncrementalCpuMillisecondsP99 = 0.0,
AbsoluteReceiverCpuMillisecondsP50 = 0.0,
AbsoluteReceiverCpuMillisecondsP95 = 0.0,
AbsoluteReceiverCpuMillisecondsP99 = 0.0,
InclusiveGpuMillisecondsP50 = 0.0,
InclusiveGpuMillisecondsP95 = 0.0,
InclusiveGpuMillisecondsP99 = 0.0,
ResidentGpuBytes = 0L,
TransientGpuBytes = 0L,
},
},
});
private static JsonElement RunMetadataOracle(
string metadataPath,
string preset,
bool allowSafeFallback = false)
{
string helper = Path.Combine(FindRepoRoot(), "tools", "atmospheric-performance-matrix-common.ps1");
string quote(string value) => "'" + value.Replace("'", "''", StringComparison.Ordinal) + "'";
var start = new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
start.ArgumentList.Add("-NoProfile");
start.ArgumentList.Add("-NonInteractive");
start.ArgumentList.Add("-Command");
start.ArgumentList.Add(
$". {quote(helper)}; Test-AtmosphericPerformanceMetadataEvidence " +
$"-MetadataPath {quote(metadataPath)} -Preset {preset} -ExpectedWidth 1920 " +
"-ExpectedHeight 1080 " +
(allowSafeFallback ? "-AllowSafeFallback " : string.Empty) +
"| ConvertTo-Json -Depth 8 -Compress");
using Process process = Process.Start(start)!;
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
Assert.True(process.WaitForExit(30_000), "PowerShell oracle did not exit.");
Assert.True(process.ExitCode == 0, $"PowerShell oracle failed.\n{stdout}\n{stderr}");
using JsonDocument document = JsonDocument.Parse(stdout);
return document.RootElement.Clone();
}
private static void AssertPresetBudget(
string source,
string preset,
string cpuP50,
string cpuP99,
string gpuP50,
string gpuP99,
string memory)
{
int start = source.IndexOf($"{preset} = [pscustomobject]", StringComparison.Ordinal);
Assert.True(start >= 0, $"Missing {preset} budget.");
int end = source.IndexOf(" }", start, StringComparison.Ordinal);
Assert.True(end > start, $"Malformed {preset} budget.");
string budget = source[start..end];
Assert.Contains($"IncrementalCpuMillisecondsP50 = {cpuP50}", budget);
Assert.Contains($"IncrementalCpuMillisecondsP99 = {cpuP99}", budget);
Assert.Contains($"InclusiveGpuMillisecondsP50At1080p = {gpuP50}", budget);
Assert.Contains($"InclusiveGpuMillisecondsP99At1080p = {gpuP99}", budget);
Assert.Contains($"ResidentGpuBytes = {memory} * 1024L * 1024L", budget);
}
private static string ReadScript() => File.ReadAllText(ScriptPath());
private static string ScriptPath() => Path.Combine(
FindRepoRoot(),
"tools",
"run-atmospheric-performance-matrix.ps1");
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.");
}
}

View file

@ -0,0 +1,121 @@
using System.Diagnostics;
namespace AcDream.App.Tests.Diagnostics;
public sealed class AtmosphericPreviewLauncherContractTests
{
[Fact]
public void ScriptParsesWithoutLaunchingTheClient()
{
string script = ScriptPath();
var start = new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
start.ArgumentList.Add("-NoProfile");
start.ArgumentList.Add("-NonInteractive");
start.ArgumentList.Add("-Command");
string quotedScript = "'" + script.Replace("'", "''", StringComparison.Ordinal) + "'";
start.ArgumentList.Add(
$"[scriptblock]::Create((Get-Content -Raw -LiteralPath {quotedScript})) | Out-Null");
using Process process = Process.Start(start)
?? throw new InvalidOperationException("Could not start pwsh parser process.");
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
Assert.True(process.WaitForExit(30_000), "PowerShell parser did not exit.");
Assert.True(
process.ExitCode == 0,
$"PowerShell parser failed with exit code {process.ExitCode}.\n{stdout}\n{stderr}");
}
[Fact]
public void PreviewIsAudioSafeIsolatedAndDiagnosticByDefault()
{
string source = File.ReadAllText(ScriptPath());
Assert.Contains("[switch]$EnableAudio", source, StringComparison.Ordinal);
Assert.Contains("$audioEnabled = [bool]$EnableAudio", source, StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_NO_AUDIO = if ($audioEnabled) { $null } else { '1' }",
source,
StringComparison.Ordinal);
Assert.Contains("'enabled-explicit'", source, StringComparison.Ordinal);
Assert.Contains("'disabled-default'", source, StringComparison.Ordinal);
Assert.Contains(
".StartsWith('ACDREAM_', [StringComparison]::OrdinalIgnoreCase)",
source,
StringComparison.Ordinal);
Assert.Contains(
"[Environment]::SetEnvironmentVariable($name, $null, 'Process')",
source,
StringComparison.Ordinal);
Assert.Contains(
"[Environment]::SetEnvironmentVariable($name, $prior[$name], 'Process')",
source,
StringComparison.Ordinal);
AssertAppearsInOrder(
source,
"[Environment]::SetEnvironmentVariable($name, $null, 'Process')",
"$env:ACDREAM_CONFIG_DIR = $config",
"$process = Start-Process",
"[Environment]::SetEnvironmentVariable($name, $prior[$name], 'Process')");
Assert.Contains("schemaVersion = 2", source, StringComparison.Ordinal);
Assert.Contains("executableSha256", source, StringComparison.Ordinal);
Assert.Contains("executableProductVersion", source, StringComparison.Ordinal);
Assert.Contains("stdoutLog = $stdoutLog", source, StringComparison.Ordinal);
Assert.Contains("stderrLog = $stderrLog", source, StringComparison.Ordinal);
Assert.Contains("status = 'prepared'", source, StringComparison.Ordinal);
Assert.Contains("$launch.status = 'start-failed'", source, StringComparison.Ordinal);
Assert.Contains("$launch.status = 'started'", source, StringComparison.Ordinal);
Assert.Contains("-RedirectStandardOutput $stdoutLog", source, StringComparison.Ordinal);
Assert.Contains("-RedirectStandardError $stderrLog", source, StringComparison.Ordinal);
Assert.DoesNotContain("-WindowStyle Hidden", source, StringComparison.Ordinal);
Assert.Contains("if (Test-Path -LiteralPath $root)", source, StringComparison.Ordinal);
Assert.Contains(
"New-Item -ItemType Directory -Path $config, $data, $cache",
source,
StringComparison.Ordinal);
Assert.DoesNotContain(
"New-Item -ItemType Directory -Force -Path $config, $data, $cache",
source,
StringComparison.Ordinal);
Assert.DoesNotContain("prior = $prior", source, StringComparison.OrdinalIgnoreCase);
}
private static string ScriptPath() => Path.Combine(
FindRepoRoot(),
"tools",
"launch-atmospheric-preview.ps1");
private static void AssertAppearsInOrder(string source, params string[] fragments)
{
int cursor = -1;
foreach (string fragment in fragments)
{
int next = source.IndexOf(fragment, cursor + 1, StringComparison.Ordinal);
Assert.True(next > cursor, $"Missing or out-of-order fragment: {fragment}");
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.");
}
}

View file

@ -0,0 +1,505 @@
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Nodes;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Scene;
namespace AcDream.App.Tests.Diagnostics;
public sealed class ConnectedRenderPackGateContractTests
{
private const string LifecycleScript = "run-connected-world-lifecycle-gate.ps1";
private const string SoakScript = "run-connected-r6-soak.ps1";
[Fact]
public void ScreenshotJsonCarriesAuthoritativeCasterClassCounters()
{
DirectionalShadowTransformChurnDiagnostics churn = default;
churn = churn with
{
CasterClasses = new DirectionalShadowCasterClassDiagnostics(
TerrainCommands: 1,
OutdoorStatics: 2,
Buildings: 3,
AnimatedStatics: 4,
LocalPlayers: 5,
RemotePlayers: 6,
NonPlayerCreatures: 7,
OtherLiveDynamics: 8,
EquippedChildren: 9),
};
using JsonDocument json = JsonDocument.Parse(
JsonSerializer.Serialize(churn));
JsonElement classes = json.RootElement.GetProperty("CasterClasses");
Assert.Equal(1, classes.GetProperty("TerrainCommands").GetInt32());
Assert.Equal(2, classes.GetProperty("OutdoorStatics").GetInt32());
Assert.Equal(3, classes.GetProperty("Buildings").GetInt32());
Assert.Equal(4, classes.GetProperty("AnimatedStatics").GetInt32());
Assert.Equal(5, classes.GetProperty("LocalPlayers").GetInt32());
Assert.Equal(6, classes.GetProperty("RemotePlayers").GetInt32());
Assert.Equal(7, classes.GetProperty("NonPlayerCreatures").GetInt32());
Assert.Equal(8, classes.GetProperty("OtherLiveDynamics").GetInt32());
Assert.Equal(9, classes.GetProperty("EquippedChildren").GetInt32());
}
private const string CommonScript = "connected-render-pack-gate-common.ps1";
[Fact]
public void ConnectedGatesExposeTheSameRetailDefaultAndOptionalOverrides()
{
foreach (string scriptName in new[] { LifecycleScript, SoakScript })
{
string source = ReadTool(scriptName);
Assert.Contains(
"[ValidateSet('retail', 'low', 'medium', 'high', 'auto')]",
source,
StringComparison.Ordinal);
Assert.Contains(
"[string]$RenderPackPreset = 'retail'",
source,
StringComparison.Ordinal);
Assert.Contains(
"[hashtable]$RenderPackSettingOverrides = @{}",
source,
StringComparison.Ordinal);
Assert.Contains(
". (Join-Path $PSScriptRoot 'connected-render-pack-gate-common.ps1')",
source,
StringComparison.Ordinal);
Assert.Contains(
"-Preset $RenderPackPreset",
source,
StringComparison.Ordinal);
Assert.Contains(
"-SettingOverrides $RenderPackSettingOverrides",
source,
StringComparison.Ordinal);
}
}
[Fact]
public void SharedSeamPinsSchemaAndOwnsTheCompleteConnectedEnvironmentTransaction()
{
string source = ReadTool(CommonScript);
foreach (string variable in new[]
{
"ACDREAM_CONFIG_DIR", "ACDREAM_DATA_DIR", "ACDREAM_CACHE_DIR",
"ACDREAM_DAT_DIR", "ACDREAM_PAK_PATH", "ACDREAM_LIVE", "ACDREAM_TEST_HOST",
"ACDREAM_TEST_PORT", "ACDREAM_TEST_USER", "ACDREAM_TEST_PASS",
"ACDREAM_RETAIL_UI", "ACDREAM_FRAME_PROF", "ACDREAM_FRAME_HISTORY",
"ACDREAM_UNCAPPED_RENDER", "ACDREAM_DEVTOOLS", "ACDREAM_UI_PROBE_DUMP",
"ACDREAM_UI_PROBE_SCRIPT", "ACDREAM_AUTOMATION_ARTIFACT_DIR",
"ACDREAM_DUMP_MOVE_TRUTH", "ACDREAM_NO_AUDIO", "ACDREAM_WB_DIAG",
"ACDREAM_RENDER_BACKEND", "ACDREAM_NET_DROP_PCT",
"ACDREAM_NET_DROP_SEED", "ACDREAM_NET_DROP_DIR",
"ACDREAM_COLLISION_SHADOW_EVERY", "ACDREAM_COLLISION_SHADOW_DIR",
"ACDREAM_AUTOMATION_EXACT_FRAMEBUFFER", "ACDREAM_DAY_GROUP",
"ACDREAM_WORLD_TIME", "ACDREAM_SKY_PHASE_SECONDS",
"ACDREAM_ORBIT_DISTANCE_METERS", "ACDREAM_ORBIT_YAW_DEGREES",
"ACDREAM_ORBIT_PITCH_DEGREES", "ACDREAM_VULKAN_DEVICE",
"ACDREAM_VULKAN_FORCE_UNSUPPORTED", "ACDREAM_VULKAN_PROBE",
"ACDREAM_VULKAN_PROBE_FRAMES",
})
Assert.Contains($"'{variable}'", source, StringComparison.Ordinal);
Assert.Contains("$State.PreviousEnvironment.GetEnumerator()", source, StringComparison.Ordinal);
Assert.Contains("Get-ChildItem Env:", source, StringComparison.Ordinal);
Assert.Contains("Remove-Item -LiteralPath \"Env:$name\"", source, StringComparison.Ordinal);
Assert.Contains("Assert-ConnectedGateContainedPath", source, StringComparison.Ordinal);
Assert.Contains("Assert-ConnectedGateNoReparsePoint", source, StringComparison.Ordinal);
}
[Fact]
public void PowerShellRoundTripRestoresEveryConnectedVariableIncludingCredentials()
{
string root = Path.Combine(Path.GetTempPath(), $"acdream-connected-pack-{Guid.NewGuid():N}");
Directory.CreateDirectory(root);
try
{
string common = PsQuote(Path.Combine(FindRepoRoot(), "tools", CommonScript));
string rootQuoted = PsQuote(root);
string command = $@"
. {common}
foreach ($name in $script:ConnectedGateEnvironmentNames) {{
[Environment]::SetEnvironmentVariable($name, ""sentinel-$name"", 'Process')
}}
[Environment]::SetEnvironmentVariable('ACDREAM_FUTURE_GATE_KNOB', 'sentinel-future', 'Process')
$state = New-ConnectedRenderPackGateState -Root {rootQuoted} -Preset medium
$isolated=@($state.PreviousEnvironment.Keys | Where-Object {{
$_ -notin @('ACDREAM_CONFIG_DIR', 'ACDREAM_DATA_DIR', 'ACDREAM_CACHE_DIR') -and
[Environment]::GetEnvironmentVariable($_, 'Process') -ne $null
}})
foreach ($name in $script:ConnectedGateEnvironmentNames) {{
[Environment]::SetEnvironmentVariable($name, ""mutated-$name"", 'Process')
}}
[Environment]::SetEnvironmentVariable('ACDREAM_FUTURE_GATE_KNOB', 'mutated-future', 'Process')
Restore-ConnectedRenderPackGateEnvironment $state
$mismatches=@($script:ConnectedGateEnvironmentNames | Where-Object {{
[Environment]::GetEnvironmentVariable($_, 'Process') -cne ""sentinel-$_""
}})
$unsafeLeafRejected=$false
try {{ Assert-ConnectedGateSafeLeafName '../escape' }} catch {{ $unsafeLeafRejected=$true }}
$escapeRejected=$false
try {{ Assert-ConnectedGateContainedPath {rootQuoted} (Join-Path {rootQuoted} '..\escape') }} catch {{ $escapeRejected=$true }}
[pscustomobject]@{{
Password=$env:ACDREAM_TEST_PASS; User=$env:ACDREAM_TEST_USER;
Config=$env:ACDREAM_CONFIG_DIR; History=$env:ACDREAM_FRAME_HISTORY;
Future=$env:ACDREAM_FUTURE_GATE_KNOB; Isolated=$isolated; Mismatches=$mismatches;
UnsafeLeafRejected=$unsafeLeafRejected; EscapeRejected=$escapeRejected;
Settings=(Get-Content -Raw -LiteralPath (Join-Path $state.ConfigDirectory 'settings.json') | ConvertFrom-Json).display.renderPack.presetId
}} | ConvertTo-Json -Compress";
using JsonDocument result = JsonDocument.Parse(RunPowerShell(command));
JsonElement rootElement = result.RootElement;
Assert.Equal("sentinel-ACDREAM_TEST_PASS", rootElement.GetProperty("Password").GetString());
Assert.Equal("sentinel-ACDREAM_TEST_USER", rootElement.GetProperty("User").GetString());
Assert.Equal("sentinel-ACDREAM_CONFIG_DIR", rootElement.GetProperty("Config").GetString());
Assert.Equal("sentinel-ACDREAM_FRAME_HISTORY", rootElement.GetProperty("History").GetString());
Assert.Equal("sentinel-future", rootElement.GetProperty("Future").GetString());
Assert.Empty(rootElement.GetProperty("Isolated").EnumerateArray());
Assert.Empty(rootElement.GetProperty("Mismatches").EnumerateArray());
Assert.True(rootElement.GetProperty("UnsafeLeafRejected").GetBoolean());
Assert.True(rootElement.GetProperty("EscapeRejected").GetBoolean());
Assert.Equal("medium", rootElement.GetProperty("Settings").GetString());
}
finally { Directory.Delete(root, recursive: true); }
}
[Fact]
public void EveryConnectedScreenshotMustProveExactFailureFreeActivation()
{
string common = ReadTool(CommonScript);
Assert.Contains("screenshots\\$name.metadata.json", common, StringComparison.Ordinal);
Assert.Contains("@('PackId', [string]$State.PackId)", common, StringComparison.Ordinal);
Assert.Contains("@('PresetId', [string]$State.PresetId)", common, StringComparison.Ordinal);
Assert.Contains("[int]$actual.State -ne [int]$State.ExpectedState", common, StringComparison.Ordinal);
Assert.Contains(
"[string]::IsNullOrWhiteSpace([string]$actual.FailureReason)",
common,
StringComparison.Ordinal);
Assert.Contains("SchemaVersion", common, StringComparison.Ordinal);
Assert.Contains("ActivationGeneration", common, StringComparison.Ordinal);
Assert.Contains("EffectiveQuality", common, StringComparison.Ordinal);
Assert.Contains("retained GPU byte ledgers disagree", common, StringComparison.Ordinal);
Assert.Contains("expected zero pack work", common, StringComparison.Ordinal);
Assert.Contains("recorded no complete pack graph work", common, StringComparison.Ordinal);
Assert.Contains("positive shadow strength but no shadow casters", common, StringComparison.Ordinal);
string lifecycle = ReadTool(LifecycleScript);
Assert.Contains("-ScreenshotNames @($name)", lifecycle, StringComparison.Ordinal);
Assert.Contains("-Label $Label", lifecycle, StringComparison.Ordinal);
string soak = ReadTool(SoakScript);
Assert.Contains("-ScreenshotNames $expectedCheckpointNames", soak, StringComparison.Ordinal);
Assert.Contains("-Label $runName", soak, StringComparison.Ordinal);
}
[Fact]
public void LifecycleGateExecutesAtomicTransitionsResizeEnvironmentAndFreshContextRow()
{
string lifecycle = ReadTool(LifecycleScript);
Assert.Contains("if ($RenderPackPreset -eq 'medium')", lifecycle, StringComparison.Ordinal);
Assert.Contains("connected-render-pack-transitions.route.txt", lifecycle, StringComparison.Ordinal);
Assert.Contains("Get-ConnectedRenderPackExpectation -Preset high", lifecycle, StringComparison.Ordinal);
Assert.Contains("Get-ConnectedRenderPackExpectation -Preset retail", lifecycle, StringComparison.Ordinal);
Assert.Contains("ScreenshotStateOverrides", lifecycle, StringComparison.Ordinal);
Assert.Contains("Get-FreshContextRecreationGate $capped $uncapped", lifecycle, StringComparison.Ordinal);
Assert.Contains("StartTimeUtc", lifecycle, StringComparison.Ordinal);
Assert.Contains("resized screenshot was", lifecycle, StringComparison.OrdinalIgnoreCase);
Assert.Contains("authored time change did not alter published sun elevation", lifecycle, StringComparison.Ordinal);
Assert.Contains("first weather edge did not publish Overcast", lifecycle, StringComparison.Ordinal);
Assert.Contains("$selected.ShadowTransformChurn.CasterClasses", lifecycle, StringComparison.Ordinal);
foreach (string casterClass in new[]
{
"TerrainCommands",
"OutdoorStatics",
"Buildings",
"AnimatedStatics",
"LocalPlayers",
"NonPlayerCreatures",
"EquippedChildren",
})
{
Assert.Contains(casterClass, lifecycle, StringComparison.Ordinal);
}
Assert.Contains("second live client", lifecycle, StringComparison.Ordinal);
Assert.Contains("not hostile monster", lifecycle, StringComparison.Ordinal);
Assert.Contains("no authoritative tree discriminator", lifecycle, StringComparison.Ordinal);
string route = ReadTool("connected-render-pack-transitions.route.txt");
AssertAppearsInOrder(
route,
"renderpack select high",
"wait render-pack high 90000",
"renderpack disable",
"wait render-pack retail 90000",
"renderpack reenable",
"wait render-pack high 90000",
"resize 1024 768",
"wait framebuffer 1024 768 30000",
"input press AcdreamCycleTimeOfDay",
"input press AcdreamCycleWeather",
"input press AcdreamCycleWeather",
"checkpoint atmospheric_transitions");
Assert.Contains("transition_selected_high", route, StringComparison.Ordinal);
Assert.Contains("transition_disabled_retail", route, StringComparison.Ordinal);
Assert.Contains("transition_reenabled_high", route, StringComparison.Ordinal);
Assert.Contains("transition_resized_high", route, StringComparison.Ordinal);
Assert.Contains("transition_overcast_high", route, StringComparison.Ordinal);
Assert.Contains("transition_rain_high", route, StringComparison.Ordinal);
}
[Fact]
public void ExecutableMetadataGateAcceptsAutoQualityAndRejectsLedgerOrVersionDrift()
{
string root = Path.Combine(Path.GetTempPath(), $"acdream-connected-metadata-{Guid.NewGuid():N}");
Directory.CreateDirectory(Path.Combine(root, "screenshots"));
string path = Path.Combine(root, "screenshots", "checkpoint.metadata.json");
try
{
var document = new
{
SchemaVersion = 1,
RenderPack = new
{
PackId = "acdream.atmospheric",
PackVersion = "1.0.0",
PresetId = "auto",
State = 2,
ActivationGeneration = 3,
EffectiveQuality = "medium",
FailureReason = (string?)null,
RetainedGpuBytes = 123L,
TransientGpuBytes = 4L,
ImageCount = 4,
BufferCount = 2,
DrawCalls = 6,
DispatchCalls = 0,
ShadowCasterCount = 22,
CascadeDrawCount = 3,
CpuClassificationCalls = 0,
SharedWorldTransformUsedInstances = 68_395u,
Outdoor = true,
DirectionalShadowStrength = 0.75,
Passes = new[]
{
new { PassId = "directional-shadow", GpuMilliseconds = 0.2, DrawCalls = 2, DispatchCalls = 0 },
},
Performance = new { ResidentGpuBytes = 123L, TransientGpuBytes = 4L },
},
};
File.WriteAllText(path, JsonSerializer.Serialize(document));
JsonElement valid = RunConnectedMetadataGate(root);
Assert.Empty(valid.GetProperty("Failures").EnumerateArray());
JsonNode invalid = JsonNode.Parse(File.ReadAllText(path))!;
invalid["SchemaVersion"] = 2;
invalid["RenderPack"]!["PackVersion"] = "9.9.9";
invalid["RenderPack"]!["EffectiveQuality"] = "ultra";
invalid["RenderPack"]!["RetainedGpuBytes"] = 999;
File.WriteAllText(path, invalid.ToJsonString());
JsonElement rejected = RunConnectedMetadataGate(root);
string failures = rejected.GetProperty("Failures").ToString();
Assert.Contains("schema was 2", failures, StringComparison.Ordinal);
Assert.Contains("PackVersion '9.9.9'", failures, StringComparison.Ordinal);
Assert.Contains("effective quality 'ultra'", failures, StringComparison.Ordinal);
Assert.Contains("retained GPU byte ledgers disagree", failures, StringComparison.Ordinal);
}
finally { Directory.Delete(root, recursive: true); }
}
[Fact]
public void ExecutableMetadataGateRejectsActiveNoWorkAndRetailPackWork()
{
string root = Path.Combine(Path.GetTempPath(), $"acdream-connected-work-{Guid.NewGuid():N}");
Directory.CreateDirectory(Path.Combine(root, "screenshots"));
string path = Path.Combine(root, "screenshots", "checkpoint.metadata.json");
try
{
var activeNoWork = new
{
SchemaVersion = 1,
RenderPack = new
{
PackId = "acdream.atmospheric",
PackVersion = "1.0.0",
PresetId = "auto",
State = 2,
ActivationGeneration = 1,
EffectiveQuality = "low",
FailureReason = (string?)null,
RetainedGpuBytes = 0L,
TransientGpuBytes = 0L,
ImageCount = 0,
BufferCount = 0,
DrawCalls = 0,
DispatchCalls = 0,
ShadowCasterCount = 0,
CascadeDrawCount = 0,
CpuClassificationCalls = 0,
SharedWorldTransformUsedInstances = 0u,
Outdoor = true,
DirectionalShadowStrength = 0.5,
Passes = Array.Empty<object>(),
Performance = new { ResidentGpuBytes = 0L, TransientGpuBytes = 0L },
},
};
File.WriteAllText(path, JsonSerializer.Serialize(activeNoWork));
JsonElement activeRejected = RunConnectedMetadataGate(root);
string activeFailures = activeRejected.GetProperty("Failures").ToString();
Assert.Contains("recorded no complete pack graph work", activeFailures, StringComparison.Ordinal);
Assert.Contains("positive shadow strength but no shadow casters", activeFailures, StringComparison.Ordinal);
Assert.Contains("positive shadow strength but no combined shared-world-transform usage", activeFailures, StringComparison.Ordinal);
var retailWork = new
{
SchemaVersion = 1,
RenderPack = new
{
PackId = "retail",
PackVersion = (string?)null,
PresetId = "off",
State = 0,
ActivationGeneration = 0,
EffectiveQuality = "off",
FailureReason = (string?)null,
RetainedGpuBytes = 64L,
TransientGpuBytes = 0L,
ImageCount = 1,
BufferCount = 0,
DrawCalls = 1,
DispatchCalls = 0,
ShadowCasterCount = 0,
CascadeDrawCount = 0,
CpuClassificationCalls = 0,
SharedWorldTransformUsedInstances = 1u,
Outdoor = false,
DirectionalShadowStrength = 0.0,
Passes = new[]
{
new { PassId = "unexpected", GpuMilliseconds = 0.1, DrawCalls = 1, DispatchCalls = 0 },
},
Performance = new { ResidentGpuBytes = 64L, TransientGpuBytes = 0L },
},
};
File.WriteAllText(path, JsonSerializer.Serialize(retailWork));
JsonElement retailRejected = RunConnectedMetadataGate(root, "retail");
string retailFailures = retailRejected.GetProperty("Failures").ToString();
Assert.Contains("expected zero pack work", retailFailures, StringComparison.Ordinal);
Assert.Contains("recorded pack passes, expected none", retailFailures, StringComparison.Ordinal);
}
finally { Directory.Delete(root, recursive: true); }
}
[Fact]
public void BothGatesFailClosedOnUnprovableBinaryIdentity()
{
string common = ReadTool(CommonScript);
Assert.Contains("Measured binary commit $binaryCommit differs", common, StringComparison.Ordinal);
Assert.Contains("status --short --untracked-files=all", common, StringComparison.Ordinal);
Assert.Contains("Connected closeout evidence cannot prove binary/source identity", common, StringComparison.Ordinal);
foreach (string scriptName in new[] { LifecycleScript, SoakScript })
Assert.Contains("Get-ConnectedGateBinaryIdentity", ReadTool(scriptName), StringComparison.Ordinal);
}
[Fact]
public void BothGatesRestoreEnvironmentAndRecordRequestedSelection()
{
foreach (string scriptName in new[] { LifecycleScript, SoakScript })
{
string source = ReadTool(scriptName);
int selectionStart = source.IndexOf(
"$renderPackGate = New-ConnectedRenderPackGateState",
StringComparison.Ordinal);
Assert.True(selectionStart >= 0, $"{scriptName} does not initialize isolated state.");
string selectionScope = source[selectionStart..];
AssertAppearsInOrder(
selectionScope,
"$renderPackGate = New-ConnectedRenderPackGateState",
"try {",
"RenderPackSelection = (Get-ConnectedRenderPackGateReport $renderPackGate)",
"finally {",
"Restore-ConnectedRenderPackGateEnvironment $renderPackGate");
Assert.Contains(
"Add-ConnectedRenderPackMetadataFailures",
source,
StringComparison.Ordinal);
Assert.Contains("Start-Process -FilePath $exe", source, StringComparison.Ordinal);
}
}
private static string ReadTool(string fileName) => File.ReadAllText(Path.Combine(
FindRepoRoot(),
"tools",
fileName));
private static string PsQuote(string value) => "'" + value.Replace("'", "''", StringComparison.Ordinal) + "'";
private static string RunPowerShell(string command)
{
var start = new ProcessStartInfo
{
FileName = OperatingSystem.IsWindows() ? "pwsh.exe" : "pwsh",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
};
start.ArgumentList.Add("-NoProfile");
start.ArgumentList.Add("-NonInteractive");
start.ArgumentList.Add("-Command");
start.ArgumentList.Add(command);
using Process process = Process.Start(start)!;
string stdout = process.StandardOutput.ReadToEnd();
string stderr = process.StandardError.ReadToEnd();
Assert.True(process.WaitForExit(30_000), "PowerShell did not exit.");
Assert.True(process.ExitCode == 0, $"PowerShell failed.\n{stdout}\n{stderr}");
return stdout.Trim();
}
private static JsonElement RunConnectedMetadataGate(
string artifactRoot,
string requestedPreset = "auto")
{
string common = PsQuote(Path.Combine(FindRepoRoot(), "tools", CommonScript));
string root = PsQuote(artifactRoot);
string preset = PsQuote(requestedPreset);
string packId = PsQuote(requestedPreset == "retail" ? "retail" : "acdream.atmospheric");
string packVersion = requestedPreset == "retail" ? "$null" : "'1.0.0'";
string presetId = PsQuote(requestedPreset == "retail" ? "off" : requestedPreset);
int expectedState = requestedPreset == "retail" ? 0 : 2;
string command = $@"
. {common}
$state=[pscustomobject]@{{RequestedPreset={preset};PackId={packId};PackVersion={packVersion};PresetId={presetId};ExpectedState={expectedState};ExpectedSchemaVersion=1}}
$failures=[Collections.Generic.List[string]]::new()
Add-ConnectedRenderPackMetadataFailures -ArtifactDirectory {root} -ScreenshotNames @('checkpoint') -State $state -Failures $failures -Label synthetic
[pscustomobject]@{{Failures=@($failures)}} | ConvertTo-Json -Depth 5 -Compress";
using JsonDocument document = JsonDocument.Parse(RunPowerShell(command));
return document.RootElement.Clone();
}
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.");
}
}

View file

@ -268,6 +268,115 @@ public sealed class ConnectedWorldSoakRouteContractTests
StringComparison.Ordinal);
}
[Fact]
public void AtmosphericOfflineGateDefaultsToCappedAndExposesUncappedMeasurement()
{
string source = File.ReadAllText(Path.Combine(
FindRepoRoot(),
"tools",
"run-offline-pixel-gate.ps1"));
Assert.Contains("[switch]$Uncapped", source, StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_UNCAPPED_RENDER = if ($Uncapped) { '1' } else { $null }",
source,
StringComparison.Ordinal);
Assert.Contains(
"$previousUncappedRender = $env:ACDREAM_UNCAPPED_RENDER",
source,
StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_UNCAPPED_RENDER = $previousUncappedRender",
source,
StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_AUTOMATION_EXACT_FRAMEBUFFER = '1'",
source,
StringComparison.Ordinal);
Assert.Contains(
"$previousExactFramebuffer = $env:ACDREAM_AUTOMATION_EXACT_FRAMEBUFFER",
source,
StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_AUTOMATION_EXACT_FRAMEBUFFER = $previousExactFramebuffer",
source,
StringComparison.Ordinal);
Assert.Contains("-WindowStyle Hidden", source, StringComparison.Ordinal);
Assert.DoesNotContain("-WindowStyle Minimized", source, StringComparison.Ordinal);
Assert.Contains(
"[int]$RequiredRenderPackSamples = 0",
source,
StringComparison.Ordinal);
Assert.Contains(
"$probeCommands.Add('renderpack reset-performance')",
source,
StringComparison.Ordinal);
Assert.Contains(
"if ($RenderPackPreset -ne 'auto')",
source,
StringComparison.Ordinal);
Assert.Contains(
"wait render-pack-samples $RequiredRenderPackSamples $RenderPackSampleTimeoutMs",
source,
StringComparison.Ordinal);
int reset = source.IndexOf(
"$probeCommands.Add('renderpack reset-performance')",
StringComparison.Ordinal);
int wait = source.IndexOf(
"wait render-pack-samples $RequiredRenderPackSamples $RenderPackSampleTimeoutMs",
StringComparison.Ordinal);
int screenshot = source.IndexOf(
"$probeCommands.Add('screenshot world-offline 30000')",
StringComparison.Ordinal);
int closeClient = source.IndexOf(
"$probeCommands.Add('close-client')",
StringComparison.Ordinal);
Assert.True(
reset >= 0 && wait > reset && screenshot > wait
&& closeClient > screenshot);
Assert.Contains("$proc.WaitForExit(15000)", source, StringComparison.Ordinal);
Assert.DoesNotContain(
"Get-Process -Name AcDream.App",
source,
StringComparison.Ordinal);
Assert.DoesNotContain(".CloseMainWindow()", source, StringComparison.Ordinal);
}
[Fact]
public void AtmosphericPreviewLaunchesAcdreamWithDisposableStateAndNoLiveCredentials()
{
string source = File.ReadAllText(Path.Combine(
FindRepoRoot(),
"tools",
"launch-atmospheric-preview.ps1"));
Assert.Contains("AcDream.App.exe", source, StringComparison.Ordinal);
Assert.Contains("packId = 'acdream.atmospheric'", source, StringComparison.Ordinal);
Assert.Contains("artifacts\\atmospheric-rendering\\visible-", source, StringComparison.Ordinal);
Assert.Contains("$env:ACDREAM_CONFIG_DIR = $config", source, StringComparison.Ordinal);
Assert.Contains("$env:ACDREAM_DATA_DIR = $data", source, StringComparison.Ordinal);
Assert.Contains("$env:ACDREAM_CACHE_DIR = $cache", source, StringComparison.Ordinal);
Assert.Contains(
".StartsWith('ACDREAM_', [StringComparison]::OrdinalIgnoreCase)",
source,
StringComparison.Ordinal);
Assert.Contains(
"[Environment]::SetEnvironmentVariable($name, $null, 'Process')",
source,
StringComparison.Ordinal);
Assert.Contains(
"[Environment]::SetEnvironmentVariable($name, $prior[$name], 'Process')",
source,
StringComparison.Ordinal);
Assert.Contains(
"$env:ACDREAM_NO_AUDIO = if ($audioEnabled) { $null } else { '1' }",
source,
StringComparison.Ordinal);
Assert.Contains("-RedirectStandardOutput $stdoutLog", source, StringComparison.Ordinal);
Assert.Contains("-RedirectStandardError $stderrLog", source, StringComparison.Ordinal);
Assert.DoesNotContain("-WindowStyle Hidden", source, StringComparison.Ordinal);
}
[Fact]
public void StationaryDwellSamplesAfterTheLivenessDeadline()
{
@ -317,7 +426,7 @@ public sealed class ConnectedWorldSoakRouteContractTests
source,
StringComparison.Ordinal);
Assert.Contains(
"$sensitive = $_.Name -match '(?i)(PASS|PASSWORD|TOKEN|SECRET|KEY)'",
"$sensitive = $_.Name -match '(?i)(PASS|PASSWORD|TOKEN|SECRET|KEY|USER|ACCOUNT)'",
source,
StringComparison.Ordinal);
Assert.Contains(
@ -337,24 +446,23 @@ public sealed class ConnectedWorldSoakRouteContractTests
"tools",
"run-connected-r6-soak.ps1"));
string common = File.ReadAllText(Path.Combine(
FindRepoRoot(), "tools", "connected-render-pack-gate-common.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);
"$binaryIdentity = Get-ConnectedGateBinaryIdentity",
"$sourceCommit = $binaryIdentity.SourceCommit",
"$binaryCommit = $binaryIdentity.BinaryCommit",
"$commit = $binaryCommit");
Assert.Contains("[Diagnostics.FileVersionInfo]::GetVersionInfo($Executable).ProductVersion", common);
Assert.Contains("status --short --untracked-files=all", common, 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,
"Measured binary commit $binaryCommit differs from checked-out source commit $sourceCommit",
common,
StringComparison.Ordinal);
}

View file

@ -1,6 +1,7 @@
using System.Text.Json;
using AcDream.App.Diagnostics;
using AcDream.App.Rendering;
using AcDream.App.Rendering.Packs;
using AcDream.App.Rendering.Residency;
using AcDream.App.Rendering.Scene;
using AcDream.App.Streaming;
@ -82,6 +83,70 @@ public sealed class WorldLifecycleAutomationControllerTests
}
}
[Fact]
public void ScreenshotCapture_WritesRenderPackChoiceAndAtmosphereMetadata()
{
string directory = NewDirectory();
var diagnostics = new RenderPackDiagnosticsSnapshot(
RenderPackActivationState.Active,
"acdream.atmospheric",
"1.0.0",
"high",
"medium",
FailureReason: null,
ActivationGeneration: 7,
RetainedGpuBytes: 64,
TransientGpuBytes: 32,
ImageCount: 5,
BufferCount: 2,
DrawCalls: 12,
DispatchCalls: 4,
ShadowCasterCount: 22,
CascadeDrawCount: 44,
CpuClassificationCalls: 1,
SunElevationDegrees: 14.5,
ActiveDayGroup: 2,
Weather: "Clear",
WeatherIntensity: 0.25,
Outdoor: true,
DirectionalShadowStrength: 0.8,
Passes: [])
{
SharedWorldTransformUsedInstances = 68_395,
};
var controller = new FrameScreenshotController(
(_, _) => [255, 255, 255, 255],
directory,
renderPackMetadata: () => diagnostics);
Assert.Contains(
"worldTransforms=68395used",
RenderPackDiagnosticsFormatter.Format(diagnostics),
StringComparison.Ordinal);
try
{
Assert.True(controller.TryRequest("enhanced", out string error), error);
Assert.True(controller.CapturePending(1, 1));
using JsonDocument metadata = JsonDocument.Parse(
File.ReadAllText(Path.Combine(directory, "enhanced.metadata.json")));
JsonElement root = metadata.RootElement;
Assert.Equal(1, root.GetProperty("SchemaVersion").GetInt32());
JsonElement pack = root.GetProperty("RenderPack");
Assert.Equal("acdream.atmospheric", pack.GetProperty("PackId").GetString());
Assert.Equal("medium", pack.GetProperty("EffectiveQuality").GetString());
Assert.Equal(14.5, pack.GetProperty("SunElevationDegrees").GetDouble());
Assert.True(pack.GetProperty("Outdoor").GetBoolean());
Assert.Equal(
68_395u,
pack.GetProperty("SharedWorldTransformUsedInstances").GetUInt32());
}
finally
{
Directory.Delete(directory, recursive: true);
}
}
[Theory]
[InlineData("")]
[InlineData("../escape")]
@ -377,6 +442,7 @@ public sealed class WorldLifecycleAutomationControllerTests
var screenshots = new FrameScreenshotController(
(_, _) => [0, 0, 0, 255],
Path.Combine(directory, "screenshots"));
int clientCloseRequests = 0;
var controller = new WorldLifecycleAutomationController(
() => reveal,
() => new RuntimeWorldEnvironmentOwnershipSnapshot(
@ -395,13 +461,18 @@ public sealed class WorldLifecycleAutomationControllerTests
() => 3,
_ => resources,
screenshots,
directory);
directory,
requestClientClose: () => clientCloseRequests++);
try
{
Assert.True(controller.IsWorldReady);
Assert.True(controller.IsWorldViewportVisible);
Assert.Equal(3, controller.PortalMaterializationCount);
Assert.True(
controller.TryRequestClientClose(out string closeError),
closeError);
Assert.Equal(1, clientCloseRequests);
Assert.True(controller.TryRequestCheckpoint(
"dungeon",
out IRetailUiAutomationCheckpoint? request,
@ -591,6 +662,115 @@ public sealed class WorldLifecycleAutomationControllerTests
}
}
[Fact]
public void RenderPackPerformanceReset_IsNoOpOnlyAfterFailedToRetail()
{
string directory = NewDirectory();
bool failedToRetail = true;
int resetCalls = 0;
var controller = new WorldLifecycleAutomationController(
() => default,
() => default,
() => default,
() => 0,
_ => EmptyResources(),
new FrameScreenshotController((_, _) => [], directory),
directory,
getRenderPackPerformanceSampleCount: () => 0,
resetRenderPackPerformance: () =>
{
resetCalls++;
return (true, string.Empty);
},
getRenderPackFailedToRetail: () => failedToRetail);
try
{
Assert.True(controller.RenderPackFailedToRetail);
Assert.True(controller.TryResetRenderPackPerformance(out string fallbackError));
Assert.Empty(fallbackError);
Assert.Equal(0, resetCalls);
failedToRetail = false;
Assert.True(controller.TryResetRenderPackPerformance(out string activeError));
Assert.Empty(activeError);
Assert.Equal(1, resetCalls);
}
finally
{
controller.Dispose();
Directory.Delete(directory, recursive: true);
}
}
[Fact]
public void TransitionAutomationDelegatesPreserveExactDisableReenableAndResizeOwnership()
{
string directory = NewDirectory();
var status = new RetailUiAutomationRenderPackStatus(
RetailUiAutomationRenderPackState.Active,
"acdream.atmospheric",
"medium",
ActivationGeneration: 1,
FailureReason: null);
var framebuffer = (Width: 1280, Height: 720);
var calls = new List<string>();
var controller = new WorldLifecycleAutomationController(
() => default,
() => default,
() => default,
() => 0,
_ => EmptyResources(),
new FrameScreenshotController((_, _) => [], directory),
directory,
getRenderPackStatus: () => status,
selectRenderPack: preset =>
{
calls.Add($"select:{preset}");
return (true, string.Empty);
},
disableRenderPack: () =>
{
calls.Add("disable-exact");
return (true, string.Empty);
},
reenableRenderPack: () =>
{
calls.Add("reenable-exact");
return (true, string.Empty);
},
getFramebufferSize: () => framebuffer,
resizeFramebuffer: (width, height) =>
{
calls.Add($"resize:{width}x{height}");
framebuffer = (width, height);
return (true, string.Empty);
});
try
{
Assert.Equal(status, controller.RenderPackStatus);
Assert.True(controller.TrySelectRenderPack("high", out string selectError));
Assert.Empty(selectError);
Assert.True(controller.TryDisableRenderPack(out string disableError));
Assert.Empty(disableError);
Assert.True(controller.TryReenableRenderPack(out string reenableError));
Assert.Empty(reenableError);
Assert.True(controller.TryResizeFramebuffer(1024, 768, out string resizeError));
Assert.Empty(resizeError);
Assert.Equal(1024, controller.FramebufferWidth);
Assert.Equal(768, controller.FramebufferHeight);
Assert.Equal(
["select:high", "disable-exact", "reenable-exact", "resize:1024x768"],
calls);
}
finally
{
controller.Dispose();
Directory.Delete(directory, recursive: true);
}
}
private static WorldLifecycleAutomationController CreateController(
string directory,
Func<RenderFrameOutcome, WorldLifecycleResourceSnapshot> capture) =>