Queue consumed on dispatch; engine chain hardened; queued planes unsellable (ISS-088)
CI / build + unit + e2e (pull_request) Failing after 12m59s

This commit is contained in:
2026-09-21 22:36:01 +00:00
parent 76f5b6f8ce
commit 479b993c09
10 changed files with 407 additions and 27 deletions
+46
View File
@@ -378,6 +378,52 @@ describe('deliverPackages (v0.12.0 arrival delivery)', () => {
expect(plane.status).toBe('available'); // unchanged landing behavior…
expect(JSON.parse(plane.queue)).toEqual([]); // …and the queue stays empty
});
it('grounds with the queue intact when the next leg does not fit even a full tank (v0.46.0 backstop)', async () => {
const { inst, to, km, type } = await setupFlight('chain-nofit.db'); // full tank EDDF→LEMD
const fc = await loadAirportsGeoJson();
const farP = fc.features.find((f) => f.properties.icao === 'FGSL')!.properties; // ~4267 km from LEMD — beyond ATR range
// Precondition sanity: the LEMD→FGSL hop genuinely does not fit a full tank (wind-adjusted,
// exactly as deliverPackages computes it) — so no top-up could ever make it flyable.
const wTo = weatherFor(TO);
const fNext = windBurnFactor(wTo.windKt, wTo.windDirDeg, initialBearingDeg(to.lat, to.lon, farP.lat, farP.lon));
const nextRequiredL = requiredFuelFor(
type.burnPerKm * fNext,
type.emptyWeightKg,
type.maxFuel,
haversineKm(to.lat, to.lon, farP.lat, farP.lon),
);
expect(nextRequiredL).toBeGreaterThan(type.maxFuel);
await inst.db.update(schema.planes)
.set({ queue: JSON.stringify(['FGSL']) })
.where(eq(schema.planes.id, 'plane-starter'));
const clock = T0 + travelMs(km, type.speedKmh); // exactly at arrival
expect(await deliverPackages(inst, clock)).toBe(1);
const plane = (await inst.db.select().from(schema.planes))[0];
expect(plane.status).toBe('available'); // grounded — the unflyable leg was NOT chained…
expect(plane.destIcao).toBeNull();
expect(JSON.parse(plane.queue)).toEqual(['FGSL']); // …queue kept intact for a later dispatch
});
it('drops a queued leg to the arrival airport without flying — defensive guard for legacy rows (v0.46.0)', async () => {
const { inst, km, type } = await setupFlight('chain-selfleg.db'); // full tank EDDF→LEMD
// Legacy state: queue[0] is the airport we are about to land at — pre-v0.46.0 this chained a
// zero-distance self-hop (the phantom hop). The guard drops it and grounds instead.
await inst.db.update(schema.planes)
.set({ queue: JSON.stringify(['LEMD', 'EHAM']) })
.where(eq(schema.planes.id, 'plane-starter'));
expect(await deliverPackages(inst, T0 + travelMs(km, type.speedKmh))).toBe(1);
const plane = (await inst.db.select().from(schema.planes))[0];
expect(plane.status).toBe('available'); // grounded — the self-leg was dropped, not flown…
expect(plane.destIcao).toBeNull();
expect(JSON.parse(plane.queue)).toEqual(['EHAM']); // …the rest of the queue kept for a later dispatch
});
});
describe('wear on landed legs (v0.39.0, ISS-069)', () => {