# 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. ### 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.