using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Channels; using XFEEDToolBox.Core.Data; using XFEEDToolBox.Core.Models; using XFEEDToolBox.Core.Native; using XFEEDToolBox.Core.Navigation; using XFEEDToolBox.Core.Session; using XFEEDToolBox.NativeSupport; /// Production driving, thermal stops and re-engagement on one existing clear SC leg. internal static class SCOThermalCycleAcceptance { private const double LightSecond = 299792458; private static readonly JsonSerializerOptions EvidenceJson = new(ToolboxSettings.JsonOptions) { NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals }; private static readonly JsonSerializerOptions EventJson = new(EvidenceJson) { WriteIndented = false }; private static bool True(JsonElement value, string key) => value.TryGetProperty(key, out var item) && item.ValueKind == JsonValueKind.True; private static long At(JsonElement value) => value.GetProperty("observedAtUnixMilliseconds").GetInt64(); private static string Text(JsonElement value, string key) => value.GetProperty(key).GetString()!; private static Vector3d Vector(JsonElement value, string key) { var array = value.GetProperty(key); return new(array[0].GetDouble(), array[1].GetDouble(), array[2].GetDouble()); } private static string Cargo(PlayerState state) => JsonSerializer.Serialize(state.Inventory .OrderBy(item => item.Key, StringComparer.Ordinal).ThenBy(item => item.MissionId) .Select(item => new { item.Key, item.Count, item.Stolen, item.MissionId, item.Group }), ToolboxSettings.JsonOptions); private sealed class Cycle(JsonElement enable) { public JsonElement Enable { get; } = enable.Clone(); public Dictionary Renewals { get; } = new(StringComparer.Ordinal); public SortedDictionary Active { get; } = new(); public SortedDictionary StoppedHeatSamples { get; } = new(); public long? ReenabledAt { get; set; } public JsonElement? Stop { get; set; } public JsonElement? Off { get; set; } public CruiseOverchargeDecision? PolicyAtStop { get; set; } public CruiseOverchargeObservation? BeforeEnableObservation { get; init; } public CruiseOverchargeDecision? BeforeEnablePolicy { get; init; } public bool CoolingObserved { get; set; } public double ObservedCoolingPercent => StoppedHeatSamples.Count > 1 ? StoppedHeatSamples.First().Value.GetProperty("heatPercent").GetDouble() - StoppedHeatSamples.Values.Min(sample => sample.GetProperty("heatPercent").GetDouble()) : 0; public bool ActualCoolingObserved => ObservedCoolingPercent >= .05; public bool HeatLimited => Stop is { } stop && (Text(stop, "reason") == "heat" || PolicyAtStop?.Reason == CruiseOverchargeReason.Heat); public double ActiveSeconds => Active.Count > 1 ? (Active.Keys.Last() - Active.Keys.First()) / 1000d : 0; public bool Matches(JsonElement value) => Text(value, "owner") == Text(Enable, "owner") && value.GetProperty("selectionGeneration").GetUInt64() == Enable.GetProperty("selectionGeneration").GetUInt64() && Text(value, "entityId") == Text(Enable, "entityId") && Text(value, "referenceWorldAddress") == Text(Enable, "referenceWorldAddress"); public bool Complete => Stop is { } stop && Off is { } off && True(stop, "nativeMethodCalled") && !True(stop, "argument") && Text(stop, "nativeMethodRva") == "2eaacd0" && Text(stop, "startRequestId") == Text(Enable, "requestId") && Matches(stop) && stop.GetProperty("owningThread").GetInt32() == Enable.GetProperty("owningThread").GetInt32() && stop.GetProperty("stateAfter").GetInt32() is 0 or 3 && At(stop) >= At(Enable) && (Active.Count == 0 || At(stop) >= Active.Keys.Last()) && At(off) > At(stop) && off.GetProperty("state").GetInt32() is 0 or 3 && !True(off, "active"); public bool Qualified => Complete && Active.Count >= 5 && Renewals.Count >= 5; public object Evidence => new { startRequestId = Text(Enable, "requestId"), enable = Enable, renewals = Renewals.Values, renewalCount = Renewals.Count, activeSamples = Active.Values, activeSampleCount = Active.Count, activeSeconds = ActiveSeconds, stop = Stop, policyAtStop = PolicyAtStop, subsequentOff = Off, coolingObserved = CoolingObserved, heatLimited = HeatLimited, stoppedHeatSamples = StoppedHeatSamples.Values, observedCoolingPercent = ObservedCoolingPercent, actualCoolingObserved = ActualCoolingObserved, reenabledAtUnixMilliseconds = ReenabledAt, beforeEnableObservation = BeforeEnableObservation, beforeEnablePolicy = BeforeEnablePolicy, complete = Complete, qualified = Qualified }; } internal static async Task RunAsync(int pid, string directory) { directory = Path.GetFullPath(directory); if (Directory.Exists(directory)) throw new IOException("Use a fresh SCO thermal-cycle evidence directory."); var parent = Path.GetDirectoryName(directory)!; Directory.CreateDirectory(parent); using var exclusive = new FileStream(Path.Combine(parent, "docking-fixture-wait.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); Directory.CreateDirectory(directory); var start = DateTimeOffset.UtcNow; var flightUntil = start.AddSeconds(60); using var timeout = new CancellationTokenSource(TimeSpan.FromSeconds(65)); using var sentinel = new Timer(_ => { if (File.Exists(Path.Combine(directory, "stop"))) timeout.Cancel(); }, null, 100, 100); var token = timeout.Token; using var process = Process.GetProcessById(pid); var processStarted = process.StartTime.ToUniversalTime().Ticks; var settings = ToolboxSettings.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "XFEstudio", "XFEEDToolBox", "settings.json")); await using var journal = new JournalMonitor(settings.JournalDirectory); await journal.StartAsync(token); var initial = journal.State; var initialCargo = Cargo(initial); var rawPipe = new NavigationPipeClient(pid); var cruisePipe = new NavigationPipeClient(pid, NativeCruiseControlChannel.Service); var previousGuardian = PersistentProtectionProcess.Current; FlightTestProtectionScope? protection = null; NativeSystemFlightControlDriver? driver = null; SystemNavigationTarget? target = null; SystemFlightFrame? firstFrame = null, lastFrame = null; JsonElement? inventoryBefore = null, inventoryAfter = null, finalRaw = null, finalCruise = null; string phase = "preflight", stopReason = "not-started"; string? failure = null, releaseFailure = null, writerFailure = null; var cycles = new List(); var receipts = new List(); var stops = new List(); var recoveryCount = 0; var zeroThrottleObserved = false; var targetPreserved = false; var overallPassed = false; var inputSubmitted = false; double reserve = double.NaN, maximumSpeed = 0, maximumHeat = 0, minimumDistance = double.PositiveInfinity; var events = Channel.CreateUnbounded(new() { SingleReader = true }); await using var log = new StreamWriter(new FileStream(Path.Combine(directory, "frames.jsonl"), FileMode.CreateNew, FileAccess.Write, FileShare.Read)); var writer = Task.Run(async () => { try { await foreach (var value in events.Reader.ReadAllAsync()) { await log.WriteLineAsync(JsonSerializer.Serialize(value, EventJson)); await log.FlushAsync(); } } catch (Exception error) { writerFailure = error.ToString(); timeout.Cancel(); } }); void Record(object value) { if (!events.Writer.TryWrite(value)) throw new IOException("SCO thermal-cycle evidence writer stopped."); } void Session(CancellationToken cancellation) { cancellation.ThrowIfCancellationRequested(); process.Refresh(); var state = journal.State; if (process.HasExited || process.StartTime.ToUniversalTime().Ticks != processStarted || !state.InGame || state.GameMode != "Solo" || state.LoadGameAt != initial.LoadGameAt || state.CommanderId != initial.CommanderId || state.CurrentShipId != initial.CurrentShipId || state.Navigation.CurrentSystemAddress != initial.Navigation.CurrentSystemAddress || state.Docked || !state.CargoReliable || state.CargoCount != initial.CargoCount || state.CargoCapacity != initial.CargoCapacity || Cargo(state) != initialCargo || NavigationSafety.HasExternalThreat(state) || NavigationSafety.UnhealthyHull(state) || TravelPreparation.HasDeployedEquipment(state)) throw new InvalidOperationException("SCO thermal-cycle session, cargo, ship, equipment, system or safety identity changed."); if (writerFailure is not null) throw new IOException(writerFailure); } Task Protection(CancellationToken cancellation) { Session(cancellation); if (protection?.Stopped == true) throw new InvalidOperationException(protection.LastIssue ?? "Flight protection stopped."); NativeFlightTestProtection.CheckBeforeInput(pid); return Task.CompletedTask; } async Task Read(CancellationToken cancellation) { Session(cancellation); var raw = await rawPipe.CallAsync(new { op = "read" }, cancellation); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "raw-navigation-and-input-diagnostics", raw }); if (True(raw, "playerOverride") || !True(raw, "inGame") || raw.TryGetProperty("shipHealth", out var health) && True(health, "emergency")) throw new InvalidOperationException("Original navigation reports player takeover, scene loss or emergency."); var frame = await driver!.ReadSystemFlightAsync(cancellation); await Protection(cancellation); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "local-frame", frame, local = driver.LastTelemetry }); if (frame.Mode != LocalFlightMode.Supercruise || frame.PlayerOverride || frame.ExternalThreat || frame.TargetObscured || frame.CollisionCourse || frame.HeatPercent is not { } heat || !double.IsFinite(heat) || heat >= CruiseOverchargePolicy.MaximumHeatPercent || firstFrame is { } pinned && (frame.ShipEntity != pinned.ShipEntity || frame.ReferenceWorld != pinned.ReferenceWorld || frame.LoadoutFingerprint != pinned.LoadoutFingerprint) || frame.SupercruiseAssist is NativeAssistState.Engaged or NativeAssistState.Requested or NativeAssistState.Aligning) throw new InvalidOperationException("The unchanged, clear, healthy SC leg is no longer available."); var assist = driver.LastTelemetry!.Value.GetProperty("supercruiseAssist"); if (True(assist, "enabled") || True(assist, "engaged")) throw new InvalidOperationException("Game SCA acquired control during the thermal-cycle proof."); ClearRay(frame, raw); lastFrame = frame; maximumSpeed = Math.Max(maximumSpeed, frame.Speed); maximumHeat = Math.Max(maximumHeat, heat); minimumDistance = Math.Min(minimumDistance, frame.TargetDistance); return frame; } async Task Apply(SystemFlightFrame frame, SystemFlightDecision decision, CancellationToken cancellation) { if (DateTimeOffset.UtcNow - frame.ObservedAt > TimeSpan.FromMilliseconds(150)) throw new FlightTelemetryUnavailableException("Proof input source is older than 150ms."); var deadline = frame.ObservedAt.AddMilliseconds(250); if (phase != "release-sco-zero-throttle-and-release-inputs" && deadline > flightUntil) deadline = flightUntil; if (deadline <= DateTimeOffset.UtcNow) throw new TimeoutException("The 60-second flight budget is exhausted."); inputSubmitted = true; await driver!.ApplySystemFlightAsync(decision, frame, target!, deadline, cancellation); } void RequireRecoverableStop() { if (stops.Count == 0) return; var reason = Text(stops[^1], "reason"); if (reason is not ("heat" or "native-refusal" or "native-telemetry" or "released" or "expired" or "lease-expired" or "no-lease")) throw new InvalidOperationException("SCO thermal-cycle proof reached a non-recoverable native boundary: " + reason); } void CaptureStatus(JsonElement value) { Record(new { at = DateTimeOffset.UtcNow, phase, kind = "original-sco-status", value }); if (firstFrame is null || !True(value, "sampleReady") || !value.TryGetProperty("sample", out var sample) || sample.ValueKind != JsonValueKind.Object || !True(sample, "verified") || Text(sample, "entityId") != firstFrame.ShipEntity.ToString() || Text(sample, "referenceWorldAddress") != firstFrame.ReferenceWorld.ToString()) return; var at = At(sample); var state = sample.GetProperty("state").GetInt32(); foreach (var cycle in cycles) { if (at < At(cycle.Enable)) continue; if (state == 2 && (cycle.Stop is not { } stopped || at <= At(stopped))) cycle.Active.TryAdd(at, sample.Clone()); if (!True(value, "owned") && state is 0 or 3 && cycle.Stop is { } stop && at > At(stop)) { cycle.Off ??= sample.Clone(); cycle.CoolingObserved |= state == 3 || !True(sample, "nativeCanEngage"); if (cycle.ReenabledAt is null || at < cycle.ReenabledAt) cycle.StoppedHeatSamples.TryAdd(at, sample.Clone()); } } } double CumulativeActive() => cycles.Where(cycle => cycle.Qualified).Sum(cycle => cycle.ActiveSeconds); bool ThermalRestartVerified() => cycles.Zip(cycles.Skip(1)).Any(pair => pair.First.Qualified && pair.Second.Qualified && pair.First.HeatLimited && pair.First.CoolingObserved && pair.First.ActualCoolingObserved && pair.First.Off is { } off && At(off) < At(pair.Second.Enable) && pair.Second.BeforeEnableObservation is { OriginalCanEngage: true, State: CruiseOverchargeState.Idle } && pair.Second.BeforeEnablePolicy is { UseOvercharge: true, Reason: CruiseOverchargeReason.Ready }); bool EnoughCycles() => cycles.Count(cycle => cycle.Qualified) >= 2 && CumulativeActive() >= 2 && ThermalRestartVerified(); async Task Inventory(CancellationToken cancellation) { var inventory = await rawPipe.CallAsync(new { op = "commerce.inventory" }, cancellation); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "actual-inventory", inventory }); if (!True(inventory, "verified") || inventory.GetProperty("count").GetInt64() != initial.CargoCount || inventory.GetProperty("capacity").GetInt64() != initial.CargoCapacity || firstFrame is { } frame && Text(inventory, "entityId") != frame.ShipEntity.ToString()) throw new InvalidDataException("Original cargo count/capacity differs from the unchanged Journal inventory."); return inventory.Clone(); } try { if (!initial.InGame || initial.Docked || initial.CurrentShipId is null || initial.GameMode != "Solo" || !initial.CargoReliable || initial.Navigation.CurrentSystemAddress <= 0 || NavigationSafety.HasExternalThreat(initial) || NavigationSafety.UnhealthyHull(initial) || TravelPreparation.HasDeployedEquipment(initial)) throw new InvalidOperationException("Healthy Solo SC and known unchanged cargo are required."); using var source = new NativeCurrentSystemSource(pid, NativeSystemLocationReader.GameSha256, () => journal.State); var catalogue = await source.ReadLocationsAsync(token); var row = catalogue.Locations.SingleOrDefault(location => location.Selected) ?? throw new InvalidOperationException("An already selected target is required; no replacement target will be chosen."); if (row.DistanceMetres is not { } distance || !double.IsFinite(distance) || distance < 50_000 * LightSecond || row.Category is not (SystemLocationCategory.Station or SystemLocationCategory.Carrier or SystemLocationCategory.Star or SystemLocationCategory.Planet or SystemLocationCategory.LandablePlanet)) throw new InvalidOperationException("The existing clear SC target must be at least 50,000ls away."); target = new(catalogue.SystemAddress, row.WorldAddress, row.Name, row.Category is SystemLocationCategory.Station or SystemLocationCategory.Carrier ? SystemTargetKind.Station : SystemTargetKind.Orbit, row.MarketId) { NativeKey = row.Key, NativeKind = row.NativeKind, NativeIdentity = row.Identity }; Record(new { at = DateTimeOffset.UtcNow, kind = "selected-existing-target", catalogue, target }); PersistentProtectionProcess.Current = null; protection = await FlightTestProtectionScope.ArmAsync(pid, exitForFailedHandoff: false, token: token); driver = new(pid, NativeSystemLocationReader.GameSha256, () => journal.State, new NativeGameInputChannel(pid, NativeSystemLocationReader.GameSha256, NativeSupportPackage.Directory), Protection, useNativeSupercruiseAssist: false); await driver.SelectAsync(target, token); // Binds the exact existing identity; no destination change. firstFrame = await Read(token); inventoryBefore = await Inventory(token); await driver.PrepareAsync(token); phase = "align-existing-target-at-zero-throttle"; while (true) { var frame = await Read(token); var direction = (frame.TargetPosition - frame.Position).Unit(); await Apply(frame, new(SystemNavigationPhase.Waiting, phase, direction, 0), token); if (Vector3d.AngleDegrees(frame.Forward, direction) <= 2 && Math.Abs(frame.Throttle) < .001) break; if (DateTimeOffset.UtcNow >= flightUntil) throw new TimeoutException("Alignment exhausted the 60-second flight budget."); await Task.Delay(40, token); } var prepared = new NativeCruiseControlChannel(pid, NativeSystemLocationReader.GameSha256); await prepared.PrepareAsync(Path.Combine(NativeSupportPackage.Directory, "CruiseControl"), token); var ship = initial.Ships.Single(ship => ship.ShipId == initial.CurrentShipId); if (ship.FuelMain is not > 8 || !double.IsFinite(ship.FuelMain.Value)) throw new InvalidDataException("Verified main tank capacity and fuel reserve are required."); reserve = Math.Max(8, ship.FuelMain.Value * .25); await driver.ConfigureOriginalCruiseControlAsync(() => reserve, token: token); var control = driver.CruiseControl!; control.Observed += CaptureStatus; control.OriginalReceipt += value => { receipts.Add(value.Clone()); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "original-sco-receipt", value }); if (True(value, "nativeMethodCalled") && True(value, "argument")) { if (cycles.Any(item => Text(item.Enable, "requestId") == Text(value, "requestId"))) return; if (cycles.Any(item => !item.Complete)) throw new InvalidDataException("A new SCO enable preceded the previous cycle's matched stop and subsequent Off."); if (cycles.LastOrDefault() is { } previousCycle) previousCycle.ReenabledAt = At(value); cycles.Add(new(value) { BeforeEnableObservation = control.LastObservation, BeforeEnablePolicy = control.LastDecision }); } else if (True(value, "applied") && cycles.LastOrDefault() is { } currentCycle && currentCycle.Matches(value)) currentCycle.Renewals.TryAdd(Text(value, "requestId"), value.Clone()); }; control.OriginalStopReceipt += value => { stops.Add(value.Clone()); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "original-sco-stop", value }); var cycle = cycles.SingleOrDefault(item => Text(item.Enable, "requestId") == Text(value, "startRequestId")); if (cycle is not null && cycle.Matches(value)) { cycle.Stop = value.Clone(); cycle.PolicyAtStop = control.LastDecision; } }; var navigator = new SystemFlightNavigator(); var handledStops = 0; phase = "production-driving-and-thermal-recovery"; stopReason = "flight-budget-exhausted"; while (DateTimeOffset.UtcNow < flightUntil) { try { var frame = await Read(token); if (EnoughCycles()) { stopReason = "two-qualified-thermal-cycles-and-two-active-seconds"; break; } RequireRecoverableStop(); if (stops.Count != handledStops) { await driver.SuspendSystemFlightAsync(); handledStops = stops.Count; recoveryCount++; Record(new { at = DateTimeOffset.UtcNow, phase, kind = "native-stop-suspended-and-refreshed", stops = handledStops }); await Task.Delay(40, token); continue; } var decision = navigator.Decide(frame, target, DateTimeOffset.UtcNow); if (decision.Phase is not (SystemNavigationPhase.Supercruise or SystemNavigationPhase.Aligning) || (decision.Actions & ~SystemNavigationAction.CancelOwnedAssists) != SystemNavigationAction.None) throw new InvalidOperationException("The existing SC leg reached an approach, assist or scene-change boundary."); await Apply(frame, decision, token); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "production-decision", decision, policy = control.LastDecision, observation = control.LastObservation, qualifiedCycles = cycles.Count(cycle => cycle.Qualified), cumulativeActiveSeconds = CumulativeActive() }); if (control.LastDecision?.Reason is CruiseOverchargeReason.Fuel or CruiseOverchargeReason.TargetClose) throw new InvalidOperationException("Production SCO policy reached a real fuel or approach boundary: " + control.LastDecision.Reason); } catch (Exception error) when (NavigationRecovery.CanRetry(error, token)) { Session(token); RequireRecoverableStop(); recoveryCount++; Record(new { at = DateTimeOffset.UtcNow, phase, kind = "production-recovery", recovery = NavigationRecovery.Kind(error), error = error.ToString() }); await driver.SuspendSystemFlightAsync(); handledStops = stops.Count; // Preserve this driver/channel and its heat hysteresis; only real // new observations and native CanEngage may permit another start. } await Task.Delay(40, token); } } catch (Exception error) { failure = error.ToString(); Record(new { at = DateTimeOffset.UtcNow, phase, failure }); } finally { phase = "release-sco-zero-throttle-and-release-inputs"; using var cleanup = new CancellationTokenSource(TimeSpan.FromSeconds(8)); try { if (driver is not null) { if (driver.CruiseControl is { } control) await control.ReleaseAsync(cleanup.Token); if (protection?.Stopped == false) { var frame = await Read(cleanup.Token); await Apply(frame, new(SystemNavigationPhase.Waiting, phase, null, 0), cleanup.Token); await Task.Delay(80, cleanup.Token); zeroThrottleObserved = Math.Abs((await Read(cleanup.Token)).Throttle) < .001; } } } catch (Exception error) { releaseFailure = error.ToString(); Record(new { at = DateTimeOffset.UtcNow, phase, releaseFailure }); } finally { if (driver is not null) try { await driver.ReleaseSystemFlightAsync(); } catch (Exception error) { releaseFailure ??= error.ToString(); Record(new { at = DateTimeOffset.UtcNow, phase, releaseFailure }); } } try { finalRaw = await rawPipe.CallAsync(new { op = "read" }, cleanup.Token); finalCruise = await cruisePipe.CallAsync(new { op = "read" }, cleanup.Token); CaptureStatus(finalCruise.Value); Record(new { at = DateTimeOffset.UtcNow, phase, kind = "final-raw-and-native-status", raw = finalRaw, cruise = finalCruise }); inventoryAfter = await Inventory(cleanup.Token); using var finalSource = new NativeCurrentSystemSource(pid, NativeSystemLocationReader.GameSha256, () => journal.State); var final = await finalSource.ReadLocationsAsync(cleanup.Token); var selected = final.Locations.SingleOrDefault(location => location.Selected); targetPreserved = target is not null && selected?.WorldAddress == target.BodyAddress && selected.NativeKind == target.NativeKind && selected.Name == target.Name && selected.MarketId == target.MarketId; } catch (Exception error) { releaseFailure ??= error.ToString(); Record(new { at = DateTimeOffset.UtcNow, phase, releaseFailure }); } try { if (protection is not null) await protection.DisposeAsync(); } catch (Exception error) { releaseFailure ??= error.ToString(); } PersistentProtectionProcess.Current = previousGuardian; events.Writer.TryComplete(); await writer; var cargoPreserved = journal.State.CargoCount == initial.CargoCount && journal.State.CargoCapacity == initial.CargoCapacity && Cargo(journal.State) == initialCargo; var inventoryPreserved = inventoryBefore is { } before && inventoryAfter is { } after && before.GetProperty("count").GetInt64() == after.GetProperty("count").GetInt64() && before.GetProperty("capacity").GetInt64() == after.GetProperty("capacity").GetInt64() && before.GetProperty("credits").GetUInt64() == after.GetProperty("credits").GetUInt64(); var activeSamples = cycles.SelectMany(cycle => cycle.Active.Values).OrderBy(At).ToArray(); var firstActiveSpeed = activeSamples.Length > 0 ? activeSamples[0].GetProperty("speedMetresPerSecond").GetDouble() : 0; var maximumActiveSpeed = activeSamples.Length > 0 ? activeSamples.Max(sample => sample.GetProperty("speedMetresPerSecond").GetDouble()) : 0; var speedIncreased = maximumActiveSpeed > firstActiveSpeed + Math.Max(1000, firstActiveSpeed * .01); var originalOff = finalCruise is { } status && !True(status, "owned") && True(status, "sampleReady") && status.TryGetProperty("sample", out var sample) && sample.ValueKind == JsonValueKind.Object && sample.GetProperty("state").GetInt32() is 0 or 3 && cycles.All(cycle => cycle.Complete); overallPassed = failure is null && releaseFailure is null && writerFailure is null && EnoughCycles() && speedIncreased && originalOff && zeroThrottleObserved && cargoPreserved && inventoryPreserved && targetPreserved; var report = new { passed = overallPassed, pid, processStarted, start, at = DateTimeOffset.UtcNow, maximumFlightSeconds = 60, phase, stopReason, failure, releaseFailure, writerFailure, initial.CurrentShipId, initial.Ship, initial.CargoCount, initial.CargoCapacity, initialCargo, finalCargo = Cargo(journal.State), cargoPreserved, inventoryBefore, inventoryAfter, inventoryPreserved, target, targetPreserved, reserveFuelTonnes = reserve, cycleCount = cycles.Count, qualifiedCycleCount = cycles.Count(cycle => cycle.Qualified), cumulativeActiveSeconds = CumulativeActive(), minimumActiveSamplesPerCycle = 5, minimumRenewalsPerCycle = 5, requiredCumulativeActiveSeconds = 2, firstActiveSpeed, maximumActiveSpeed, speedIncreased, maximumSpeed, maximumHeat, initialDistance = firstFrame?.TargetDistance, minimumDistance, finalDistance = lastFrame?.TargetDistance, observedDistanceProgress = firstFrame is null || !double.IsFinite(minimumDistance) ? (double?)null : firstFrame.TargetDistance - minimumDistance, thermalRestartVerified = ThermalRestartVerified(), originalOff, zeroThrottleObserved, firstFrame, lastFrame, finalRaw, finalCruise, recoveryCount, cycles = cycles.Select(cycle => cycle.Evidence), receipts, stops, inputSubmitted, tradeOrdersSent = 0, serviceOrdersSent = 0, launchCommandsSent = 0, scEntryCommandsSent = 0, targetReplaced = false, gameSupercruiseAssistUsed = false, crossSystemFlight = false, clientRestarted = false, singleTwentySecondIntervalClaimed = false }; await File.WriteAllTextAsync(Path.Combine(directory, "result.json"), JsonSerializer.Serialize(report, EvidenceJson)); Console.WriteLine(JsonSerializer.Serialize(new { passed = overallPassed, qualifiedCycles = cycles.Count(cycle => cycle.Qualified), cumulativeActiveSeconds = CumulativeActive(), maximumActiveSpeed, maximumHeat, stopReason, failure, releaseFailure, directory }, EventJson)); } if (!overallPassed) throw new InvalidOperationException("SCO thermal-cycle proof did not meet its declared requirements; see the preserved report."); } private static void ClearRay(SystemFlightFrame frame, JsonElement raw) { var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var geometry = raw.GetProperty("geometry"); var at = At(raw); if (now - at is < 0 or > 250 || !True(geometry, "fresh") || !True(geometry, "referenceFrameVerified") || Text(geometry, "worldAddress") != frame.ReferenceWorld.ToString()) throw new FlightTelemetryUnavailableException("Fresh matching clearance geometry is required."); var offset = frame.Position - Vector(geometry, "position"); var direction = (frame.TargetPosition - frame.Position).Unit(); var horizon = frame.TargetDistance - 10 * LightSecond; if (horizon <= 0) throw new InvalidOperationException("The existing target is inside the unchanged SCO approach boundary."); var bodies = geometry.GetProperty("nearbyBodies"); if (bodies.ValueKind != JsonValueKind.Array || bodies.GetArrayLength() == 0) throw new FlightTelemetryUnavailableException("Original body clearance geometry is unavailable."); foreach (var body in bodies.EnumerateArray()) { var centre = Vector(body, "centre") + offset; var radius = body.GetProperty("exclusionRadius").GetDouble(); if (!centre.Finite || !double.IsFinite(radius) || radius <= 0) throw new InvalidDataException("Invalid original exclusion geometry."); var relative = centre - frame.Position; var projected = Math.Clamp(Vector3d.Dot(relative, direction), 0, horizon); if ((relative - direction * projected).Length <= radius * 1.2) throw new InvalidOperationException("The existing target ray crosses an original exclusion envelope."); } } }