Step 10B.10: CR-002 plan amendments, GDD update and regression
CI / check (push) Successful in 3m13s Details

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
fireshaper 2026-10-03 15:16:18 -04:00
parent 3a3bb84c29
commit f7698166bb
4 changed files with 27 additions and 7 deletions

View File

@ -668,3 +668,8 @@ Implementation decisions not spelled out in `memory-bank/implementation-plan.md`
- **The delivery picker is a dialog with radio buttons and a "Buy for N cr" confirm**, so buying always takes two taps, even with one bay (preselected). The confirm is disabled until a bay is chosen.
- **"Bay owned" now reads "Your HQ is here"**, and the map panel says "Your HQ is here." or "No HQ here."; the player-facing word for a bay is HQ, while the action keeps "Lease bay" as in the CR.
- **The success message names the delivery location** ("… is waiting at Moon.") instead of always Earth.
## Step 10B.10
- **GDD §12 ("Each bay has one contract board") was also corrected**, since it contradicted §10; the CR named only §4 and §10.
- **The manual check was also scripted** against a live dev server with the test clock: after the deal, a Courier flies Earth→Moon and then takes a Moon→Earth job from the Moon board with no Moon bay. The user's own manual check on a device is still the review gate.

View File

@ -29,10 +29,10 @@ The game is about **logistics decisions**: which jobs to take, which ship and pi
## 4. Core Loop
1. Browse contracts at a docking bay.
1. Browse the freight market (contract board) wherever an idle ship is. Every discovered location has one.
2. Choose a ship and pilot, set the throttle, and dispatch.
3. Ship travels in real time (continues while offline).
4. Delivery completes: payout, pilot XP, possible new destination discovered.
4. Delivery completes: payout, pilot XP, possible new destination discovered. The ship takes a backhaul from where it landed, or deadheads (flies empty, fuel only) somewhere better.
5. Reinvest: ships, bays, pilots, pilot skills.
## 5. Progression
@ -128,9 +128,10 @@ Ship tiers should feel like upgrading from a box truck to a top-end rig.
## 10. Docking Bays & Discovery
- **Docking bays** are rented at a location and act as the player's base there: a place to pick up contracts and house ships.
- A location must be **discovered** before a bay can be rented there. Discovery happens by **completing a delivery to that location**.
- Contracts to undiscovered destinations appear occasionally at existing bays as well-paying "first contact" or survey jobs, giving players a path to expand.
- **Every discovered location has a contract board** (its freight market), like the job markets in American/Euro Truck Simulator. Any idle ship can pick up work wherever it is, so backhauls are always possible and a ship is never stranded.
- **Docking bays are HQs** (like ATS garages), rented at a discovered location. A bay is where pilots are hired, where newly bought ships are delivered, and where pilots can be unassigned. A bay does **not** control where contracts are offered.
- A location must be **discovered** before it has a board, a bay can be rented there, or ships can deadhead there. Discovery happens only by **completing a delivery to that location**.
- Contracts to undiscovered destinations appear occasionally on discovered locations' boards as well-paying "first contact" or survey jobs, giving players a path to expand.
## 11. Pilots
@ -162,7 +163,7 @@ Pilots are hired, assigned to ships, and gain **XP** from deliveries. XP is spen
### Contract Generation
- Every destination **produces** some goods and **needs** others. Contracts are generated from these flows.
- Backhaul matters: the best routes avoid flying home empty.
- Each bay has one contract board per refresh period. Contracts expire when the period ends.
- Each discovered location has one contract board per player per refresh period. Contracts expire when the period ends.
- Payout is fixed when a contract is offered; travel time and fuel depend on the distance at departure.
### Payout Factors

View File

