import { content } from "@deadhead/content"; import { beforeAll, describe, expect, it } from "vitest"; import { formatFuelShares, fuelShares, type FuelShare } from "../balance/fuel-share"; import { checkRoute, fuelPriceAt, legFuel, routeDistance } from "../src/index"; const loc = (id: string) => content.location(id)!; let rows: FuelShare[]; beforeAll(() => { rows = fuelShares(content); }); describe("fuel-to-payout check (CR-018 Step 18.1, decision 0.5.110)", () => { it("reports every purchasable ship on every route it can fly", () => { const models = content.shipModels.filter((m) => m.purchasable); expect(new Set(rows.map((r) => r.modelId))).toEqual(new Set(models.map((m) => m.id))); for (const row of rows) { const model = content.shipModel(row.modelId)!; expect(checkRoute(model, loc(row.originId), loc(row.destinationId), content.config).ok).toBe( true, ); expect(row.contracts).toBeGreaterThan(0); } // Every Earth–Moon leg is flown by every purchasable ship, and boards always offer it. for (const model of models) { expect( rows.some( (r) => r.modelId === model.id && r.originId === "earth" && r.destinationId === "moon", ), ).toBe(true); } }); it("prices a leg's fuel at the origin and divides by the median fitting payout", () => { const row = rows.find( (r) => r.modelId === "courier" && r.originId === "earth" && r.destinationId === "moon", )!; const courier = content.shipModel("courier")!; const fuel = legFuel(courier, loc("earth"), routeDistance(loc("earth"), loc("moon")), content.config) * fuelPriceAt(loc("earth"), content.config); expect(row.fuelCost).toBeCloseTo(fuel, 9); expect(row.share).toBeCloseTo(row.fuelCost / row.medianPayout, 12); expect(row.medianPayout).toBeGreaterThan(0); }); it("keeps fuel at most 25% of the median payout on every route but the Clipper's Mars → Earth (Step 18.2)", () => { // One price can't put every row in 15–25% (user decision, CR-018): only the top is gated. // Few Mars → Earth jobs are small enough for the Clipper's 30 t hold, so their median is low. const over = rows .filter((r) => r.share > 0.25) .map((r) => `${r.modelId} ${r.originId} → ${r.destinationId}`); expect(over).toEqual(["clipper mars → earth"]); }); it("reports the share for each ship and route as a table", () => { const table = formatFuelShares(rows).split("\n"); expect(table).toHaveLength(rows.length + 1); expect( table.find((line) => line.startsWith("courier") && line.includes("earth → moon")), ).toMatch(/\d+\.\d%$/); }); });