feat(app): observe canonical placement receipts

This commit is contained in:
Erik 2026-08-01 15:22:52 +02:00
parent 378ca95a67
commit f05ed5c3cd
14 changed files with 545 additions and 31 deletions

View file

@ -34,11 +34,25 @@ public sealed class RuntimePlacementProjectionSubscription
public RuntimePlacementProjectionSubscription(
GameRuntime runtime,
IRuntimePlacementProjectionSink sink)
: this(runtime, sink, retryPendingOnSubscribe: true)
{
}
/// <summary>
/// Subscribes before optionally draining the pending FIFO. A session route
/// which must publish its own disposal/retry ownership first passes
/// <c>false</c>, stores those owners, then calls <see cref="RetryPending"/>.
/// </summary>
public RuntimePlacementProjectionSubscription(
GameRuntime runtime,
IRuntimePlacementProjectionSink sink,
bool retryPendingOnSubscribe)
: this(
runtime?.Placements
?? throw new ArgumentNullException(nameof(runtime)),
() => runtime.Generation,
sink)
sink,
retryPendingOnSubscribe)
{
}
@ -46,13 +60,27 @@ public sealed class RuntimePlacementProjectionSubscription
RuntimePlacementProjectionChannel channel,
Func<RuntimeGenerationToken> generation,
IRuntimePlacementProjectionSink sink)
: this(
channel,
generation,
sink,
retryPendingOnSubscribe: true)
{
}
internal RuntimePlacementProjectionSubscription(
RuntimePlacementProjectionChannel channel,
Func<RuntimeGenerationToken> generation,
IRuntimePlacementProjectionSink sink,
bool retryPendingOnSubscribe)
{
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
_generation = generation
?? throw new ArgumentNullException(nameof(generation));
_sink = sink ?? throw new ArgumentNullException(nameof(sink));
_subscription = _channel.Subscribe(this);
_ = RetryPending();
if (retryPendingOnSubscribe)
_ = RetryPending();
}
public bool HasAppliedReceiptAwaitingAcknowledgement =>