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:
Erik 2026-07-22 20:01:06 +02:00
parent 2862622ba2
commit bca4148739
17 changed files with 995 additions and 52 deletions

View file

@ -7,6 +7,22 @@ using AcDream.UI.Abstractions.Input;
namespace AcDream.App.UI.Testing;
public enum RetailUiAutomationCheckpointStatus
{
Pending,
Succeeded,
Failed,
Cancelled,
}
public interface IRetailUiAutomationCheckpoint
{
int Sequence { get; }
string Name { get; }
RetailUiAutomationCheckpointStatus Status { get; }
string? Error { get; }
}
/// <summary>
/// Narrow bridge from retained-UI scripts to render/world lifecycle
/// diagnostics. Implementations run on the same update/render thread as the
@ -17,7 +33,11 @@ public interface IRetailUiAutomationRuntime
bool IsWorldReady { get; }
bool IsWorldViewportVisible { get; }
int PortalMaterializationCount { get; }
bool TryWriteCheckpoint(string name, out string error);
bool TryRequestCheckpoint(
string name,
out IRetailUiAutomationCheckpoint? checkpoint,
out string error);
void CancelCheckpoint(IRetailUiAutomationCheckpoint checkpoint);
bool TryRequestScreenshot(string name, out string error);
bool IsScreenshotComplete(string name);
}
@ -40,6 +60,8 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
private readonly HashSet<InputAction> _heldInputs = new();
private readonly bool _dumpOnStart;
private readonly string? _loadError;
private IRetailUiAutomationCheckpoint? _checkpoint;
private int _checkpointCommandIndex = -1;
private int _index;
private int _activeIndex = -1;
private double _commandElapsedMs;
@ -405,8 +427,47 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
return Stop(command, "usage: checkpoint <name>");
if (_runtime is null)
return Stop(command, "world lifecycle automation is unavailable");
return _runtime.TryWriteCheckpoint(command.Parts[1], out string error)
|| Stop(command, error);
if (_checkpoint is null)
{
if (!_runtime.TryRequestCheckpoint(
command.Parts[1],
out IRetailUiAutomationCheckpoint? checkpoint,
out string error))
{
return Stop(command, error);
}
if (checkpoint is null)
{
return Stop(
command,
"world lifecycle automation accepted a checkpoint without returning its acknowledgement");
}
_checkpoint = checkpoint;
_checkpointCommandIndex = _index;
}
if (_checkpointCommandIndex != _index)
{
return Stop(
command,
"checkpoint acknowledgement belongs to a different script command");
}
RetailUiAutomationCheckpointStatus status = _checkpoint.Status;
if (status == RetailUiAutomationCheckpointStatus.Pending)
return false;
string? terminalError = _checkpoint.Error;
_checkpoint = null;
_checkpointCommandIndex = -1;
return status == RetailUiAutomationCheckpointStatus.Succeeded
|| Stop(
command,
terminalError
?? $"checkpoint '{command.Parts[1]}' ended with {status}");
}
private bool DoScreenshot(ScriptCommand command)
@ -476,6 +537,12 @@ public sealed class RetailUiAutomationScriptRunner : IDisposable
public void Dispose()
{
if (_disposed) return;
if (_checkpoint is not null)
{
_runtime?.CancelCheckpoint(_checkpoint);
_checkpoint = null;
_checkpointCommandIndex = -1;
}
ReleaseHeldInputs();
_disposed = true;
}