acdream/src/AcDream.Runtime/Physics/RuntimePlacementProjectionChannel.cs
Erik fe02c4f56d feat(runtime): public initial-Create completion surface for hosts
Cutover slice C3-1 (the C3 flip's Runtime prerequisite, landed separately
after the flip itself was halted with structural findings — see the plan's
C3a/b/c decomposition). Hosts can now read the executor-completion facts
they must bind at cutover through one public, generation-gated channel
accessor: RuntimePlacementProjectionChannel.TryGetInitialCreateCompletion
returns RuntimeInitialCreatePlacementCompletion — the teleport-hook phase,
resident cell, replay outcomes, and per-Position route facts (disposition,
constrain phase, hook phase, stop-interpolation/zero-velocity/preserve-
heading/send-position flags) via public 1:1 mirror enums of the internal
classifier vocabulary. The projection is built once at completion, cached
in the same reaped entry as the internal receipt (identical acknowledge/
discard/clear lifecycle, ledger-covered), and read allocation-free.
Mirror maps enumerate every value explicitly with throwing catch-alls,
guarded by a sabotage-verified arity/round-trip reflection test. Doc
comments pin the two consumption rules: unparent/placement-frame are
already applied to the canonical snapshot (hosts must not re-apply), and
array order — not Sequence — is the authoritative Position-fact ordering.

Reviewed: architecture PASS + retail-conformance PASS (mirrors verified
member-for-member against the retail phase semantics; the route-fact
selection confirmed to cover exactly the host-bindable deferrals).
Runtime 932/932; complete Release solution 10,727 passed / 4 skips.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-02 08:17:12 +02:00

118 lines
4.7 KiB
C#

using AcDream.Runtime.Entities;
namespace AcDream.Runtime.Physics;
/// <summary>
/// Public host boundary for Runtime-owned SetPosition projection receipts.
/// The channel owns no placement state: observation, retry, and exact-token
/// acknowledgement delegate to the canonical entity lifetime's event stream
/// and SetPosition owner.
/// </summary>
public sealed class RuntimePlacementProjectionChannel
{
private readonly RuntimeEntityObjectEventStream _events;
private readonly RuntimeSetPositionState _setPosition;
private readonly RuntimeInitialCreateContinuationExecutor _initialCreateExecution;
private Func<RuntimeGenerationToken> _generation = static () => default;
private bool _generationBound;
internal RuntimePlacementProjectionChannel(
RuntimeEntityObjectEventStream events,
RuntimeSetPositionState setPosition,
RuntimeInitialCreateContinuationExecutor initialCreateExecution)
{
_events = events ?? throw new ArgumentNullException(nameof(events));
_setPosition = setPosition
?? throw new ArgumentNullException(nameof(setPosition));
_initialCreateExecution = initialCreateExecution
?? throw new ArgumentNullException(nameof(initialCreateExecution));
}
/// <summary>
/// Observes ordered immutable projection receipts on the Runtime commit
/// thread. A host must acknowledge only after its projection succeeds.
/// </summary>
public IDisposable Subscribe(IRuntimePlacementObserver observer) =>
_events.SubscribePlacement(observer);
internal void BindGeneration(Func<RuntimeGenerationToken> generation)
{
ArgumentNullException.ThrowIfNull(generation);
if (_generationBound)
{
throw new InvalidOperationException(
"The Runtime placement generation source is already bound.");
}
_generation = generation;
_generationBound = true;
}
/// <summary>
/// Acknowledges only the exact oldest outstanding receipt. Stale,
/// reordered, superseded, or already acknowledged tokens are rejected.
/// </summary>
public bool Acknowledge(
RuntimeGenerationToken expectedGeneration,
in RuntimePlacementProjectionToken token) =>
IsCurrent(expectedGeneration)
&& _setPosition.AcknowledgeProjection(token);
/// <summary>
/// Republishes every still-pending immutable receipt in canonical order.
/// Runtime authority is never replayed or recommitted by a retry.
/// </summary>
public bool RetryPending(RuntimeGenerationToken expectedGeneration)
{
if (!IsCurrent(expectedGeneration))
return false;
_setPosition.RetryPendingProjections();
return true;
}
/// <summary>
/// Returns the exact oldest outstanding receipt without consuming it.
/// </summary>
public bool TryPeek(
RuntimeGenerationToken expectedGeneration,
out RuntimePlacementProjectionSnapshot projection)
{
if (IsCurrent(expectedGeneration))
return _setPosition.TryPeekProjection(out projection);
projection = default;
return false;
}
public int PendingCount => _setPosition.PendingProjectionCount;
/// <summary>
/// C3-1: the public host consumption shape for an initial-Create
/// continuation-executor drain's completion. Reached with the exact
/// <see cref="RuntimePlacementProjectionToken"/> carried by a
/// <see cref="RuntimePlacementProjectionKind.ExecutorCompleted"/> receipt
/// observed through <see cref="Subscribe"/> - the same correlation
/// identity (Entity/Sequence) every other placement Kind uses. Exposes
/// exactly the facts a cutover host needs to bind presentation off an
/// initial placement (the teleport-hook phase, the drained Position
/// continuations' route facts for constrain/interpolation binding, and
/// the replayed-deferred-child count) without widening any internal
/// Runtime type's accessibility. Returns false for a generation
/// mismatch or a stale/superseded/unknown token, mirroring every other
/// generation-gated method on this channel.
/// </summary>
public bool TryGetInitialCreateCompletion(
RuntimeGenerationToken expectedGeneration,
in RuntimePlacementProjectionToken token,
out RuntimeInitialCreatePlacementCompletion completion)
{
if (IsCurrent(expectedGeneration))
return _initialCreateExecution.TryGetCompletion(token, out completion);
completion = default;
return false;
}
private bool IsCurrent(RuntimeGenerationToken expectedGeneration) =>
_generationBound
&& expectedGeneration.Value != 0UL
&& expectedGeneration == _generation();
}