feat(streaming): enforce typed completion queues

Replace the flat deferred list, priority scan, unload bypass, and count-only execution cap with exact destination/control/unload/Near/Far FIFOs behind one typed frame meter. Price worker results before adoption, retain exact retry identity, reject stale generations without payload retention, and publish queue pressure through lifecycle diagnostics.

Tests: dotnet build AcDream.slnx -c Release --no-restore; dotnet test AcDream.slnx -c Release --no-restore (8138 passed, 5 skipped)
This commit is contained in:
Erik 2026-07-24 17:48:24 +02:00
parent ac45cb1bd7
commit b8f6317fe1
15 changed files with 1261 additions and 336 deletions

View file

@ -18,7 +18,7 @@ public class StreamingControllerPriorityApplyTests
generation);
[Fact]
public void PriorityLandblock_isApplied_evenWhenBeyondPerFrameCap()
public void PriorityLandblock_WinsExecutionOrderAfterBoundedAdmission()
{
uint priority = StreamingRegion.EncodeLandblockIdForTest(169, 180);
var outbox = new Queue<LandblockStreamResult>(new LandblockStreamResult[]
@ -42,14 +42,18 @@ public class StreamingControllerPriorityApplyTests
return batch;
},
applyTerrain: (lb, _) => applied.Add(lb.LandblockId),
state: state, nearRadius: 4, farRadius: 12)
state: state,
nearRadius: 4,
farRadius: 12,
workBudgetOptions: GenerousBudget())
{ MaxCompletionsPerFrame = 4 };
ctrl.PriorityLandblockId = priority;
ctrl.Tick(169, 180);
Assert.Contains(priority, applied); // priority applied THIS tick
Assert.True(applied.Count <= 5); // did not blindly flush the whole outbox
Assert.NotEmpty(applied);
Assert.Equal(priority, applied[0]);
Assert.True(applied.Count <= 5);
}
[Fact]
@ -98,10 +102,8 @@ public class StreamingControllerPriorityApplyTests
public void PriorityNeverArrives_noThrow_noLoss_noDoubleApply()
{
// While a PriorityLandblockId is set but the matching completion never
// arrives (e.g. the load failed), the hunt moves outbox completions into
// _deferredApply and they drain at the per-frame budget — same backpressure
// as the normal throttle, just relocated — until the caller clears
// PriorityLandblockId (the TAS MaxContinue safety net does this on timeout).
// arrives (e.g. the load failed), ordinary results still enter the typed
// Near/Far queues and advance under the same budget without loss.
uint priority = StreamingRegion.EncodeLandblockIdForTest(169, 180);
uint otherId0 = StreamingRegion.EncodeLandblockIdForTest(169, 181);
uint otherId1 = StreamingRegion.EncodeLandblockIdForTest(169, 182);
@ -149,6 +151,15 @@ public class StreamingControllerPriorityApplyTests
Assert.Equal(3, applied.Count);
}
private static StreamingWorkBudgetOptions GenerousBudget() => new(
MaxUpdateMilliseconds: 100,
MaxCompletionAdmissions: 64,
MaxAdoptedCpuBytes: 16 * StreamingWorkBudgetOptions.MiB,
MaxEntityOperations: 10_000,
MaxGpuUploadBytes: 16 * StreamingWorkBudgetOptions.MiB,
MaxGlRetireOperations: 10_000,
DestinationReserveFraction: 0.75f);
[Fact]
public void DeferredCompaction_ApplyFailureRetainsExactResultWithoutReplayingCommittedPrefix()
{
@ -223,7 +234,15 @@ public class StreamingControllerPriorityApplyTests
applyTerrain: (build, _) => applied.Add(build.LandblockId),
state: state,
nearRadius: 4,
farRadius: 12)
farRadius: 12,
workBudgetOptions: new StreamingWorkBudgetOptions(
MaxUpdateMilliseconds: 100,
MaxCompletionAdmissions: 4,
MaxAdoptedCpuBytes: 1_000_000,
MaxEntityOperations: 1_000,
MaxGpuUploadBytes: 1_000_000,
MaxGlRetireOperations: 1_000,
DestinationReserveFraction: 0.75f))
{ MaxCompletionsPerFrame = 4, PriorityLandblockId = priority };
ctrl.Tick(169, 180);