deadhead-space-freight-tycoon/memory-bank/change-requests/CR-002-open-markets.md

11 KiB
Raw Permalink Blame History

Change Request CR-002 — Open Markets, Bays as HQs

Project: Deadhead: Space Freight Tycoon Applies to: a build with Phases 1–10 and CR-001 (Faster Start) complete Do this: as Phase 10B, after Phase 10A and before Phase 11 Related docs: implementation-plan.md, change-request-faster-start.md, game-design-document.md, DECISIONS.md

Numbering note (added when implemented): the plan's §0.5 already used 27 (pilot location storage), 28 (Git hosting) and 29–34 (CR-001). The new decisions below numbered 0.5.27 and 0.5.28 are recorded as 0.5.35 Ship delivery and 0.5.36 Undiscovered locations. The error code location_undiscovered is the existing location-undiscovered.


1. Why

Contracts are currently only offered at locations where the player has a bay, and repositioning is only allowed to and from bay locations. A ship that delivers to a location without a bay (for example the Moon) is stranded: there is no contract board there, and it cannot reposition home.

The fix follows the American/Euro Truck Simulator model:

  • Every discovered location has a contract board (the freight market). Any idle ship can pick up work wherever it is, which makes backhaul work.
  • Bays are HQs (like ATS garages). You need a bay to hire pilots there, to take delivery of newly bought ships there, and to unassign pilots there. Bays no longer control where contracts are available.
  • Discovery still gates expansion. An undiscovered location has no board until the player delivers there.

2. Rules for this change

  • All rules in implementation-plan.md §0.1 still apply: steps in order, one commit per step, each step's test must pass, packages/sim stays pure, all numbers live in packages/content.
  • Do not write data migrations for old contract boards. Resetting the dev and test databases is fine. Schema migrations are still required.
  • Update existing tests whose expectations change. Do not delete a test unless §5 says the step is replaced.
  • Update architecture.md for every schema or API change and progress.md after every step.
  • Stop for the user's review at the end of Phase 10B.

3. Decision changes

Record these in DECISIONS.md and in implementation-plan.md §0.4 and §0.5.

Glossary changes (§0.4)

  • Bay → A docking bay the player leases at a discovered location. It is an HQ: pilots are hired there, newly bought ships are delivered there, and pilots can be unassigned there. A bay does not control where contracts are offered.
  • Contract board (new) → The freight market at a discovered location. Every discovered location has one per player per board period, whether or not the player has a bay there.
  • Deadhead (new) → A reposition: a ship flying empty to another location. Fuel only, no payout, no XP.

Replaced

  • 0.5.5 (Contract boards are stored) → A board exists for every discovered location, per player, per period. It is generated on the first request in a period and stored; later requests in that period return the stored board. Every contract expires at the end of its board period. (Amended by CR-019:) a stored location board also records the qualifying fleet it was generated for, and reads hide jobs the current qualifying fleet can't complete (Step 19.3).
  • Step 3.14 rule (reposition only to a bay) → An idle ship can deadhead from any location to any discovered location other than its current one, subject to the normal range and landing checks.

New

  • 0.5.27 Ship delivery. Buying a ship requires choosing one of the player's bays. The new ship appears there, idle and uncrewed.
  • 0.5.28 Undiscovered locations. Requesting the board of an undiscovered location fails with a location_undiscovered error. Deadheading to an undiscovered location is not allowed; only a contract delivery discovers a location.

