test(app): add canonical connected soak snapshots
Make scripted lifecycle checkpoints acknowledged post-diagnostics render barriers, capture the exact frame outcome beside canonical resource ownership, and harden the nine-stop route with ordered same-location cache and lifetime gates without weakening process residency thresholds. Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
parent
2862622ba2
commit
bca4148739
17 changed files with 995 additions and 52 deletions
|
|
@ -40,6 +40,7 @@ input up MovementForward
|
|||
sleep 700
|
||||
input press CombatToggleCombat
|
||||
sleep 7400
|
||||
checkpoint caul-baseline
|
||||
|
||||
# Sawato baseline.
|
||||
command /teleloc 0x3032001C 83.3 89.2 133.005
|
||||
|
|
@ -49,6 +50,7 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint sawato-baseline
|
||||
|
||||
# Rynthid world-edge streaming.
|
||||
command /teleloc 0xF6820033 145.7 49.855 58.010
|
||||
|
|
@ -58,6 +60,7 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint rynthid
|
||||
|
||||
# Aerlinthe dense island.
|
||||
command /teleloc 0x09040008 11.4 188.6 87.705
|
||||
|
|
@ -67,6 +70,7 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint aerlinthe
|
||||
|
||||
# Same-location lifecycle revisit.
|
||||
command /teleloc 0x3032001C 83.3 89.2 133.005
|
||||
|
|
@ -76,6 +80,7 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint sawato-return
|
||||
|
||||
# Holtburg mixed-town workload + local exercise.
|
||||
command /teleloc 0xA9B40019 84.0 7.1 94.005
|
||||
|
|
@ -113,6 +118,7 @@ input up MovementForward
|
|||
sleep 700
|
||||
input press CombatToggleCombat
|
||||
sleep 7400
|
||||
checkpoint holtburg
|
||||
|
||||
# Caul return/leak oracle + final local exercise.
|
||||
command /teleloc 0xC95B0001 14.8 0.3 12.005
|
||||
|
|
@ -150,6 +156,7 @@ input up MovementForward
|
|||
sleep 700
|
||||
input press CombatToggleCombat
|
||||
sleep 15000
|
||||
checkpoint caul-return
|
||||
|
||||
# A second warm-cache Sawato/Caul revisit is the plateau oracle. The first
|
||||
# circuit intentionally warms bounded DAT/GPU caches, so comparing the cold
|
||||
|
|
@ -162,6 +169,7 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint sawato-plateau
|
||||
|
||||
command /teleloc 0xC95B0001 14.8 0.3 12.005
|
||||
wait materialized 9 60000
|
||||
|
|
@ -170,3 +178,4 @@ input down MovementTurnRight
|
|||
sleep 6000
|
||||
input up MovementTurnRight
|
||||
sleep 22000
|
||||
checkpoint caul-plateau
|
||||
|
|
|
|||
|
|
@ -24,6 +24,17 @@ $destinations = @(
|
|||
[pscustomobject]@{ Name = 'Sawato plateau'; Occurrence = 8; Exercise = $false },
|
||||
[pscustomobject]@{ Name = 'Caul plateau'; Occurrence = 9; Exercise = $false }
|
||||
)
|
||||
$expectedCheckpointNames = @(
|
||||
'caul-baseline',
|
||||
'sawato-baseline',
|
||||
'rynthid',
|
||||
'aerlinthe',
|
||||
'sawato-return',
|
||||
'holtburg',
|
||||
'caul-return',
|
||||
'sawato-plateau',
|
||||
'caul-plateau'
|
||||
)
|
||||
|
||||
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$logDir = Join-Path $Repository 'logs'
|
||||
|
|
@ -35,6 +46,7 @@ $markerLog = "$prefix.markers.log"
|
|||
$sampleCsv = "$prefix.samples.csv"
|
||||
$reportJson = "$prefix.report.json"
|
||||
$artifactDir = "$prefix.artifacts"
|
||||
$checkpointTimeline = Join-Path $artifactDir 'world-lifecycle.checkpoints.jsonl'
|
||||
$routePath = Join-Path $Repository 'tools\connected-r6-soak.route.txt'
|
||||
$exe = Join-Path $Repository 'src\AcDream.App\bin\Release\net10.0\AcDream.App.exe'
|
||||
|
||||
|
|
@ -45,6 +57,7 @@ $process = $null
|
|||
$stopwatch = [Diagnostics.Stopwatch]::StartNew()
|
||||
$gracefulExit = $false
|
||||
$exitCode = $null
|
||||
$canonicalCheckpoints = @()
|
||||
|
||||
function Read-LogLines([string]$Path) {
|
||||
if (-not (Test-Path -LiteralPath $Path)) { return @() }
|
||||
|
|
@ -253,6 +266,203 @@ function Observe-R6Exercise(
|
|||
Write-Marker "exercise destination='$Destination' forward=$forwardPressDelta/$forwardReleaseDelta jump=$jumpPressDelta/$jumpReleaseDelta combat=$combatDelta moveTruth=$moveTruthDelta"
|
||||
}
|
||||
|
||||
function Read-CanonicalCheckpoints {
|
||||
if (-not (Test-Path -LiteralPath $checkpointTimeline)) { return @() }
|
||||
|
||||
$records = [System.Collections.Generic.List[object]]::new()
|
||||
$lineNumber = 0
|
||||
foreach ($line in Get-Content -LiteralPath $checkpointTimeline) {
|
||||
$lineNumber++
|
||||
if ([string]::IsNullOrWhiteSpace($line)) { continue }
|
||||
try {
|
||||
$records.Add(($line | ConvertFrom-Json))
|
||||
}
|
||||
catch {
|
||||
throw "checkpoint timeline line $lineNumber is invalid JSON: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
return @($records)
|
||||
}
|
||||
|
||||
function Add-CanonicalCheckpointFailures([Diagnostics.Process]$Client) {
|
||||
if ($canonicalCheckpoints.Count -ne $expectedCheckpointNames.Count) {
|
||||
$failures.Add("expected $($expectedCheckpointNames.Count) canonical checkpoints, found $($canonicalCheckpoints.Count)")
|
||||
}
|
||||
|
||||
$count = [Math]::Min($canonicalCheckpoints.Count, $expectedCheckpointNames.Count)
|
||||
for ($index = 0; $index -lt $count; $index++) {
|
||||
$checkpoint = $canonicalCheckpoints[$index]
|
||||
$expectedName = $expectedCheckpointNames[$index]
|
||||
$expectedSequence = $index + 1
|
||||
if ($checkpoint.name -ne $expectedName) {
|
||||
$failures.Add("canonical checkpoint $expectedSequence was '$($checkpoint.name)', expected '$expectedName'")
|
||||
}
|
||||
if ([int]$checkpoint.sequence -ne $expectedSequence) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' had sequence $($checkpoint.sequence), expected $expectedSequence")
|
||||
}
|
||||
if ([int]$checkpoint.processId -ne $Client.Id) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' came from process $($checkpoint.processId), expected $($Client.Id)")
|
||||
}
|
||||
|
||||
if ($null -eq $checkpoint.render -or $null -eq $checkpoint.resources) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' is missing render/resources data")
|
||||
continue
|
||||
}
|
||||
|
||||
$renderWorldProperty = $checkpoint.render.PSObject.Properties['world']
|
||||
$renderVisibleProperty = if ($null -ne $renderWorldProperty) {
|
||||
$renderWorldProperty.Value.PSObject.Properties['visibleLandblocks']
|
||||
}
|
||||
$renderTotalProperty = if ($null -ne $renderWorldProperty) {
|
||||
$renderWorldProperty.Value.PSObject.Properties['totalLandblocks']
|
||||
}
|
||||
$resourceVisibleProperty =
|
||||
$checkpoint.resources.PSObject.Properties['visibleLandblocks']
|
||||
$resourceTotalProperty =
|
||||
$checkpoint.resources.PSObject.Properties['totalLandblocks']
|
||||
if ($null -eq $renderWorldProperty -or
|
||||
$null -eq $renderVisibleProperty -or
|
||||
$null -eq $renderTotalProperty -or
|
||||
$null -eq $resourceVisibleProperty -or
|
||||
$null -eq $resourceTotalProperty) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' is missing render-world synchronization fields")
|
||||
}
|
||||
elseif ([int]$renderVisibleProperty.Value -ne
|
||||
[int]$resourceVisibleProperty.Value) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' mixed render/resource visible-landblock frames")
|
||||
}
|
||||
elseif ([int]$renderTotalProperty.Value -ne
|
||||
[int]$resourceTotalProperty.Value) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' mixed render/resource total-landblock frames")
|
||||
}
|
||||
|
||||
$namedCheckpointPath =
|
||||
Join-Path $artifactDir "checkpoint-$expectedName.json"
|
||||
if (-not (Test-Path -LiteralPath $namedCheckpointPath)) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' is missing named artifact '$namedCheckpointPath'")
|
||||
}
|
||||
else {
|
||||
try {
|
||||
$namedCheckpoint =
|
||||
Get-Content -LiteralPath $namedCheckpointPath -Raw |
|
||||
ConvertFrom-Json
|
||||
if ($namedCheckpoint.name -ne $checkpoint.name -or
|
||||
[int]$namedCheckpoint.sequence -ne [int]$checkpoint.sequence -or
|
||||
[int]$namedCheckpoint.processId -ne [int]$checkpoint.processId) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' named artifact does not match its timeline row")
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$failures.Add("canonical checkpoint '$expectedName' named artifact is invalid JSON: $($_.Exception.Message)")
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($field in @(
|
||||
'pendingLiveTeardowns',
|
||||
'pendingLandblockRetirements',
|
||||
'stagedMeshUploads',
|
||||
'stagedMeshBytes',
|
||||
'compositeWarmupPending')) {
|
||||
$property = $checkpoint.resources.PSObject.Properties[$field]
|
||||
if ($null -eq $property) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' is missing resources.$field")
|
||||
}
|
||||
elseif ([long]$property.Value -ne 0) {
|
||||
$failures.Add("canonical checkpoint '$expectedName' has resources.$field=$($property.Value), expected zero")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$caulReturn = $canonicalCheckpoints |
|
||||
Where-Object { $_.name -eq 'caul-return' } |
|
||||
Select-Object -First 1
|
||||
$caulPlateau = $canonicalCheckpoints |
|
||||
Where-Object { $_.name -eq 'caul-plateau' } |
|
||||
Select-Object -First 1
|
||||
if ($null -eq $caulReturn -or $null -eq $caulPlateau) {
|
||||
$failures.Add('canonical Caul return/plateau comparison is unavailable')
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($field in @(
|
||||
'loadedLandblocks',
|
||||
'visibleLandblocks',
|
||||
'totalLandblocks',
|
||||
'pendingLiveTeardowns',
|
||||
'pendingLandblockRetirements',
|
||||
'meshRenderData',
|
||||
'meshAtlasArrays',
|
||||
'meshEstimatedBytes',
|
||||
'stagedMeshUploads',
|
||||
'stagedMeshBytes',
|
||||
'trackedGpuBytes',
|
||||
'trackedGpuBuffers',
|
||||
'trackedGpuTextures',
|
||||
'ownedCompositeTextures',
|
||||
'compositeTextureOwners',
|
||||
'activeParticleTextures',
|
||||
'particleTextureOwners',
|
||||
'compositeWarmupPending')) {
|
||||
$first = $caulReturn.resources.PSObject.Properties[$field]
|
||||
$plateau = $caulPlateau.resources.PSObject.Properties[$field]
|
||||
if ($null -eq $first -or $null -eq $plateau) {
|
||||
$failures.Add("canonical Caul comparison is missing resources.$field")
|
||||
}
|
||||
elseif ([long]$first.Value -ne [long]$plateau.Value) {
|
||||
$failures.Add("Caul plateau canonical owner '$field' changed $($first.Value) -> $($plateau.Value)")
|
||||
}
|
||||
}
|
||||
|
||||
$populationChanged = $false
|
||||
foreach ($field in @(
|
||||
'worldEntities',
|
||||
'animatedEntities',
|
||||
'liveEntities',
|
||||
'materializedLiveEntities')) {
|
||||
$first = $caulReturn.resources.PSObject.Properties[$field]
|
||||
$plateau = $caulPlateau.resources.PSObject.Properties[$field]
|
||||
if ($null -eq $first -or $null -eq $plateau) {
|
||||
$failures.Add("canonical Caul population comparison is missing resources.$field")
|
||||
}
|
||||
elseif ([long]$first.Value -ne [long]$plateau.Value) {
|
||||
$populationChanged = $true
|
||||
$warnings.Add("Caul plateau authoritative population '$field' changed $($first.Value) -> $($plateau.Value)")
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($field in @(
|
||||
'particleBindings',
|
||||
'particleOwners',
|
||||
'effectOwners',
|
||||
'lightOwners',
|
||||
'scriptOwners')) {
|
||||
$first = $caulReturn.resources.PSObject.Properties[$field]
|
||||
$plateau = $caulPlateau.resources.PSObject.Properties[$field]
|
||||
if ($null -eq $first -or $null -eq $plateau) {
|
||||
$failures.Add("canonical Caul owner comparison is missing resources.$field")
|
||||
}
|
||||
elseif ([long]$first.Value -ne [long]$plateau.Value) {
|
||||
$message = "Caul plateau population-sensitive owner '$field' changed $($first.Value) -> $($plateau.Value)"
|
||||
if ($populationChanged) { $warnings.Add($message) }
|
||||
else { $failures.Add($message) }
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($field in @(
|
||||
'particleEmitters',
|
||||
'particles',
|
||||
'activeScripts')) {
|
||||
$first = $caulReturn.resources.PSObject.Properties[$field]
|
||||
$plateau = $caulPlateau.resources.PSObject.Properties[$field]
|
||||
if ($null -eq $first -or $null -eq $plateau) {
|
||||
$failures.Add("canonical Caul transient comparison is missing resources.$field")
|
||||
}
|
||||
elseif ([long]$first.Value -ne [long]$plateau.Value) {
|
||||
$warnings.Add("Caul plateau authoritative/transient workload '$field' changed $($first.Value) -> $($plateau.Value)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Add-RelativeGateFailures {
|
||||
$caulReturn = $samples | Where-Object { $_.Destination -eq 'Caul return' -and $_.Phase -eq 'stationary' } | Select-Object -First 1
|
||||
$caulPlateau = $samples | Where-Object { $_.Destination -eq 'Caul plateau' -and $_.Phase -eq 'stationary' } | Select-Object -First 1
|
||||
|
|
@ -430,6 +640,14 @@ try {
|
|||
$failures.Add("expected $($destinations.Count) teleport materializations")
|
||||
}
|
||||
|
||||
$null = Wait-ForLogPattern `
|
||||
$process `
|
||||
$stdoutLog `
|
||||
'[world-gate] checkpoint name=caul-plateau sequence=9' `
|
||||
1 `
|
||||
30
|
||||
$canonicalCheckpoints = @(Read-CanonicalCheckpoints)
|
||||
Add-CanonicalCheckpointFailures $process
|
||||
Add-RelativeGateFailures
|
||||
|
||||
Write-Marker 'route-complete requesting graceful close'
|
||||
|
|
@ -474,12 +692,14 @@ finally {
|
|||
SourceStatus = $sourceStatus
|
||||
VideoControllers = $videoControllers
|
||||
Samples = @($samples)
|
||||
CanonicalCheckpoints = @($canonicalCheckpoints)
|
||||
Artifacts = [pscustomobject]@{
|
||||
Stdout = $stdoutLog
|
||||
Stderr = $stderrLog
|
||||
Markers = $markerLog
|
||||
SamplesCsv = $sampleCsv
|
||||
ReportJson = $reportJson
|
||||
CheckpointTimeline = $checkpointTimeline
|
||||
}
|
||||
}
|
||||
$report | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $reportJson -Encoding utf8
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue