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 XFEEDToolBox.Core.Data;
using XFEEDToolBox.Core.Models;
using XFEEDToolBox.Core.Native;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Session;

/// <summary>Empty local SC observation only. Never enables SCO or game SCA, trades, or creates a client.</summary>
internal static class CruiseLifecycleAcceptance
{
    internal static async Task RunAsync(int pid,string directory,string recoveryPackage,string observationService="CruiseObservation0514b")
    {
        if(observationService is not("CruiseObservation0514b" or "CruiseObservation0514c"))throw new ArgumentException("A pinned read-only cruise observation service is required.");
        directory=Path.GetFullPath(directory);recoveryPackage=Path.GetFullPath(recoveryPackage);
        if(Directory.Exists(directory))throw new IOException("Use a fresh SC lifecycle directory.");
        var workRoot=Path.GetDirectoryName(directory)!;
        using var exclusivity=new FileStream(Path.Combine(workRoot,"docking-fixture-wait.lock"),FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
        Directory.CreateDirectory(directory);var explicitStop=Path.Combine(directory,"stop");
        var report=Path.Combine(directory,"result.json");var start=DateTimeOffset.UtcNow;
        using var stop=new CancellationTokenSource(TimeSpan.FromMinutes(15));var token=stop.Token;
        using var sentinel=new Timer(_=>{if(File.Exists(explicitStop))stop.Cancel();},null,100,100);
        using var process=Process.GetProcessById(pid);var started=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();var initial=journal.State;
        if(!initial.InGame||!initial.Docked||initial.MarketId!=4210924803||initial.CurrentShipId!=5||initial.CargoCapacity!=192||initial.CargoCount!=0
            ||NavigationSafety.HasExternalThreat(initial)||NavigationSafety.UnhealthyHull(initial))throw new InvalidOperationException("Healthy empty docked Homer Corsair/5 required.");
        using var guardian=await PersistentProtectionProcess.StartOrReuseAsync(pid,workRoot,token,allowStart:false);PersistentProtectionProcess.Current=guardian;
        var pipe=new NavigationPipeClient(pid);var observer=new NavigationPipeClient(pid,observationService);
        FlightTestProtectionScope? protection=null;NativeSystemFlightControlDriver? driver=null;SystemNavigationTarget? target=null;
        string phase="preflight";string? failure=null;var maintainedBefore=false;var launchSeen=false;var launched=false;var entered=false;var observed=false;var exited=false;var docked=false;var maintainedAfter=false;var recovered=false;var flightStarted=false;
        var enterRequests=0;var dropRequests=0;var rebinds=0;ulong observedEntity=0;var samples=new List<JsonElement>();var entities=new HashSet<ulong>();JsonElement? finalDock=null;
        await using var log=new StreamWriter(new FileStream(Path.Combine(directory,"frames.jsonl"),FileMode.CreateNew,FileAccess.Write,FileShare.Read));
        async Task Record(object value){await log.WriteLineAsync(JsonSerializer.Serialize(value,ToolboxSettings.JsonOptions));await log.FlushAsync();}
        async Task Save()
        {
            var temporary=report+".tmp";
            await File.WriteAllTextAsync(temporary,JsonSerializer.Serialize(new{passed=maintainedBefore&&launched&&entered&&observed&&exited&&docked&&maintainedAfter&&failure is null,pid,started,start,at=DateTimeOffset.UtcNow,phase,
                maintainedBefore,launchSeen,launched,entered,observed,exited,docked,maintainedAfter,recovered,enterRequests,dropRequests,rebinds,entities,samples,finalDock,failure,
                observationService,localLifecycleOnly=true,crossSystemFlight=false,gameSupercruiseAssistUsed=false,overchargeCommandsSent=0,tradeOrdersSent=0,persistent075Acceptance=false,clientTerminated=false},ToolboxSettings.JsonOptions));
            File.Move(temporary,report,true);
        }
        async Task Phase(string value){phase=value;Console.WriteLine(value);await Save();}
        void Session()
        {
            token.ThrowIfCancellationRequested();process.Refresh();var state=journal.State;
            if(process.HasExited||process.StartTime.ToUniversalTime().Ticks!=started||!state.InGame||state.CommanderId!=initial.CommanderId||state.LoadGameAt!=initial.LoadGameAt
                ||state.CurrentShipId!=5||state.CargoCount!=0||state.CargoCapacity!=192||state.Navigation.CurrentSystemAddress!=initial.Navigation.CurrentSystemAddress
                ||NavigationSafety.HasExternalThreat(state)||NavigationSafety.UnhealthyHull(state))throw new InvalidOperationException("SC lifecycle session, empty ship, system or safety identity changed.");
            guardian.RequireReady(pid);
        }
        async Task Protection(CancellationToken cancellation)
        {
            cancellation.ThrowIfCancellationRequested();Session();
            if(protection?.Stopped==true)
            {
                var nav=journal.State.Navigation;
                if(protection.LastIssue!="飞船实体已切换,已暂停驾驶输入并继续监测健康。"
                    ||!(entered&&nav.SupercruiseExitedAt>=start.AddSeconds(-1)||nav.SupercruiseEnteredAt>=start.AddSeconds(-1)))
                    throw new InvalidOperationException("Stopped protection cannot be rebound without the exact verified scene-change reason.");
                await protection.DisposeAsync();protection=await FlightTestProtectionScope.ArmAsync(pid,exitForFailedHandoff:false);rebinds++;
            }
            NativeFlightTestProtection.CheckBeforeInput(pid);
        }
        async Task<SystemFlightFrame> Read()
        {
            var until=DateTimeOffset.UtcNow.AddSeconds(20);
            while(true)
            {
                try
                {
                    Session();var frame=await driver!.ReadSystemFlightAsync(token);await Protection(token);
                    if(frame.PlayerOverride||frame.ExternalThreat||frame.SupercruiseAssist==NativeAssistState.Engaged||(frame.HeatPercent??100)>=75
                        ||frame.Mode is LocalFlightMode.Glide or LocalFlightMode.OrbitalCruise)throw new InvalidOperationException("SC lifecycle flight safety boundary exceeded.");
                    entities.Add(frame.ShipEntity);return frame;
                }
                catch(Exception error)when(NavigationRecovery.CanRetry(error,token)&&DateTimeOffset.UtcNow<until)
                {await Record(new{at=DateTimeOffset.UtcNow,phase,recovering=error.Message});await Task.Delay(40,token);}
            }
        }
        async Task Apply(SystemFlightFrame frame,Vector3d? direction,double throttle,SystemNavigationAction actions=SystemNavigationAction.None)
        {
            flightStarted=true;await driver!.ApplySystemFlightAsync(new(SystemNavigationPhase.NormalApproach,phase,direction,throttle,actions),frame,target!,frame.ObservedAt.AddMilliseconds(250),token);
        }
        try
        {
            var hello=await observer.CallAsync(new{op="describe"},token);
            if(hello.GetProperty("service").GetString()!=observationService||!hello.GetProperty("enabled").GetBoolean()||hello.GetProperty("processId").GetInt32()!=pid||hello.GetProperty("gameSha256").GetString()!=NativeSystemLocationReader.GameSha256
                ||hello.GetProperty("overchargeControl").GetBoolean()||hello.GetProperty("overchargeCommandsSent").GetInt32()!=0)throw new InvalidDataException("Read-only SC observer is not ready for this game.");
            var cargo=await pipe.CallAsync(new{op="commerce.inventory"},token);
            if(!cargo.GetProperty("verified").GetBoolean()||cargo.GetProperty("count").GetInt32()!=0||cargo.GetProperty("capacity").GetInt32()!=192||cargo.GetProperty("credits").GetInt64()<4427098+200000)
                throw new InvalidDataException("Verified empty original cargo and rebuy/service reserve required.");
            await Phase("docked-maintenance-before");await DockedMaintenance.RunAsync(pid,Path.Combine(directory,"maintenance-before"),token);maintainedBefore=true;Session();
            protection=await FlightTestProtectionScope.ArmAsync(pid,exitForFailedHandoff:false);
            using var source=new NativeCurrentSystemSource(pid,NativeSystemLocationReader.GameSha256,()=>journal.State);var catalogue=await source.ReadLocationsAsync(token);
            var row=catalogue.Locations.Single(x=>x.MarketId==4210924803&&x.Name=="Homer Platform");
            target=new(catalogue.SystemAddress,row.WorldAddress,row.Name,SystemTargetKind.Station,row.MarketId){NativeKey=row.Key,NativeKind=row.NativeKind,NativeIdentity=row.Identity};
            driver=new(pid,NativeSystemLocationReader.GameSha256,()=>journal.State,new NativeGameInputChannel(pid,NativeSystemLocationReader.GameSha256,Path.Combine(AppContext.BaseDirectory,"PluginPackage")),Protection,useNativeSupercruiseAssist:false);
            await driver.SelectAsync(target,token);await Phase("original-launch");flightStarted=true;await driver.RequestLaunchAsync(token);var launchLimit=DateTimeOffset.UtcNow.AddMinutes(4);
            while(true)
            {
                var frame=await Read();var active=driver.LastTelemetry!.Value.GetProperty("docking").GetProperty("nativeLaunchActive").GetBoolean();launchSeen|=active;
                await Record(new{at=DateTimeOffset.UtcNow,phase,frame,local=driver.LastTelemetry});
                if(launchSeen&&!active&&!journal.State.Docked&&journal.State.Navigation.UndockedAt>=start.AddSeconds(-1))break;
                if(DateTimeOffset.UtcNow>launchLimit)throw new TimeoutException("Original launch did not complete.");await Task.Delay(80,token);
            }
            driver.ConfirmDockingValidationLaunchCompleted();launched=true;await driver.PrepareAsync(token);await Phase("outward-and-original-sc-entry");var entryLimit=DateTimeOffset.UtcNow.AddSeconds(90);
            while(true)
            {
                var frame=await Read();await Record(new{at=DateTimeOffset.UtcNow,phase,frame,local=driver.LastTelemetry});
                if(frame.Mode==LocalFlightMode.Supercruise){entered=true;await Apply(frame,null,0);break;}
                if(DateTimeOffset.UtcNow>entryLimit||frame.TargetDistance>60000)throw new TimeoutException("Local SC entry did not complete within its bounded departure.");
                var outward=(frame.Position-frame.TargetPosition).Unit();var aligned=Vector3d.AngleDegrees(frame.Forward,outward)<=5;
                var action=aligned&&frame.FsdReady&&enterRequests==0?SystemNavigationAction.EnterSupercruise:SystemNavigationAction.None;
                await Apply(frame,outward,aligned?1:.25,action);if(action!=SystemNavigationAction.None)enterRequests++;await Task.Delay(50,token);
            }
            await Phase("zero-throttle-readonly-sc-observation");var sampleLimit=DateTimeOffset.UtcNow.AddSeconds(6);long lastSample=0;
            while(samples.Count<5)
            {
                var frame=await Read();if(frame.Mode!=LocalFlightMode.Supercruise||frame.TargetDistance>700000)throw new InvalidOperationException("SC observation left its local volume.");await Apply(frame,null,0);
                if(observedEntity!=frame.ShipEntity){await observer.CallAsync(new{op="watch"},token);observedEntity=frame.ShipEntity;}
                var value=await observer.CallAsync(new{op="read"},token);await Record(new{at=DateTimeOffset.UtcNow,phase,frame,observer=value});
                if(value.GetProperty("sampleReady").GetBoolean())
                {
                    var sample=value.GetProperty("sample");var sampleAt=sample.GetProperty("observedAtUnixMilliseconds").GetInt64();
                    if(!sample.GetProperty("verified").GetBoolean()||!sample.GetProperty("inSupercruise").GetBoolean()||!sample.GetProperty("stableFsd").GetBoolean()||sample.GetProperty("rawFsdState").GetInt32()!=2
                        ||sample.GetProperty("entityId").GetString()!=frame.ShipEntity.ToString()||sample.GetProperty("referenceWorldAddress").GetString()!=frame.ReferenceWorld.ToString()
                        ||!sample.GetProperty("fuelVerified").GetBoolean()||sample.GetProperty("active").GetBoolean()||sample.GetProperty("overchargeCommandsSent").GetInt32()!=0
                        ||sample.GetProperty("heatPercent").GetDouble()>=75||sample.GetProperty("fuelMainTonnes").GetDouble()<Math.Max(1,sample.GetProperty("fuelCapacityTonnes").GetDouble()*.15)
                        ||DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()-sampleAt is <0 or >300)throw new InvalidDataException("Original SC/fuel/temperature sample identity or safety predicate failed.");
                    if(observationService=="CruiseObservation0514c"&&(!sample.GetProperty("fuelBoundVerified").GetBoolean()
                        ||sample.GetProperty("fuelRateUpperTonnesPerSecond").ValueKind!=JsonValueKind.Number
                        ||!double.IsFinite(sample.GetProperty("fuelRateUpperTonnesPerSecond").GetDouble())||sample.GetProperty("fuelRateUpperTonnesPerSecond").GetDouble()<=0))
                        throw new InvalidDataException("The original registered fuel callback has not supplied a verified positive finite upper bound.");
                    if(sampleAt!=lastSample){samples.Add(sample.Clone());lastSample=sampleAt;}
                }
                if(DateTimeOffset.UtcNow>sampleLimit)throw new TimeoutException("No five distinct verified original SC observations formed.");await Task.Delay(50,token);
            }
            await File.WriteAllTextAsync(Path.Combine(directory,"sco-components.json"),JsonSerializer.Serialize(await NativeCruiseOverchargeDiagnostics.ReadAsync(pid,token),ToolboxSettings.JsonOptions));observed=true;
            await Phase("original-station-safe-sc-exit");var exitLimit=DateTimeOffset.UtcNow.AddSeconds(45);
            while(true)
            {
                var frame=await Read();await Record(new{at=DateTimeOffset.UtcNow,phase,frame,local=driver.LastTelemetry});
                if(frame.Mode==LocalFlightMode.Normal){exited=true;await Apply(frame,null,0);break;}
                if(DateTimeOffset.UtcNow>exitLimit||frame.TargetDistance>2000000)throw new TimeoutException("Original station safe exit did not complete.");
                if(frame.Mode==LocalFlightMode.Transition){await Task.Delay(60,token);continue;}
                if(frame.Mode!=LocalFlightMode.Supercruise)throw new InvalidOperationException("Unexpected mode during original station safe exit.");
                var home=(frame.TargetPosition-frame.Position).Unit();
                var drop=dropRequests==0&&frame.SafeDisengage&&frame.SafeDropDistance>frame.TargetDistance&&frame.SafeDropSpeed>frame.Speed?SystemNavigationAction.SafeDisengage:SystemNavigationAction.None;
                await Apply(frame,home,0,drop);if(drop!=SystemNavigationAction.None)dropRequests++;await Task.Delay(60,token);
            }
            await driver.ReleaseSystemFlightAsync();await protection.DisposeAsync();protection=null;await Phase("original-ai-return-homer");
            var returnReport=Path.Combine(directory,"return-docking.json");await OriginalDockingResetAcceptance.RunAsync(pid,returnReport,recoveryPackage,requireNonzero:false,sharedStopFile:explicitStop,protectionWorkRoot:workRoot);
            using(var returned=JsonDocument.Parse(await File.ReadAllTextAsync(returnReport,token)))docked=returned.RootElement.GetProperty("passed").GetBoolean();
            if(!docked)throw new InvalidDataException("Original AI return was not fully confirmed.");PersistentProtectionProcess.Current=guardian;
            await Phase("docked-maintenance-after");await DockedMaintenance.RunAsync(pid,Path.Combine(directory,"maintenance-after"),token);maintainedAfter=true;
            finalDock=await pipe.CallAsync(new{op="commerce.docked.status",marketId=4210924803},token);
            if(!finalDock.Value.GetProperty("ready").GetBoolean()||finalDock.Value.GetProperty("actualMarketId").GetInt64()!=4210924803)throw new InvalidDataException("Final original docked services are not ready.");await Phase("passed-local-sc-lifecycle");
        }
        catch(Exception error)
        {
            failure=error.ToString();await Record(new{at=DateTimeOffset.UtcNow,phase,failure});Console.WriteLine(error.Message);await Save();
            try{if(driver is not null)await driver.ReleaseSystemFlightAsync();}catch(Exception release){await Record(new{releaseFailure=release.ToString()});}
            if(protection is not null){await protection.DisposeAsync();protection=null;}
            if(flightStarted&&!File.Exists(explicitStop)&&!journal.State.Docked&&!process.HasExited&&journal.State.CurrentShipId==5&&journal.State.CargoCount==0)
            {
                try
                {
                    await Phase("same-process-original-menu-recovery");await OriginalDockingResetAcceptance.EnterPauseAsync(pid,guardian,Path.Combine(directory,"recovery-pause.json"));
                    await SessionRecoveryAcceptance.RunAsync(pid,recoveryPackage,Path.Combine(directory,"recovery-menu.json"),leave:true,protectionWorkRoot:workRoot);
                    await GameSessionAcceptance.StartAsync(settings.PluginGameExecutable,Path.Combine(directory,"recovery-solo.json"),pid);recovered=true;
                }
                catch(Exception recovery){await Record(new{recoveryFailure=recovery.ToString(),clientTerminated=false});}
            }
        }
        finally
        {
            try{if(driver is not null)await driver.ReleaseSystemFlightAsync();}catch(Exception release){await Record(new{finalReleaseFailure=release.ToString()});}
            if(protection is not null)await protection.DisposeAsync();PersistentProtectionProcess.Current=null;await Save();
        }
        if(failure is not null)throw new InvalidOperationException("Local SC lifecycle failed; the original failure is preserved.");
    }

    internal static async Task FinishReturnAsync(int pid,string directory,string recoveryPackage,string attemptName="return",bool reuseCurrentSolo=false)
    {
        if(attemptName.Length is 0 or >48||attemptName.Any(c=>!(char.IsAsciiLetterLower(c)||char.IsAsciiDigit(c)||c=='-')))throw new ArgumentException("A bounded lowercase attempt name is required.");
        directory=Path.GetFullPath(directory);recoveryPackage=Path.GetFullPath(recoveryPackage);var report=Path.Combine(directory,attemptName+"-reconciliation.json");
        if(File.Exists(report))throw new IOException("Use a new return reconciliation report.");
        var root=Path.GetDirectoryName(directory)!;
        using var exclusivity=new FileStream(Path.Combine(root,"docking-fixture-wait.lock"),FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
        using var guardian=await PersistentProtectionProcess.StartOrReuseAsync(pid,root,CancellationToken.None,allowStart:false);PersistentProtectionProcess.Current=guardian;
        using var process=Process.GetProcessById(pid);var ticks=process.StartTime.ToUniversalTime().Ticks;var started=DateTimeOffset.UtcNow;
        var settings=ToolboxSettings.Load(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),"XFEstudio","XFEEDToolBox","settings.json"));
        using var timeout=new CancellationTokenSource(TimeSpan.FromMinutes(10));var token=timeout.Token;
        await using var journal=new JournalMonitor(settings.JournalDirectory);await journal.StartAsync();var initial=journal.State;
        var explicitStop=Path.Combine(directory,"stop");var recovered=false;var docked=false;var maintained=false;string? failure=null;JsonElement? finalDock=null,health=null;
        try
        {
            if(File.Exists(explicitStop)||!initial.InGame||initial.Docked||initial.CurrentShipId!=5||initial.CargoCount!=0||initial.CargoCapacity!=192||NavigationSafety.HasExternalThreat(initial)||NavigationSafety.UnhealthyHull(initial))
                throw new InvalidOperationException("Healthy empty undocked same-session ship required for return recovery.");
            guardian.RequireReady(pid);
            var session=await new NavigationPipeClient(pid).CallAsync(new{op="session.status"},token);
            if(reuseCurrentSolo)
            {
                using var original=JsonDocument.Parse(await File.ReadAllTextAsync(Path.Combine(directory,"result.json"),token));
                var originalStart=original.RootElement.GetProperty("start").GetDateTimeOffset();
                if(session.GetProperty("state").GetString()!="InGame"||session.GetProperty("nextState").GetString()!="InGame"||initial.LoadGameAt is not {} resumedAt||resumedAt<=originalStart)
                    throw new InvalidDataException("The actual same-PID new Solo entry has not been confirmed.");
                recovered=true;
            }
            else
            {
            var alreadyPaused=session.GetProperty("state").GetString()=="Pause"&&session.GetProperty("nextState").GetString()=="Pause";
            if(!alreadyPaused)
            {
                var native=await new NavigationPipeClient(pid).CallAsync(new{op="read"},token);
                if(!native.GetProperty("inGame").GetBoolean()||!native.GetProperty("localPlayerShipVerified").GetBoolean()||native.GetProperty("rawFsdState").GetInt32()!=2)
                    throw new InvalidDataException("Wait for stable original normal-space FSD state before one native menu recovery.");
                await OriginalDockingResetAcceptance.EnterPauseAsync(pid,guardian,Path.Combine(directory,attemptName+"-recovery-pause.json"));
            }
            await SessionRecoveryAcceptance.RunAsync(pid,recoveryPackage,Path.Combine(directory,attemptName+"-recovery-menu.json"),leave:true,protectionWorkRoot:root);
            await GameSessionAcceptance.StartAsync(settings.PluginGameExecutable,Path.Combine(directory,attemptName+"-recovery-solo.json"),pid);
            var journalLimit=DateTimeOffset.UtcNow.AddSeconds(3);
            while(!(journal.State.InGame&&journal.State.LoadGameAt>initial.LoadGameAt)&&DateTimeOffset.UtcNow<journalLimit)await Task.Delay(50,token);
            recovered=journal.State.InGame&&journal.State.LoadGameAt>initial.LoadGameAt&&journal.State.CurrentShipId==5&&journal.State.CargoCount==0;
            if(!recovered)throw new InvalidDataException("Same-PID original Solo recovery not confirmed.");
            }
            await OriginalDockingResetAcceptance.RunAsync(pid,Path.Combine(directory,attemptName+"-docking-after-recovery.json"),recoveryPackage,requireNonzero:false,sharedStopFile:explicitStop,protectionWorkRoot:root);docked=true;
            PersistentProtectionProcess.Current=guardian;await DockedMaintenance.RunAsync(pid,Path.Combine(directory,"maintenance-after"),token);maintained=true;
            guardian.RequireReady(pid);finalDock=await new NavigationPipeClient(pid).CallAsync(new{op="commerce.docked.status",marketId=4210924803},token);
            health=await new NavigationPipeClient(pid).CallAsync(new{op="health.read"},token);
            if(!finalDock.Value.GetProperty("ready").GetBoolean()||finalDock.Value.GetProperty("actualMarketId").GetInt64()!=4210924803||!health.Value.GetProperty("shipHealth").GetProperty("verified").GetBoolean())
                throw new InvalidDataException("Final original docked services or healthy main ship not confirmed.");
        }
        catch(Exception error){failure=error.ToString();}
        finally
        {
            PersistentProtectionProcess.Current=null;
            await File.WriteAllTextAsync(report,JsonSerializer.Serialize(new{passed=recovered&&docked&&maintained&&failure is null,pid,ticks,started,at=DateTimeOffset.UtcNow,recovered,docked,maintained,finalDock,health,failure,
                originalFailurePreserved=true,originalAttempt=Path.Combine(directory,"result.json"),reuseCurrentSolo,supercruiseReplayed=false,tradeOrdersSent=0,clientTerminated=false},ToolboxSettings.JsonOptions));
        }
        if(failure is not null)throw new InvalidOperationException("Same-PID SC lifecycle return remains incomplete: "+failure);
    }

