using System; namespace AcDream.App.Streaming; /// /// Diagnostic owner for the streaming/reveal probe family (CLAUDE.md Code /// Structure Rules §5 — one static class per subsystem, typed properties read /// from the environment once at startup, never per-call-site /// GetEnvironmentVariable reads). /// internal static class StreamingDiagnostics { /// /// #280 A/B measurement probe. When set, the outdoor reveal gate uses this /// landblock radius instead of the derived streaming window, so the same /// binary can run the connected route once with the pre-fix behaviour /// (ACDREAM_PROBE_REVEAL_RADIUS=1, the old /// OutdoorNeighborhoodRadius) and once without. It is NOT a user /// setting: it is not surfaced in Settings, not persisted, and not part of /// RuntimeOptions. A shipped prefetch knob would re-expose exactly /// the reveal-window/visible-window decoupling #280 exists to close. /// Unset or unparseable leaves the derivation in charge. /// public static int? RevealRadiusOverride { get; } = ParseRadius( Environment.GetEnvironmentVariable("ACDREAM_PROBE_REVEAL_RADIUS")); /// /// Applies to a live streaming window. /// public static StreamingRevealWindow ApplyRevealRadiusOverride( StreamingRevealWindow window) => ApplyRevealRadiusOverride(window, RevealRadiusOverride); /// /// Pure override application, separated so the clamp is testable without /// mutating process-wide diagnostic state. The near radius is clamped to /// the (possibly overridden) far radius: the gate's inner arm demands /// Near-tier publication, so it can never exceed the outer arm. /// public static StreamingRevealWindow ApplyRevealRadiusOverride( StreamingRevealWindow window, int? overrideRadius) { if (overrideRadius is not { } radius) return window; int far = Math.Max(0, radius); return new StreamingRevealWindow( Math.Clamp(window.NearRadius, 0, far), far); } /// /// The floor is 1, not 0. An outdoor destination's acknowledgement must /// carry RequiredRenderRadius >= 1 or /// RuntimeWorldTransitState.AcknowledgeDestinationReadiness fails /// invalid-readiness-shape on every frame — so accepting 0 here /// would hang the very A/B route this probe exists to measure. Reject it /// at the parser rather than let the two halves of one commit disagree. /// internal static int? ParseRadius(string? raw) => int.TryParse(raw, out int value) && value >= 1 ? value : null; }