Skip to content
Next — unreleased

Moving a fleet starts with an explicit choice. You choose one movement primitive, inspect the resulting Plan, let your wallet sign it, execute it once, and then read the fleet again. No step silently chooses a route or movement mode for you, and the available primitives are alternatives rather than one chained journey. The rules behind that flow are laid out in How Atlas Kit changes the game; this guide walks it end to end.

This guide uses undocking because it is the smallest complete movement: the fleet begins docked and finishes idle at the same system. Subwarp, coordinate warp, lane warp, and docking follow the same Plan flow with their own explicit destinations.

Subwarp start, coordinate/lane warp and explicit stop-subwarp require Game 2 and the owning Character’s existing, reconciled Career XP data. The SDK finds and validates that data, then checks it again before signing. Missing or unreconciled state produces a local repair remedy; planning never creates, funds or migrates XP data. Ordinary XP gains do not invalidate the Plan. Movement-start Plans still reject changes to Character modifiers, spent XP and other guarded Character state.

The current unsigned PTR checks cover subwarp and coordinate warp from one elapsed journey; lane warp and intentional early stop are covered by binding contracts and offline regressions, without a current live qualification. See the scope of the evidence.

The embedded playground remains read-only. It is useful for exploring live state before planning, but it will not request a wallet or run this signing flow.

Planning accepts game intent plus the Profile authorization your wallet will satisfy later. It does not open the wallet or change the game. Here authoritySigner is the Kit signer returned by your wallet integration, and keyIndex is its matching Profile key slot; the example uses the first slot. movementFleet is a separately loaded Fleet that is idle or finishing travel away from system, because creating the undock Plan does not mutate fleet.

import type { PlanAuthorization } from '@aephia/atlas-kit/fleets/actions';
import {
planFleetSubwarp,
planFleetUndock,
} from '@aephia/atlas-kit/fleets/actions';
import { deriveFleetSubwarpEstimate } from '@aephia/atlas-kit/fleets';
const authorization = {
profile: fleet.ownerProfile.address,
authority: authoritySigner.address,
keyIndex: 0,
} satisfies PlanAuthorization;
const plan = await planFleetUndock(ctx, fleet, { authorization });
console.log(plan.summary);
console.table(plan.describe());
const destinationRaw = system.coordinatesRaw;
const estimate = deriveFleetSubwarpEstimate({
fromRaw: movementFleet.locationRaw,
toRaw: destinationRaw,
speedRaw: movementFleet.stats.movement.subwarpSpeed.raw,
fuelRateRaw: movementFleet.stats.movement.subwarpFuelConsumptionRate.raw,
speedModifierRaw: character.modifiers.values.subwarpSpeedModifierRaw,
});
const exactPlan = await planFleetSubwarp(ctx, movementFleet, {
authorization,
destinationRaw,
});
console.log(estimate, exactPlan.summary);

describe() returns stable game-language steps. Show those lines to the person signing so they can decide whether the move matches their intent. If fleet state has changed since it was read, create a new Plan instead of trying to repair the old one.

The signer comes from your wallet integration. The SDK receives only the Kit signer interface for this call; it does not take custody of keys. Here the same signer pays the fee and satisfies the selected Profile authorization.

import type { PlanAuthorization } from '@aephia/atlas-kit/fleets/actions';
import { planFleetUndock } from '@aephia/atlas-kit/fleets/actions';
import { executePlan, simulatePlan } from '@aephia/atlas-kit/planning';
const authorization = {
profile: fleet.ownerProfile.address,
authority: authoritySigner.address,
keyIndex: 0,
} satisfies PlanAuthorization;
const plan = await planFleetUndock(ctx, fleet, { authorization });
// Illustrative ceiling: measure this Plan and choose an appropriate limit.
const computeUnitLimit = 400_000;
const simulation = await simulatePlan(ctx, plan, {
feePayer: authoritySigner.address,
computeUnitLimit,
});
console.log(simulation.unitsConsumed);
const result = await executePlan(ctx, plan, {
feePayer: authoritySigner,
computeUnitLimit,
});
if (result.status === 'unknown') {
console.log('Check wallet history before deciding what to do next.');
return;
}
const refreshedFleet = await sage.fleets.get(fleet.address);
console.log(result.signature, refreshedFleet.state);

