using System.Text.Json;
using System.Text.Json.Nodes;
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public sealed class ScoExitEstimatePolicyTests
{
private const double C=299792458;
private static readonly ScoExitProfile Profile=new(1000*C,150*C,75*C,170*C,1,100*C,30000,.36,2.64){OrdinaryApproachThrottle=.75};
private static ScoExitNativeFrame Frame(int step,int state=2,double speed=400,double cap=40,int target=1)=>new()
{
Entity=10,World=20,At=(ulong)(1000+step*10),ClockEpoch=1,Steps=(ulong)step,SimulationSeconds=step*.01,StepSeconds=.01,
SourceDomainVerified=true,ParameterBindingVerified=true,ShipIdentityHealthVerified=true,NativeOffStateVerified=state==0,InSupercruise=true,RawFsdState=2,ClockValid=true,TargetKey=target,State=state,Speed=speed*C,Distance=(1000000-step*4)*C,
OrdinaryCap=cap*C,Blend=1,RawThrottle=.75,OriginalOrdinaryApproachThrottle=.75,SafeSpeed=1e6,SafeDistance=1e6,ArrivalWindow=6,CurrentAccelerationUpper=100*C,Profile=Profile,
SampleScalarSpeed=speed*C,CurrentVectorSpeed=speed*C,CompletedPhysicsSpeed=speed*C,SpeedSource="max(current-dynamics-vector,last-completed-physics-scalar)"
};
private static ScoExitEstimatePolicy Shadow(double activeRawThrottle=.75)
{
var policy=new ScoExitEstimatePolicy();policy.BindLoadout(new('a',64));for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=activeRawThrottle});policy.OriginalStopped(true);
for(var i=10;i<15;i++)policy.Observe(Frame(i,3,400-(i-9)*20) with{Blend=.5+(i-10)*.1});
for(var i=15;i<20;i++)policy.Observe(Frame(i,0,300-(i-14)*50));
policy.Observe(Frame(20,0,30));Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());return policy;
}
[Test]public void CompleteOriginalClockCountsEveryStepAndAnInvalidDeltaCannotPretendToBeWallTime()
{
var clock=new ScoExitSimulationClock();for(var i=0;i<1000;i++){Check.That(clock.AcceptIncoming(.005));clock.Complete(.005);}
Check.Equal(1000UL,clock.CompletedSteps);Check.That(Math.Abs(clock.CompletedSeconds-5)<1e-10);
var epoch=clock.Epoch;Check.That(!clock.AcceptIncoming(double.NaN));clock.Complete(.005);
Check.That(!clock.Valid&&clock.Epoch>epoch&&clock.CompletedSteps==0&&clock.CompletedSeconds==0);
clock.Reset();Check.That(clock.AcceptIncoming(.005));clock.Complete(.005);Check.Equal(1UL,clock.CompletedSteps);
}
[Test]public void AClockGapRequiresANewEpochAndFiveConsecutiveGoodUpdatesBeforeShadowRecovers()
{
var clock=new ScoExitSimulationClock();clock.Complete(.01);var before=clock.Epoch;
Check.That(!clock.AcceptIncoming(.1));var broken=clock.Epoch;Check.That(broken>before);
for(var i=0;i<4;i++){Check.That(!clock.AcceptIncoming(.01));clock.Complete(.01);}
Check.Equal(0UL,clock.CompletedSteps);Check.That(clock.AcceptIncoming(.01));clock.Complete(.01);
Check.That(clock.Valid&&clock.Epoch>broken&&clock.CompletedSteps==1&&clock.CompletedSeconds==.01);
}
private static ScoExitEstimatePolicy PassedTrial(double activeRawThrottle=.75)
{
var policy=Shadow(activeRawThrottle);Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst();
for(var i=21;i<=25;i++)Check.That(policy.Observe(Frame(i,2,350,50) with{RawThrottle=activeRawThrottle}).UseEstimatedStop);
policy.OriginalStopped(true);
for(var i=26;i<=30;i++)policy.Observe(Frame(i,3,350-(i-25)*20,50) with{Blend=.5+(i-26)*.1});
for(var i=31;i<=35;i++)policy.Observe(Frame(i,0,250-(i-30)*45,50));
Check.Equal(1,policy.Status()["successfulTrialExits"]!.GetValue<int>());return policy;
}
[Test]public void ProductionRequiresAnExplicitSuccessfulTrialAndATrustedSha256Fingerprint()
{
var shadow=Shadow();Check.That(!shadow.PromoteProduction(10,20,1200,10000,out _));
var policy=PassedTrial();Check.That(!policy.PromoteProduction(10,20,1350,604801351,out _));
Check.That(policy.PromoteProduction(10,20,1350,10000,out _));
policy.BindLoadout(new('b',64));Check.That(!policy.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void ACompleteTrialReceiptPreservesNativeClocksIntegralBudgetAndABoundedCurve()
{
var receipt=PassedTrial().Status()["lastExitReceipt"]!.AsObject();
Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(25UL,receipt["startCompletedSteps"]!.GetValue<ulong>());Check.Equal(35UL,receipt["endCompletedSteps"]!.GetValue<ulong>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0);
Check.That(receipt["forecastStopDistanceMetres"]!.GetValue<double>()>receipt["integratedPathDistanceMetres"]!.GetValue<double>()+receipt["ordinaryArrivalEnvelopeMetres"]!.GetValue<double>());
Check.That(receipt["curve"]!.AsArray().Count is >1 and <=64);
}
[Test]public void ActiveFullInputRecordsTheRealStartButForecastUsesTheBoundOrdinaryController()
{
var ordinary=Shadow();var activeFull=Shadow(1);
Check.Equal(1d,activeFull.Status()["lastExitReceipt"]!["stopRawThrottle"]!.GetValue<double>());
Check.Equal(.75,activeFull.Status()["lastExitReceipt"]!["originalOrdinaryApproachThrottle"]!.GetValue<double>());
foreach(var policy in new[]{ordinary,activeFull})
{Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst();}
var a=ordinary.Observe(Frame(21,2,350,50));var b=activeFull.Observe(Frame(21,2,350,50) with{RawThrottle=1});
Check.That(a.UseEstimatedStop&&b.UseEstimatedStop);Check.Equal(a.StopDistance,b.StopDistance);
var receipt=PassedTrial(1).Status()["lastExitReceipt"]!;
Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(1d,receipt["stopRawThrottle"]!.GetValue<double>());Check.Equal(.75,receipt["originalOrdinaryApproachThrottle"]!.GetValue<double>());
}
[Test]public void FullInputPersistingAfterOriginalStopCannotUseTheOrdinaryServoOrCompleteAProof()
{
foreach(var state in new[]{0,3})
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(true);
Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>());
policy.Observe(Frame(10,state,350) with{RawThrottle=1});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["shadowExitPending"]!.GetValue<bool>());
Check.That(!policy.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
}
[Test]public void ProductionUsesFreshNewSceneIdentityAndPreservesTheDominatingBaselineEnvelope()
{
var policy=PassedTrial();Check.That(policy.PromoteProduction(10,20,1350,10000,out _));
var status=policy.Status();Check.Equal(400*C,status["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>());
Check.Equal(10d,status["productionMaximumProvenSpeedCapRatio"]!.GetValue<double>()); // trial was only 350c/ratio7
var start=Frame(0,0,30,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2000};policy.Observe(start);policy.BeginOwnedBurst();
var next=policy.Observe(Frame(1,2,75,15,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2010});
Check.That(next.UseEstimatedStop&&next.Mode=="production"&&next.Entity==11&&next.World==21);
Check.That(!next.Applies(10,20,2,2010));Check.That(next.Applies(11,21,2,2010));
policy.Observe(Frame(2,2,75,15,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2020,Profile=Profile with{Jerk=101*C}});
Check.That(!policy.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void NoCrossSessionFixtureOrOneActiveReceiptCanArmATrial()
{
var policy=new ScoExitEstimatePolicy();policy.Observe(Frame(0));policy.OriginalStopped(true);policy.Observe(Frame(1,0,30));
Check.That(!policy.ArmTrial(10,20,1010,2000,1,out _));
Check.That(!policy.Latest.UseEstimatedStop&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
[Test]public void SameBindingShadowThenExplicitBoundedTrialCanSurviveANormalTargetAndRunnerChange()
{
var policy=Shadow();var fresh=Frame(21,0,30,target:2);policy.Observe(fresh);
Check.That(policy.ArmTrial(10,20,fresh.At,3000,2,out _));policy.BeginOwnedBurst();
var next=policy.Observe(Frame(22,2,350,50,target:2));
Check.That(next.UseEstimatedStop&&next.ShadowKnown&&next.TargetKey==2&&next.Entity==10&&next.World==20);
Check.That(next.StopDistance<350*C*13);Check.Equal(1,policy.Status()["maximumTrialBurstsRemaining"]!.GetValue<int>());
}
[Test]public void DefaultShadowNeverChangesTheThirteenSecondRule()
{
var policy=Shadow();var next=policy.Observe(Frame(21,2,350,50));
Check.That(next.ShadowKnown&&!next.UseEstimatedStop);
Check.That(next.RequiresStop(350*C*12,350*C,true,true,6,10,20,1,next.At));
}
[Test]public void BriefTargetGeometryResetInOrdinaryFlightPreservesOnlyTheCompletedSameBindingProof()
{
var policy=Shadow();policy.Observe(Frame(21,0,30,target:2) with{SourceDomainVerified=false});
Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());
policy.Observe(Frame(22,0,30,target:2));Check.That(policy.ArmTrial(10,20,1220,3000,1,out _));
policy.BeginOwnedBurst();Check.That(policy.Observe(Frame(23,2,350,50,target:2)).UseEstimatedStop);
policy.Observe(Frame(24,0,30,target:3) with{SourceDomainVerified=false});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()); // a current trial is never carried through it
}
[Test]public void TrialRequiresFreshExactBindingAHardDeadlineAndAtMostTwoBursts()
{
var policy=Shadow();
foreach(var args in new[]{(11UL,20UL,1200UL,2000UL,1),(10UL,21UL,1200UL,2000UL,1),(10UL,20UL,1500UL,2000UL,1),
(10UL,20UL,1200UL,601201UL,1),(10UL,20UL,1200UL,1200UL,1),(10UL,20UL,1200UL,2000UL,3)})
Check.That(!policy.ArmTrial(args.Item1,args.Item2,args.Item3,args.Item4,args.Item5,out _));
Check.That(policy.ArmTrial(10,20,1200,2000,1,out _));policy.BeginOwnedBurst();
Check.That(!policy.Observe(Frame(100,2,350,50)).UseEstimatedStop); // discontinuity and deadline
}
[Test]public void RebindingParameterChangesMissingSourcesAndClockGapsDiscardTheShadowProof()
{
foreach(var changed in new[]{Frame(21) with{Entity=11},Frame(21) with{World=21},Frame(21) with{ClockEpoch=2},
Frame(21) with{Profile=Profile with{Jerk=101*C}},Frame(21) with{SourceDomainVerified=false},Frame(22),
Frame(21) with{OriginalOrdinaryApproachThrottle=.5,RawThrottle=.5,Profile=Profile with{OrdinaryApproachThrottle=.5}}})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,2000,1,out _));policy.BeginOwnedBurst();
Check.That(!policy.Observe(changed).UseEstimatedStop);Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void HigherSpeedOrWorseCoolingRatioFallsBackToLegacyRatherThanExtrapolatingTheProof()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,3000,1,out _));policy.BeginOwnedBurst();
var speedFallback=policy.Observe(Frame(21,2,401,50));Check.That(!speedFallback.UseEstimatedStop);
Check.Equal(ScoExitApproachDecision.OutsideCalibrationReason,speedFallback.Reason);
var ratioFallback=policy.Observe(Frame(22,2,350,30));Check.That(!ratioFallback.UseEstimatedStop);
Check.Equal(ScoExitApproachDecision.OutsideCalibrationReason,ratioFallback.Reason);
Check.That(policy.Observe(Frame(23,2,350,50)).UseEstimatedStop);
}
[Test]public void UnqualifiedShadowKeepsMixedBelowCapEvidenceUntilTheActualOffHandoff()
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i));policy.OriginalStopped(true);
policy.Observe(Frame(10,3,30,40) with{Blend=.5});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&policy.Status()["shadowExitPending"]!.GetValue<bool>());
for(var i=11;i<=15;i++)policy.Observe(Frame(i,0,30,40));
Check.That(policy.Status()["lastExitReceipt"]!["mixedBelowCapSeen"]!.GetValue<bool>());
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>());
}
[Test]public void NativeDecisionProjectionKeepsBindingAndExpiryAndOnlyAffectsActiveApproach()
{
var choice=new ScoExitApproachDecision{UseEstimatedStop=true,ShadowKnown=true,Entity=10,World=20,TargetKey=1,At=1200,TrialExpiresAt=2000,SourceSpeed=75*C,StopDistance=600*C};
var node=new JsonObject{["scoExitApproach"]=choice.Json()};var wire=JsonSerializer.SerializeToElement(node);
var read=ScoExitApproachDecision.Read(wire)!;Check.That(read.Applies(10,20,1,1201));
Check.That(!read.RequiresStop(700*C,75*C,true,true,6,10,20,1,1201));
Check.That(read.RequiresStop(500*C,75*C,true,true,6,10,20,1,1201));
foreach(var changed in new[]{(11UL,20UL,1,1201UL),(10UL,21UL,1,1201UL),(10UL,20UL,2,1201UL),(10UL,20UL,1,1401UL),(10UL,20UL,1,2000UL)})
Check.That(read.RequiresStop(700*C,75*C,true,true,6,changed.Item1,changed.Item2,changed.Item3,changed.Item4));
Check.That(read.RequiresStop(700*C,75*C,false,true,6,10,20,1,1201));
}
[Test]public void NativeAndManagedGuardsUseTheSameBoundedDecisionWithoutWeakeningHeatOrIdentity()
{
var now=DateTimeOffset.FromUnixTimeMilliseconds(1200);var choice=new ScoExitApproachDecision
{UseEstimatedStop=true,Entity=10,World=20,TargetKey=1,At=1200,TrialExpiresAt=2000,SourceSpeed=75*C,StopDistance=600*C};
var thermal=new ScoThermalInput{Verified=true,HeatCapacity=100,HeatDisplayScale=1,ScoInputUpper=10,OtherInputUpper=5,
CoolingPassive=10,CoolingMaximum=10,CoolingScale=1,CoolingHeatLower=0,CoolingHeatUpper=1,LeaseRemainingSeconds=.15,ResponseDelaySeconds=.01,AfterStopSeconds=.5};
var gate=new CruiseOverchargeGateFrame{IdentityVerified=true,GeometryVerified=true,TargetVerified=true,InSupercruise=true,NativeCanEngage=true,
RawFsdState=2,OverchargeState=2,ObservedAt=1200,Hull=1,Heat=40,MainFuel=32,FuelCapacity=32,FuelRateUpper=1,RequiredFuelReserve=8,
Distance=700*C,Speed=75*C,AimErrorDegrees=0,CruiseParametersVerified=true,CruiseApproachSeconds=6,
ShipEntity=10,ReferenceWorld=20,TargetKey=1,ExitApproach=choice,ThermalInput=thermal};
var flight=new SystemFlightFrame{ObservedAt=now,InGame=true,GeometryVerified=true,GameSha256=new('a',64),ShipEntity=10,ReferenceWorld=20,
SystemAddress=1,Mode=LocalFlightMode.Supercruise,Position=new(0,0,0),TargetPosition=new(0,0,700*C),Forward=new(0,0,1),TargetDistance=700*C,
Speed=75*C,CruiseParametersVerified=true,CruiseApproachSeconds=6,SelectedTarget=new(1,9,"Station",SystemTargetKind.Station,10){NativeKey=1}};
var observed=new CruiseOverchargeObservation{ObservedAt=now,ShipEntity=10,ReferenceWorld=20,GameSha256=new('a',64),OriginalInterfacesVerified=true,
OriginalCanEngage=true,NativeFlightConstraintsVerified=true,NativeGeometryVerified=true,State=CruiseOverchargeState.Active,HeatPercent=40,
FuelMainTonnes=32,FuelCapacityTonnes=32,FuelBurnTonnesPerSecond=0,FuelRateUpperTonnesPerSecond=1,ThermalInput=thermal,ExitApproach=choice};
Check.That(CruiseOverchargeNativeGuard.Refusal(gate,1200,1350) is null);
Check.That(new CruiseOverchargePolicy().Decide(flight,observed,8,now).UseOvercharge);
Check.Equal("approach-or-alignment",CruiseOverchargeNativeGuard.Refusal(gate with{ExitApproach=null},1200,1350));
Check.Equal(CruiseOverchargeReason.TargetClose,new CruiseOverchargePolicy().Decide(flight,observed with{ExitApproach=null},8,now).Reason);
Check.Equal("heat",CruiseOverchargeNativeGuard.Refusal(gate with{Heat=100},1200,1350));
Check.Equal(CruiseOverchargeReason.Heat,new CruiseOverchargePolicy().Decide(flight,observed with{HeatPercent=100},8,now).Reason);
Check.Equal("identity-or-target",CruiseOverchargeNativeGuard.Refusal(gate with{TargetVerified=false},1200,1350));
Check.Equal(CruiseOverchargeReason.Ownership,new CruiseOverchargePolicy().Decide(flight,observed with{ShipEntity=11},8,now).Reason);
}
private static JsonObject NativeJson()
{
var p=new JsonObject
{
["sameFrameSourceVerified"]=true,["targetVelocityCorrectionDisabled"]=true,["externalMotionDisabled"]=true,["externalMotionPredicateVerified"]=true,
["completedPhysicsEffects"]=new JsonObject
{
["available"]=true,["phase"]="after-original-PhysicsUpdate-return",["entityId"]="10",["referenceWorldAddress"]="20",["owningThread"]=7,
["observedAtUnixMilliseconds"]=1000,["completedPhysicsSteps"]=1,["originalPhysicsStepSeconds"]=.01,["targetWeight620"]=0,
["completedPhysicsSpeedMetresPerSecond"]=400*C,
["rawTranslationInputAtCompletion"]=new JsonObject{["x"]=0,["y"]=0,["z"]=.75},
["targetVector660"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},["externalVector720"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},
["externalVector740"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},["externalPredicateVerified"]=true,["externalActuallyDisabled"]=true
},
["originalBrakeScalingMode"]=2,["physicsMode980"]=0,["controlFlag5E0"]=1,["translationScale"]=1,["forwardTargetBiasSentinel"]=0,
["forwardVelocityCosine"]=1,["angularSpeedRadiansPerSecond"]=0,["linearVelocityMagnitude"]=400*C,
["rawTranslationInput5D0"]=new JsonObject{["x"]=0,["y"]=0,["z"]=.75},["flightAssistBlend"]=1,
["baseMaximumSpeedMetresPerSecond"]=Profile.Maximum,["baseOverspeedBrakeAcceleration"]=Profile.Brake,
["baseForwardAcceleration"]=Profile.Forward,["baseSideAcceleration"]=Profile.Side,["currentResponseTimeSeconds"]=1,
["nativeJerkMetresPerSecondCubed"]=Profile.Jerk,["forwardTargetBiasMetresPerSecond"]=Profile.Bias,
["currentForwardAcceleration"]=75*C,["currentOverspeedBrakeAcceleration"]=150*C,["currentSideAcceleration"]=170*C
};
return new()
{
["verified"]=true,["inSupercruise"]=true,["rawFsdState"]=2,["localTargetSelected"]=true,["hullFraction"]=1,["geometryVerified"]=true,["healthEmergency"]=false,["playerOverride"]=false,
["entityId"]="10",["referenceWorldAddress"]="20",["observedAtUnixMilliseconds"]=1000,["state"]=2,["speedMetresPerSecond"]=400*C,
["distanceMetres"]=1000000*C,["target"]=new JsonObject{["key"]=1},["cruiseParametersVerified"]=true,["cruiseApproachSeconds"]=6,["cruiseApproachThrottle"]=.75,
["safeDropSpeedMetresPerSecond"]=1e6,["safeDropDistanceMetres"]=1e6,
["cruiseBrakeProviderDiagnostics"]=new JsonObject
{
["available"]=true,["entityId"]="10",["referenceWorldAddress"]="20",["observedAtUnixMilliseconds"]=1000,["owningThread"]=7,["sampleThread"]=7,
["cachedSpeedValue"]=1000*C,["speedReduction"]=.96,["physicsConfiguration"]=p,
["coolingParameters"]=new JsonObject{["available"]=true,["coolingDragPerSecond"]=.36,["coolingEndFraction"]=2.64}
}
};
}
[Test]public void MissingFastgateWrongWorldThreadAndStaleProviderCannotBecomeASourceQualifiedFrame()
{
var valid=NativeJson();Check.That(ScoExitNativeFrame.Read(valid,1,1,.01,true,.01).SourceDomainVerified);
foreach(var field in new[]{"sameFrameSourceVerified","targetVelocityCorrectionDisabled","externalMotionDisabled","nativeJerkMetresPerSecondCubed","forwardVelocityCosine"})
{
var node=NativeJson();node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject().Remove(field);
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
if(field=="nativeJerkMetresPerSecondCubed")
{var policy=new ScoExitEstimatePolicy();Check.That(!policy.Observe(frame).UseEstimatedStop);}
else Check.That(!frame.SourceDomainVerified);
}
foreach(var change in new[]{("entityId","11"),("referenceWorldAddress","21"),("sampleThread","8"),("observedAtUnixMilliseconds","999")})
{
var node=NativeJson();var provider=node["cruiseBrakeProviderDiagnostics"]!.AsObject();
provider[change.Item1]=change.Item1.EndsWith("Id")||change.Item1=="referenceWorldAddress"?JsonValue.Create(change.Item2):JsonValue.Create(int.Parse(change.Item2));
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void RegisteredTargetContextCanQualifyOnlyThroughFreshCompletedZeroEffectsAndTheFullExternalPredicate()
{
var valid=NativeJson();var p=valid["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject();
p["targetVelocityCorrectionDisabled"]=false;p["externalMotionPrefixDisabled"]=false;
Check.That(ScoExitNativeFrame.Read(valid,1,1,.01,true,.01).SourceDomainVerified);
foreach(var change in new[]{"missing-target-weight","nonzero-target","nonzero-external","unknown-external","enabled-external","old-output","wrong-phase"})
{
var node=valid.DeepClone().AsObject();var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject();
var output=physics["completedPhysicsEffects"]!.AsObject();
switch(change)
{
case "missing-target-weight":output.Remove("targetWeight620");break;
case "nonzero-target":output["targetWeight620"]=.5;output["targetVector660"]!["z"]=1;break;
case "nonzero-external":output["externalVector720"]!["x"]=1;break;
case "unknown-external":output["externalPredicateVerified"]=false;break;
case "enabled-external":output["externalActuallyDisabled"]=false;break;
case "old-output":output["observedAtUnixMilliseconds"]=900;break;
case "wrong-phase":output["phase"]="before-original-PhysicsUpdate";break;
}
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void NativeFullInputIsAnActiveStartingConditionOnlyWithAKnownBoundOrdinaryThrottle()
{
foreach(var state in new[]{0,1,2,3})
{
var node=NativeJson();node["state"]=state;node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["rawTranslationInput5D0"]!["z"]=1;
node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=1;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.Equal(state is 1 or 2,frame.SourceDomainVerified);Check.Equal(1d,frame.RawThrottle);Check.Equal(.75,frame.OriginalOrdinaryApproachThrottle);
}
foreach(var invalid in new[]{0d,-.1,.7500001,1})
{
var node=NativeJson();node["cruiseApproachThrottle"]=invalid;
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
foreach(var change in new[]{"missing","unknown","unverified","over-full","negative","ordinary-mismatch"})
{
var node=NativeJson();var raw=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["rawTranslationInput5D0"]!;
if(change=="missing")node.Remove("cruiseApproachThrottle");
else if(change=="unknown")node["cruiseApproachThrottle"]=null;
else if(change=="unverified")node["cruiseParametersVerified"]=false;
else if(change=="over-full")raw["z"]=1.0000001;
else if(change=="negative")raw["z"]=-.001;
else{node["state"]=3;node["cruiseApproachThrottle"]=.5;raw["z"]=.75;}
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void ARejectedFirstExitFrameAndAnUnqualifiedOriginalStopKeepOnlyBoundedSourceDiagnostics()
{
var node=NativeJson();node["state"]=3;node["observedAtUnixMilliseconds"]=1100;
var provider=node["cruiseBrakeProviderDiagnostics"]!;provider["observedAtUnixMilliseconds"]=1100;
var physics=provider["physicsConfiguration"]!;physics["rawTranslationInput5D0"]!["z"]=1;
var effects=physics["completedPhysicsEffects"]!;effects["available"]=false;effects["unavailableReason"]="completed-raw-input-mismatch";
effects["failureDiagnostics"]=new JsonObject{["readerAvailable"]=true,["rawMatch"]=false,["completedAt"]=1095,["currentAt"]=1100,
["ageMilliseconds"]=5,["dt"]=.005,["completedRaw"]=new JsonArray(0,0,1),["currentRaw"]=new JsonArray(0,0,.75)};
var failed=ScoExitNativeFrame.Read(node,1,10,.1,true,.01);
Check.That(!failed.SourceDomainVerified&&!failed.SourceFailureDiagnostics!["throttleDomain"]!.GetValue<bool>());
Check.Equal("completed-raw-input-mismatch",failed.SourceFailureDiagnostics["effectsUnavailableReason"]!.GetValue<string>());
Check.That(failed.SourceFailureDiagnostics.ToJsonString().Length<2500);
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(true);
policy.Observe(failed);
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(!receipt["pass"]!.GetValue<bool>());
Check.Equal(1d,receipt["failureFrame"]!["rawThrottle"]!.GetValue<double>());
Check.Equal("completed-raw-input-mismatch",receipt["failureFrame"]!["source"]!["effectsUnavailableReason"]!.GetValue<string>());
policy.OriginalStopped(true);
var denied=policy.Status()["lastStopQualificationFailure"]!;
Check.Equal("last-frame-not-Active",denied["reason"]!.GetValue<string>());
Check.Equal(3,denied["frame"]!["state"]!.GetValue<int>());
}
[Test]public void RapidAccelerationComparesTheScalarWithItsCompletedPhaseAndBudgetsTheCurrentVector()
{
const double scalar=19734650,vector=20197590.89757189; // real n observation: 2.346% phase difference
var node=NativeJson();node["speedMetresPerSecond"]=scalar;
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["linearVelocityMagnitude"]=vector;physics["rawTranslationInput5D0"]!["z"]=1;
physics["completedPhysicsEffects"]!["completedPhysicsSpeedMetresPerSecond"]=scalar;
physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=1;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.That(frame.SourceDomainVerified);Check.Equal(vector,frame.Speed);
Check.Equal(scalar,frame.SampleScalarSpeed);Check.Equal(scalar,frame.CompletedPhysicsSpeed);Check.Equal(vector,frame.CurrentVectorSpeed);
Check.That(frame.SourceFailureDiagnostics!["completedScalarPhaseMatch"]!.GetValue<bool>());
Check.Equal("max(current-dynamics-vector,last-completed-physics-scalar)",frame.SpeedSource);
physics["completedPhysicsEffects"]!["completedPhysicsSpeedMetresPerSecond"]=scalar*1.010001;
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
[Test]public void DecelerationRetainsTheLargerCompletedScalarRatherThanCreditingTheNewerLowerSpeed()
{
var node=NativeJson();node["state"]=3;
node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["linearVelocityMagnitude"]=390*C;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.That(frame.SourceDomainVerified);Check.Equal(400*C,frame.Speed);Check.Equal(390*C,frame.CurrentVectorSpeed);
Check.Equal(400*C,frame.CompletedPhysicsSpeed);Check.Equal(400*C,frame.SampleScalarSpeed);
}
[Test]public void WrongOrMissingCompletedScalarAndUnknownCurrentVectorCannotBecomeASpeedEnvelope()
{
foreach(var invalid in new[]{"missing-completed","zero-completed","wrong-completed","missing-vector","unknown-vector","negative-vector","missing-output"})
{
var node=NativeJson();var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
var effects=physics["completedPhysicsEffects"]!;
if(invalid=="missing-completed")effects.AsObject().Remove("completedPhysicsSpeedMetresPerSecond");
else if(invalid=="zero-completed")effects["completedPhysicsSpeedMetresPerSecond"]=0;
else if(invalid=="wrong-completed")effects["completedPhysicsSpeedMetresPerSecond"]=405*C;
else if(invalid=="missing-vector")physics.AsObject().Remove("linearVelocityMagnitude");
else if(invalid=="unknown-vector")physics["linearVelocityMagnitude"]="unknown";
else if(invalid=="negative-vector")physics["linearVelocityMagnitude"]=-1;
else effects["available"]=false;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);Check.That(!frame.SourceDomainVerified);
if(invalid is not ("wrong-completed" or "missing-output"))Check.That(double.IsNaN(frame.Speed));
}
}
private static ScoExitNativeFrame StopTransitionFrame(int step=10,Action<JsonObject>? alter=null)
{
var node=NativeJson();var at=1000+step*10;node["state"]=3;node["observedAtUnixMilliseconds"]=at;
var provider=node["cruiseBrakeProviderDiagnostics"]!;provider["observedAtUnixMilliseconds"]=at;
var output=provider["physicsConfiguration"]!["completedPhysicsEffects"]!;output["observedAtUnixMilliseconds"]=at-5;
output["rawTranslationInputAtCompletion"]!["z"]=1;alter?.Invoke(node);
return ScoExitNativeFrame.Read(node,1,(ulong)step,step*.01,true,.01);
}
private static ScoExitEstimatePolicy PendingFullInputStop(bool called=true,int nativeStateBefore=-1,int nativeStateAfter=-1)
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(called,nativeStateBefore,nativeStateAfter);return policy;
}
[Test]public void OnlyTheFirstCoolingCallbackCanUseTheKnownCompletedActiveInputAfterARealOriginalStop()
{
var transition=StopTransitionFrame();Check.That(!transition.SourceDomainVerified&&transition.SourceExceptCompletedInputVerified
&&transition.OriginalStopInputTransitionCandidate&&!transition.CompletedInputMatchesCurrent);
var policy=PendingFullInputStop();policy.Observe(transition);
Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=11;i<15;i++)policy.Observe(Frame(i,3,400-(i-9)*20) with{Blend=.5+(i-10)*.1});
for(var i=15;i<20;i++)policy.Observe(Frame(i,0,300-(i-14)*50));policy.Observe(Frame(20,0,30));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>());
Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
var repeated=PendingFullInputStop();repeated.Observe(transition);repeated.Observe(StopTransitionFrame(11));
Check.That(!repeated.Status()["shadowExitPending"]!.GetValue<bool>()&&!repeated.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
[Test]public void ACompletedInputMismatchCannotAuthorizeItselfWithoutTheExactStopBindingAndBoundedCallback()
{
var candidate=StopTransitionFrame();
var noStop=PendingFullInputStop(false);noStop.Observe(candidate);Check.That(!noStop.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
foreach(var invalid in new[]{candidate with{Entity=11},candidate with{World=21},candidate with{TargetKey=2},candidate with{ClockEpoch=2},
candidate with{Steps=11},candidate with{At=1116},candidate with{ClockValid=false},candidate with{State=0},
candidate with{SourceExceptCompletedInputVerified=false},candidate with{Profile=Profile with{Jerk=101*C}}})
{
var policy=PendingFullInputStop();policy.Observe(invalid);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void UnknownInputsAndNonzeroEffectsCannotBorrowARealStopTransitionWitness()
{
foreach(var invalid in new[]{"missing-input","unknown-input","transverse-input","other-old-input","nonzero-effect","enabled-external"})
{
var frame=StopTransitionFrame(alter:node=>
{
var output=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["completedPhysicsEffects"]!;
if(invalid=="missing-input")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(invalid=="unknown-input")output["rawTranslationInputAtCompletion"]!["z"]=null;
else if(invalid=="transverse-input")output["rawTranslationInputAtCompletion"]!["x"]=.1;
else if(invalid=="other-old-input")output["rawTranslationInputAtCompletion"]!["z"]=.9;
else if(invalid=="nonzero-effect")output["externalVector720"]!["x"]=1;
else output["externalActuallyDisabled"]=false;
});
var policy=PendingFullInputStop();policy.Observe(frame);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void ARealSynchronousCoolingStateCanBeFollowedByOffWithoutInventingACoolingCallback()
{
var policy=PendingFullInputStop(true,2,3);var firstOff=StopTransitionFrame(alter:node=>node["state"]=0);
policy.Observe(firstOff);Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=11;i<=15;i++)policy.Observe(Frame(i,0,400-(i-10)*75));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["coolingSeen"]!.GetValue<bool>());
Check.That(receipt["synchronousCoolingStateConfirmed"]!.GetValue<bool>()&&receipt["zeroCompleteCoolingCallbacks"]!.GetValue<bool>());
Check.Equal(0,receipt["coolingObservedCallbacks"]!.GetValue<int>());Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
Check.Equal(2,receipt["originalStopStateBefore"]!.GetValue<int>());Check.Equal(3,receipt["originalStopStateAfter"]!.GetValue<int>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0&&receipt["offFrames"]!.GetValue<int>()>=5);
}
[Test]public void AnImmediateOffCannotBorrowAnUnknownUnconfirmedOrRepeatedCoolingState()
{
var off=StopTransitionFrame(alter:node=>node["state"]=0);
foreach(var state in new[]{(-1,-1),(2,-1),(2,0),(2,2),(-1,3),(0,3)})
{
var policy=PendingFullInputStop(true,state.Item1,state.Item2);policy.Observe(off);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var repeated=PendingFullInputStop(true,2,3);repeated.Observe(off);
repeated.Observe(StopTransitionFrame(11,node=>node["state"]=0));
Check.That(!repeated.Status()["shadowExitPending"]!.GetValue<bool>()&&!repeated.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
private static ScoExitNativeFrame OrdinaryExitInputFrame(int step,double completed,double current,Action<JsonObject>? alter=null)
=>StopTransitionFrame(step,node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["rawTranslationInput5D0"]!["z"]=current;physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=completed;
alter?.Invoke(node);
});
private static ScoExitEstimatePolicy AcceptedFirstStopTransition()
{var policy=PendingFullInputStop(true,2,3);policy.Observe(StopTransitionFrame());Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>());return policy;}
[Test]public void OrdinaryInputChangesWithinTheSameWorstCaseServoDomainPreserveARealExitIntegral()
{
var policy=AcceptedFirstStopTransition();var down=OrdinaryExitInputFrame(11,.75,0);var up=OrdinaryExitInputFrame(12,0,.75);
Check.That(!down.SourceDomainVerified&&down.SourceExceptCompletedInputVerified&&down.OrdinaryInputTransitionCandidate);
policy.Observe(down);policy.Observe(up);Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=13;i<=17;i++)policy.Observe(Frame(i,0,400-(i-12)*75));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>());
Check.Equal(2,receipt["ordinaryInputTransitionFrames"]!.GetValue<int>());Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0);
}
[Test]public void OrdinaryInputDomainChangesCannotArmATrialOrBorrowAnUnrelatedOrLowCapExit()
{
var frame=OrdinaryExitInputFrame(11,.75,0);var noStop=new ScoExitEstimatePolicy();noStop.Observe(frame);
Check.That(!noStop.Status()["currentSourceDomainVerified"]!.GetValue<bool>()&&!noStop.ArmTrial(10,20,frame.At,3000,1,out _));
foreach(var wrong in new[]{frame with{Entity=11},frame with{World=21},frame with{TargetKey=2},frame with{ClockEpoch=2},frame with{Steps=12},
frame with{Profile=Profile with{Bias=30001}},frame with{OrdinaryCap=29999},frame with{At=1126}})
{
var policy=AcceptedFirstStopTransition();policy.Observe(wrong);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var lowPrior=PendingFullInputStop(true,2,3);lowPrior.Observe(StopTransitionFrame() with{OrdinaryCap=29999});lowPrior.Observe(frame);
Check.That(!lowPrior.Status()["shadowExitPending"]!.GetValue<bool>());
}
[Test]public void NegativeExcessiveTransverseOrUnknownOrdinaryInputCannotUseTheServoDomainWitness()
{
foreach(var bad in new[]{"negative-old","excessive-old","missing-old","unknown-old","transverse-old","negative-current","excessive-current","transverse-current","nonzero-effect"})
{
var frame=OrdinaryExitInputFrame(11,.75,0,node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;var output=physics["completedPhysicsEffects"]!;
if(bad=="negative-old")output["rawTranslationInputAtCompletion"]!["z"]=-.001;
else if(bad=="excessive-old")output["rawTranslationInputAtCompletion"]!["z"]=.750001;
else if(bad=="missing-old")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(bad=="unknown-old")output["rawTranslationInputAtCompletion"]!["z"]=null;
else if(bad=="transverse-old")output["rawTranslationInputAtCompletion"]!["x"]=.01;
else if(bad=="negative-current")physics["rawTranslationInput5D0"]!["z"]=-.001;
else if(bad=="excessive-current")physics["rawTranslationInput5D0"]!["z"]=.750001;
else if(bad=="transverse-current")physics["rawTranslationInput5D0"]!["y"]=.01;
else output["externalVector720"]!["x"]=1;
});
var policy=AcceptedFirstStopTransition();policy.Observe(frame);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void TheFirstAuthorizedDomainRevocationKeepsItsFrameAndIsNotOverwrittenByLaterFailures()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,4000,2,out _));policy.BeginOwnedBurst();
policy.Observe(Frame(21,1) with{SourceDomainVerified=false,SourceFailureDiagnostics=new(){["first-cause"]="phase-input"}});
var first=policy.Status()["lastPolicyRevocationFailure"]!;
Check.That(first["trialBurst"]!.GetValue<bool>());Check.Equal(4000UL,first["trialUntil"]!.GetValue<ulong>());
Check.Equal(0,first["previousFrame"]!["state"]!.GetValue<int>());Check.Equal(20UL,first["previousFrame"]!["steps"]!.GetValue<ulong>());
Check.Equal(1,first["failureFrame"]!["state"]!.GetValue<int>());Check.Equal("phase-input",first["failureFrame"]!["source"]!["first-cause"]!.GetValue<string>());
policy.Observe(Frame(22,2) with{SourceDomainVerified=false,SourceFailureDiagnostics=new(){["later-cause"]=true}});
Check.Equal(first.ToJsonString(),policy.Status()["lastPolicyRevocationFailure"]!.ToJsonString());
}
[Test]public void AKeptOrdinaryProofIsNotARevocationAndTheNextSuccessfulTrialArmClearsOldEvidence()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,4000,2,out _));
policy.Observe(Frame(21,0,30) with{SourceDomainVerified=false});Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
policy.BeginOwnedBurst();policy.Observe(Frame(22,1) with{SourceDomainVerified=false});Check.That(policy.Status()["lastPolicyRevocationFailure"] is not null);
for(var i=23;i<=32;i++)policy.Observe(Frame(i));policy.OriginalStopped(true);
for(var i=33;i<=37;i++)policy.Observe(Frame(i,3,400-(i-32)*20));
for(var i=38;i<=42;i++)policy.Observe(Frame(i,0,300-(i-37)*50));policy.Observe(Frame(43,0,30));
Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());Check.That(policy.ArmTrial(10,20,1430,6000,1,out _));
Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
}
private static ScoExitNativeFrame EnableTransitionFrame(int step=21,Action<JsonObject>? alter=null)
=>StopTransitionFrame(step,node=>
{
node["state"]=1;var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["rawTranslationInput5D0"]!["z"]=1;physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=.75;
alter?.Invoke(node);
});
[Test]public void ARealOffToArmedOriginalCallPreservesTheCompletedProofThroughItsSingleInputPhaseBoundary()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);
var first=EnableTransitionFrame();Check.That(first.SourceExceptCompletedInputVerified&&first.OriginalEnableInputTransitionCandidate&&!first.SourceDomainVerified);
policy.Observe(first);Check.That(policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>()&&policy.Status()["proofAvailable"]!.GetValue<bool>());
Check.Equal(1,policy.Status()["originalEnableInputTransitionFrames"]!.GetValue<int>());Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
for(var i=22;i<=26;i++)Check.That(policy.Observe(Frame(i,2,350,50) with{RawThrottle=1}).UseEstimatedStop);
policy.OriginalStopped(true,2,3);
for(var i=27;i<=31;i++)policy.Observe(Frame(i,3,350-(i-26)*20,50));
for(var i=32;i<=36;i++)policy.Observe(Frame(i,0,250-(i-31)*45,50));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(1,receipt["originalEnableInputTransitionFrames"]!.GetValue<int>());Check.Equal(0,receipt["originalEnableStateBefore"]!.GetValue<int>());
Check.Equal(1,receipt["originalEnableStateAfter"]!.GetValue<int>());
}
[Test]public void UnknownExternalOrWrongNativeEnableReceiptsCannotClaimTheOffToArmedBoundary()
{
foreach(var native in new[]{(false,0,1),(true,-1,-1),(true,-1,1),(true,0,-1),(true,0,2),(true,1,1)})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(native.Item1,native.Item2,native.Item3);
policy.Observe(EnableTransitionFrame());Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
}
}
[Test]public void AnEnableBoundaryCannotBeReusedLateAcrossBindingsOrWithUnknownAndUnmatchedInputs()
{
var candidate=EnableTransitionFrame();
foreach(var wrong in new[]{candidate with{Entity=11},candidate with{World=21},candidate with{TargetKey=2},candidate with{ClockEpoch=2},
candidate with{Steps=22},candidate with{At=1226},candidate with{State=2},candidate with{ClockValid=false},
candidate with{SourceExceptCompletedInputVerified=false},candidate with{Profile=Profile with{Jerk=101*C}},candidate with{CompletedRawThrottle=.5}})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);policy.Observe(wrong);
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
}
foreach(var bad in new[]{"missing-old","negative-old","above-ordinary-old","old-transverse","current-transverse","unknown-old","nonzero-effect"})
{
var wrong=EnableTransitionFrame(alter:node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;var output=physics["completedPhysicsEffects"]!;
if(bad=="missing-old")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(bad=="negative-old")output["rawTranslationInputAtCompletion"]!["z"]=-.001;
else if(bad=="above-ordinary-old")output["rawTranslationInputAtCompletion"]!["z"]=.750001;
else if(bad=="old-transverse")output["rawTranslationInputAtCompletion"]!["x"]=.01;
else if(bad=="current-transverse")physics["rawTranslationInput5D0"]!["y"]=.01;
else if(bad=="unknown-old")output["rawTranslationInputAtCompletion"]!["z"]=null;
else output["externalVector720"]!["x"]=1;
});
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);policy.Observe(wrong);
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var repeated=Shadow();Check.That(repeated.ArmTrial(10,20,1200,5000,2,out _));repeated.BeginOwnedBurst(true,0,1);
repeated.Observe(candidate);repeated.Observe(EnableTransitionFrame(22));Check.That(!repeated.Status()["proofAvailable"]!.GetValue<bool>());
Check.Equal(1,repeated.Status()["originalEnableInputTransitionFrames"]!.GetValue<int>());
}
private static ScoExitEstimatePolicy Promoted()
{var policy=PassedTrial();Check.That(policy.PromoteProduction(10,20,1350,86400000,out _));return policy;}
private static ScoExitNativeFrame IdleReferenceGap()=>Frame(0,0,30) with{World=21,ClockEpoch=2,At=1400,SourceDomainVerified=false,ParameterBindingVerified=false,Profile=null};
[Test]public void AVerifiedOrdinaryOffReferenceGapKeepsApprovalButCannotUseAnOldFrameAsTheNewSource()
{
var policy=Promoted();var before=policy.Status();var gap=IdleReferenceGap();
Check.That(!policy.Observe(gap).UseEstimatedStop);var waiting=policy.Status();
Check.That(waiting["productionAvailable"]!.GetValue<bool>()&&waiting["productionCalibrationValid"]!.GetValue<bool>());
Check.That(!waiting["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>()&&waiting["productionSourceSuspended"]!.GetValue<bool>());
policy.ResetBinding(); // normal new-world watch must not destroy the proven idle context
policy.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1450});
var fresh=policy.Status();Check.That(fresh["productionCalibrationValid"]!.GetValue<bool>()&&fresh["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.That(fresh["productionIdleSourceQuarantine"] is null);
Check.That(!fresh["productionSourceSuspended"]!.GetValue<bool>());
Check.Equal(before["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>(),fresh["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>());
Check.Equal(before["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>(),fresh["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>());
policy.BeginOwnedBurst();Check.That(policy.Observe(Frame(2,2,75,15) with{World=21,ClockEpoch=3,At=1460}).UseEstimatedStop);
}
[Test]public void AnIdleClockRecoveryWithholdsCurrentUseWithoutRenewingTheOriginalCalibrationAge()
{
var policy=Promoted();policy.Observe(Frame(0,0,30) with{ClockEpoch=2,At=1400,ClockValid=false,SourceDomainVerified=false});
Check.That(policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.Observe(Frame(1,0,30) with{ClockEpoch=3,At=1450});Check.That(policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.ResetBinding();policy.Observe(Frame(0,0,30) with{World=22,ClockEpoch=4,At=7201400});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>(),"Requalification must not move the original envelope timestamp forward.");
}
[Test]public void AnActivePredictionOrPendingExitLostAtAReferenceChangeStillInvalidatesProduction()
{
foreach(var pending in new[]{false,true})
{
var policy=Promoted();policy.BeginOwnedBurst();
for(var i=36;i<=40;i++)Check.That(policy.Observe(Frame(i,2,75,15)).UseEstimatedStop);
if(pending)policy.OriginalStopped(true,2,3);
policy.Observe(IdleReferenceGap() with{At=1410});
Check.That(!policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&policy.Status()["productionIdleSourceQuarantine"] is null);
policy.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1420});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
}
[Test]public void MissingIdleSourcesPreserveOnlyPhysicalApprovalDataAndCannotAuthorizeAControlFrame()
{
foreach(var bad in new[]{IdleReferenceGap() with{Entity=11},IdleReferenceGap() with{World=0},IdleReferenceGap() with{ShipIdentityHealthVerified=false},
IdleReferenceGap() with{TargetKey=2},IdleReferenceGap() with{At=1600}})
{
var policy=Promoted();Check.That(!policy.Observe(bad).UseEstimatedStop);
Check.That(policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
var timed=Promoted();timed.Observe(IdleReferenceGap());timed.Observe(IdleReferenceGap() with{Steps=1,SimulationSeconds=.01,At=3401});
Check.That(timed.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!timed.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
timed.Observe(Frame(2,0,30) with{World=21,ClockEpoch=2,At=3410});Check.That(timed.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
[Test]public void KnownProfileAndTrustedLoadoutChangesClearTheApprovalDuringIdleRequalification()
{
var profile=Promoted();profile.Observe(IdleReferenceGap());
profile.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1450,Profile=Profile with{Jerk=101*C}});
Check.That(!profile.Status()["productionAvailable"]!.GetValue<bool>());
var loadout=Promoted();loadout.Observe(IdleReferenceGap());loadout.BindLoadout(new('c',64));Check.That(!loadout.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void NormalScExitDockAndNewScenePreserveTheOriginalApprovalWithoutUsingNormalModeParameters()
{
var policy=Promoted();var before=policy.Status();
var leaving=Frame(36,0,30) with{RawFsdState=5,InSupercruise=false,ShipIdentityHealthVerified=false,SourceDomainVerified=false,ParameterBindingVerified=false,World=21,Profile=null};
Check.That(!policy.Observe(leaving).UseEstimatedStop);
// Normal-space physics is not the approved supercruise profile. Even a
// typed normal-mode parameter record must not be compared with it.
var normal=leaving with{At=5000,Steps=1,World=22,RawFsdState=0,ParameterBindingVerified=true,Profile=Profile with{Maximum=1000,Brake=100}};
Check.That(!policy.Observe(normal).UseEstimatedStop);
policy.ResetBinding();
Check.That(!policy.Observe(normal with{At=60000,Steps=0,Entity=0,World=0,Profile=null,ParameterBindingVerified=false,ClockValid=false}).UseEstimatedStop);
var suspended=policy.Status();Check.That(suspended["productionCalibrationValid"]!.GetValue<bool>()&&!suspended["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.Equal(before["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>(),suspended["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>());
Check.Equal(before["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>(),suspended["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>());
var fresh=Frame(0,0,30,target:2) with{At=60100,Entity=12,World=23,ClockEpoch=8};policy.Observe(fresh);
Check.That(policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.BeginOwnedBurst();var active=policy.Observe(Frame(1,2,75,15,target:2) with{At=60110,Entity=12,World=23,ClockEpoch=8});
Check.That(active.UseEstimatedStop&&active.Mode=="production"&&active.Entity==12&&active.World==23);
}
[Test]public void IdleLifecycleSuspensionCannotRefreshCalibrationAgeOrTheHardDeadline()
{
var policy=Promoted();var at=policy.Status()["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>();
policy.Observe(IdleReferenceGap() with{InSupercruise=false,RawFsdState=0,ShipIdentityHealthVerified=false});
policy.Observe(Frame(0,0,30) with{World=22,ClockEpoch=3,At=at+7200001});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
var deadline=PassedTrial();Check.That(deadline.PromoteProduction(10,20,1350,2000,out _));
deadline.Observe(IdleReferenceGap());deadline.Observe(Frame(0,0,30) with{World=22,ClockEpoch=3,At=2001});
Check.That(!deadline.Status()["productionAvailable"]!.GetValue<bool>()&&!deadline.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
[Test]public void ExplicitNativeSafetyEvidenceInvalidatesIdleApprovalAndPreservesTheFirstFailure()
{
foreach(var field in new[]{"healthEmergency","playerOverride","hullFraction"})
{
var policy=Promoted();var node=NativeJson();node["state"]=0;node["inSupercruise"]=false;node["rawFsdState"]=0;node["observedAtUnixMilliseconds"]=1400;
if(field=="hullFraction")node[field]=0;else node[field]=true;
var unsafeFrame=ScoExitNativeFrame.Read(node,2,0,0,true,.01);Check.That(unsafeFrame.ExplicitSafetyFailureReason is not null);
policy.Observe(unsafeFrame);var failure=policy.Status()["firstProductionCalibrationInvalidation"]!;
Check.That(!policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&failure["frame"]!["at"]!.GetValue<ulong>()==1400);
var first=failure.ToJsonString();policy.Observe(Frame(1,0,30) with{At=1450,ClockEpoch=2});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.Equal(first,policy.Status()["firstProductionCalibrationInvalidation"]!.ToJsonString());
}
}
[Test]public void AnUnverifiedOffClaimOrAPendingEnableCannotShelveALostPredictionAsIdleApproval()
{
var unverified=Promoted();unverified.Observe(IdleReferenceGap() with{NativeOffStateVerified=false});
Check.That(!unverified.Status()["productionCalibrationValid"]!.GetValue<bool>());
var enabling=Promoted();enabling.BeginOwnedBurst(true,0,1);enabling.Observe(IdleReferenceGap());
Check.That(!enabling.Status()["productionCalibrationValid"]!.GetValue<bool>()&&enabling.Status()["firstProductionCalibrationInvalidation"] is not null);
}
}
using System.Text.Json;
using System.Text.Json.Nodes;
using XFEEDToolBox.Core.Navigation;
using XFEExtension.NetCore.XUnit.Attributes;
namespace XFEEDToolBox.Test;
[TestFixture]
public sealed class ScoExitEstimatePolicyTests
{
private const double C=299792458;
private static readonly ScoExitProfile Profile=new(1000*C,150*C,75*C,170*C,1,100*C,30000,.36,2.64){OrdinaryApproachThrottle=.75};
private static ScoExitNativeFrame Frame(int step,int state=2,double speed=400,double cap=40,int target=1)=>new()
{
Entity=10,World=20,At=(ulong)(1000+step*10),ClockEpoch=1,Steps=(ulong)step,SimulationSeconds=step*.01,StepSeconds=.01,
SourceDomainVerified=true,ParameterBindingVerified=true,ShipIdentityHealthVerified=true,NativeOffStateVerified=state==0,InSupercruise=true,RawFsdState=2,ClockValid=true,TargetKey=target,State=state,Speed=speed*C,Distance=(1000000-step*4)*C,
OrdinaryCap=cap*C,Blend=1,RawThrottle=.75,OriginalOrdinaryApproachThrottle=.75,SafeSpeed=1e6,SafeDistance=1e6,ArrivalWindow=6,CurrentAccelerationUpper=100*C,Profile=Profile,
SampleScalarSpeed=speed*C,CurrentVectorSpeed=speed*C,CompletedPhysicsSpeed=speed*C,SpeedSource="max(current-dynamics-vector,last-completed-physics-scalar)"
};
private static ScoExitEstimatePolicy Shadow(double activeRawThrottle=.75)
{
var policy=new ScoExitEstimatePolicy();policy.BindLoadout(new('a',64));for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=activeRawThrottle});policy.OriginalStopped(true);
for(var i=10;i<15;i++)policy.Observe(Frame(i,3,400-(i-9)*20) with{Blend=.5+(i-10)*.1});
for(var i=15;i<20;i++)policy.Observe(Frame(i,0,300-(i-14)*50));
policy.Observe(Frame(20,0,30));Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());return policy;
}
[Test]public void CompleteOriginalClockCountsEveryStepAndAnInvalidDeltaCannotPretendToBeWallTime()
{
var clock=new ScoExitSimulationClock();for(var i=0;i<1000;i++){Check.That(clock.AcceptIncoming(.005));clock.Complete(.005);}
Check.Equal(1000UL,clock.CompletedSteps);Check.That(Math.Abs(clock.CompletedSeconds-5)<1e-10);
var epoch=clock.Epoch;Check.That(!clock.AcceptIncoming(double.NaN));clock.Complete(.005);
Check.That(!clock.Valid&&clock.Epoch>epoch&&clock.CompletedSteps==0&&clock.CompletedSeconds==0);
clock.Reset();Check.That(clock.AcceptIncoming(.005));clock.Complete(.005);Check.Equal(1UL,clock.CompletedSteps);
}
[Test]public void AClockGapRequiresANewEpochAndFiveConsecutiveGoodUpdatesBeforeShadowRecovers()
{
var clock=new ScoExitSimulationClock();clock.Complete(.01);var before=clock.Epoch;
Check.That(!clock.AcceptIncoming(.1));var broken=clock.Epoch;Check.That(broken>before);
for(var i=0;i<4;i++){Check.That(!clock.AcceptIncoming(.01));clock.Complete(.01);}
Check.Equal(0UL,clock.CompletedSteps);Check.That(clock.AcceptIncoming(.01));clock.Complete(.01);
Check.That(clock.Valid&&clock.Epoch>broken&&clock.CompletedSteps==1&&clock.CompletedSeconds==.01);
}
private static ScoExitEstimatePolicy PassedTrial(double activeRawThrottle=.75)
{
var policy=Shadow(activeRawThrottle);Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst();
for(var i=21;i<=25;i++)Check.That(policy.Observe(Frame(i,2,350,50) with{RawThrottle=activeRawThrottle}).UseEstimatedStop);
policy.OriginalStopped(true);
for(var i=26;i<=30;i++)policy.Observe(Frame(i,3,350-(i-25)*20,50) with{Blend=.5+(i-26)*.1});
for(var i=31;i<=35;i++)policy.Observe(Frame(i,0,250-(i-30)*45,50));
Check.Equal(1,policy.Status()["successfulTrialExits"]!.GetValue<int>());return policy;
}
[Test]public void ProductionRequiresAnExplicitSuccessfulTrialAndATrustedSha256Fingerprint()
{
var shadow=Shadow();Check.That(!shadow.PromoteProduction(10,20,1200,10000,out _));
var policy=PassedTrial();Check.That(!policy.PromoteProduction(10,20,1350,604801351,out _));
Check.That(policy.PromoteProduction(10,20,1350,10000,out _));
policy.BindLoadout(new('b',64));Check.That(!policy.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void ACompleteTrialReceiptPreservesNativeClocksIntegralBudgetAndABoundedCurve()
{
var receipt=PassedTrial().Status()["lastExitReceipt"]!.AsObject();
Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(25UL,receipt["startCompletedSteps"]!.GetValue<ulong>());Check.Equal(35UL,receipt["endCompletedSteps"]!.GetValue<ulong>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0);
Check.That(receipt["forecastStopDistanceMetres"]!.GetValue<double>()>receipt["integratedPathDistanceMetres"]!.GetValue<double>()+receipt["ordinaryArrivalEnvelopeMetres"]!.GetValue<double>());
Check.That(receipt["curve"]!.AsArray().Count is >1 and <=64);
}
[Test]public void ActiveFullInputRecordsTheRealStartButForecastUsesTheBoundOrdinaryController()
{
var ordinary=Shadow();var activeFull=Shadow(1);
Check.Equal(1d,activeFull.Status()["lastExitReceipt"]!["stopRawThrottle"]!.GetValue<double>());
Check.Equal(.75,activeFull.Status()["lastExitReceipt"]!["originalOrdinaryApproachThrottle"]!.GetValue<double>());
foreach(var policy in new[]{ordinary,activeFull})
{Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst();}
var a=ordinary.Observe(Frame(21,2,350,50));var b=activeFull.Observe(Frame(21,2,350,50) with{RawThrottle=1});
Check.That(a.UseEstimatedStop&&b.UseEstimatedStop);Check.Equal(a.StopDistance,b.StopDistance);
var receipt=PassedTrial(1).Status()["lastExitReceipt"]!;
Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(1d,receipt["stopRawThrottle"]!.GetValue<double>());Check.Equal(.75,receipt["originalOrdinaryApproachThrottle"]!.GetValue<double>());
}
[Test]public void FullInputPersistingAfterOriginalStopCannotUseTheOrdinaryServoOrCompleteAProof()
{
foreach(var state in new[]{0,3})
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(true);
Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>());
policy.Observe(Frame(10,state,350) with{RawThrottle=1});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["shadowExitPending"]!.GetValue<bool>());
Check.That(!policy.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
}
[Test]public void ProductionUsesFreshNewSceneIdentityAndPreservesTheDominatingBaselineEnvelope()
{
var policy=PassedTrial();Check.That(policy.PromoteProduction(10,20,1350,10000,out _));
var status=policy.Status();Check.Equal(400*C,status["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>());
Check.Equal(10d,status["productionMaximumProvenSpeedCapRatio"]!.GetValue<double>()); // trial was only 350c/ratio7
var start=Frame(0,0,30,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2000};policy.Observe(start);policy.BeginOwnedBurst();
var next=policy.Observe(Frame(1,2,75,15,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2010});
Check.That(next.UseEstimatedStop&&next.Mode=="production"&&next.Entity==11&&next.World==21);
Check.That(!next.Applies(10,20,2,2010));Check.That(next.Applies(11,21,2,2010));
policy.Observe(Frame(2,2,75,15,target:2) with{Entity=11,World=21,ClockEpoch=2,At=2020,Profile=Profile with{Jerk=101*C}});
Check.That(!policy.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void NoCrossSessionFixtureOrOneActiveReceiptCanArmATrial()
{
var policy=new ScoExitEstimatePolicy();policy.Observe(Frame(0));policy.OriginalStopped(true);policy.Observe(Frame(1,0,30));
Check.That(!policy.ArmTrial(10,20,1010,2000,1,out _));
Check.That(!policy.Latest.UseEstimatedStop&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
[Test]public void SameBindingShadowThenExplicitBoundedTrialCanSurviveANormalTargetAndRunnerChange()
{
var policy=Shadow();var fresh=Frame(21,0,30,target:2);policy.Observe(fresh);
Check.That(policy.ArmTrial(10,20,fresh.At,3000,2,out _));policy.BeginOwnedBurst();
var next=policy.Observe(Frame(22,2,350,50,target:2));
Check.That(next.UseEstimatedStop&&next.ShadowKnown&&next.TargetKey==2&&next.Entity==10&&next.World==20);
Check.That(next.StopDistance<350*C*13);Check.Equal(1,policy.Status()["maximumTrialBurstsRemaining"]!.GetValue<int>());
}
[Test]public void DefaultShadowNeverChangesTheThirteenSecondRule()
{
var policy=Shadow();var next=policy.Observe(Frame(21,2,350,50));
Check.That(next.ShadowKnown&&!next.UseEstimatedStop);
Check.That(next.RequiresStop(350*C*12,350*C,true,true,6,10,20,1,next.At));
}
[Test]public void BriefTargetGeometryResetInOrdinaryFlightPreservesOnlyTheCompletedSameBindingProof()
{
var policy=Shadow();policy.Observe(Frame(21,0,30,target:2) with{SourceDomainVerified=false});
Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());
policy.Observe(Frame(22,0,30,target:2));Check.That(policy.ArmTrial(10,20,1220,3000,1,out _));
policy.BeginOwnedBurst();Check.That(policy.Observe(Frame(23,2,350,50,target:2)).UseEstimatedStop);
policy.Observe(Frame(24,0,30,target:3) with{SourceDomainVerified=false});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()); // a current trial is never carried through it
}
[Test]public void TrialRequiresFreshExactBindingAHardDeadlineAndAtMostTwoBursts()
{
var policy=Shadow();
foreach(var args in new[]{(11UL,20UL,1200UL,2000UL,1),(10UL,21UL,1200UL,2000UL,1),(10UL,20UL,1500UL,2000UL,1),
(10UL,20UL,1200UL,601201UL,1),(10UL,20UL,1200UL,1200UL,1),(10UL,20UL,1200UL,2000UL,3)})
Check.That(!policy.ArmTrial(args.Item1,args.Item2,args.Item3,args.Item4,args.Item5,out _));
Check.That(policy.ArmTrial(10,20,1200,2000,1,out _));policy.BeginOwnedBurst();
Check.That(!policy.Observe(Frame(100,2,350,50)).UseEstimatedStop); // discontinuity and deadline
}
[Test]public void RebindingParameterChangesMissingSourcesAndClockGapsDiscardTheShadowProof()
{
foreach(var changed in new[]{Frame(21) with{Entity=11},Frame(21) with{World=21},Frame(21) with{ClockEpoch=2},
Frame(21) with{Profile=Profile with{Jerk=101*C}},Frame(21) with{SourceDomainVerified=false},Frame(22),
Frame(21) with{OriginalOrdinaryApproachThrottle=.5,RawThrottle=.5,Profile=Profile with{OrdinaryApproachThrottle=.5}}})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,2000,1,out _));policy.BeginOwnedBurst();
Check.That(!policy.Observe(changed).UseEstimatedStop);Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void HigherSpeedOrWorseCoolingRatioFallsBackToLegacyRatherThanExtrapolatingTheProof()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,3000,1,out _));policy.BeginOwnedBurst();
var speedFallback=policy.Observe(Frame(21,2,401,50));Check.That(!speedFallback.UseEstimatedStop);
Check.Equal(ScoExitApproachDecision.OutsideCalibrationReason,speedFallback.Reason);
var ratioFallback=policy.Observe(Frame(22,2,350,30));Check.That(!ratioFallback.UseEstimatedStop);
Check.Equal(ScoExitApproachDecision.OutsideCalibrationReason,ratioFallback.Reason);
Check.That(policy.Observe(Frame(23,2,350,50)).UseEstimatedStop);
}
[Test]public void UnqualifiedShadowKeepsMixedBelowCapEvidenceUntilTheActualOffHandoff()
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i));policy.OriginalStopped(true);
policy.Observe(Frame(10,3,30,40) with{Blend=.5});
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&policy.Status()["shadowExitPending"]!.GetValue<bool>());
for(var i=11;i<=15;i++)policy.Observe(Frame(i,0,30,40));
Check.That(policy.Status()["lastExitReceipt"]!["mixedBelowCapSeen"]!.GetValue<bool>());
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>());
}
[Test]public void NativeDecisionProjectionKeepsBindingAndExpiryAndOnlyAffectsActiveApproach()
{
var choice=new ScoExitApproachDecision{UseEstimatedStop=true,ShadowKnown=true,Entity=10,World=20,TargetKey=1,At=1200,TrialExpiresAt=2000,SourceSpeed=75*C,StopDistance=600*C};
var node=new JsonObject{["scoExitApproach"]=choice.Json()};var wire=JsonSerializer.SerializeToElement(node);
var read=ScoExitApproachDecision.Read(wire)!;Check.That(read.Applies(10,20,1,1201));
Check.That(!read.RequiresStop(700*C,75*C,true,true,6,10,20,1,1201));
Check.That(read.RequiresStop(500*C,75*C,true,true,6,10,20,1,1201));
foreach(var changed in new[]{(11UL,20UL,1,1201UL),(10UL,21UL,1,1201UL),(10UL,20UL,2,1201UL),(10UL,20UL,1,1401UL),(10UL,20UL,1,2000UL)})
Check.That(read.RequiresStop(700*C,75*C,true,true,6,changed.Item1,changed.Item2,changed.Item3,changed.Item4));
Check.That(read.RequiresStop(700*C,75*C,false,true,6,10,20,1,1201));
}
[Test]public void NativeAndManagedGuardsUseTheSameBoundedDecisionWithoutWeakeningHeatOrIdentity()
{
var now=DateTimeOffset.FromUnixTimeMilliseconds(1200);var choice=new ScoExitApproachDecision
{UseEstimatedStop=true,Entity=10,World=20,TargetKey=1,At=1200,TrialExpiresAt=2000,SourceSpeed=75*C,StopDistance=600*C};
var thermal=new ScoThermalInput{Verified=true,HeatCapacity=100,HeatDisplayScale=1,ScoInputUpper=10,OtherInputUpper=5,
CoolingPassive=10,CoolingMaximum=10,CoolingScale=1,CoolingHeatLower=0,CoolingHeatUpper=1,LeaseRemainingSeconds=.15,ResponseDelaySeconds=.01,AfterStopSeconds=.5};
var gate=new CruiseOverchargeGateFrame{IdentityVerified=true,GeometryVerified=true,TargetVerified=true,InSupercruise=true,NativeCanEngage=true,
RawFsdState=2,OverchargeState=2,ObservedAt=1200,Hull=1,Heat=40,MainFuel=32,FuelCapacity=32,FuelRateUpper=1,RequiredFuelReserve=8,
Distance=700*C,Speed=75*C,AimErrorDegrees=0,CruiseParametersVerified=true,CruiseApproachSeconds=6,
ShipEntity=10,ReferenceWorld=20,TargetKey=1,ExitApproach=choice,ThermalInput=thermal};
var flight=new SystemFlightFrame{ObservedAt=now,InGame=true,GeometryVerified=true,GameSha256=new('a',64),ShipEntity=10,ReferenceWorld=20,
SystemAddress=1,Mode=LocalFlightMode.Supercruise,Position=new(0,0,0),TargetPosition=new(0,0,700*C),Forward=new(0,0,1),TargetDistance=700*C,
Speed=75*C,CruiseParametersVerified=true,CruiseApproachSeconds=6,SelectedTarget=new(1,9,"Station",SystemTargetKind.Station,10){NativeKey=1}};
var observed=new CruiseOverchargeObservation{ObservedAt=now,ShipEntity=10,ReferenceWorld=20,GameSha256=new('a',64),OriginalInterfacesVerified=true,
OriginalCanEngage=true,NativeFlightConstraintsVerified=true,NativeGeometryVerified=true,State=CruiseOverchargeState.Active,HeatPercent=40,
FuelMainTonnes=32,FuelCapacityTonnes=32,FuelBurnTonnesPerSecond=0,FuelRateUpperTonnesPerSecond=1,ThermalInput=thermal,ExitApproach=choice};
Check.That(CruiseOverchargeNativeGuard.Refusal(gate,1200,1350) is null);
Check.That(new CruiseOverchargePolicy().Decide(flight,observed,8,now).UseOvercharge);
Check.Equal("approach-or-alignment",CruiseOverchargeNativeGuard.Refusal(gate with{ExitApproach=null},1200,1350));
Check.Equal(CruiseOverchargeReason.TargetClose,new CruiseOverchargePolicy().Decide(flight,observed with{ExitApproach=null},8,now).Reason);
Check.Equal("heat",CruiseOverchargeNativeGuard.Refusal(gate with{Heat=100},1200,1350));
Check.Equal(CruiseOverchargeReason.Heat,new CruiseOverchargePolicy().Decide(flight,observed with{HeatPercent=100},8,now).Reason);
Check.Equal("identity-or-target",CruiseOverchargeNativeGuard.Refusal(gate with{TargetVerified=false},1200,1350));
Check.Equal(CruiseOverchargeReason.Ownership,new CruiseOverchargePolicy().Decide(flight,observed with{ShipEntity=11},8,now).Reason);
}
private static JsonObject NativeJson()
{
var p=new JsonObject
{
["sameFrameSourceVerified"]=true,["targetVelocityCorrectionDisabled"]=true,["externalMotionDisabled"]=true,["externalMotionPredicateVerified"]=true,
["completedPhysicsEffects"]=new JsonObject
{
["available"]=true,["phase"]="after-original-PhysicsUpdate-return",["entityId"]="10",["referenceWorldAddress"]="20",["owningThread"]=7,
["observedAtUnixMilliseconds"]=1000,["completedPhysicsSteps"]=1,["originalPhysicsStepSeconds"]=.01,["targetWeight620"]=0,
["completedPhysicsSpeedMetresPerSecond"]=400*C,
["rawTranslationInputAtCompletion"]=new JsonObject{["x"]=0,["y"]=0,["z"]=.75},
["targetVector660"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},["externalVector720"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},
["externalVector740"]=new JsonObject{["x"]=0,["y"]=0,["z"]=0},["externalPredicateVerified"]=true,["externalActuallyDisabled"]=true
},
["originalBrakeScalingMode"]=2,["physicsMode980"]=0,["controlFlag5E0"]=1,["translationScale"]=1,["forwardTargetBiasSentinel"]=0,
["forwardVelocityCosine"]=1,["angularSpeedRadiansPerSecond"]=0,["linearVelocityMagnitude"]=400*C,
["rawTranslationInput5D0"]=new JsonObject{["x"]=0,["y"]=0,["z"]=.75},["flightAssistBlend"]=1,
["baseMaximumSpeedMetresPerSecond"]=Profile.Maximum,["baseOverspeedBrakeAcceleration"]=Profile.Brake,
["baseForwardAcceleration"]=Profile.Forward,["baseSideAcceleration"]=Profile.Side,["currentResponseTimeSeconds"]=1,
["nativeJerkMetresPerSecondCubed"]=Profile.Jerk,["forwardTargetBiasMetresPerSecond"]=Profile.Bias,
["currentForwardAcceleration"]=75*C,["currentOverspeedBrakeAcceleration"]=150*C,["currentSideAcceleration"]=170*C
};
return new()
{
["verified"]=true,["inSupercruise"]=true,["rawFsdState"]=2,["localTargetSelected"]=true,["hullFraction"]=1,["geometryVerified"]=true,["healthEmergency"]=false,["playerOverride"]=false,
["entityId"]="10",["referenceWorldAddress"]="20",["observedAtUnixMilliseconds"]=1000,["state"]=2,["speedMetresPerSecond"]=400*C,
["distanceMetres"]=1000000*C,["target"]=new JsonObject{["key"]=1},["cruiseParametersVerified"]=true,["cruiseApproachSeconds"]=6,["cruiseApproachThrottle"]=.75,
["safeDropSpeedMetresPerSecond"]=1e6,["safeDropDistanceMetres"]=1e6,
["cruiseBrakeProviderDiagnostics"]=new JsonObject
{
["available"]=true,["entityId"]="10",["referenceWorldAddress"]="20",["observedAtUnixMilliseconds"]=1000,["owningThread"]=7,["sampleThread"]=7,
["cachedSpeedValue"]=1000*C,["speedReduction"]=.96,["physicsConfiguration"]=p,
["coolingParameters"]=new JsonObject{["available"]=true,["coolingDragPerSecond"]=.36,["coolingEndFraction"]=2.64}
}
};
}
[Test]public void MissingFastgateWrongWorldThreadAndStaleProviderCannotBecomeASourceQualifiedFrame()
{
var valid=NativeJson();Check.That(ScoExitNativeFrame.Read(valid,1,1,.01,true,.01).SourceDomainVerified);
foreach(var field in new[]{"sameFrameSourceVerified","targetVelocityCorrectionDisabled","externalMotionDisabled","nativeJerkMetresPerSecondCubed","forwardVelocityCosine"})
{
var node=NativeJson();node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject().Remove(field);
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
if(field=="nativeJerkMetresPerSecondCubed")
{var policy=new ScoExitEstimatePolicy();Check.That(!policy.Observe(frame).UseEstimatedStop);}
else Check.That(!frame.SourceDomainVerified);
}
foreach(var change in new[]{("entityId","11"),("referenceWorldAddress","21"),("sampleThread","8"),("observedAtUnixMilliseconds","999")})
{
var node=NativeJson();var provider=node["cruiseBrakeProviderDiagnostics"]!.AsObject();
provider[change.Item1]=change.Item1.EndsWith("Id")||change.Item1=="referenceWorldAddress"?JsonValue.Create(change.Item2):JsonValue.Create(int.Parse(change.Item2));
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void RegisteredTargetContextCanQualifyOnlyThroughFreshCompletedZeroEffectsAndTheFullExternalPredicate()
{
var valid=NativeJson();var p=valid["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject();
p["targetVelocityCorrectionDisabled"]=false;p["externalMotionPrefixDisabled"]=false;
Check.That(ScoExitNativeFrame.Read(valid,1,1,.01,true,.01).SourceDomainVerified);
foreach(var change in new[]{"missing-target-weight","nonzero-target","nonzero-external","unknown-external","enabled-external","old-output","wrong-phase"})
{
var node=valid.DeepClone().AsObject();var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!.AsObject();
var output=physics["completedPhysicsEffects"]!.AsObject();
switch(change)
{
case "missing-target-weight":output.Remove("targetWeight620");break;
case "nonzero-target":output["targetWeight620"]=.5;output["targetVector660"]!["z"]=1;break;
case "nonzero-external":output["externalVector720"]!["x"]=1;break;
case "unknown-external":output["externalPredicateVerified"]=false;break;
case "enabled-external":output["externalActuallyDisabled"]=false;break;
case "old-output":output["observedAtUnixMilliseconds"]=900;break;
case "wrong-phase":output["phase"]="before-original-PhysicsUpdate";break;
}
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void NativeFullInputIsAnActiveStartingConditionOnlyWithAKnownBoundOrdinaryThrottle()
{
foreach(var state in new[]{0,1,2,3})
{
var node=NativeJson();node["state"]=state;node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["rawTranslationInput5D0"]!["z"]=1;
node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=1;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.Equal(state is 1 or 2,frame.SourceDomainVerified);Check.Equal(1d,frame.RawThrottle);Check.Equal(.75,frame.OriginalOrdinaryApproachThrottle);
}
foreach(var invalid in new[]{0d,-.1,.7500001,1})
{
var node=NativeJson();node["cruiseApproachThrottle"]=invalid;
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
foreach(var change in new[]{"missing","unknown","unverified","over-full","negative","ordinary-mismatch"})
{
var node=NativeJson();var raw=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["rawTranslationInput5D0"]!;
if(change=="missing")node.Remove("cruiseApproachThrottle");
else if(change=="unknown")node["cruiseApproachThrottle"]=null;
else if(change=="unverified")node["cruiseParametersVerified"]=false;
else if(change=="over-full")raw["z"]=1.0000001;
else if(change=="negative")raw["z"]=-.001;
else{node["state"]=3;node["cruiseApproachThrottle"]=.5;raw["z"]=.75;}
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
}
[Test]public void ARejectedFirstExitFrameAndAnUnqualifiedOriginalStopKeepOnlyBoundedSourceDiagnostics()
{
var node=NativeJson();node["state"]=3;node["observedAtUnixMilliseconds"]=1100;
var provider=node["cruiseBrakeProviderDiagnostics"]!;provider["observedAtUnixMilliseconds"]=1100;
var physics=provider["physicsConfiguration"]!;physics["rawTranslationInput5D0"]!["z"]=1;
var effects=physics["completedPhysicsEffects"]!;effects["available"]=false;effects["unavailableReason"]="completed-raw-input-mismatch";
effects["failureDiagnostics"]=new JsonObject{["readerAvailable"]=true,["rawMatch"]=false,["completedAt"]=1095,["currentAt"]=1100,
["ageMilliseconds"]=5,["dt"]=.005,["completedRaw"]=new JsonArray(0,0,1),["currentRaw"]=new JsonArray(0,0,.75)};
var failed=ScoExitNativeFrame.Read(node,1,10,.1,true,.01);
Check.That(!failed.SourceDomainVerified&&!failed.SourceFailureDiagnostics!["throttleDomain"]!.GetValue<bool>());
Check.Equal("completed-raw-input-mismatch",failed.SourceFailureDiagnostics["effectsUnavailableReason"]!.GetValue<string>());
Check.That(failed.SourceFailureDiagnostics.ToJsonString().Length<2500);
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(true);
policy.Observe(failed);
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(!receipt["pass"]!.GetValue<bool>());
Check.Equal(1d,receipt["failureFrame"]!["rawThrottle"]!.GetValue<double>());
Check.Equal("completed-raw-input-mismatch",receipt["failureFrame"]!["source"]!["effectsUnavailableReason"]!.GetValue<string>());
policy.OriginalStopped(true);
var denied=policy.Status()["lastStopQualificationFailure"]!;
Check.Equal("last-frame-not-Active",denied["reason"]!.GetValue<string>());
Check.Equal(3,denied["frame"]!["state"]!.GetValue<int>());
}
[Test]public void RapidAccelerationComparesTheScalarWithItsCompletedPhaseAndBudgetsTheCurrentVector()
{
const double scalar=19734650,vector=20197590.89757189; // real n observation: 2.346% phase difference
var node=NativeJson();node["speedMetresPerSecond"]=scalar;
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["linearVelocityMagnitude"]=vector;physics["rawTranslationInput5D0"]!["z"]=1;
physics["completedPhysicsEffects"]!["completedPhysicsSpeedMetresPerSecond"]=scalar;
physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=1;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.That(frame.SourceDomainVerified);Check.Equal(vector,frame.Speed);
Check.Equal(scalar,frame.SampleScalarSpeed);Check.Equal(scalar,frame.CompletedPhysicsSpeed);Check.Equal(vector,frame.CurrentVectorSpeed);
Check.That(frame.SourceFailureDiagnostics!["completedScalarPhaseMatch"]!.GetValue<bool>());
Check.Equal("max(current-dynamics-vector,last-completed-physics-scalar)",frame.SpeedSource);
physics["completedPhysicsEffects"]!["completedPhysicsSpeedMetresPerSecond"]=scalar*1.010001;
Check.That(!ScoExitNativeFrame.Read(node,1,1,.01,true,.01).SourceDomainVerified);
}
[Test]public void DecelerationRetainsTheLargerCompletedScalarRatherThanCreditingTheNewerLowerSpeed()
{
var node=NativeJson();node["state"]=3;
node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["linearVelocityMagnitude"]=390*C;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);
Check.That(frame.SourceDomainVerified);Check.Equal(400*C,frame.Speed);Check.Equal(390*C,frame.CurrentVectorSpeed);
Check.Equal(400*C,frame.CompletedPhysicsSpeed);Check.Equal(400*C,frame.SampleScalarSpeed);
}
[Test]public void WrongOrMissingCompletedScalarAndUnknownCurrentVectorCannotBecomeASpeedEnvelope()
{
foreach(var invalid in new[]{"missing-completed","zero-completed","wrong-completed","missing-vector","unknown-vector","negative-vector","missing-output"})
{
var node=NativeJson();var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
var effects=physics["completedPhysicsEffects"]!;
if(invalid=="missing-completed")effects.AsObject().Remove("completedPhysicsSpeedMetresPerSecond");
else if(invalid=="zero-completed")effects["completedPhysicsSpeedMetresPerSecond"]=0;
else if(invalid=="wrong-completed")effects["completedPhysicsSpeedMetresPerSecond"]=405*C;
else if(invalid=="missing-vector")physics.AsObject().Remove("linearVelocityMagnitude");
else if(invalid=="unknown-vector")physics["linearVelocityMagnitude"]="unknown";
else if(invalid=="negative-vector")physics["linearVelocityMagnitude"]=-1;
else effects["available"]=false;
var frame=ScoExitNativeFrame.Read(node,1,1,.01,true,.01);Check.That(!frame.SourceDomainVerified);
if(invalid is not ("wrong-completed" or "missing-output"))Check.That(double.IsNaN(frame.Speed));
}
}
private static ScoExitNativeFrame StopTransitionFrame(int step=10,Action<JsonObject>? alter=null)
{
var node=NativeJson();var at=1000+step*10;node["state"]=3;node["observedAtUnixMilliseconds"]=at;
var provider=node["cruiseBrakeProviderDiagnostics"]!;provider["observedAtUnixMilliseconds"]=at;
var output=provider["physicsConfiguration"]!["completedPhysicsEffects"]!;output["observedAtUnixMilliseconds"]=at-5;
output["rawTranslationInputAtCompletion"]!["z"]=1;alter?.Invoke(node);
return ScoExitNativeFrame.Read(node,1,(ulong)step,step*.01,true,.01);
}
private static ScoExitEstimatePolicy PendingFullInputStop(bool called=true,int nativeStateBefore=-1,int nativeStateAfter=-1)
{
var policy=new ScoExitEstimatePolicy();for(var i=0;i<10;i++)policy.Observe(Frame(i) with{RawThrottle=1});policy.OriginalStopped(called,nativeStateBefore,nativeStateAfter);return policy;
}
[Test]public void OnlyTheFirstCoolingCallbackCanUseTheKnownCompletedActiveInputAfterARealOriginalStop()
{
var transition=StopTransitionFrame();Check.That(!transition.SourceDomainVerified&&transition.SourceExceptCompletedInputVerified
&&transition.OriginalStopInputTransitionCandidate&&!transition.CompletedInputMatchesCurrent);
var policy=PendingFullInputStop();policy.Observe(transition);
Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=11;i<15;i++)policy.Observe(Frame(i,3,400-(i-9)*20) with{Blend=.5+(i-10)*.1});
for(var i=15;i<20;i++)policy.Observe(Frame(i,0,300-(i-14)*50));policy.Observe(Frame(20,0,30));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>());
Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
var repeated=PendingFullInputStop();repeated.Observe(transition);repeated.Observe(StopTransitionFrame(11));
Check.That(!repeated.Status()["shadowExitPending"]!.GetValue<bool>()&&!repeated.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
[Test]public void ACompletedInputMismatchCannotAuthorizeItselfWithoutTheExactStopBindingAndBoundedCallback()
{
var candidate=StopTransitionFrame();
var noStop=PendingFullInputStop(false);noStop.Observe(candidate);Check.That(!noStop.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
foreach(var invalid in new[]{candidate with{Entity=11},candidate with{World=21},candidate with{TargetKey=2},candidate with{ClockEpoch=2},
candidate with{Steps=11},candidate with{At=1116},candidate with{ClockValid=false},candidate with{State=0},
candidate with{SourceExceptCompletedInputVerified=false},candidate with{Profile=Profile with{Jerk=101*C}}})
{
var policy=PendingFullInputStop();policy.Observe(invalid);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void UnknownInputsAndNonzeroEffectsCannotBorrowARealStopTransitionWitness()
{
foreach(var invalid in new[]{"missing-input","unknown-input","transverse-input","other-old-input","nonzero-effect","enabled-external"})
{
var frame=StopTransitionFrame(alter:node=>
{
var output=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!["completedPhysicsEffects"]!;
if(invalid=="missing-input")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(invalid=="unknown-input")output["rawTranslationInputAtCompletion"]!["z"]=null;
else if(invalid=="transverse-input")output["rawTranslationInputAtCompletion"]!["x"]=.1;
else if(invalid=="other-old-input")output["rawTranslationInputAtCompletion"]!["z"]=.9;
else if(invalid=="nonzero-effect")output["externalVector720"]!["x"]=1;
else output["externalActuallyDisabled"]=false;
});
var policy=PendingFullInputStop();policy.Observe(frame);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void ARealSynchronousCoolingStateCanBeFollowedByOffWithoutInventingACoolingCallback()
{
var policy=PendingFullInputStop(true,2,3);var firstOff=StopTransitionFrame(alter:node=>node["state"]=0);
policy.Observe(firstOff);Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=11;i<=15;i++)policy.Observe(Frame(i,0,400-(i-10)*75));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["coolingSeen"]!.GetValue<bool>());
Check.That(receipt["synchronousCoolingStateConfirmed"]!.GetValue<bool>()&&receipt["zeroCompleteCoolingCallbacks"]!.GetValue<bool>());
Check.Equal(0,receipt["coolingObservedCallbacks"]!.GetValue<int>());Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
Check.Equal(2,receipt["originalStopStateBefore"]!.GetValue<int>());Check.Equal(3,receipt["originalStopStateAfter"]!.GetValue<int>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0&&receipt["offFrames"]!.GetValue<int>()>=5);
}
[Test]public void AnImmediateOffCannotBorrowAnUnknownUnconfirmedOrRepeatedCoolingState()
{
var off=StopTransitionFrame(alter:node=>node["state"]=0);
foreach(var state in new[]{(-1,-1),(2,-1),(2,0),(2,2),(-1,3),(0,3)})
{
var policy=PendingFullInputStop(true,state.Item1,state.Item2);policy.Observe(off);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var repeated=PendingFullInputStop(true,2,3);repeated.Observe(off);
repeated.Observe(StopTransitionFrame(11,node=>node["state"]=0));
Check.That(!repeated.Status()["shadowExitPending"]!.GetValue<bool>()&&!repeated.Status()["lastExitReceipt"]!["pass"]!.GetValue<bool>());
}
private static ScoExitNativeFrame OrdinaryExitInputFrame(int step,double completed,double current,Action<JsonObject>? alter=null)
=>StopTransitionFrame(step,node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["rawTranslationInput5D0"]!["z"]=current;physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=completed;
alter?.Invoke(node);
});
private static ScoExitEstimatePolicy AcceptedFirstStopTransition()
{var policy=PendingFullInputStop(true,2,3);policy.Observe(StopTransitionFrame());Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>());return policy;}
[Test]public void OrdinaryInputChangesWithinTheSameWorstCaseServoDomainPreserveARealExitIntegral()
{
var policy=AcceptedFirstStopTransition();var down=OrdinaryExitInputFrame(11,.75,0);var up=OrdinaryExitInputFrame(12,0,.75);
Check.That(!down.SourceDomainVerified&&down.SourceExceptCompletedInputVerified&&down.OrdinaryInputTransitionCandidate);
policy.Observe(down);policy.Observe(up);Check.That(policy.Status()["shadowExitPending"]!.GetValue<bool>()&&policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
for(var i=13;i<=17;i++)policy.Observe(Frame(i,0,400-(i-12)*75));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>());
Check.Equal(2,receipt["ordinaryInputTransitionFrames"]!.GetValue<int>());Check.Equal(1,receipt["originalStopInputTransitionFrames"]!.GetValue<int>());
Check.That(receipt["integratedPathDistanceMetres"]!.GetValue<double>()>0);
}
[Test]public void OrdinaryInputDomainChangesCannotArmATrialOrBorrowAnUnrelatedOrLowCapExit()
{
var frame=OrdinaryExitInputFrame(11,.75,0);var noStop=new ScoExitEstimatePolicy();noStop.Observe(frame);
Check.That(!noStop.Status()["currentSourceDomainVerified"]!.GetValue<bool>()&&!noStop.ArmTrial(10,20,frame.At,3000,1,out _));
foreach(var wrong in new[]{frame with{Entity=11},frame with{World=21},frame with{TargetKey=2},frame with{ClockEpoch=2},frame with{Steps=12},
frame with{Profile=Profile with{Bias=30001}},frame with{OrdinaryCap=29999},frame with{At=1126}})
{
var policy=AcceptedFirstStopTransition();policy.Observe(wrong);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var lowPrior=PendingFullInputStop(true,2,3);lowPrior.Observe(StopTransitionFrame() with{OrdinaryCap=29999});lowPrior.Observe(frame);
Check.That(!lowPrior.Status()["shadowExitPending"]!.GetValue<bool>());
}
[Test]public void NegativeExcessiveTransverseOrUnknownOrdinaryInputCannotUseTheServoDomainWitness()
{
foreach(var bad in new[]{"negative-old","excessive-old","missing-old","unknown-old","transverse-old","negative-current","excessive-current","transverse-current","nonzero-effect"})
{
var frame=OrdinaryExitInputFrame(11,.75,0,node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;var output=physics["completedPhysicsEffects"]!;
if(bad=="negative-old")output["rawTranslationInputAtCompletion"]!["z"]=-.001;
else if(bad=="excessive-old")output["rawTranslationInputAtCompletion"]!["z"]=.750001;
else if(bad=="missing-old")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(bad=="unknown-old")output["rawTranslationInputAtCompletion"]!["z"]=null;
else if(bad=="transverse-old")output["rawTranslationInputAtCompletion"]!["x"]=.01;
else if(bad=="negative-current")physics["rawTranslationInput5D0"]!["z"]=-.001;
else if(bad=="excessive-current")physics["rawTranslationInput5D0"]!["z"]=.750001;
else if(bad=="transverse-current")physics["rawTranslationInput5D0"]!["y"]=.01;
else output["externalVector720"]!["x"]=1;
});
var policy=AcceptedFirstStopTransition();policy.Observe(frame);
Check.That(!policy.Status()["shadowExitPending"]!.GetValue<bool>()&&!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
}
[Test]public void TheFirstAuthorizedDomainRevocationKeepsItsFrameAndIsNotOverwrittenByLaterFailures()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,4000,2,out _));policy.BeginOwnedBurst();
policy.Observe(Frame(21,1) with{SourceDomainVerified=false,SourceFailureDiagnostics=new(){["first-cause"]="phase-input"}});
var first=policy.Status()["lastPolicyRevocationFailure"]!;
Check.That(first["trialBurst"]!.GetValue<bool>());Check.Equal(4000UL,first["trialUntil"]!.GetValue<ulong>());
Check.Equal(0,first["previousFrame"]!["state"]!.GetValue<int>());Check.Equal(20UL,first["previousFrame"]!["steps"]!.GetValue<ulong>());
Check.Equal(1,first["failureFrame"]!["state"]!.GetValue<int>());Check.Equal("phase-input",first["failureFrame"]!["source"]!["first-cause"]!.GetValue<string>());
policy.Observe(Frame(22,2) with{SourceDomainVerified=false,SourceFailureDiagnostics=new(){["later-cause"]=true}});
Check.Equal(first.ToJsonString(),policy.Status()["lastPolicyRevocationFailure"]!.ToJsonString());
}
[Test]public void AKeptOrdinaryProofIsNotARevocationAndTheNextSuccessfulTrialArmClearsOldEvidence()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,4000,2,out _));
policy.Observe(Frame(21,0,30) with{SourceDomainVerified=false});Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
policy.BeginOwnedBurst();policy.Observe(Frame(22,1) with{SourceDomainVerified=false});Check.That(policy.Status()["lastPolicyRevocationFailure"] is not null);
for(var i=23;i<=32;i++)policy.Observe(Frame(i));policy.OriginalStopped(true);
for(var i=33;i<=37;i++)policy.Observe(Frame(i,3,400-(i-32)*20));
for(var i=38;i<=42;i++)policy.Observe(Frame(i,0,300-(i-37)*50));policy.Observe(Frame(43,0,30));
Check.That(policy.Status()["proofAvailable"]!.GetValue<bool>());Check.That(policy.ArmTrial(10,20,1430,6000,1,out _));
Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
}
private static ScoExitNativeFrame EnableTransitionFrame(int step=21,Action<JsonObject>? alter=null)
=>StopTransitionFrame(step,node=>
{
node["state"]=1;var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;
physics["rawTranslationInput5D0"]!["z"]=1;physics["completedPhysicsEffects"]!["rawTranslationInputAtCompletion"]!["z"]=.75;
alter?.Invoke(node);
});
[Test]public void ARealOffToArmedOriginalCallPreservesTheCompletedProofThroughItsSingleInputPhaseBoundary()
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);
var first=EnableTransitionFrame();Check.That(first.SourceExceptCompletedInputVerified&&first.OriginalEnableInputTransitionCandidate&&!first.SourceDomainVerified);
policy.Observe(first);Check.That(policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>()&&policy.Status()["proofAvailable"]!.GetValue<bool>());
Check.Equal(1,policy.Status()["originalEnableInputTransitionFrames"]!.GetValue<int>());Check.That(policy.Status()["lastPolicyRevocationFailure"] is null);
for(var i=22;i<=26;i++)Check.That(policy.Observe(Frame(i,2,350,50) with{RawThrottle=1}).UseEstimatedStop);
policy.OriginalStopped(true,2,3);
for(var i=27;i<=31;i++)policy.Observe(Frame(i,3,350-(i-26)*20,50));
for(var i=32;i<=36;i++)policy.Observe(Frame(i,0,250-(i-31)*45,50));
var receipt=policy.Status()["lastExitReceipt"]!;Check.That(receipt["pass"]!.GetValue<bool>()&&receipt["trial"]!.GetValue<bool>());
Check.Equal(1,receipt["originalEnableInputTransitionFrames"]!.GetValue<int>());Check.Equal(0,receipt["originalEnableStateBefore"]!.GetValue<int>());
Check.Equal(1,receipt["originalEnableStateAfter"]!.GetValue<int>());
}
[Test]public void UnknownExternalOrWrongNativeEnableReceiptsCannotClaimTheOffToArmedBoundary()
{
foreach(var native in new[]{(false,0,1),(true,-1,-1),(true,-1,1),(true,0,-1),(true,0,2),(true,1,1)})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(native.Item1,native.Item2,native.Item3);
policy.Observe(EnableTransitionFrame());Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
}
}
[Test]public void AnEnableBoundaryCannotBeReusedLateAcrossBindingsOrWithUnknownAndUnmatchedInputs()
{
var candidate=EnableTransitionFrame();
foreach(var wrong in new[]{candidate with{Entity=11},candidate with{World=21},candidate with{TargetKey=2},candidate with{ClockEpoch=2},
candidate with{Steps=22},candidate with{At=1226},candidate with{State=2},candidate with{ClockValid=false},
candidate with{SourceExceptCompletedInputVerified=false},candidate with{Profile=Profile with{Jerk=101*C}},candidate with{CompletedRawThrottle=.5}})
{
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);policy.Observe(wrong);
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>()&&!policy.Status()["currentSourceDomainVerified"]!.GetValue<bool>());
}
foreach(var bad in new[]{"missing-old","negative-old","above-ordinary-old","old-transverse","current-transverse","unknown-old","nonzero-effect"})
{
var wrong=EnableTransitionFrame(alter:node=>
{
var physics=node["cruiseBrakeProviderDiagnostics"]!["physicsConfiguration"]!;var output=physics["completedPhysicsEffects"]!;
if(bad=="missing-old")output.AsObject().Remove("rawTranslationInputAtCompletion");
else if(bad=="negative-old")output["rawTranslationInputAtCompletion"]!["z"]=-.001;
else if(bad=="above-ordinary-old")output["rawTranslationInputAtCompletion"]!["z"]=.750001;
else if(bad=="old-transverse")output["rawTranslationInputAtCompletion"]!["x"]=.01;
else if(bad=="current-transverse")physics["rawTranslationInput5D0"]!["y"]=.01;
else if(bad=="unknown-old")output["rawTranslationInputAtCompletion"]!["z"]=null;
else output["externalVector720"]!["x"]=1;
});
var policy=Shadow();Check.That(policy.ArmTrial(10,20,1200,5000,2,out _));policy.BeginOwnedBurst(true,0,1);policy.Observe(wrong);
Check.That(!policy.Status()["proofAvailable"]!.GetValue<bool>());
}
var repeated=Shadow();Check.That(repeated.ArmTrial(10,20,1200,5000,2,out _));repeated.BeginOwnedBurst(true,0,1);
repeated.Observe(candidate);repeated.Observe(EnableTransitionFrame(22));Check.That(!repeated.Status()["proofAvailable"]!.GetValue<bool>());
Check.Equal(1,repeated.Status()["originalEnableInputTransitionFrames"]!.GetValue<int>());
}
private static ScoExitEstimatePolicy Promoted()
{var policy=PassedTrial();Check.That(policy.PromoteProduction(10,20,1350,86400000,out _));return policy;}
private static ScoExitNativeFrame IdleReferenceGap()=>Frame(0,0,30) with{World=21,ClockEpoch=2,At=1400,SourceDomainVerified=false,ParameterBindingVerified=false,Profile=null};
[Test]public void AVerifiedOrdinaryOffReferenceGapKeepsApprovalButCannotUseAnOldFrameAsTheNewSource()
{
var policy=Promoted();var before=policy.Status();var gap=IdleReferenceGap();
Check.That(!policy.Observe(gap).UseEstimatedStop);var waiting=policy.Status();
Check.That(waiting["productionAvailable"]!.GetValue<bool>()&&waiting["productionCalibrationValid"]!.GetValue<bool>());
Check.That(!waiting["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>()&&waiting["productionSourceSuspended"]!.GetValue<bool>());
policy.ResetBinding(); // normal new-world watch must not destroy the proven idle context
policy.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1450});
var fresh=policy.Status();Check.That(fresh["productionCalibrationValid"]!.GetValue<bool>()&&fresh["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.That(fresh["productionIdleSourceQuarantine"] is null);
Check.That(!fresh["productionSourceSuspended"]!.GetValue<bool>());
Check.Equal(before["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>(),fresh["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>());
Check.Equal(before["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>(),fresh["productionMaximumProvenStopSpeedMetresPerSecond"]!.GetValue<double>());
policy.BeginOwnedBurst();Check.That(policy.Observe(Frame(2,2,75,15) with{World=21,ClockEpoch=3,At=1460}).UseEstimatedStop);
}
[Test]public void AnIdleClockRecoveryWithholdsCurrentUseWithoutRenewingTheOriginalCalibrationAge()
{
var policy=Promoted();policy.Observe(Frame(0,0,30) with{ClockEpoch=2,At=1400,ClockValid=false,SourceDomainVerified=false});
Check.That(policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.Observe(Frame(1,0,30) with{ClockEpoch=3,At=1450});Check.That(policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.ResetBinding();policy.Observe(Frame(0,0,30) with{World=22,ClockEpoch=4,At=7201400});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>(),"Requalification must not move the original envelope timestamp forward.");
}
[Test]public void AnActivePredictionOrPendingExitLostAtAReferenceChangeStillInvalidatesProduction()
{
foreach(var pending in new[]{false,true})
{
var policy=Promoted();policy.BeginOwnedBurst();
for(var i=36;i<=40;i++)Check.That(policy.Observe(Frame(i,2,75,15)).UseEstimatedStop);
if(pending)policy.OriginalStopped(true,2,3);
policy.Observe(IdleReferenceGap() with{At=1410});
Check.That(!policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&policy.Status()["productionIdleSourceQuarantine"] is null);
policy.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1420});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
}
[Test]public void MissingIdleSourcesPreserveOnlyPhysicalApprovalDataAndCannotAuthorizeAControlFrame()
{
foreach(var bad in new[]{IdleReferenceGap() with{Entity=11},IdleReferenceGap() with{World=0},IdleReferenceGap() with{ShipIdentityHealthVerified=false},
IdleReferenceGap() with{TargetKey=2},IdleReferenceGap() with{At=1600}})
{
var policy=Promoted();Check.That(!policy.Observe(bad).UseEstimatedStop);
Check.That(policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
var timed=Promoted();timed.Observe(IdleReferenceGap());timed.Observe(IdleReferenceGap() with{Steps=1,SimulationSeconds=.01,At=3401});
Check.That(timed.Status()["productionCalibrationValid"]!.GetValue<bool>()&&!timed.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
timed.Observe(Frame(2,0,30) with{World=21,ClockEpoch=2,At=3410});Check.That(timed.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
[Test]public void KnownProfileAndTrustedLoadoutChangesClearTheApprovalDuringIdleRequalification()
{
var profile=Promoted();profile.Observe(IdleReferenceGap());
profile.Observe(Frame(1,0,30) with{World=21,ClockEpoch=3,At=1450,Profile=Profile with{Jerk=101*C}});
Check.That(!profile.Status()["productionAvailable"]!.GetValue<bool>());
var loadout=Promoted();loadout.Observe(IdleReferenceGap());loadout.BindLoadout(new('c',64));Check.That(!loadout.Status()["productionAvailable"]!.GetValue<bool>());
}
[Test]public void NormalScExitDockAndNewScenePreserveTheOriginalApprovalWithoutUsingNormalModeParameters()
{
var policy=Promoted();var before=policy.Status();
var leaving=Frame(36,0,30) with{RawFsdState=5,InSupercruise=false,ShipIdentityHealthVerified=false,SourceDomainVerified=false,ParameterBindingVerified=false,World=21,Profile=null};
Check.That(!policy.Observe(leaving).UseEstimatedStop);
// Normal-space physics is not the approved supercruise profile. Even a
// typed normal-mode parameter record must not be compared with it.
var normal=leaving with{At=5000,Steps=1,World=22,RawFsdState=0,ParameterBindingVerified=true,Profile=Profile with{Maximum=1000,Brake=100}};
Check.That(!policy.Observe(normal).UseEstimatedStop);
policy.ResetBinding();
Check.That(!policy.Observe(normal with{At=60000,Steps=0,Entity=0,World=0,Profile=null,ParameterBindingVerified=false,ClockValid=false}).UseEstimatedStop);
var suspended=policy.Status();Check.That(suspended["productionCalibrationValid"]!.GetValue<bool>()&&!suspended["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.Equal(before["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>(),suspended["productionAuthorizationExpiresAtUnixMilliseconds"]!.GetValue<ulong>());
Check.Equal(before["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>(),suspended["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>());
var fresh=Frame(0,0,30,target:2) with{At=60100,Entity=12,World=23,ClockEpoch=8};policy.Observe(fresh);
Check.That(policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
policy.BeginOwnedBurst();var active=policy.Observe(Frame(1,2,75,15,target:2) with{At=60110,Entity=12,World=23,ClockEpoch=8});
Check.That(active.UseEstimatedStop&&active.Mode=="production"&&active.Entity==12&&active.World==23);
}
[Test]public void IdleLifecycleSuspensionCannotRefreshCalibrationAgeOrTheHardDeadline()
{
var policy=Promoted();var at=policy.Status()["productionCalibrationObservedAtUnixMilliseconds"]!.GetValue<ulong>();
policy.Observe(IdleReferenceGap() with{InSupercruise=false,RawFsdState=0,ShipIdentityHealthVerified=false});
policy.Observe(Frame(0,0,30) with{World=22,ClockEpoch=3,At=at+7200001});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
var deadline=PassedTrial();Check.That(deadline.PromoteProduction(10,20,1350,2000,out _));
deadline.Observe(IdleReferenceGap());deadline.Observe(Frame(0,0,30) with{World=22,ClockEpoch=3,At=2001});
Check.That(!deadline.Status()["productionAvailable"]!.GetValue<bool>()&&!deadline.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
}
[Test]public void ExplicitNativeSafetyEvidenceInvalidatesIdleApprovalAndPreservesTheFirstFailure()
{
foreach(var field in new[]{"healthEmergency","playerOverride","hullFraction"})
{
var policy=Promoted();var node=NativeJson();node["state"]=0;node["inSupercruise"]=false;node["rawFsdState"]=0;node["observedAtUnixMilliseconds"]=1400;
if(field=="hullFraction")node[field]=0;else node[field]=true;
var unsafeFrame=ScoExitNativeFrame.Read(node,2,0,0,true,.01);Check.That(unsafeFrame.ExplicitSafetyFailureReason is not null);
policy.Observe(unsafeFrame);var failure=policy.Status()["firstProductionCalibrationInvalidation"]!;
Check.That(!policy.Status()["productionCalibrationValid"]!.GetValue<bool>()&&failure["frame"]!["at"]!.GetValue<ulong>()==1400);
var first=failure.ToJsonString();policy.Observe(Frame(1,0,30) with{At=1450,ClockEpoch=2});
Check.That(!policy.Status()["productionCalibrationReadyForCurrentProfile"]!.GetValue<bool>());
Check.Equal(first,policy.Status()["firstProductionCalibrationInvalidation"]!.ToJsonString());
}
}
[Test]public void AnUnverifiedOffClaimOrAPendingEnableCannotShelveALostPredictionAsIdleApproval()
{
var unverified=Promoted();unverified.Observe(IdleReferenceGap() with{NativeOffStateVerified=false});
Check.That(!unverified.Status()["productionCalibrationValid"]!.GetValue<bool>());
var enabling=Promoted();enabling.BeginOwnedBurst(true,0,1);enabling.Observe(IdleReferenceGap());
Check.That(!enabling.Status()["productionCalibrationValid"]!.GetValue<bool>()&&enabling.Status()["firstProductionCalibrationInvalidation"] is not null);
}
}