v1.2.0: planes.owner_id + ownership checks + per-player onboarding (ISS-108, ISS-109)
CI / build + unit + e2e (pull_request) Successful in 13m46s

This commit is contained in:
2026-09-26 16:27:00 +00:00
parent ba2c36a3f8
commit ec26f9f366
25 changed files with 436 additions and 148 deletions
+18 -11
View File
@@ -360,19 +360,14 @@ function pickHub(airports: SeedAirport[]): SeedAirport {
return airports.find((a) => a.icao === HUB_ICAO) ?? airports[0];
}
export function buildSeed(input: {
airports: SeedAirport[];
rng: Rng;
nowMs: number;
}): SeedData {
const { airports, rng, nowMs } = input;
if (airports.length < 2) throw new Error('seed needs at least two airports');
// v1.2.0 (ISS-108): the starter plane, extracted from buildSeed so per-player onboarding can reuse
// it — same values as the fresh-install seed's plane (no RNG draws), only the id differs. The
// caller stamps ownership (planes.owner_id) at insert time; this stays a pure SeedPlane.
export function buildStarterPlane(airports: SeedAirport[], id: string): SeedPlane {
const type = PLANE_TYPES[STARTER_MODEL];
const hub = pickHub(airports);
const plane: SeedPlane = {
id: 'plane-starter',
return {
id,
model: STARTER_MODEL,
status: 'available',
fuel: type.maxFuel, // starts full
@@ -384,6 +379,18 @@ export function buildSeed(input: {
queue: [], // no queued legs on first run (v0.25.0)
health: 100, // full health on first run (v0.39.0, ISS-069)
};
}
export function buildSeed(input: {
airports: SeedAirport[];
rng: Rng;
nowMs: number;
}): SeedData {
const { airports, rng, nowMs } = input;
if (airports.length < 2) throw new Error('seed needs at least two airports');
const plane = buildStarterPlane(airports, 'plane-starter');
const hub = pickHub(airports);
// v0.65.0: the seed market is a full pool at the starter's home hub — the same per-airport
// composition (POOL_BANDS) the runtime spawner maintains, so first run looks like any other tick.