Execution checks that the supplied signer matches the Plan, verifies that the Plan is still fresh, sends exactly once, and waits for a terminal result. A confirmed result makes the next ordinary Fleet read fresh. An unknown result means submission could not be confirmed: do not retry until wallet and chain history prove whether the move happened.

Choose the primitive yourself rather than asking the SDK to infer a route:

  • planFleetSubwarp moves an idle or arrived-but-unsettled fleet to a coordinate.
  • planFleetWarpToCoordinate warps an idle or arrived-but-unsettled fleet to a coordinate.
  • planFleetWarpLane warps an idle or arrived-but-unsettled fleet to an explicit connected destination system.
  • planFleetDock docks an idle fleet at its current system or an arrived Fleet at its movement destination.

Coordinate movement accepts exactly one destination representation. Use destination when caller-selected display-number rounding is intentional, or use destinationRaw to preserve exact signed-I8F56 axes. A Star System’s coordinatesRaw can feed both a qualified estimate and the matching planner without a Number round-trip, as the compiled Plan example above demonstrates.

The estimate remains advisory. Its Fuel budget does not prove that the Fleet can afford the move or that the game will accept it; refresh and simulate the Plan before signing.

Docking resolves its faction policy internally. A Fleet whose Starbase Player belongs to the Starbase’s controlling faction docks whatever the territory and economics settings. The controller is the legacy Starbase owner unless dynamic capture is on and a current ownership record names another faction. A foreign Starbase Player is refused while territory access is off. Foreign docking under territory access, which depends on diplomacy and standing, and docking at a Starbase run by a dynamic faction stay unsupported and fail locally with a remedy; the SDK does not infer permission for them. Saved Plans from before this contract repair must be recreated with the current SDK.

Faction-4-controlled Systems remain outside this supported route. The policy observed on 2026-10-09 had territoryAccessEnabled=0, documented by the pinned bindings as own-faction docking only. It predicts refusal for a player Fleet at controller 4; this has not been measured on the processor. A positive qualification needs a same-faction NPC fixture and fresh policy checks, not another player registration. Qualification is tracked in #831.

getFleetDockDebitBounds(plan) reports a conservative maximum Profile debit for a qualified idle Fleet. An unavailable result means the SDK cannot provide that estimate; it does not mean docking is free. Inspect each docking Plan separately before composing actions. This illustrative example assumes an idle Fleet at a registered Starbase and an authorized wallet signer.

import {
getFleetDockDebitBounds,
planFleetDock,
} from '@aephia/atlas-kit/fleets/actions';
const dockPlan = await planFleetDock(ctx, fleet, {
authorization: {
profile: fleet.ownerProfile.address,
authority: authoritySigner.address,
keyIndex: 0,
},
});
const dockBounds = getFleetDockDebitBounds(dockPlan);
if (dockBounds.status === 'available') {
console.log(dockBounds.maximumProfileDebit, dockBounds.profileUnit);
} else {
console.log(dockBounds.reason);
}

The estimate is available for the qualified ordinary idle route with current definitions, no active stimulants or pending recovery, and sufficient funding. Previously available bounds are checked again before signing. RPC failures, missing required funding inputs, context disposal and lifecycle cancellation reject planning; they do not create a Plan with its funding check disabled. Unsupported estimate data, stale sequences, pending recovery, active stimulants and insufficient funding can produce an explicit unavailable result. Within one executePlan call, including a Plan made with combinePlans, guarded storage debits for the same Profile must fit together while preserving its rent reserve once. Fund the Profile itself when its combined gross ceiling is short; prefunding the Fleet or StarbasePlayer does not reduce that quoted ceiling. The inspection helper returns unavailable for combined Plans, so inspect each individual docking Plan. Its result supports JSON.stringify, with amounts serialized as decimal strings. A dock cannot share its Fleet or StarbasePlayer with another action in the same Plan, and another action cannot change its Star System, the Game or the faction policies it reads within that Plan. If its estimate is unavailable, it also cannot share its Profile with another action. Refresh and recreate a qualified Plan, or execute the actions separately with fresh balances between them. Separate Plan executions, sequence steps and concurrent application requests have no shared reservation: applications must coordinate those operations and refresh balances between them. The SDK does not top up funds or reserve funds on chain.

A fleet that reaches its destination keeps reporting the move it was on. Nothing rewrites that on a timer, so a fleet that arrived weeks ago still reads as warping until something acts on it.