@ -208,6 +208,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
- Rules: the board has the configured number of contracts; destinations are mostly discovered locations; cargo type is chosen from types the origin produces and the destination demands, falling back to Standard if none match; the configured first-contact chance decides whether a contract targets a random undiscovered location instead (flagged first-contact); mass comes from the configured range; non-Standard contracts get a tier from 1 to 5, which is their required skill level; required Long Haul level comes from the distance cut-offs; every contract expires at the end of the board period.
- **Test:** The same inputs always produce an identical board. A different period index produces a different board. No contract has origin equal to destination. Over 1,000 generated boards, first-contact contracts are between 5% and 15% of all contracts and every one targets an undiscovered location.
- **Amended after the CR-001 playtest:** contract mass comes from per-ship-size bands (`contractMassBands`, e.g. 3 × 5–20 t, 3 × 21–100 t, 2 × 101–400 t), and the first contract in each band is Standard cargo to a discovered location, so every ship size always has a job a new pilot can fly.
- **Amended by CR-002:** Input is a location, not a bay: boards are generated for any discovered location (Step 10B.1).
### Step 3.10 — Tutorial contract board
- Add a separate generator for the tutorial "company board": Earth↔Moon only, Standard cargo only, payout reduced by the tutorial payout share, always flown with the company loaner Courier. Contracts start at the loaner's current location: Earth→Moon when it is at Earth, Moon→Earth when it is at the Moon.
@ -230,6 +231,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
### Step 3.14 — Reposition dispatch
- Allow a dispatch with no contract to any discovered location that has a player bay, paying fuel only and earning no payout or XP.
- **Test:** A reposition record has zero payout and zero XP. A reposition to a location without a player bay fails validation.
- **Amended by CR-002:** Deadhead rules replace reposition-to-bay: from wherever the ship is to any other discovered location, range and landing only, `location-undiscovered` otherwise (Step 10B.2).
### Step 3.15 — In-flight position and progress
- Add functions that return, for a dispatch and a real time: progress (0 to 1, clamped) and an interpolated 2D position along a straight line from the origin's position at departure to the destination's position at arrival.
@ -277,6 +279,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
- Using Drizzle, define tables: players (with world seed), companies, ships, pilots (with current location and an is-avatar flag), bays, discovered_locations, contract_boards (one stored board per bay per period, plus tutorial boards per period per loaner location), accepted_contracts, dispatches. Dispatches store the full record including a snapshot of the contract, plus a status (in_flight or resolved), a resolved-at time, and an acknowledged-at time.
- Add a migration command.
- **Test:** Running migrations against the empty test database succeeds; running them a second time is a no-op.
- **Amended by CR-002:** `contract_boards` is keyed by player, kind (`location` / `tutorial`), location and period (plus tutorial run); one board per player, location and period (Step 10B.3).
### Step 5.4 — Test database harness
- Add a test helper that resets the test database between integration tests and can seed a player in a given state (tutorial, owner with one ship, etc.).
@ -318,6 +321,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
- Allow buying any ship model if the player has enough credits. A new ship appears idle at Earth with no pilot assigned.
- **Test:** Buying with enough credits deducts the price and adds the ship. Buying without enough credits returns the insufficient-funds error and changes nothing.
- **Amended by CR-001:** Blocked during the tutorial with `tutorial-active` (Step 10A.7, decision 0.5.16 as replaced).
- **Amended by CR-002:** `buyShip` takes a `bayId`; the ship appears at that bay's location. No bay id is a validation error; another player's bay is `not-found` (Step 10B.6, decision 0.5.35).
### Step 6.6 — Lease a bay
- Allow leasing a bay at any discovered location where the player does not already have one, for that location's one-time lease price.
@ -337,14 +341,17 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
### Step 6.9 — Bay contract board endpoint
- Return the contract board for one of the player's bays for the current period. On the first request in a period, generate it with the sim using the player's discovered locations at that moment and store it in contract_boards; later requests in the period return the stored board. Exclude already-accepted contracts. Contracts from earlier periods are never shown.
- **Test:** A bay board is returned for an owned bay. Requesting a board for a location without a player bay fails. Two requests in the same period return the same board, even if a location is discovered between them. After the period rolls over, a new board is returned, and dispatching a contract from the old board fails as expired.
- **Amended by CR-002:** `GET /api/locations/:locationId/board` serves any discovered location, no bay needed; undiscovered is `location-undiscovered` (Step 10B.4, decision 0.5.36).
### Step 6.10 — Contract dispatch
- Dispatching a contract runs sim validation, deducts fuel cost, marks the contract accepted, and stores the dispatch record. Ship and pilot become in-flight.
- **Test:** One integration test per sim validation failure confirms the matching error code is returned and nothing changes. A valid dispatch deducts fuel, stores the record, and makes the contract disappear from the board.
- **Amended by CR-002:** No bay checks: any idle ship can take a contract from its current location's board (Step 10B.5).
### Step 6.11 — Reposition dispatch
- Dispatching with no contract to a discovered location with a player bay deducts fuel and moves the ship and pilot with no payout.
- **Test:** A reposition succeeds and, after arrival, the ship is at the new location with credits reduced only by fuel.
- **Amended by CR-002:** Deadhead rules (Step 3.14 as amended); bays play no part (Step 10B.5).
### Step 6.12 — Spend skill points
- Allow spending an available skill point on a skill below max level.
@ -421,6 +428,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
### Step 9.4 — Bay contract boards
- After tutorial, the Contracts screen has a selector for the player's bays and shows each bay's board. Each contract shows route, cargo type, mass, distance, payout, required skill, expiry countdown, and a first-contact badge where applicable.
- **Test:** Component test switches bays and shows the right board. A first-contact contract displays its badge.
- **Amended by CR-002:** The selector lists every discovered location with an idle-ship badge, defaulting to the most recently arrived idle ship's location, else Earth; Fleet gets "Find work here" (Step 10B.7).
### Step 9.5 — Dispatch flow
- Selecting a contract opens a dispatch sheet: choose an eligible ship+pilot pair at the origin. Show trip time, fuel cost, net profit, and ETA in both game time and real time. Ineligible pairs are listed but disabled with the reason shown (out of range, can't land, skill too low, too heavy).
@ -430,6 +438,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
### Step 9.6 — Fleet screen
- List all ships: name, model, location or route, assigned pilot, and for in-flight ships a progress bar and countdown. Idle ships at a bay location have a "Reposition" action to another bay location.
- **Test:** Component test: an in-flight ship's progress bar matches sim progress for the mocked time. Reposition opens a destination picker listing only bay locations.
- **Amended by CR-002:** "Reposition" becomes "Deadhead (fly empty)" for every idle ship, with fuel, time and disabled-with-reason destinations (Step 10B.8).
### Step 9.7 — Pilots screen
- List pilots: name, level, XP progress to next level, skill levels, available skill points, assignment, status. Actions: hire pilot (shows cost), assign to ship, spend skill point.
@ -438,10 +447,12 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
### Step 9.8 — Market screen
- List the three ship models with stats (speed, capacity, range, landing class, price). "Buy" is disabled with insufficient credits.
- **Test:** Component test: buy is disabled when credits are below price; buying calls the endpoint and the new ship appears in Fleet.
- **Amended by CR-002:** Buy opens a "Deliver to which HQ?" bay picker, preselected with one bay (Step 10B.9).
### Step 9.9 — Locations screen
- List all locations. Discovered ones show type, landing requirement, current distance from Earth, produces/demands, and a "Lease bay" action with price (or "Bay owned"). Undiscovered ones show only the name and "Undiscovered — deliver here to unlock."
- **Test:** Component test: undiscovered locations hide details; leasing is available only for discovered locations without a bay.
- **Amended by CR-002:** Every discovered location shows "View contracts"; the lease action explains "Open an HQ here: hire pilots and take delivery of new ships at this location." (Step 10B.9).
### Step 9.10 — Empty and error states
- Every screen has a sensible empty state (e.g., "No ships yet — visit the Market") and a retry option on network failure.
@ -464,6 +475,7 @@ These answer the pre-build review. Log each one in `DECISIONS.md` as it is imple
- **Test:** Component test with simulated taps opens the correct panels.
---
- **Amended by CR-002:** The location panel links every discovered location to "View contracts", with or without a bay (Step 10B.9).
## Phase 10A — Faster Start (CR-001)
@ -496,6 +508,7 @@ Steps 10B.1–10B.10 are specified in `memory-bank/change-requests/CR-002-open-m
- Output: real time to finish the tutorial, real time to own 3 ships, credits over time, and pilot levels over time.
- **Test:** Running the script with a fixed seed produces identical output twice. With default content, tutorial completion falls between 45 and 120 real minutes of active play. (Adjust content values, not the test thresholds, if it fails; record changes in `DECISIONS.md`.)
- **Amended by CR-001:** Change the thresholds to: deal accepted under 10 real minutes; first pilot hired between 30 and 45 minutes; first discovery under 90 minutes; and a new check that after the deal the player always either has a ship in flight or can afford fuel for at least one contract. The simulated player accepts the deal as soon as it is available, takes the highest credits-per-minute contract, and pays down the loan only through automatic repayment. Adjust content values, not thresholds.
- **Amended by CR-002:** 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.
### Step 12.2 — Revisit the tutorial economy test
- Replace the placeholder average in the Step 2.5 test with the average tutorial payout measured by the balance script.
@ -514,6 +527,7 @@ Steps 10B.1–10B.10 are specified in `memory-bank/change-requests/CR-002-open-m
### Step 12.5 — End-to-end: discovery
- Playwright test: take a first-contact contract to Mars with an eligible ship and pilot, advance the clock past arrival.
- **Test:** Mars shows as discovered on the Locations screen and can now be leased.
- **Amended by CR-002:** After Mars is discovered, also confirm Mars's contract board is available without a Mars bay.
### Step 12.6 — End-to-end: pilot progression
- Playwright test: complete enough deliveries to level up a pilot, spend a point in Heavy Cargo, then confirm a previously ineligible Heavy contract becomes eligible in the dispatch flow.

View File

@ -143,4 +143,4 @@ Spec: `memory-bank/change-requests/CR-002-open-markets.md`. New decisions record
- [x] **Step 10B.7 — Client: Contracts screen by location.** `LocationBoards` (was `BayBoards`) shows a Location button group of every discovered location with an idle-ship count badge, defaulting to the most recently arrived idle ship's location (else Earth); `?location=` selects one (map link and Fleet's new "Find work here"). API: `Ship.lastArrivalAt`. Tests: `location-boards.test.tsx`, `last-arrival.test.ts`.
- [x] **Step 10B.8 — Client: deadhead action.** Fleet's "Reposition" is now "Deadhead (fly empty)" on every idle ship. The picker lists discovered locations except the ship's own, each with sim fuel cost and trip time; destinations the sim rejects (out of range, can't land, fuel, no pilot) are disabled with the reason. Test: `fleet.test.tsx`.
- [x] **Step 10B.9 — Client: bays as HQs.** Market Buy opens "Deliver to which HQ?" (radio list of bays, preselected when there is one) and sends `bayId`. Locations and the map panel link every discovered location to "View contracts" and say whether the HQ is there; the lease action shows "Open an HQ here: hire pilots and take delivery of new ships at this location." Tests: `market`, `locations`, `map-interactions`.
- [ ] Step 10B.10 — Plan amendments and regression
- [x] **Step 10B.10 — Plan amendments and regression.** CR-002 §5 amendments added to steps 3.9, 3.14, 5.3, 6.5, 6.9–6.11, 9.4, 9.6, 9.8, 9.9, 10.3, 12.1 and 12.5 (glossary and §0.5 were done with the CR). GDD §4, §10 and §12 now describe open markets and bays as HQs. Full suite and coverage green; an end-to-end smoke run against a live server (guest → 4 runs → deal → Earth→Moon → Moon→Earth backhaul with only the Earth bay) passed. **Phase 10B complete — stopped for review.**