XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
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;

/// <summary>Production driving, thermal stops and re-engagement on one existing clear SC leg.</summary>
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<string, JsonElement> Renewals { get; } = new(StringComparer.Ordinal);
        public SortedDictionary<long, JsonElement> Active { get; } = new();
        public SortedDictionary<long, JsonElement> 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<Cycle>(); var receipts = new List<JsonElement>(); var stops = new List<JsonElement>();
        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<object>(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<SystemFlightFrame> 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<JsonElement> 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.");
        }
    }
}