Movement and docking have their own program refresh paths. Mining after completed subwarp needs explicit settlement; completed warp can refresh directly into mining on the qualified PTR deployment. See the mining arrival rules; do not assume every action completes an arrival automatically.

planFleetSettleArrival settles a journey after its scheduled duration has elapsed. It reads the chain Clock and exact journey values during planning and again before signing. Journeys whose scheduled duration has not elapsed and Idle Fleets fail locally. For Game version 2 subwarp, supply the owning Profile’s direct, unexpired authority:

import { planFleetSettleArrival } from '@aephia/atlas-kit/fleets/actions';
const settle = await planFleetSettleArrival(ctx, fleet, { authorization });
console.log(settle.describe());

The selected key must have Profile AUTH or SAGE moveFleet permission. The program still decides whether its permissions suffice; the SDK never adds vault-drain permission. Character, RegionTracker and reconciled Career XP data must already exist. Certificates and delegated sub-Profiles are unsupported here. The transaction fee payer is a separate assembly/execution choice.

Only Game version 2 subwarp is supported. Warp settlement, superseded Game version 0, migration-sealed version 1 and unknown runtimes are rejected. The funder-only settlement input is no longer accepted. Subwarp settlement charges fuel, awards XP on the supported current route, and may refund released storage to the Profile. It does not clear warp cooldown. Use planFleetStopSubwarp for intentional early stopping; it uses the same existing Game-2 XP data.

Settlement is not proof of reaching the destination. A Fleet with insufficient Fuel can settle Idle short of its destination, with no Fuel remaining. The Plan warns when the fresh tank is below the recorded journey budget; this is a planning-time observation, not a Fuel lock. Settlement remains available so an underfunded Fleet can leave its travel state. Successful simulation or execution alone does not prove arrival: inspect the refreshed Fleet state and location before planning its next action or docking. Do not assume Fuel can be loaded in open space; ordinary Fleet cargo transfer requires docking.

Automation can inspect a fresh Fleet without parsing Plan prose. When fleet.state.kind === 'subwarp', compare (fleet.fuel.amount << 56n) < fleet.state.totalFuelExpenditureRaw. A true result means the tank is below the stored journey budget. Both sides are exact integers; the stored budget has 56 fractional bits. These fields describe an already recorded journey, not a quote for a proposed departure. A shortfall should trigger an explicit recovery decision, not an assumption that settlement will reach the destination; settlement remains available.

Ensure enough Fuel before departure. Movement-start planners currently do not calculate or guarantee the full journey’s Fuel requirement. Intentional stopping before the scheduled duration remains the separate planFleetStopSubwarp action.

Saved arrival Plans retain the exact journey and authority. Changed trips, ownership, invalid XP state and expired authority require replanning. Old unguarded settlement Plans also require recreation. Other Fleet updates and XP accrual do not invalidate the Plan. A preceding action may not reference the same Fleet; settle first, then compose an otherwise supported move/dock. Current live qualification does not cover every composed path.

A race remains: these checks cannot atomically bind the action to the checked journey. Another transaction could start a new trip before execution, and the authorized settlement action could stop that new trip. There is no automatic retry.

Movement planners accept stored warp and subwarp states and let the program perform its normal refresh-to-idle step. Docking accepts a stored warp state but refuses a subwarp state: the dock step refreshes the Fleet without its Character and cannot settle a subwarp journey, so settle the arrival or stop the subwarp first. All of them use the stored movement destination without guessing from local time; a genuinely in-transit action is still rejected by chain simulation.

Each planner produces the same inspectable Plan shape and uses the same execution call. The planner validates facts it can prove from current game state. The pure movement estimates below are separate from Plan validation.

combinePlans places the combined steps in one transaction; it inserts neither elapsed time nor a confirmation boundary. It rejects conflicting subwarp, coordinate warp, and lane warp starts for the same Fleet. If the Plans do not contain enough information to identify a conflict, the SDK leaves their compatibility unknown instead of assuming they are safe to combine.

For a journey that must move, wait/confirm, then move again, use the shipped PlanSequence coordinator. It preserves separate confirmed transactions, lazy capability readiness, caller-owned checkpoints, and fresh authorization for every reached Plan.