    internal static async Task FinishMaintenanceAsync(int pid,string directory,string attemptName)
    {
        directory=Path.GetFullPath(directory);var root=Path.GetDirectoryName(directory)!;
        if(attemptName.Length is 0 or >48||attemptName.Any(c=>!(char.IsAsciiLetterLower(c)||char.IsAsciiDigit(c)||c=='-')))throw new ArgumentException("A bounded lowercase maintenance attempt is required.");
        var serviceDirectory=Path.Combine(directory,attemptName);var report=Path.Combine(directory,attemptName+"-reconciliation.json");
        if(Directory.Exists(serviceDirectory)||File.Exists(report))throw new IOException("Use a fresh maintenance attempt; preserve all earlier results.");
        using var lease=new FileStream(Path.Combine(root,"docking-fixture-wait.lock"),FileMode.OpenOrCreate,FileAccess.ReadWrite,FileShare.None);
        using var guardian=await PersistentProtectionProcess.StartOrReuseAsync(pid,root,CancellationToken.None,allowStart:false);PersistentProtectionProcess.Current=guardian;
        using var process=Process.GetProcessById(pid);var started=process.StartTime.ToUniversalTime().Ticks;JsonElement? docked=null,health=null,inventory=null;string? failure=null;var maintained=false;
        try
        {
            foreach(var pending in Directory.EnumerateFiles(directory,"*.pending.json",SearchOption.AllDirectories))
                if(!File.Exists(pending.Replace(".pending.json",".confirmed.json",StringComparison.Ordinal)))throw new InvalidDataException("An earlier monetary intent remains unresolved; it cannot be replayed.");
            if(File.Exists(Path.Combine(directory,"stop")))throw new OperationCanceledException("Lifecycle explicitly stopped.");
            await DockedMaintenance.RunAsync(pid,serviceDirectory);maintained=true;guardian.RequireReady(pid);
            var pipe=new NavigationPipeClient(pid);docked=await pipe.CallAsync(new{op="commerce.docked.status",marketId=4210924803});health=await pipe.CallAsync(new{op="health.read"});inventory=await pipe.CallAsync(new{op="commerce.inventory"});
            if(!docked.Value.GetProperty("ready").GetBoolean()||!docked.Value.GetProperty("serviceReady").GetBoolean()||docked.Value.GetProperty("actualMarketId").GetInt64()!=4210924803
                ||!health.Value.GetProperty("shipHealth").GetProperty("verified").GetBoolean()||inventory.Value.GetProperty("count").GetInt32()!=0)throw new InvalidDataException("Final empty docked maintenance evidence differs.");
        }
        catch(Exception error){failure=error.ToString();}
        finally
        {
            PersistentProtectionProcess.Current=null;
            await File.WriteAllTextAsync(report,JsonSerializer.Serialize(new{passed=maintained&&failure is null,pid,started,at=DateTimeOffset.UtcNow,maintained,docked,health,inventory,failure,
                priorFailurePreserved=true,tradeOrdersSent=0,flightInputsSent=0,clientTerminated=false},ToolboxSettings.JsonOptions));
        }
        if(failure is not null)throw new InvalidOperationException("Final docked maintenance remains unresolved: "+failure);
    }
}