8.6 KiB
8.6 KiB
Decisions
Implementation decisions not spelled out in memory-bank/implementation-plan.md. Design decisions from plan §0.5 are logged here as they are implemented.
Step 1.1
- Repo lives on an NTFS drive (
C:\Projects\...). The original location (G:) is exFAT, which cannot hold symlinks, so pnpm could not link workspace packages. Do not move the repo back to an exFAT drive. - TypeScript is pinned to
~6.0. TypeScript 7 is the latest release, buttypescript-eslint(needed in Step 1.2) only supports<6.1. Upgrade once typescript-eslint supports 7. - Packages export TypeScript source directly (
main/typespoint atsrc/index.ts). There is no build step for internal packages; Vite, Vitest and the server's TS runner consume the source. The base config usesmoduleResolution: "Bundler"andnoEmit. - Node 24 is the required runtime (
engines+.nvmrc). - Line endings are LF everywhere (
.gitattributes), overriding the machine's globalcore.autocrlf, to match Prettier and the Linux CI runner.
Step 1.2
- ESLint 10 flat config with
typescript-eslintrecommended (not type-aware, to keep lint fast) andeslint-config-prettier.pnpm lintruns ESLint thenprettier --check. - Purity rule for
packages/simandpackages/content:no-restricted-propertiesbansMath.randomandDate.now;no-restricted-syntaxbansnew Date()with no arguments (new Date(x)is allowed). - Prettier skips
memory-bank/so tooling never rewrites the design docs.
Step 1.3
- Vitest projects: the root
vitest.config.tstreats eachapps/*andpackages/*folder as a project, sopnpm testruns every package's tests. Packages can add their ownvitest.config.tswhen they need a different environment. - Tests live in each package's
test/folder and are included in that package's tsconfig, sopnpm typecheckcovers them.
Step 1.4
- CI runs on Gitea Actions (
.gitea/workflows/ci.yml): install with a frozen lockfile, then typecheck, lint and test. .pnpm-store/is ignored by Prettier, ESLint and git. On the Gitea runner, pnpm puts its store inside the workspace, andprettier --checkfailed on the store's files (CI run #1).
Step 1.5
- One Postgres container, two databases.
docker-compose.ymlruns a singlepostgres:18server on port 5432 (user/passworddeadhead). The default databasedeadheadis for development;docker/postgres/init/01-create-test-db.sqlcreatesdeadhead_testthe first time the data volume is created. To recreate both from scratch, rundocker compose down -v. - Env var names in
.env.example:DATABASE_URL,TEST_DATABASE_URL,BETTER_AUTH_SECRETandBETTER_AUTH_URL(Better Auth's own names),PORT, andGAME_EPOCH_REAL_STARTplusGAME_EPOCH_EPHEMERIS_DATE(decision 0.5.9). The game-clock speed is not an env var; it belongs in GameConfig (rule 0.1.5). - Epoch values in
.env.exampleare placeholders. The design docs do not fix an ephemeris date yet.
Step 2.1
- Ids are lowercase kebab-case strings (
earth,bulk-hauler,long-haul). - One landing-class enum (
vacuum,atmospheric,hardened) serves both a location's landing requirement and a ship's landing class.hardenedis not used in the base game. - Location
bodyis an enum of the five astronomy bodies (earth,moon,mars,ceres,jupiter) so the sim can map each to a position source in Step 3.3. - Epoch fields are ISO 8601 UTC strings (
epoch.realStart,epoch.ephemerisDate), notDateobjects, so content stays plain data. tutorialBoardSizeis a GameConfig field in addition tocontractBoardSize, because decision 0.5.21 sets the tutorial board's size separately.- XP per delivery inputs are
base,perMillionKmandperCargoTier. Step 3.16 decides how they combine. pilotLevelXpThresholdslists the total XP needed for level 1, 2, 3, ...; it and the Long Haul cut-offs must be strictly increasing.tierPayMultiplieris one number per cargo type. Step 3.8 decides how it scales with tier.- Imports omit the
.tsextension (moduleResolution: "Bundler").
Step 2.2
- Location ids:
earth,moon,mars,ceres-station,jupiter-cloud-platform. - Cargo flows follow GDD §9: Earth and Mars produce standard and high-value goods and demand ore (heavy) and fuel (dangerous); the Moon produces standard and heavy; Ceres produces heavy; Jupiter produces dangerous (fuel). The outposts import high-value equipment.
- Launch multipliers: Earth 3, Jupiter Cloud Platform 2, Mars 1.5, Moon 0.5, Ceres 0.3.
- Bay lease prices are first guesses (Earth 5,000 up to Jupiter 15,000). Step 2.5 tunes the Earth price against the tutorial.
- The cargo-id check uses a placeholder list of the four cargo ids planned in Step 2.4 until the cargo data exists.
Step 2.3
- Ranges (million km): Courier 5 (Moon only; Mars is ~55 at its closest), Freighter 650 (covers Ceres at its farthest, ~600, and Jupiter near its closest, ~590, per decision 0.5.25), Bulk Hauler 1,000 (Jupiter at its farthest, ~970). Step 3.7 checks these against real positions.
- Speeds and overheads aim at GDD §6 durations at compression 60: Courier 3M km/h with 2 h overhead (Earth→Moon ≈ 2 real minutes, mostly overhead), Freighter 2M km/h with 4 h (Earth→Mars ≈ 1–2 real hours), Bulk Hauler 1.2M km/h with 8 h.
- Prices (30,000 / 150,000 / 600,000), capacities (20 / 100 / 400 t), fuel costs (20 / 40 / 80 per million km) and hull ratings (1 / 2 / 3) are first guesses; Step 2.5 tunes the Courier price.
Step 2.4
- Ids: cargo
standard,heavy,high-value,dangerous; skillslong-haul,heavy-cargo,expensive-cargo,dangerous-cargo. - Base pay (credits per tonne per million km): Standard 10, Heavy 14, High-Value 18, Dangerous 20. Tier multipliers: 1, 1.2, 1.25, 1.3. First guesses, to be tuned in Phase 12.
- Cargo and skills share one data file (
src/data/cargo.ts), since every cargo skill exists to gate a cargo type.
Step 2.5
- The game epoch lives in GameConfig, not in env vars. Step 2.1 puts it in GameConfig, and rule 0.1.5 keeps game numbers in
packages/content. TheGAME_EPOCH_*variables added to.env.examplein Step 1.5 are removed; the placeholder values (real start 2026-01-01, in-game 2100-01-01) are unchanged. - Money values scaled up. With the Step 2.2–2.4 rates a tutorial run paid ~24 credits. Pay rates and fuel costs are ×10, and prices are set so a Courier (4,000) plus an Earth bay (1,000) takes ~21 runs at ~240 credits each. Freighter 100,000, Bulk Hauler 400,000; leases Moon 800, Mars 20,000, Ceres 40,000, Jupiter 80,000.
- Placeholder tutorial payout in the test: Standard pay × 0.384M km × average mass (midpoint of the contract minimum and Courier capacity, 12.5 t) × tutorial share (0.5).
- Starting credits are 0. The company pays fuel during the tutorial, and the ~21-run target already assumes the player starts with nothing.
- Other defaults: board size 8, tutorial board 40 (more than the ~30 runs that fit in a 60-minute period), first contact 10% at ×2 pay, contract mass 5–400 t, Long Haul cut-offs 100/250/400/600/800M km, ten pilot levels at 2 skill points each (enough to max all four skills), hire cost 2,000, pilot pay 100 per delivery.
- Known balance issue for Phase 12: pay is linear in distance, but every trip pays a fixed overhead, so short Earth–Moon runs earn far less per real hour than long runs (a Freighter on Mars earns roughly 50× a Courier on the Moon).
Step 2.6
- Lookups return
undefinedfor an unknown id ("not found" without throwing). Callers decide whether a missing id is an error. - The package also exports each data list and schema individually, alongside the
contentbundle, so tests and the server can validate data with the schemas.
Step 3.1
- Times are Unix-millisecond numbers. A real time is a wall-clock instant; a game time is the instant of the in-game date, so
new Date(gameTime)gives the in-game date and can be passed straight toastronomy-engine. - Every sim function takes the content it needs as arguments (here the
GameConfig), rather than importing the default bundle, so tests can pass custom fixtures.
Step 3.2
- Seeds are 32-bit unsigned integers. The PRNG is mulberry32; child seeds are an FNV-1a hash of the label, started from the parent seed, plus a final mixing step.
createRngreturns an object with internal state. It is still deterministic: the same seed always gives the same sequence. Each use (a board, a name) creates its own generator from a derived seed, so draws never depend on call order elsewhere.