deriveFleetMovementCooldown predicts the assigned cooldown timestamp, not whether a movement transaction can succeed. Supply an already-known arrival time for coordinate warp; this helper does not calculate travel time. Use deriveFleetTimers to display an existing Fleet’s observed timers.

import { deriveFleetMovementCooldown } from '@aephia/atlas-kit/fleets';
const expiresAt = deriveFleetMovementCooldown({
kind: 'coordinateWarp',
arrivesAtUnixSeconds: 1_800_000_000n,
baseCooldownSeconds: 61,
cooldownModifierRaw: 2_147_483_648n, // raw Character modifier: 0.5
});
console.log(expiresAt); // 1800000031n

Coordinate warp rounds the modified cooldown upward and adds it after arrival. A zero modifier uses the unmodified base. For warpLane, supply departsAtUnixSeconds and existingCooldownExpiresAt: a lane adds no cooldown but keeps an active one, so the result is the later of the two. For subwarp, supply existingCooldownExpiresAt: it is preserved unchanged.

Use the Fleet’s stats.movement.warpCoolDownSeconds and the Character’s modifiers.values.warpCooldownModifierRaw value. Base seconds must be an integer from 0 to 65535. New timestamps and raw modifiers must be nonnegative signed-i64 values; results outside signed i64 are rejected. An existing expiry may retain negative sentinels. The result is bigint Unix seconds, not a JavaScript Date.

This calculation is empirically qualified against PTR deployment slot 54356023. It checks no active cooldown, state, permissions, Fuel, range or lane eligibility. Refresh and simulate the intended action before signing.

deriveFleetSubwarpEstimate predicts direct subwarp duration and fractional Fuel expenditure for an Idle Fleet. It also returns fuelBudget, rounded up to whole Fuel units. Compare that budget with fleet.fuel.amount: subwarp can start without enough Fuel, so a successful start does not promise arrival.

This standalone example is runnable and needs no RPC or wallet:

import { deriveFleetSubwarpEstimate } from '@aephia/atlas-kit/fleets';
const estimate = deriveFleetSubwarpEstimate({
fromRaw: { x: 0n, y: 0n },
toRaw: { x: 1n << 56n, y: 0n }, // one AU east, exact I8F56
speedRaw: 65_536n, // one AU/second, U16F16
fuelRateRaw: 64n, // one Fuel/AU, U26F6
speedModifierRaw: 4_294_967_296n, // neutral I32F32
});
console.log(estimate.durationSeconds, estimate.fuelBudget); // 1, 1n

For real inputs, use fleet.locationRaw, fleet.stats.movement.subwarpSpeed.raw, fleet.stats.movement.subwarpFuelConsumptionRate.raw, and character.modifiers.values.subwarpSpeedModifierRaw. Use the exact encoded raw destination too; do not recover a Fleet’s raw position by multiplying its approximate location display numbers. The stored position is not a moving Fleet’s interpolated position. Values ending in Raw on the result retain 56 fractional bits; display numbers are approximate, and JSON serializes bigint as decimal strings.

The model is qualified against PTR deployment slot 54356023. A zero modifier means neutral. Inputs must fit their documented fixed-point ranges; zero speed, negative modifiers, identical endpoints and unsupported coordinate differences or distances are rejected. So is a route shorter than the program can measure (a displacement below 2^28 raw quanta on both axes), because the program refuses to start such a subwarp; planFleetSubwarp refuses it too. This helper predicts neither planet departure nor warp, lane travel, XP, permissions or journey completion. The budget is not a measured settlement debit. Refresh and simulate the actual Plan before signing.

deriveFleetCoordinateWarpEstimate predicts whole-second duration including spool time, the Fuel debit at departure, and whether the computed distance is within the Fleet’s maximum range. It uses coordinate-warp stats, not lane stats. This standalone example is runnable without a wallet or RPC:

import { deriveFleetCoordinateWarpEstimate } from '@aephia/atlas-kit/fleets';
const warp = deriveFleetCoordinateWarpEstimate({
fromRaw: { x: 0n, y: 0n },
toRaw: { x: 1n << 56n, y: 0n },
speedRaw: 65_536n,
fuelRateRaw: 64n,
speedModifierRaw: 4_294_967_296n,
spoolSeconds: 3,
maxWarpDistanceRaw: 256n, // one AU, U8F8
});
console.log(warp.durationSeconds, warp.fuelDebit, warp.withinRange); // 4n, 1n, true