Unchanged (confirm, don't modify)

  • 0.5.2 Pilot locations. Hiring happens at a player bay; unassigning is allowed only at a location with a player bay.
  • CR-001 deal. The deal still includes the Earth bay.

4. Steps — Phase 10B

Step 10B.1 — Sim: boards at any location

  • Change the contract board generator's input from "the bay's location" to "the board's location". No other generation rules change.
  • Rename any sim types or functions that say "bay board" to "location board".
  • Test: The Step 3.9 tests still pass with a location input. Generating a board for the Moon with no bay data supplied anywhere works and is deterministic.

Step 10B.2 — Sim: deadhead validation

  • Reposition validation allows any origin. The destination must be discovered, must differ from the origin, and must pass the range and landing checks. The bay requirement is removed.
  • Update the Step 3.14 tests.
  • Test: A Courier idle at the Moon with no Moon bay can deadhead to Earth. Deadheading to an undiscovered location fails with location_undiscovered. Deadheading to the ship's own location fails. Deadheading out of range fails with the out-of-range reason. A deadhead record still has zero payout and zero XP.

Step 10B.3 — Database: boards keyed by location

  • Change contract_boards to be keyed by player, location, and board period (the tutorial board keeps its own key).
  • Update architecture.md.
  • Test: Migrations run on a fresh database and are a no-op the second time. Two boards for the same player and period at different locations can coexist; a second board for the same player, location, and period is rejected by a unique constraint.

Step 10B.4 — Server: board endpoint for any discovered location

  • Replace "get contract board for a bay" with "get contract board for a location" in the route catalog and server. Any discovered location works; an undiscovered location returns location_undiscovered.
  • Update the Step 6.9 tests.
  • Test: The Moon's board is returned for a player with no Moon bay. Two requests in the same period return the same board. Requesting Mars's board before discovery fails with location_undiscovered; after a delivery discovers Mars, it succeeds.

Step 10B.5 — Server: no more stranded ships

  • Contract dispatch works from any discovered location where the ship is idle (it already validates that the ship is at the contract's origin; confirm no bay check remains).
  • Deadhead dispatch uses the Step 10B.2 rules.
  • Update the Step 6.10 and 6.11 tests.
  • Test (the original bug): A ship delivers Earth→Moon with no Moon bay. After arrival, the Moon's board is available, a Moon→Earth contract can be dispatched with that ship, and it resolves normally. Separately, the same ship can instead deadhead Moon→Earth.

Step 10B.6 — Server: ship delivery to a bay

  • Buying a ship takes a bay id. The ship appears idle and uncrewed at that bay's location. Buying without a bay, or with a bay the player doesn't own, fails.
  • Update the Step 6.5 tests.
  • Test: With bays at Earth and the Moon, buying a Freighter for the Moon bay places it at the Moon. Buying with no bay id fails with a validation error. Buying with another player's bay id fails and changes nothing.

Step 10B.7 — Client: Contracts screen by location

  • The Contracts screen's selector lists all discovered locations instead of bays. Each entry shows a badge with the number of idle ships there.
  • Default selection: the location of the most recently arrived idle ship; otherwise Earth.
  • Fleet screen: each idle ship gets a "Find work here" action that opens its location's board.
  • Update the Step 9.4 tests.
  • Test: Component test: the selector lists every discovered location and no undiscovered ones; idle-ship badges match state; the default is the most recently arrived idle ship's location; "Find work here" opens the right board.
  • Amended (decision 0.5.164): "Find work here" is disabled when the ship can't be dispatched now: its pilot is resting (CR-004; rest beside service, CR-023/CR-027, included), it's in the shop for an upgrade, repair or service (CR-009/CR-026/CR-027), or it has no pilot. The button says why with the countdown that ends last ("Resting · 04:12", "In the shop · 12:30", "No pilot assigned") and re-enables on its own when it ends. Every ship, Independent pilots' included; the Contracts tab stays browsable.

Step 10B.8 — Client: deadhead action

  • Rename the Fleet screen's "Reposition" action to "Deadhead (fly empty)". It is available for every idle ship. The destination picker lists discovered locations; ones out of range or not landable are shown disabled with the reason. Show fuel cost and trip time for each.
  • Update the Step 9.6 tests.
  • Test: Component test: an idle ship at the Moon with no Moon bay shows the action; the picker excludes undiscovered locations and the ship's current location; an out-of-range destination is disabled with its reason; fuel and time match the sim.

Step 10B.9 — Client: bays as HQs

  • Market screen: "Buy" opens a bay picker ("Deliver to which HQ?"). With only one bay, preselect it.
  • Locations screen and map panels: every discovered location has a "View contracts" link. The "Lease bay" action explains what a bay does: "Open an HQ here: hire pilots and take delivery of new ships at this location."
  • Update the Step 9.8, 9.9, and 10.3 tests.
  • Test: Component test: Buy shows the bay picker and sends the chosen bay id; with one bay it is preselected. Every discovered location shows "View contracts", with or without a bay. The lease action shows the HQ explanation.

Step 10B.10 — Plan amendments and regression

  • Apply the amendments in §5 to implementation-plan.md, and update game-design-document.md §4 and §10 to match §1 of this document.
  • Run the full suite.
  • Test: CI is green. Manual check: on a fresh account after the CR-001 deal, deliver to the Moon, pick up a Moon→Earth contract with the same ship, and deliver it back to Earth without leasing a Moon bay.

5. Amendments to implementation-plan.md

Step Change
0.4, 0.5 Apply §3 of this document.
3.9 Input is a location, not a bay (10B.1).
3.14 Deadhead rules replace reposition-to-bay (10B.2).
5.3 contract_boards keyed by player, location, and period (10B.3).
6.5 Ship purchase takes a bay id (10B.6).
6.9 Boards for any discovered location (10B.4).
6.10, 6.11 No bay checks on dispatch; deadhead rules (10B.5).
9.4 Selector lists discovered locations (10B.7).
9.6 "Deadhead (fly empty)" for every idle ship (10B.8).
9.8, 9.9, 10.3 Bay picker on purchase; "View contracts" everywhere; HQ explanation (10B.9).
12.1 The simulated player picks up contracts at whatever location its ships are at, and only deadheads when no eligible contract exists there. Add a check: across the whole run, no ship is ever idle with no eligible contract and no reachable deadhead destination.
12.5 After Mars is discovered, also confirm Mars's contract board is available without a Mars bay.

6. Out of scope

Garage-style bay capacity or slot limits, bay upgrades, recurring bay rent, pilots that pick their own jobs from their home bay (ATS-style AI drivers), and anything else in implementation-plan.md §0.3.