refactor(runtime): own interaction transactions

Move use throttling, appraisal identity, queued interactions, and exact post-arrival pickup state beneath RuntimeActionState. Keep App as the picker, movement, transport, and retained-presentation adapter while preserving retail send and UseDone ordering. Add reset, disposal, GUID-reuse, callback-reentrancy, and transport-failure coverage.

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Erik 2026-07-26 11:13:09 +02:00
parent be73bccf5a
commit f5f7b4177f
31 changed files with 1365 additions and 432 deletions

View file

@ -1,95 +0,0 @@
using AcDream.App.Input;
namespace AcDream.App.Tests.Input;
public sealed class OutboundInteractionQueueTests
{
[Fact]
public void Drain_PreservesInputOrder()
{
var queue = new OutboundInteractionQueue();
var actual = new List<string>();
queue.Enqueue(() => actual.Add("use-corpse"));
queue.Enqueue(() => actual.Add("pickup-item"));
queue.Drain();
Assert.Equal(new[] { "use-corpse", "pickup-item" }, actual);
Assert.Equal(0, queue.Count);
}
[Fact]
public void Drain_ReentrantEnqueueWaitsForNextFrame()
{
var queue = new OutboundInteractionQueue();
var actual = new List<string>();
queue.Enqueue(() =>
{
actual.Add("first");
queue.Enqueue(() => actual.Add("next-frame"));
});
queue.Drain();
Assert.Equal(new[] { "first" }, actual);
Assert.Equal(1, queue.Count);
queue.Drain();
Assert.Equal(new[] { "first", "next-frame" }, actual);
Assert.Equal(0, queue.Count);
}
[Fact]
public void Clear_DropsPendingSessionActions()
{
var queue = new OutboundInteractionQueue();
bool invoked = false;
queue.Enqueue(() => invoked = true);
queue.Clear();
queue.Drain();
Assert.False(invoked);
}
[Fact]
public void Drain_ReentrantClearStopsTheCapturedBatch()
{
var queue = new OutboundInteractionQueue();
var actual = new List<string>();
queue.Enqueue(() =>
{
actual.Add("first");
queue.Clear();
});
queue.Enqueue(() => actual.Add("stale"));
queue.Drain();
Assert.Equal(new[] { "first" }, actual);
Assert.Equal(0, queue.Count);
}
[Fact]
public void Drain_ReentrantClearAndEnqueueDefersTheNewEpoch()
{
var queue = new OutboundInteractionQueue();
var actual = new List<string>();
queue.Enqueue(() =>
{
actual.Add("first");
queue.Clear();
queue.Enqueue(() => actual.Add("new-session"));
});
queue.Enqueue(() => actual.Add("stale"));
queue.Drain();
Assert.Equal(new[] { "first" }, actual);
Assert.Equal(1, queue.Count);
queue.Drain();
Assert.Equal(new[] { "first", "new-session" }, actual);
}
}