For actual inputs, use the same exact coordinate rules as subwarp, with fleet.stats.movement.warpSpeed.raw, fleet.stats.movement.warpFuelConsumptionRate.raw, fleet.stats.movement.maxWarpDistance.raw, fleet.stats.combat.warpSpoolTimeSeconds, and character.modifiers.values.warpSpeedModifierRaw.

Duration includes spool; Fuel and duration round upward after the measured fixed-point intermediates. Exact maximum range is inclusive. withinRange compares only distance: it does not check cooldown, crew, permissions, region rules or Fuel in the tank. Out-of-range requests still return estimates with withinRange: false. Use the cooldown helper separately. This deployment-pinned model covers Idle departures, not planets or lanes; simulate before signing.

deriveFleetWarpLaneEstimate calculates travel time from exact System coordinates and Fleet lane speed. Current qualified lanes debit zero Fuel; Character warp-speed modifiers and spool time do not apply. This runnable standalone example needs no RPC or wallet:

import { deriveFleetWarpLaneEstimate } from '@aephia/atlas-kit/fleets';
const lane = deriveFleetWarpLaneEstimate({
fromRaw: { x: 0n, y: 0n },
toRaw: { x: 1n << 56n, y: 0n },
speedRaw: 65_536n,
});
console.log(lane.durationSeconds, lane.fuelDebit); // 1n, 0n

For real inputs, use each System’s coordinatesRaw and the Fleet’s stats.movement.warpLaneSpeed.raw. Display coordinates can lose bits, so do not reconstruct raw values by multiplying display numbers. Duration rounds up after the measured fixed-point intermediates. Identical and zero-quantized paths are rejected; coordinates, axis differences and distance must fit signed I8F56, and lane speed must be positive u32 raw.

This model is qualified against PTR deployment slot 54356023, not every future version of the game. It does not establish a lane connection, faction/risk permission, ATLAS toll, affordability or Fleet readiness. Use the cooldown helper separately, and refresh and simulate the actual Plan before signing.

deriveFleetWarpLaneToll predicts the Character’s in-game ATLAS debit, not a wallet charge. Use the source System’s connection entry for the destination, the source Starbase level, and the Fleet-to-destination-owner relationship. This runnable example shows a CSS departure with a 0.75 fee modifier and an allied foreign destination:

import { deriveFleetWarpLaneToll } from '@aephia/atlas-kit/fleets';
const toll = deriveFleetWarpLaneToll({
costs: {
level1Raw: 100000n,
level2Raw: 200000n,
level3Raw: 300000n,
level4Raw: 400000n,
level5Raw: 500000n,
cssRaw: 600000n,
},
sourceLevel: 'css',
fleetFaction: 'oni',
sourceOwner: 'oni',
destinationOwner: 'mud',
destinationRelationship: 'allied',
feeModifierRaw: 3221225472n,
alliedTollBps: 5000,
neutralTollBps: 20000,
});
console.log(toll.modifiedBaseRaw, toll.surchargeRaw, toll.totalRaw);
// 450000n, 300000n, 750000n raw ATLAS

Pass the connection’s costs, source Starbase’s level and owners, Character’s modifiers.values.warpLaneFeeModifierRaw, and current relationship tracker bps. The modified base rounds upward. If either endpoint is foreign to the Fleet, the surcharge uses the unmodified base and rounds downward. Allied uses allied bps; other relationships use neutral bps, as does a foreign-source trip back to the Fleet’s own faction. A zero fee modifier removes only the modified base.

All amounts returned are exact raw ATLAS (Floyds), serialized as decimal strings in JSON. Only playable factions, usable source levels, unsigned u64 base/total, nonnegative signed-i64 modifier and u16 bps are supported. The qualified model does not check the cross-faction enable flag, destination risk, connection, available ATLAS or transaction eligibility. Refresh and simulate the Plan.

deriveFleetWarpLanePolicy reports a bounded set of policy failures. A passing result does not mean the transaction will succeed. Supply current endpoint ownership/levels, the cross-faction flag, Character security access, and the region that contains the destination coordinates. This runnable standalone example assumes that region was already resolved:

