refactor(app): compose session and player startup

Move streaming, live-session, hydration, local-player, combat, and teleport construction behind the typed Phase-7 boundary. Add exact-owner runtime bindings and focused spawn-claim classification so partial startup rolls back without retaining old session targets while preserving the accepted construction and frame dependencies.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-22 18:28:32 +02:00
parent 3573da12e1
commit 7771c07fb6
31 changed files with 1759 additions and 532 deletions

View file

@ -32,6 +32,24 @@ public sealed class LiveEntityHydrationControllerTests
Assert.Throws<InvalidOperationException>(() => bridge.Bind(_ => false));
}
[Fact]
public void ParentAcceptanceOwnedBindingReleasesExactlyAndAllowsRebind()
{
var bridge = new DeferredLiveEntityParentAcceptance();
Func<ParentEvent.Parsed, bool> first = _ => true;
Func<ParentEvent.Parsed, bool> second = _ => false;
IDisposable firstBinding = bridge.BindOwned(first);
Assert.True(bridge.TryAccept(default));
Assert.Throws<InvalidOperationException>(() => bridge.BindOwned(second));
firstBinding.Dispose();
using IDisposable secondBinding = bridge.BindOwned(second);
firstBinding.Dispose();
Assert.False(bridge.TryAccept(default));
}
[Fact]
public void FreshCreate_PublishesCanonicalOrderAndReadyAfterMaterialization()
{
@ -1580,6 +1598,25 @@ public sealed class LiveEntityHydrationControllerTests
deferred.Bind(new RecordingNetworkSink()));
}
[Fact]
public void DeferredNetworkOwnedBindingReleasesExactlyAndAllowsRebind()
{
var deferred = new DeferredLiveEntityNetworkUpdateSink();
var first = new RecordingNetworkSink();
var second = new RecordingNetworkSink();
IDisposable firstBinding = deferred.BindOwned(first);
Assert.Throws<InvalidOperationException>(() => deferred.BindOwned(second));
firstBinding.Dispose();
using IDisposable secondBinding = deferred.BindOwned(second);
firstBinding.Dispose();
deferred.ApplySameGeneration(default);
Assert.Equal(0, first.ApplyCount);
Assert.Equal(1, second.ApplyCount);
}
private const uint Guid = 0x70000001u;
private const uint Cell = 0x01010001u;