import { deriveFleetWarpLanePolicy } from '@aephia/atlas-kit/fleets';
const policy = deriveFleetWarpLanePolicy({
fleetFaction: 'oni',
sourceOwner: 'oni',
destinationOwner: 'oni',
sourceLevel: 'css',
destinationLevel: 'level-1',
crossFactionEconomicsEnabled: false,
securityZoneAccess: 'low',
enemyFactionZoneAccess: false,
destinationRegion: {
owner: 'oni',
safety: 'safe',
risk: { kind: 'low', faction: 'oni' },
},
});
console.log(policy.passesPolicy, policy.failures); // true, []

The helper does not perform spatial lookup. Do not infer a different risk region merely by changing a System’s stored region ID or tracker membership: the program’s observed check follows destination position. Pass a region you have resolved from those coordinates, plus Character modifiers.values.securityZoneAccess and modifiers.values.enemyFactionZoneAccess and the current tracker flag.

FailureMeaning
source-level-zeroThe departure Starbase has no usable lane level.
destination-level-zeroThe destination Starbase has no usable lane level.
cross-faction-disabledAt least one endpoint is foreign to the Fleet while cross-faction economics is disabled.
foreign-low-riskThe destination’s effective low-risk faction differs from the Fleet’s. Allies are still rejected.
security-zone-accessCharacter access is lower than the destination’s effective risk tier.
region-owner-accessA medium/high destination region belongs to another playable faction and the Character lacks enemy-faction-zone access.

Stored low risk retains its embedded faction. Safe medium/high regions owned by a playable faction resolve to low risk of their owner; Border regions and Unaligned-owned regions retain their stored tier. The result exposes that effectiveRisk. Only playable factions (an Unaligned destination region is allowed) and known tiers/levels are qualified; unsupported values throw a typed SDK error rather than guessing NPC policy. Relationship/combat/docking rules are not substituted for lane policy.

This deployment-pinned calculation does not check connectivity, permissions, Fleet state, cooldown, crew, XP, tolls or balances. It also cannot bind a later transaction to the checked state. Refresh and simulate the actual Plan.

Comparing ships: a reference travel profile

Section titled “Comparing ships: a reference travel profile”

deriveFleetTravelProfile turns movement stats into numbers you can compare across ships: seconds and Fuel per AU of subwarp, how far a full tank reaches, what one maximum-range warp costs, and how fast chained warps travel once each cooldown is waited out. It composes the subwarp, coordinate-warp, lane and cooldown estimates above over a one-AU trip and a maximum-range jump. This runnable standalone example needs no RPC or wallet:

import { deriveFleetTravelProfile } from '@aephia/atlas-kit/fleets';
const profile = deriveFleetTravelProfile({
stats: {
movement: {
subwarpSpeed: { raw: 65_536n, value: 1 }, // one AU per second
subwarpFuelConsumptionRate: { raw: 64n, value: 1 }, // one Fuel per AU
warpSpeed: { raw: 65_536n, value: 1 },
warpFuelConsumptionRate: { raw: 128n, value: 2 },
maxWarpDistance: { raw: 512n, value: 2 }, // two AU
warpCoolDownSeconds: 6,
warpLaneSpeed: { raw: 131_072n, value: 2 },
},
cargo: { fuelCapacity: 100n },
combat: { warpSpoolTimeSeconds: 2 },
},
});
console.log(profile.subwarp?.fullTankRangeAu); // 100
console.log(profile.coordinateWarp?.maxJumpFuel); // 4n
console.log(profile.coordinateWarp?.cycleSeconds); // 10n: 2 spool + 2 travel + 6 cooldown
console.log(profile.coordinateWarp?.sustainedAuPerHour); // 720

Pass fleet.stats for a Fleet, or a ship configuration’s stats from listShipConfigurations for one ship of that configuration; a one-ship Fleet has the same stats. Character modifiers are optional raw I32F32 values (subwarpSpeedModifierRaw, warpSpeedModifierRaw, warpCooldownModifierRaw from character.modifiers.values); omit them for base values.

Full-tank range divides the tank by the Fuel rate. Sustained warp speed assumes each maximum-range warp departs when the cooldown assigned at arrival expires. Jumps per tank counts warp debits that fit in a full tank; whether a warp may depart with less Fuel than its debit is not established. A section is null when its speed or range is zero, and a full-tank value is null when that mode burns no Fuel.

These are reference values from Idle, not a route: planet departure, region policy, lane connections and tolls, crew, XP, active timers and current Fuel are not considered. Fleets mixing configurations have not been qualified. See the reference profile evidence.