MoneyCQ release notes

Changelog

Current version: v77

Life Game — Changelog

Version numbers map 1:1 to shipped change cycles (see `VERSION`). Entries are compiled by the Project Manager from worker reports and approved by the CEO.


Build 77 — 25 Aug 2026 (public release notes)

**Why:** players, teachers, and website visitors need a clear record of what has shipped and an easy way to identify the version currently running.

What changed

- **Public changelog (`/changelog`):** the complete MoneyCQ release history is now available in the app as a readable public page. - **Version link:** the visible app version badge now links directly to the changelog, so the current build and release notes are always one click away. - **Website release marker:** the MoneyCQ website footer now shows the current release and links to the public changelog.

Verification

- App build completed successfully and `/changelog` renders the full release history with the current version. - Website footer displays the same current release and changelog link.

Build 76 — 19 Aug 2026 (global admin console + content editor)

**Why:** the game had per-world GM and per-class teacher panels but no site-wide administration, and no way to update prices/items or events without a code deploy. This build adds a global admin console with a GUI content/event editor that changes the live game.

What changed

- **Admin console (`/admin`):** gated by an allow-list of account emails (`ADMIN_EMAILS` env). Sections: Overview (counts + recent worlds/classes), Users (list accounts via the GoTrue admin API, impersonate, reset password, suspend/unsuspend), Worlds (all worlds + GM link), Classes, Content editor, Feature flags, and a global Audit trail. Every admin action is recorded in `admin_actions`. - **Content editor (GUI):** add/edit/disable jobs, housing, vehicles, businesses, market instruments and events via JSON overrides stored in `content_overrides` (migration 0041). Edits flow into the live game: `getState`'s catalog, job/housing/vehicle/business selection commands, and market prices all read the effective (merged) catalog — so an admin price change is what players actually pay, and a newly added job/vehicle/ house is actually selectable. Removing an item disables it. - **Feature flags:** admin toggles stored in `feature_flags` (migration 0041) with a `/admin` UI. - **Admin API:** `GET/POST /api/admin` (overview, overrides, flags, audit) and `/api/admin/users` (GoTrue service-role operations + impersonation via a minted session JWT). - **Tests:** new `tests/admin.test.ts` (suite 13) covers the audit trail, feature flags, override merge (new + edited + disabled), effective catalog in game state, and that a vehicle purchase actually posts the admin-edited price. - **Verification:** typecheck, lint, full suite (13 suites), production build and E2E 17/17 all green. VERSION bumped to 76.

Live verification + fixes (deployed 20 Aug 2026)

Deployed to https://app.moneycq.com and verified end-to-end with a disposable admin account (created, tested, removed):

- **Admin gate email propagation fixed:** `requireUser` dropped the JWT `email` claim, so the allow-list check always saw an empty email and every signed-in user got "not an admin". `AuthUser` now carries `email`, with a regression test that mints a real JWT and asserts pass/reject. - **Suspend fixed:** GoTrue rejects a bare `ban_duration` number; now sends `87600h` (10 years). - **Reset-password fixed:** GoTrue's `generate_link` requires the user's email, not the user id; the route now passes it and surfaces GoTrue's error message. Verified the recovery link completes a real password reset (public link → verify → session at app.moneycq.com). - **Public auth path wired:** `app.moneycq.com/auth/v1/*` now proxies to the Supabase Kong gateway (nginx location block, `nginx -t` validated), and `API_EXTERNAL_URL` is `https://app.moneycq.com/auth/v1` so recovery links are public. App `.env` gained `SUPABASE_SERVICE_ROLE_KEY` for the Users tab. - **Used-vehicle market respects admin prices:** `BUY_USED_VEHICLE` now reads the effective catalog like the new-vehicle path; test asserts the used price is derived from the admin-edited price. - **Verified live:** overview/worlds/classes, user list, impersonate, suspend/unsuspend, reset link, content override create/list/delete, feature flags, audit trail, 401 gate for non-admins. Test account and all test rows removed afterwards; `auth.users` back to 0.

Build 75 — 16 Aug 2026 (tax-year refresh maintenance)

**Why:** the annual tax-rule refresh (NZ 1 Apr, AU 1 Jul, US 1 Jan, GB 6 Apr) was documented but purely manual — nothing flagged when a region's rates passed their verified tax year, so stale rates could ship silently.

What changed

- **Refresh metadata on every region:** `RegionDef.taxRefresh` now declares when each pack's rates took effect (`effectiveDate`), when they must be re-verified (`nextCheckDate` — the start of the next tax year), and the authority source. Added to all 18 packs (17 countries + generic). - **Checker tool:** `npm run test:tax-year` (or `npx tsx tools/tax-year-check.ts [date]`) prints a status table — region, tax year, effective date, next check, days left, OK / DUE SOON / OVERDUE — and exits 1 if any pack is overdue or missing metadata. It is wired into `npm run verify` so CI/deploy gates fail loudly. - **Tests:** new `tests/tax-refresh.test.ts` (suite 12) asserts every pack declares valid ISO dates + a source, the four named cadences match the documented starts, the status thresholds are correct, the date math is calendar-aware, a past-date pack is flagged overdue, and nothing is overdue today. - **Docs:** `docs/REGIONS.md` gains a tax-year refresh schedule table and a step-by-step "how to refresh a region". - **Verification:** typecheck, lint, full suite (12 suites), production build, E2E 17/17 and `npm run test:tax-year` all green. VERSION bumped to 75.

Build 74 — 16 Aug 2026 (email-invite Postgres fix)

**Why:** live verification of Build 73's email invites found the unbound invite row used an empty string for the uuid `invitee_user_id` column — Postgres rejects `''` for uuid, so inviting by email failed on production (SQLite tolerated it, which is why local tests stayed green).

What changed

- **NULL for unbound invites:** `inviteToWorldByEmail` now inserts `NULL` for `invitee_user_id`, and `bindInvitationsForEmail` matches unbound rows with `invitee_user_id IS NULL` (no `= ''` comparison). Invitation serialisation maps a null id to `""` for the client. - **Verification:** typecheck, lint, full suite (11 suites) and production build green; live email-invite flow re-run against Postgres. VERSION bumped to 74.

Build 73 — 16 Aug 2026 (optional infra upgrades)

**Why:** the three named optional infra upgrades — native Supabase Realtime for presence, email-based invites, and a public challenge leaderboard on the marketing site.

What changed

- **Presence over Supabase Realtime:** class presence now publishes through a Supabase Realtime broadcast channel (`class-presence:{classId}`) when configured (`SUPABASE_REALTIME_URL` + anon key, defaulting to the local envoy gateway). The SSE browser edge is unchanged, but fan-out between heartbeats and dashboards now rides Realtime — multi-instance safe and survives restarts. Falls back to the in-process bus when Realtime isn't configured (local dev / SQLite tests). Deps: `@supabase/realtime-js`. - **Email-based invites:** world owners can invite a player by email address (`POST /api/worlds/:id/invitations { email }`, and an "Invite a player by email" field on the home "Multiplayer & family" panel). Pending invites keyed by email bind to the account on signup/login (`bindInvitationsForEmail`) — the invitee sees it on their landing page. A pluggable email adapter (`EMAIL_PROVIDER` = none/console/smtp) composes and sends the invitation; `none` is the safe default. Migration 0040 (both dialects) adds `invitee_email` and relaxes `invitee_user_id`. Deps: `nodemailer` (+ `@types/nodemailer`). - **Public challenge leaderboard:** unauthenticated `GET /api/public/leaderboard?challengeKey=&limit=` returns the top challengers (name, week, CQ, net worth — derived rows only), and a public `/public/leaderboard` page renders it for embedding on moneycq.com via iframe. - **Tests:** classes suite covers email invite creation, email normalisation, idempotent duplicates, invalid-email rejection, bind-on- signup, and acceptance granting membership. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 73.

Build 72 — 16 Aug 2026 (PWA verified + versioned service worker)

**Why:** Build 66's PWA had shipped but was never verified as an installable app, and its service worker used a hardcoded cache name — future deploys would never advance or prune the shell cache, leaving stale assets behind.

What changed

- **Versioned service worker:** the worker now lives as a template (`lib/sw-template.js`) and is served through `app/sw.js/route.ts` with the current VERSION injected into the cache name (e.g. `moneycq-shell-v72`). Every deploy advances the cache and the activate handler prunes the previous one — no stale shell assets survive a release. The static `public/sw.js` was removed so the route can't be shadowed. - **Manifest hardening:** icons now declare `purpose: any` + `maskable` (192/512), improving install presentation on Android home screens. - **Live verification:** a browser-level PWA audit passes 16/16 on the deployed app — manifest JSON + name/display/start_url/theme, all four icons (any/maskable) serve 200, the service worker registers/activates and controls the page, and a real offline reload renders the cached MoneyCQ shell (not a browser error). `/manifest.webmanifest`, `/sw.js`, `/offline.html` and `/icon-512.png` all 200. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 72.

Build 71 — 16 Aug 2026 (launch pack close-out)

**Why:** Build 65's launch pack was prepared but unapplied and partly stale — the WordPress site still used a non-canonical band label and early-access claims, and the perk catalog's code comment disagreed with the locked spec.

What changed

- **WordPress copy applied + verified:** feature-accurate copy blocks synced to moneycq.com (Home, The Game, For Teachers, blog). Hero stat card fixed from "742 CQ · Strong" (not a canonical band) to "742 CQ · Savvy"; "Get early access" button and stale early-access lines on Regions, Why-Teachers, and posts 221/15 replaced with "Start your first life now at app.moneycq.com". All 9 pages and 80 posts swept clean. - **Defensive domains re-verified:** live Verisign RDAP check (16 Aug) — all 8 candidates still available; purchase recommendation stands. - **Perk catalog alignment:** `CQ_PERKS` code comment updated PROPOSED → LOCKED, matching `CASH_QUOTIENT.md` §16 (CEO-approved 15 Aug). - **Fresh screenshots:** `tests/e2e/screenshots.mjs` regenerated all 8 screens (01-home … 08-home-mobile) against the v70 production build. - **PWA verified live:** `/manifest.webmanifest`, `/sw.js`, `/offline.html`, `/icon-512.png` all 200 on v70. - **Docs:** new `docs/LAUNCH_PACK.md` consolidates all five deliverables and records the remaining owner decisions (domain purchase, perk confirmation). - **Verification:** typecheck, lint, full suite (11 suites) green. VERSION bumped to 71.

Build 70 — 16 Aug 2026 (P3-1/P3-2 playable build-out)

**Why:** Build 64's production-hardening engine (market provider modes, rate limiting, analytics, classroom moderation, load test) was complete and tested at the engine level, but teachers had no UI to use it — freeze controls, ledger review, and the provider/moderation state were invisible.

What changed

- **Teacher moderation UI (class dashboard):** a new Moderation panel lets a teacher freeze or unfreeze every member world's transactions in one click (and see whether the class is currently frozen). Each world in "Lives in this class" shows a Frozen chip when blocked and a "Review ledger" button that opens a side-by-side view of the student's recent transactions and command history (teacher-only, world-scoped). - **Class detail moderation state:** `GET /api/classes/:id` now reports `transactionsDisabled` per world (from `moderation_flags`), so the dashboard reflects the real freeze state on load. - **GM console visibility:** the World/GM screen shows the market provider mode (fictional/historical/delayed/live with an "(off)" marker when the licensing gate keeps it internal) and a Moderation metric (Active/Frozen); the quick-action panel gains Freeze/Unfreeze transactions buttons. - **Tests:** classes suite covers class freeze → per-world flag → money command rejection → unfreeze clearing the flag. - **Verification:** typecheck, lint, full suite (11 suites), production build, load test (20×12 weeks, p95 ≈ 300ms, zero errors) and E2E 17/17 all green. VERSION bumped to 70.

Build 69 — 16 Aug 2026 (P2-5 parent identity)

**Why:** live verification of the multiplayer build-out showed the parent could not be identified from the client — the main player character has no account binding, so the family controls and partnership UI never appeared for the world owner.

What changed

- **World owner exposed in state:** `state.world.ownerUserId` now carries the world's owner account id (mirrors `worlds.owner_user_id`), so the game page can tell who the parent is without relying on player bindings. - **Parent detection in UI:** the "Multiplayer & family" panel and its family-mode controls now key off `me === state.world.ownerUserId` instead of scanning bound players — the parent sees their controls in every world they own, including worlds created before player-account binding existed. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 69.

Build 68 — 16 Aug 2026 (P2-5 multiplayer fixes)

**Why:** live verification of Build 67's multiplayer build-out found two identity bugs — the parent was gated by their own family config, and the acting-player resolver could pick the wrong player character when the owner had no bound account player.

What changed

- **Parent exemption:** `featureStateFor` now treats the world owner (parent) as exempt from family-mode difficulty/system gating — the config applies to the child, never locks out the parent who set it. - **Acting-player resolution fix:** `resolveActingPlayer` prefers the world's main player (the one with no account binding) when the owner has no bound player, instead of picking whichever player UUID sorts first. This keeps `LIST_OFFER`/`PURCHASE_OFFER`/partnership commands acting as the right character in worlds with invited players. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 68.

Build 67 — 16 Aug 2026 (P2-5 playable build-out)

**Why:** Build 63's multiplayer economy engine was complete and tested at the engine level, but players could not actually use it from the game — the marketplace could only list services, partnerships had no buttons, and family mode had no controls. This build makes P2-5 playable end-to-end.

What changed

- **Asset trading from the UI:** the marketplace now shows everything a player owns that can be listed (vehicles, properties, equipment, business shares, investments) with derived values, and each row has a "List for sale" button (asking price + quantity). Offers display the asset kind and quantity, private-offer targeting, and a Cancel button for the seller. - **Command layer fix:** `LIST_OFFER` now passes the attached asset and target buyer through both the player and GM command paths (previously the engine accepted them but the commands dropped them). `PURCHASE_OFFER` and the partnership commands resolve the acting user's own player character (`resolveActingPlayer`) instead of always acting as the world's main player — so a second account can buy, sell and partner as themselves. - **Partnership buttons:** pending invitations show Accept/Decline, active partnerships show End, and the owner can offer a partnership in their business to any other player (choose partner + shares). - **Family-mode controls:** the world owner (parent) sees a controls panel — difficulty (Primary/Intermediate/Advanced), game speed (PAUSED/WEEKLY/ BIWEEKLY/MONTHLY), and allowed systems — with Apply. The API exposes the acting user id (`me`) so the UI knows who the parent is. - **Tests:** content test 30 covers the command paths the UI uses — vehicle listing with an attached asset, private purchase, partnership form/accept/ end/decline, and family speed/difficulty enforcement (paused block, MONTHLY advancing four weeks). - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 67.

Build 66 — 16 Aug 2026 (P3-3 → PWA first)

**Why:** the platform-scoping deliverable recommended "PWA first" — this build ships that recommendation instead of leaving it as a future plan.

What changed

- **Installable PWA:** richer web manifest (`id`, language, categories, 192/512 PNG icons generated from the logo); service worker (`/sw.js`) with network-first navigation + offline fallback, cache-first static assets, and no API caching; branded offline page (`/offline.html`); production-only registration via `PwaRegister` in the root layout. - **Art check for screenshots:** all 94 job, 9 housing, 5 vehicle and 10 city-icon assets are real vector art (no placeholder files), so the Build 65 screenshot gallery is current — re-capture only when planned additional art lands. - **Verification:** lint, typecheck, production build, E2E 17/17, and live endpoint checks for `/manifest.webmanifest`, `/sw.js`, `/offline.html` and `/icon-512.png` (all 200). VERSION bumped to 66.

Build 65 — 16 Aug 2026 (P3-3 launch pack)

**Why:** the last open checklist tier was launch actions with no decision-ready artifacts — copy to sync, a domain decision, a perk-catalog sign-off, fresh screenshots, and platform scoping.

What changed

- **WordPress copy sync:** feature-accurate copy blocks (Home / What is CQ / The Game / For Teachers / Blog) ready to paste at moneycq.com — every claim matches the implemented game (100+ jobs, events, family mode, multiplayer trading/partnerships, market modes, classroom moderation). - **Defensive domain decision pack:** all 8 candidates re-verified live against the .com registry (Verisign RDAP, still available) with a buy recommendation — cqhero.com / cqsims.com / getcashq.com (≈ $40 total). - **CQ perk-catalog sign-off sheet:** the implemented 5-perk catalog with effects, balance notes and a sign-off block (spec §16 flips to LOCKED after CEO approval). - **Fresh gameplay screenshots:** `tests/e2e/screenshots.mjs` builds a showcase world through the real API (job, housing, business, vehicle, investment, rental, two advanced weeks) and captures 8 screens — Home, Career, Money, Business, Property, Market, City, and mobile Home. - **Platform scoping:** PWA-first recommendation (manifest already ships) with a Tauri later-path and explicit non-goals for native mobile. - **Verification:** no engine changes; typecheck, lint, full suite, build and E2E 17/17 remain green. VERSION bumped to 65.

Build 64 — 16 Aug 2026 (P3-1 live market toggle + P3-2 production hardening)

**Why:** the market provider switch existed only as a bare internal/external flag, and the production checklist's hardening items — rate limits, analytics, classroom moderation, and a concurrency load test — were open.

What changed

- **P3-1 market provider toggle (config-only):** `MARKET_PROVIDER_MODE` now selects `fictional` (default) / `historical` / `delayed` / `live`. Historical replays the world's scenario price history; delayed/live engage the external adapter only when the provider URL is configured **and** the licensing terms flag is accepted (`MARKET_PROVIDER_TERMS_ACCEPTED=yes`) — otherwise the market safely stays internal. The resolved mode is exposed in state (`marketProvider`). - **P3-2 rate limiting:** token-bucket limits on the command and GM endpoints (`RATE_LIMIT_MAX` / `RATE_LIMIT_GM_MAX` / `RATE_LIMIT_WINDOW_MS`) with 429 + Retry-After responses. - **P3-2 analytics adapter:** `ANALYTICS_PROVIDER` = none | console | webhook; the engine emits `world_created`, `week_advanced` (CQ band + net worth), `mission_completed` and `achievement_unlocked` — fire-and-forget, never blocking gameplay. - **P3-2 classroom moderation (migration 0039, both dialects + RLS):** `moderation_flags` powers `SET_TRANSACTIONS_DISABLED` — teachers freeze every player transaction (26 money/ownership commands blocked at the command layer) per world or across a whole class; teachers can review a student's ledger + command log via `GET /api/classes/:id/worlds/:worldId/ledger`. - **P3-2 load test:** `npm run test:load` — 20 worlds × 12 weeks of weekly rollover under a concurrency-8 worker pool (p95 ≈ 290ms, zero errors). - **DB robustness:** the SQLite async adapter now serializes top-level transactions (AsyncLocalStorage-aware) so concurrent rollovers keep their savepoint stacks intact. - **Tests:** content test 29 — provider modes + terms gate, rate limiting, analytics events, transaction freeze, and teacher ledger access. - **Verification:** typecheck, lint, full suite (11 suites), production build, E2E 17/17 and the load test — all green. VERSION bumped to 64.

Build 63 — 16 Aug 2026 (P2-5 multiplayer economy)

**Why:** players shared a city but could not trade real assets, co-own a business formally, or hand a parent the controls of a home world — the last unfinished P2 system.

What changed

- **Player-to-player asset trading (migration 0038, both dialects + RLS):** marketplace offers can now attach a real owned asset — vehicle, property, business shares, generic asset, or investment holding — and target a single buyer for private deals. Purchase transfers ownership atomically with funds (vehicle/property/asset owner change, share transfer that always sums to 100, weighted-average holding merge for investments), with capital gains tax on property resale. Trades record the asset that moved. - **Partnerships over business shares:** `formPartnership` / `acceptPartnership` / `declinePartnership` / `endPartnership` let two players co-own a business; the existing dividend engine splits profits by shareholding automatically. The partnership record tracks the real split and lifecycle, and the home screen shows active/pending partnerships. - **Family mode:** `family_config` (world owner = parent) controls difficulty (feature level), complexity/allowed systems (feature overrides), and game speed (`PAUSED` blocks advancement, `BIWEEKLY`/`MONTHLY` roll multiple weeks). `SET_FAMILY_CONFIG` is owner-gated, `featureStateFor` enforces the flags for the child, and the state + home screen surface the config. - **UI:** the game home gains a compact "Multiplayer & family" panel listing partnerships and family settings. - **Tests:** content test 28 — private vehicle trade transfers the asset, share trade + partnership accept/decline/end, and family-mode difficulty/ system/speed enforcement (paused block, biweekly advance). - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 63. **P2-5 fully COMPLETE — P2 tier complete.**

Build 62 — 16 Aug 2026 (groups audit trail + spec close-out)

**Why:** close out the groups spec's remaining verification items — every teacher action now leaves an audit trail, the bulk-enrollment codes are shareable, and the parity suite covers the groups layer on both drivers.

What changed

- **Class audit trail (migration 0036, both dialects + RLS):** `class_actions` records every teacher action — class creation, default-level changes, group create/update/delete, member moves/removals, and bulk enrollment — with actor, action, details JSON, and timestamp. `GET /api/classes/:id/actions` exposes it (members may read; teachers act), and the class dashboard shows a "Class activity" panel for teachers. - **Shareable claim codes:** the bulk-enrollment panel gains "Copy all codes" and "Download CSV" buttons so teachers can hand codes out in one step (spec §8). - **Parity groups segment:** `tests/parity-run.ts` now exercises class creation, quick-start presets, group moves, feature-state resolution, and the audit trail on both SQLite and Postgres, printing only deterministic fingerprints (no random IDs) so the drivers must agree. - **Tests:** classes suite asserts the audit trail records each action in order, is class-scoped, and rejects non-members; groups suite unchanged but green alongside. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 62.

Build 61 — 16 Aug 2026 (P2-4 economy cascades)

**Why:** the economy drifted in isolation — unemployment never fed job security, recessions had no ripple, and whole industries were static.

What changed

- **Migration 0037 (both dialects):** `economy.field_trends_json` carries per-field pay multipliers (healthcare grows, retail shrinks) on the world economy. - **Unemployment → job security:** a weekly redundancy roll scales with the job's security label (Solid 0.1%, Decent 0.3%, Variable 0.8%) and the market's employment strength (WEAK ×3, NORMAL ×1, STRONG ×0.4), inserting the existing redundancy event with a warning notification. - **Field trends:** salaries and weekly income projections now multiply base pay by the player's field trend (default 1.0); `setEconomy` and the economy summary expose `fieldTrends`. - **Recession / boom / industry-shift events:** `recession_hits` (WEAK employment, 85% demand, BEAR markets, COOLING property, WEAK business), `boom_times` (STRONG employment, 130% demand, BULL/HOT/STRONG), and `industry_shift` (healthcare/education/tech up, retail/hospitality down). The new `ECONOMY_SHOCK` event effect re-rates every downstream system at once and warns the player. - **Tests:** content test 27 — field-trend pay up/down, weak-market redundancy roll vs a strong-market quiet window, economy-event eligibility, and shock resolution re-rating the whole economy. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 17/17 all green. VERSION bumped to 61. **P2-4 fully COMPLETE.**

Build 59 — 16 Aug 2026 (P2-3 tax & retirement completion)

**Why:** the region packs were fully scaffolded but the money loop still ignored taxes on gains, never paid retirement out, skipped government top-ups, and forced one retirement rate on everyone.

What changed

- **Investment gains tax:** selling investments now taxes the profit over average cost using the region's `capitalGainsTaxRateBp` (`CAPITAL_GAINS_TAX`), joining the existing business and property-sale taxes. All three income taxes are now live per region. - **Retirement payout:** the locked retirement balance pays out in full at life end (completion or bankruptcy) — `RETIREMENT_PAYOUT` moves it into cash before the final score. - **Government top-ups:** credited once per game year where the region's scheme has a match — NZ KiwiSaver 25c-per-dollar (capped at $260.72, phased out over $180k income) and the AU co-contribution (50c-per-dollar with the income phase-out) both use the pack's own rules (`RETIREMENT_TOPUP`). - **Per-player retirement rate:** `SET_RETIREMENT_RATE` picks from the scheme's option list (e.g. 3.5–10% KiwiSaver), the weekly payroll uses it, and a Retirement controls card on the Money screen sets it. - **Currency formatting:** every money display now routes through `formatMoneyCents` with the region's currency/locale — the game home, weekly summary, Money/Budget/Business/Property/Career screens all use the region formatter (the summary card takes a `regionKey` prop). - **Tests:** content suite test 26 covers the NZ 8% rate choice and employee share, the KiwiSaver top-up cap, the retirement payout at life end, and US investment gains tax. Typecheck, lint, full suite, build and E2E 17/17 green. VERSION bumped to 59.

Build 57 — 16 Aug 2026 (P2-2 completion pass)

**Why:** the property depth review found the features worked but had no browser-level proof, and the Property screen's new analytics UI wasn't in the mobile overflow audit.

What changed

- **E2E property scenario:** a rental is bought through the real UI, the portfolio shows the yield analytics and tenant status, and a renovation raises both value and rent — verified `renovation=100000`, `rent=30150`, `yield=62.3%` through the full-state API. This also caught a test-side units bug (the renovate input is in dollars, not cents). - **Mobile check:** the 390px overflow audit now also covers the Property screen (buy form, analytics, renovate control) — 0px overflow. - **Verification:** typecheck, lint, full suite, build and E2E 17/17 green. VERSION bumped to 57.

Build 56 — 16 Aug 2026 (P2-2 property depth)

**Why:** property stops being a passive money box — it carries rates, can be improved, comes with tenants who sometimes don't pay, and owes tax when you sell.

What changed

- **Rates/property tax per region (migration 0035 + region packs):** `propertyTaxRateBp` on all 18 packs; weekly tax on property value (`PROPERTY_TAX` ledger, expenses bucket). - **Renovations:** `RENOVATE_PROPERTY` raises the derived value basis and bumps weekly rent (0.15% of cost per week); UI control on the Property screen. - **Tenant simulation:** rentals are TENANTED or VACANT. New tenants enjoy an 8-week grace period (so early saves are unaffected), then rent can run late — arrears accumulate and eviction follows after three missed weeks (property becomes vacant, reputation −1); vacant properties refill over time. Deterministic per property, so runs stay reproducible. - **Capital gains tax on sale:** `capitalGainsTaxRateBp` per region; the gain over purchase + renovations is taxed at sale (`CAPITAL_GAINS_TAX`), with the shortfall check now covering both mortgage and tax. - **Analytics:** the Property screen shows each rental's annual yield, weekly property tax, tenant status and arrears, plus a renovate control. - **Tests:** content suite test 25 covers renovation value/rent, US property tax, tenant simulation engaging past grace, and capital gains tax on sale. Typecheck, lint, full suite, build and E2E 15/15 green. VERSION bumped to 56.

Build 55 — 16 Aug 2026 (P2-1 business depth)

**Why:** businesses stop being simple revenue machines — they pay tax, can be wound down, can automate, negotiate with hires, need equipment, and live inside an industry.

What changed

- **Business tax per region (migration 0034):** `RegionDef` gains `businessTaxRateBp` (all 17 country packs + generic); weekly profit is taxed before dividends (`BUSINESS_TAX` ledger, business bucket in the summary). Generic stays 0, so existing saves are unchanged. - **Liquidation:** `LIQUIDATE_BUSINESS` closes the venture, terminates every offer/accepted/active contract (employees released), and recovers the business account balance. UI button on the Business screen. - **Automation:** `BUY_AUTOMATION` (up to level 3, escalating cost) reduces the labour requirement 15% per level — buying back owner time. UI button on the Business screen. - **Contract negotiation:** `UPDATE_CONTRACT_OFFER` revises wages and hours on any offered contract (NPC or player) within the legal bounds. - **Equipment requirements:** lawn-care and handyman need owned equipment — without it they run at 85% revenue; an `equipment_failure` event offers repair / replace / improvise. - **Industry events:** competitor arrives, new customer, contract loss, and a business lawsuit — all gated on owning a business. - **Tests:** content suite test 24 covers automation costs and levels, contract revision, the equipment revenue boost, NZ business tax, employee release on liquidation, and industry-event eligibility; economy and NPC simulation tests updated to give lawn-care its equipment. Typecheck, lint, full suite, build and E2E 15/15 green. VERSION bumped to 55.

Build 54 — 16 Aug 2026 (P1-4 completion pass)

**Why:** the reputation review found the features worked but had no browser-level proof, and the new Career reputation panel hadn't been checked for mobile overflow.

What changed

- **E2E reputation scenario:** a work event is triggered through the Game Master (professional reputation +2), then a GM fraud ruling creates a criminal record — the Career screen renders both the dimension bars and the record. Verified `professional=52`, `record=1` through the real UI. - **Mobile check:** the 390px overflow audit now also covers the Career screen (the reputation panel's bars and record list) — 0px overflow. - **Verification:** typecheck, lint, full suite, build and E2E 15/15 green. VERSION bumped to 54.

Build 53 — 16 Aug 2026 (P1-4 reputation dimensions + criminal record)

**Why:** reputation stops being one number and becomes a character sheet — what people think of you professionally is different from your financial and legal standing, and serious wrongdoing follows you.

What changed

- **Five reputation dimensions (migration 0033):** history rows now carry a dimension (PERSONAL / PROFESSIONAL / BUSINESS / FINANCIAL / LEGAL); `applyReputationDelta` accepts a dimension, legal rulings are always LEGAL, work/business/financial events map to their area (event-key map in `lib/content.ts`), and the overall score still blends everything (no balance change). `StateSnapshot` exposes `reputationDimensions`. - **Criminal record:** serious rulings (fraud, tax, copyright, licence, unlicensed work, loan default) create a lasting record that persists after release. It blocks sensitive careers (finance, law, public service, security, childcare, education, healthcare), new business licences, player-level insurance, and permanently penalises the credit rating. - **Reputation gates:** premium roles carry reputation requirements (`JOB_REPUTATION_REQUIREMENTS`), enforced by the engine and shown as locked in the onboarding picker; a Partnership Offer event requires business reputation and a Quality Tenant event requires financial reputation. - **UI:** the Career screen gains a Reputation panel (five dimension bars + criminal record with its consequences); the job picker locks roles that need reputation or are blocked by a record. - **Tests:** content suite test 23 covers dimension movement, record creation and persistence after release, career/business/insurance/credit consequences, the premium-role reputation gate, and event eligibility gates. Typecheck, lint, full suite, build and E2E 13/13 green. VERSION bumped to 53.

Build 52 — 16 Aug 2026 (quick-start level presets)

**Why:** teachers could already change a class's level after creation, but the setup moment offered no preset choice — every new class silently started at Intermediate. Now the create-class flow preselects a level up front.

What changed

- **Quick-start presets at class creation:** the landing "Create class" form gains three preset cards — Primary (basics), Intermediate, and Advanced (everything) — each showing its one-line description. `POST /api/classes` accepts `defaultLevel` and `createClass` stores it; an invalid level still falls back to Intermediate. - **Class list shows the level:** "Your classes" on the landing page now shows a level pill next to each class so teachers can see the preset at a glance (matches the roster badges). - **Tests:** classes suite covers creating a class at Primary/Advanced, invalid-level fallback, and that ungrouped students inherit the preset (`featureStateFor`). - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 13/13 all green. VERSION bumped to 52.

Build 51 — 16 Aug 2026 (P1-3 completion pass)

**Why:** the family review found a lifecycle gap — children could never reach school age inside a 104-week life — plus three polish items worth closing.

What changed

- **Children grow up:** a game year is now 13 weeks, so a baby reaches school age (5) at week ~65. Childcare stops, a "starts school" notification fires, and the transition is tested. - **Home-screen household awareness:** an overcrowding warning banner now appears on the game home, and the setup panel shows the household (partner/children/elders) plus a **Move** control (choose any home with its rent and capacity). - **E2E coverage:** a new scenario brings the partner in through the Game Master and verifies the Household line renders with their income — 13/13. This also caught and fixed a 390px overflow from the new move selector. - **Verification:** typecheck, lint, full suite (school-age test 22), build and E2E 13/13 green. VERSION bumped to 51.

Build 50 — 16 Aug 2026 (P1-3 family & life stage)

**Why:** life gains a household — partners bring income, children bring costs, elders bring care, and the home you choose has to fit everyone.

What changed

- **Partner/dependents model:** family members live in player state (partner, children, elders) via new `ADD_FAMILY_MEMBER` / `REMOVE_FAMILY_MEMBER` effects. Partners can earn weekly income (`PARTNER_INCOME` ledger); children have childcare costs (`CHILDCARE`) that end at school age (children age every 52 weeks); elders have care costs (`ELDER_CARE`). Partner income counts toward weekly income and CQ; household costs count in weekly expenses. - **Housing capacity:** every home now has a capacity, shown in the onboarding chooser ("Fits up to N"). When the household outgrows the home, the player is flagged `overcrowded` and takes a weekly fatigue + health hit. A `MOVE_HOUSE` command (and the moving event) lets players relocate anytime. - **Family events:** partner moves in (works or keeps the home), the baby arrives (three childcare choices), school costs, elderly parent care (move in / help afar / facility), and moving day (upgrade or downsize). - **Household budget line:** the Budget planner shows household costs (childcare + elder care) as their own line and lists each family member with their income or costs. - **Tests:** content suite test 21 covers partner income posting and income projection, childcare costs, overcrowding vs a family home, moving, elder care, and the exposed household costs. Typecheck, lint, full suite, build and E2E 12/12 green. VERSION bumped to 50.

Build 49 — 16 Aug 2026 (class default level + query fixes)

**Why:** the groups milestone's last loose end — teachers can now set the whole class's default level (not just per-group levels), and two engine queries that would crash on SQLite get the parameter-passing fix they need. This build also carries the local Builds 43–48 (budget completion, career progression, achievements, vehicles, health protection) to production.

What changed

- **Class default level control:** `PATCH /api/classes/:id` now accepts `defaultLevel` (teacher-only, validates primary/intermediate/advanced), and the class dashboard shows a level picker for teachers next to "Class level". Students without a group inherit this level — so a teacher can run the whole class on Primary without creating a group. - **Roster level exposure:** the class detail now returns each member's resolved level (group level, else class default), which the roster badge uses. - **Query fix:** `listStudentLoans` passed its parameters as a nested array, which crashed the SQLite driver; now matches the shared helper signature (same fix applied to `listBudgetItems` in Build 41). - **Tests:** classes suite covers teacher set / student denied / invalid level rejected, and roster level inheritance. - **Verification:** typecheck, lint, full suite (11 suites), production build and E2E 12/12 all green. VERSION bumped to 49.

Build 48 — 16 Aug 2026 (P1-2 health & income protection)

**Why:** health stops being just a stat — it becomes something you can insure, and being sick now costs real income instead of a flat fee.

What changed

- **Player-level insurance products:** Health Cover ($20/wk, $100 excess), Income Protection ($35/wk), and Life Cover ($15/wk) — the first policies bound to the player (`insured_entity_type = PLAYER`) via the existing broker UI (new "You" target). The insurance engine stays generic. - **Medical auto-pay:** new `MEDICAL_COST` effect — illness/medical events (flu's doctor visit, unexpected prescriptions, dental) now check an active Health Cover policy: you pay the excess, the policy pays the rest, and a claim is recorded exactly once. - **Sick leave mechanic:** new `SICK_LEAVE` effect — the flu event offers "Rest and recover" (2 weeks at 80% pay) alongside the doctor choice and pushing through. While on sick leave, salary pays the reduced percentage each week, and an active Income Protection policy covers the gap. The home screen shows "Sick leave — N wk(s)" on the fatigue bar. - **Life cover:** pays out when the story ends (week-104 completion or bankruptcy), boosting the final ledger before the closing score. - **Tests:** content suite test 20 covers the three products, the health-cover payout over the excess with a recorded claim, sick leave (80% pay × 2 weeks, income protection top-up, return to full pay), and the life-cover payout at completion. Typecheck, lint, full suite, build and E2E 12/12 green. VERSION bumped to 48.

Build 47 — 15 Aug 2026 (P1-1 completion pass)

**Why:** the review of the vehicle system found four loose ends worth closing — an achievement that ignored catalogue cars, no used-car market, cars missing from the shared city, and no browser-level coverage.

What changed

- **Achievement + mission fix:** `first_vehicle` ("Wheels", new achievement) now unlocks for catalogue vehicles, not just free-form asset vans — the same fix applies to the first-vehicle mission. Roster is now 15 achievements. - **Used-car market:** `BUY_USED_VEHICLE` purchases a discounted catalogue car with an explicit starting age (migration 0032 `age_weeks`) — value derives from the purchase price/week, condition derives from total age, so used cars are cheaper but break down sooner. "Buy used" button in the catalogue. - **Shared city:** catalogue vehicles now appear on the street in the city view, flagged DAMAGED when condition drops below 40. - **E2E:** a new smoke scenario buys a hatchback through the UI, verifies it under "Your vehicles", and trades it back in — 12/12. - **Verification:** typecheck, lint, full suite (used-market + achievement tests), build and E2E 12/12 green. VERSION bumped to 47.

Build 46 — 15 Aug 2026 (P1-1 dedicated vehicle system)

**Why:** cars stop being free-form assets and become a real purchase decision — catalogue, finance, running costs, and the risk of an old car letting you down.

What changed

- **Vehicle catalogue (migration 0031 + data):** five vehicles — City Hatchback, Commuter Sedan, Family SUV, Delivery Van, Sports Coupé — each with price, weekly maintenance, fuel + registration (folded into the weekly transport line), depreciation, and reliability. `BUY_VEHICLE` / `SELL_VEHICLE` replace free-form car purchases (equipment stays generic). - **Vehicle loans:** dedicated `vehicle_loans` (RLS) with a fixed weekly payment and interest; counted as debt in net worth; settling on sale. - **Condition/age model:** derived condition decays with weeks owned; older, less reliable cars break down more, spawning a repair decision (pay / borrow / patch) with a 4-week cooldown. - **Trade-in:** resale is the derived value; if you owe more than the car is worth, you can't sell it. - **Insurance fit:** Vehicle Comprehensive now insures catalogue vehicles (`insured_entity_type = VEHICLE`), shown in the broker UI. - **UI:** the Money screen's assets store becomes a Vehicles catalogue (Buy / Finance, owned list with value, condition, and loan) plus a separate Equipment store. Vehicle thumbnails shipped to `public/content/vehicles/`. - **Tests:** content suite test 18 covers catalogue sanity, cash purchase, running costs folded into transport, maintenance, derived depreciation, trade-in at derived value, financed purchase with payments + debt accounting, and a deterministic breakdown repair event. Typecheck, lint, full suite, build and E2E 11/11 green. VERSION bumped to 46.

Build 45 — 15 Aug 2026 (P0-4 achievements)

**Why:** milestones deserve permanent badges — a data-driven achievement system gives the life a record beyond missions and XP.

What changed

- **Achievement model (migration 0030):** `achievement_progress` table (SQLite + Postgres with RLS), seeded for every new world exactly like missions; 14 data-driven definitions in `lib/content.ts` with titles, descriptions, and XP rewards. - **Evaluation:** `updateAchievements` runs weekly in the pipeline — first job, first business, first property, first claim, first investment, first policy, CQ band crossings (Growing 6 / Elite 8), a 4-week debt-free streak (loans + student loans + liabilities), the 104-week survivor, first disaster, first promotion, $1M net worth, and first negotiation. Unlocks are exactly-once: XP awarded, notification sent, progress pinned. - **UI:** the game home gains an "Achievements" section — collapsible, showing unlocked count, trophy badges with unlock week, dimmed locked badges, and progress bars for streak/band/wealth milestones. - **Tests:** content suite test 17 verifies seeding (14 locked at start), week-1 unlock + notification, the debt-free streak staying locked, the 104-week survivor unlocking at the end, and exactly-once recording. Typecheck, lint, full suite, build and E2E 11/11 green. VERSION bumped to 45.

Build 44 — 15 Aug 2026 (P0-3 career progression + education)

**Why:** careers become real ladders — study to unlock skilled roles, climb from entry to senior, negotiate your pay, and feel the economy in your job security.

What changed

- **Education (migration 0029 + data):** six paths — trade apprenticeship, university degree, three short training courses, and an entrepreneurship bootcamp — each with cost, duration, study hours per week (adds to workload/fatigue), and granted skills. `ENROLL_EDUCATION` with cash or student-loan funding; completion grants skills, XP, and a notification. - **Skills:** 10-skill catalog (`SKILLS`); `JOB_REQUIRED_SKILLS` gates ~60 mid/senior roles; entry roles stay open. `CHOOSE_JOB` and GM `CHANGE_JOB` enforce the gate (GM can `force`), the onboarding picker greys out locked jobs with "Requires: …" chips, and each skill adds +3% owner business output (capped). - **Student loans:** `student_loans` table (RLS), deferred for study + 4 weeks grace, then 3%-of-income weekly repayment with interest; counted in net worth and the money log; visible on the Career screen. - **Promotion trees:** ladders derive from the job roster per field (Entry → Mid → Senior); `PROMOTE_JOB` requires weeks in role (6/12), reputation for senior rungs (15), the rung's skills, and a 4-week cooldown. `employment.nextRung` exposes requirements + readiness. - **Negotiation + redundancy:** `NEGOTIATE_JOB` (salary roll scaled by reputation, or ±5 hours with pay adjusted; 8-week cooldown); `RESIGN_JOB` for career changes; a redundancy event tied to Variable job security or a weak economy, with a `LOSE_JOB` effect and a "take the package vs transfer" choice; players find new work with `CHOOSE_JOB` anytime they're unemployed. - **UI:** Career screen gains a full panel — next-rung requirements and promote button, negotiate controls, education catalog with cash/loan enrollment and a study progress bar, and the student-loan ledger. - **Tests:** content suite test 16 covers skill gates, negotiation outcomes and cooldowns, education completion, promotion up a ladder, student-loan deferral → repayment → debt accounting, and redundancy → re-employment. Full-life smoke updated to an entry role (skilled roles are gated now). Typecheck, lint, full suite, build and E2E 11/11 green. VERSION bumped to 44.

Build 43 — 15 Aug 2026 (P0-2 completion pass)

**Why:** the budgeting milestone needed its two promises visible where the player actually looks — the weekly summary — plus browser-level proof that the planner works end-to-end.

What changed

- **Weekly over-budget line:** the weekly summary card now shows "You spent $X over budget this week" whenever the engine's planned-vs-actual snapshot records an overage (red alert, placed right under the net-worth row). `budget` was already in the home partial state, so no extra fetch. - **E2E coverage:** a new smoke scenario drives the real Money screen — adds a bill, sets the savings auto-sweep, verifies the over-budget alert and the bill row render, then cleans up (removes the bill, sweep back to 0) so the rest of the suite runs on a normal economy. - **Verification:** typecheck, lint, full suite, production build and E2E 11/11 all green (budget scenario included). VERSION bumped to 43.

Build 42 — 15 Aug 2026 (P4 polish: groups levels)

**Why:** close out the groups polish pass — students can see their level everywhere, teachers get clearer copy on what each level unlocks, and locked screens explain themselves instead of saying a bare "locked".

What changed

- **Level badges:** the class roster now shows each student's level (Primary / Intermediate / Advanced) as a pill next to their name, so a teacher can see the mix at a glance. - **Level banner:** the game page shows a friendly banner for students on a non-advanced level — "Primary level — Basics: job, housing, savings, spending and the emergency fund. Ask your teacher if you should have more." — so players always know their scope and who to ask. - **Group manager copy:** each level picker and every group row shows a one-line summary of what that level unlocks (from `LEVEL_SUMMARIES`). - **Richer locked states:** the shared `LockedFeature` card now names the feature and its description ("Market & investments is locked — Stock exchange, trading, holdings. This isn't part of the Primary level."), and the command-layer rejection message uses the same friendly label instead of a bare feature key. Market and business screens pass the friendly labels through. - **API surface:** `useWorld` and the game page read `features.level` from the world endpoint so screens can adapt to the resolved level. - **Verification:** typecheck, lint, full suite (11 suites incl. groups, classes, regions), production build and E2E 10/10 all green. VERSION bumped to 42.

Build 41 — 15 Aug 2026 (P0-2 budgeting screen)

**Why:** the game's money loop finally gets a plan — players see income vs spending, set their own bills, and automate the savings habit.

What changed

- **Budget model (migration 0028):** `budget_items` table (SQLite + Postgres with RLS) for player-defined recurring bills; `BUDGET_LIMITS` guardrails in `lib/content.ts`; new `CUSTOM_EXPENSE` and `AUTO_SAVE` ledger types. - **Engine:** `ADD_BUDGET_ITEM` / `UPDATE_BUDGET_ITEM` / `REMOVE_BUDGET_ITEM` / `SET_AUTO_SAVE` commands; custom bills post weekly like any bill and are counted in living costs; the auto-sweep moves up to the set amount from everyday into savings each week (only what's actually there); each week's planned-vs-actual budget is stored on the player and exposed as `state.budget` (items, auto-save, last week's planned/spent/over). - **UI:** the Money screen gains a Budget planner — weekly income vs planned spending with a projected surplus/shortfall, red alerts when the week is projected over budget or last week ran over, built-in living costs listed by category, add/edit/remove custom bills, and a savings auto-sweep control. - **Tests:** content suite test 15 covers bill CRUD, weekly posting at updated amounts, exactly-once auto-sweep, savings growth, planned/spent budget snapshots, removed bills stopping, and validation rejects. Typecheck, lint, full suite, build and E2E 10/10 green. VERSION bumped to 41.

Build 40 — 15 Aug 2026 (P0-1 completion pass)

**Why:** close out the content-depth milestone — a navigable job picker for the 94-role roster and a full-life endurance test that proves the new content survives two complete years.

What changed

- **Job picker UX:** the 22+ field groups are now collapsible sections with career counts; the first field opens by default, so browsing 94 roles is a glance instead of a wall of buttons. - **Full-life smoke test:** content suite test 14 plays all 104 weeks with random event choices — life completes, all six itemized expense lines post across the run, missions track (50+ roster present, at least one completed), CQ snapshots accumulate, and no assertion anywhere fails. - **E2E:** the onboarding scenario now expands the Trades group before picking Warehouse Associate (matches the new grouped UI). - **Verification:** typecheck, lint, full suite (incl. full-life smoke), production build and E2E 10/10 all green. VERSION bumped to 40.

Build 39 — 15 Aug 2026 (P0-1 content depth pack)

**Why:** the first content-depth milestone — housing choice, honest itemized living costs, a 150+ event world, and a 50+ mission roadmap.

What changed

- **Housing:** roster grows from 3 to 9 (studio, townhouse, suburban house, family home, loft, waterfront added) with rent, copy, and on-theme SVG thumbnails (`public/content/housing/`). The onboarding chooser now shows the thumbnail next to each option. - **Itemized living costs:** the old three lump lines become six ledger entries — Groceries, Transport, Utilities, Phone, Internet, Subscriptions — via a `WEEKLY_EXPENSES` catalog in `lib/content.ts` and new `GROCERIES` / `UTILITIES` / `PHONE` / `INTERNET` ledger types. The weekly total is deliberately unchanged ($145/wk), so difficulty is untouched; the money log and future budget screen now see real categories. `FOOD` remains a legacy type for existing ledgers. - **Event pack:** 151 event definitions (156 keys including follow-ups) — 94 new events across personal, employment, business, property, home, disaster, economic, legal, family, car and lifestyle categories, all through the existing data-driven framework (choices, effects, cooldowns, once-per-life, classroom-risk gates). - **Mission pack:** 51 missions — 40 new ones covering survival milestones, savings tiers, assets, property, business expansion, investments, insurance, debt payoff, reputation, levels, high pay, promotions, CQ bands/pillars, net worth, passive income, time freedom and disasters. Engine tracking added for every new key (one shared CQ/net-worth evaluation per week, no per-mission query storms). - **Tests:** content suite now guards housing count + thumbnails, the six-line expense catalog (unique keys/types, $145 total, real ledger posting), event uniqueness/rarity/choices, mission count, and state exposure of the full mission roster. Inflation and imprisonment tests updated for the itemized lines. Typecheck, lint, full suite, build and E2E 10/10 green. VERSION bumped to 39.

Build 38 — 15 Aug 2026 (Groups — P3 bulk enrollment + claim)

**Why:** teachers can create a whole class of student worlds in one click and students claim their own life on sign-in.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). This build also carries the in-repo jobs expansion III (Build 37) into the live deploy.

What changed

- **Migration 0027** (both dialects): `worlds.claim_code` (unique partial index) + `worlds.class_id` for teacher-created placeholder worlds. - **Bulk enrollment** (`BULK_ADD_STUDENTS` via `POST /api/classes/[classId]/bulk-add`): a teacher creates 1–50 placeholder student worlds with unique claim codes in one transaction. The class dashboard shows a "Bulk enrollment" panel (codes to share) and lists unclaimed seats. - **Claim** (`POST /api/classes/claim`): a student binds their account to their seat — world owner, OWNER membership, class link, one world per class enforced; double-claims and bad codes rejected. "Claim my life" input on the landing classroom panel. - **Verification:** bulk/claim tests in `tests/groups.test.ts`; all suites + E2E green.

Build 37 — 15 Aug 2026 (Jobs expansion III: 25 more careers)

**Why:** the career table now spans 30 fields and 94 jobs, covering nearly every way a city earns its keep.

What changed

- **New fields:** emergency services, animal care, aviation, maritime & ports, fitness & sports, tourism & travel, events & entertainment, and data & analytics — each with Entry / Mid / Senior rungs (24 jobs), plus an accountant specialization in finance (25 new jobs total). `JOB_FIELDS` and `JOB_FIELD_LABELS` extended in `lib/content.ts`; engine untouched. - **Zero UI work:** the picker stays data-driven (Build 34), so all 30 fields render automatically with the shared label map. - **Art:** 25 new dusk-navy/gold SVG thumbnails at `public/content/jobs/<key>.svg` (94 total). - **Tests:** content suite test 12 now asserts ≥ 90 jobs, complete ENTRY/MID/SENIOR coverage per field, and a thumbnail for every job. - **Verification:** typecheck, lint, full suite, production build and E2E 10/10 all green. VERSION bumped to 37.

Build 36 — 15 Aug 2026 (Groups — P2 enforcement)

**Why:** turning a feature off now actually turns it off — the command layer rejects disallowed actions and the screens show locked states.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). This build also carries the in-repo jobs expansion (Builds 33–35) into the live deploy.

What changed

- **Command-layer gate** (`runCommand`): `COMMAND_FEATURES` maps ~40 player commands to the market/auctions/property/business/loans features; the acting account's feature state is resolved per request and disallowed commands are rejected with "Not available at your level (…) — ask your teacher." Local mode and allowed levels are unaffected. - **Locked screens**: Market and Property pages render a locked card; BusinessManager and the game-home business chooser + borrow panel hide when disabled; MarketExtra hides Auctions. `featureStateFor` moved to `lib/features.ts` (no import cycle) and the API responses now include `features` so the client renders the right state. - **Verification:** command-gate tests in `tests/groups.test.ts` (primary blocks loans/market; intermediate + advanced + local pass the gate); all suites + E2E green.

Build 35 — 15 Aug 2026 (Jobs expansion II: 25 more careers)

**Why:** keep widening the career table so every play style has a home; the roster now covers 22 fields and 69 jobs.

What changed

- **New fields:** agriculture, engineering, public service, real estate, beauty & wellness, insurance, childcare & caregiving, and energy & utilities — each with Entry / Mid / Senior rungs (24 jobs), plus a mechanic specialization in trades (25 new jobs total). `JOB_FIELDS` and `JOB_FIELD_LABELS` extended in `lib/content.ts`; engine untouched. - **Zero UI work:** the onboarding picker and career page already derive fields and labels from data (Build 34), so all 22 fields render automatically. - **Art:** 25 new dusk-navy/gold SVG thumbnails at `public/content/jobs/<key>.svg` (69 total). - **Tests:** content suite test 12 now asserts ≥ 60 jobs, complete ENTRY/MID/SENIOR coverage per field, and a thumbnail for every job. - **Verification:** typecheck, lint, full suite, production build and E2E 10/10 all green. VERSION bumped to 35.

Build 34 — 15 Aug 2026 (Jobs expansion: 25 new careers)

**Why:** the first jobs pack (Build 33) covered six fields; this pass takes the roster from 19 to 44 jobs so every player can find a believable ladder.

What changed

- **New fields:** hospitality, construction, finance, law, creative & media, science, security & safety, and transport & logistics — each with Entry / Mid / Senior rungs (24 jobs), plus a plumber specialization in trades (25 new jobs total). `JOB_FIELDS` and `JOB_FIELD_LABELS` extended in `lib/content.ts`; the engine stayed untouched. - **Future-proof picker:** the onboarding job list now derives its fields from the data (`Array.from(new Set(jobs.map(field)))`) instead of a hard-coded list, and both the game page and career page consume the shared field/tier labels from `lib/content.ts` — adding careers later requires zero UI changes. - **Art:** 25 new dusk-navy/gold SVG thumbnails at `public/content/jobs/<key>.svg` (44 total). - **Tests:** content suite test 12 now asserts ≥ 40 jobs, every field has a complete ENTRY/MID/SENIOR ladder, and every job has a chooser thumbnail. - **Verification:** typecheck, lint, full suite, production build and E2E 10/10 all green. VERSION bumped to 34.

Build 33 — 15 Aug 2026 (Jobs content pack)

**Why:** the game opened with three jobs; the first content-depth pass gives players real career choice and a visible ladder.

What changed

- **Job model:** `JobDef` gains `field` (retail, trades, office, healthcare, tech, education) and `tier` (ENTRY / MID / SENIOR), with `JOB_FIELDS`, `JOB_FIELD_LABELS`, and `JOB_TIER_LABELS` in `lib/content.ts`. Content stays data-driven — the engine needed no logic changes. - **Roster:** 19 jobs across 6 fields (3–4 per field), each with its own hours, weekly pay, stress, security and flavour copy. Existing keys (`warehouse`, `retail`, `delivery`) are unchanged, so saves and tests keep working. - **State snapshot:** `StateSnapshot.employment` now carries `field` and `tier` (contract v1.8), so screens can group careers without duplicating content. - **UI:** the onboarding "Pick a job" panel groups jobs by field with Entry / Mid / Senior chips, stress shown on demanding roles, and a thumbnail per job; the current job in Setup shows "Mid Tech" style labels; the Career screen shows the field/tier line under the job title. - **Art:** 19 on-theme dusk-navy/gold SVG thumbnails shipped at `public/content/jobs/<key>.svg` (swap for generated PNGs later per the image shot list). - **Tests:** content suite test 12 validates unique keys, allowed fields, complete field×tier coverage, hours/pay/stress bounds, and that field/tier flow through the state snapshot. - **Fixes (pre-existing, found by the clean build):** `lib/classes.ts` had a duplicate `groupRows` declaration, `ClassRow` was missing `default_level`, and `listGroups` omitted `featureOverrides` from its internal type; the class page's local `Member` type lacked `groups`; `tests/groups.test.ts` looked up student-2's feature state with student-1's world. All fixed; typecheck, lint, full test suite and production build green.

Build 32 — 15 Aug 2026 (Groups & feature levels — P1)

**Why:** teachers can organise students into subgroups with different feature levels (Primary / Intermediate / Advanced) and per-group toggles.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Migration 0026** (both dialects + RLS): `class_groups`, `class_group_members`, and `classes.default_level`. - **`lib/features.ts`**: `FEATURES` catalog (9 features), `LEVEL_PRESETS` (primary = basics; intermediate adds market/property/business/loans; advanced = everything), and `resolveFeatureFlags(level, overrides)`. - **Group CRUD** (`lib/classes.ts` + API): create/list/update/delete groups, move students in/out (one group per class), class-default fallback, and `featureStateFor(world, user)` resolution. - **Teacher UI**: class dashboard Groups panel — create group with a level, edit level + per-feature toggles (override the preset), move students from the roster, remove members. Roster shows group badges; `/api/me` returns each class's groups + resolved feature state. - **Verification:** `tests/groups.test.ts` (CRUD, moves, preset + override precedence, class-default fallback); all suites + E2E green.

Build 31 — 15 Aug 2026 (Phase 4 complete: identity-gated contracts)

**Why:** close the last roadmap caveat — contract responses now require the account that owns the player character.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Player ownership** (migration 0023): `players.owner_user_id` binds each player character to an account. Accepting a world invitation now creates the invitee's own account-bound player in that world (multi-player). - **Identity gate:** `RESPOND_CONTRACT` verifies the acting account owns the employee player (falling back to the world owner for the main/legacy player); the command route passes the authenticated user through. Local mode stays open for dev/tests. - **Verification:** invitation → bound player → offer → another account rejected / owning account accepted, covered by tests; all suites + E2E green. - **Fixes found during live verification:** `state.players` was passing raw SQLite rows into a client component (null-prototype objects crashed the server render of every game page) — now mapped to plain objects; Postgres folds unquoted camelCase SQL aliases to lowercase, so `AS "ownerUserId"` is quoted (SQLite preserved the case, which is why local tests passed and live didn't). Live gate 5/5, tour 18/18, class flow 11/11.

Build 30 — 15 Aug 2026 (Polish: realtime presence, invitations, challenge sign-in)

**Why:** finish the classroom loop — live presence, account invitations, and an auth-aware challenge join on the landing page.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Realtime presence:** class dashboards now subscribe to a server-sent events stream (`/api/classes/[classId]/events`) — heartbeat POSTs push a frame so online dots update instantly instead of on a 30s poll. A slow heartbeat remains as the fallback if the stream drops. - **Invitations:** a world owner can invite another account (`POST /api/worlds/[worldId]/invitations`); the invitee sees pending invitations on the landing with Accept/Decline (`/api/invitations`), and accepting grants world membership. Identity-gated — only the invitee can answer. - **Challenge sign-in UI:** landing challenge cards are auth-aware — signed out they prompt to sign in; signed in they use the per-account join (resumes your existing entry and opens it); local mode keeps the old one-click create. - **Verification:** all suites + E2E green; invitation flow tested (owner-only invite, duplicate-pending dedupe, accept→membership, decline, non-invitee rejection). - **Perk catalog approved (CEO, 15 Aug 2026):** `CASH_QUOTIENT.md` §16 flipped PROPOSED → LOCKED; live perk audit passed (player card + GM console show the active perk at its band, zero errors).

Build 29 — 15 Aug 2026 (Phases 4–5: classrooms, shared city, challenges)

**Why:** the accounts layer becomes a classroom product — teachers create classes, students join with a code, and everyone sees the shared city.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Classes** (migration 0021, SQLite + Postgres/RLS): teachers create a class with a join code; students join and get their own account-bound world (one per class per account); rosters, member management, presence heartbeats. - **Teacher dashboard** (`/classes/[classId]`): roster with CQ/band/online, class-scoped CQ analytics (averages, distribution, pillar means), lives list, and the shared city (every student's buildings labelled by player). - **API**: `/api/me`, `/api/classes`, `/api/classes/join`, `/api/classes/[classId]` (+ analytics, city, presence, members), and `/api/challenges/[challengeKey]/join` (one entry per account, resumed on re-join; unique index migration 0022). - **Owner fix:** `createWorld` now sets `owner_user_id` on the world row (previously only membership was recorded), which powers owner-based queries, RLS owner policies, and challenge resume. - **Verification:** all 10 suites + E2E green; class flow tested locally (create/join/one-world-per-class/analytics/city/presence/removal).

Build 28 — 15 Aug 2026 (Phase 3: real auth)

**Why:** accounts. Players and teachers can now sign in; worlds belong to their account and are enforced at the API and page level.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026) with `AUTH_MODE=supabase` enabled.

What changed

- **Sign-in:** email/password sign-up and login on the landing page (`AuthPanel`), backed by the self-hosted Supabase GoTrue service through server-side proxy routes (`/api/auth/signup|login|logout|status`). - **Session:** an httpOnly `moneycq_token` cookie (1h) — every API call and server-rendered page reads it automatically; no client token plumbing. - **Enforcement:** world API routes return proper 401s; server components (`game/*`, `city/*`) verify the session + membership before rendering; world creation binds to the account and the worlds list shows only your worlds. - **Legacy world claim:** the first account created claims the ownerless world (Nala) so existing progress survives the switch to accounts. - **Verification:** all suites + E2E green (local mode unaffected); GoTrue signup/login/JWT verified live against the project secret.

Build 27 — 15 Aug 2026 (Phase 2: async data layer — engine converted)

**Why:** the foundation for large scale. The engine now runs on an async Db interface with a connection-pooled Postgres driver, verified live against the provisioned database.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). The live game still runs on SQLite (DATABASE_URL unset) with identical behavior; the Postgres path is verified and ready to flip.

What changed

- **Async data layer:** `lib/db-types.ts` (Db contract + `?`→`$n` placeholder rewrite), `lib/db-sqlite.ts` (SQLite adapter), and `lib/db-postgres.ts` (connection pool, SAVEPOINT transactions, `RETURNING id` for insert helpers, bigint→number). - **Engine converted:** all 130 DB call sites in `lib/engine.ts` now go through the async `Db`; 223 functions made async (via an AST codemod); `withTransaction` → `db.tx`; `lib/city.ts` converted; every API route and server page awaits. SQLite remains the default local driver. - **Cross-driver determinism:** `ORDER BY rowid` replaced with `ORDER BY id`; async collection callbacks (`map`/`reduce`/`forEach`) awaited correctly; `assert.throws` → `assert.rejects` in tests where calls became async. - **Live verification:** all eight test suites green; E2E 10/10; async driver tested against the live Postgres (20 migrations visible); parity test proves SQLite and Postgres produce **identical week-by-week results over 8 weeks** (cash, net worth, CQ, ledger rows) from the same seed.

Infrastructure — Phase 17 database live (15 Aug 2026)

**No app build** — the live game remains v26. This entry records the production database milestone:

- Self-hosted Supabase stack provisioned on the production VPS (`/opt/supabase-src/docker`, all services localhost-bound, restart-safe). - Migrations `0001–0020` applied to the live database (including `0020_fix_rls_recursion`, which repairs an infinite-recursion bug in the original `world_members` RLS policies). - RLS + concurrency verification passes **10/10 on the live database** (anonymous blocked, owner create/read, cross-user isolation for select/update/delete, optimistic week guard with exactly one winner). - The game still runs on SQLite until the async Postgres conversion (`docs/ASYNC_POSTGRES_PLAN.md`) lands; the database is ready and verified ahead of it.

Build 26 — 15 Aug 2026 (Installable app + topbar polish)

**Why:** make MoneyCQ feel like a real app on phones and classroom tablets — add-to-home-screen with its own icon and standalone launch.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **PWA manifest** (`app/manifest.ts`): MoneyCQ can now be installed to a home screen — standalone display, navy theme, the coin icon. - **iOS home-screen metadata**: `appleWebApp` capable + black-translucent status bar, so Safari's "Add to Home Screen" launches the game full-screen. - **Topbar polish**: the world-name line under the brand now aligns to the actual logo size instead of a fixed offset. - **Verification:** lint/typecheck/build/all suites/E2E green; live tour re-audited after deploy (18/18, zero errors); manifest + icon routes 200.

Build 25 — 15 Aug 2026 (Navigation + landing explainer polish)

**Why:** finish the brand feel — consistent dock icons and a landing page that explains CQ at a glance.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Nav icon family:** all eight dock icons (home, money, career, business, property, market, GM, city) re-drawn in one consistent line/duotone style — light stroke with gold accents, matching the city landmark icons. - **Landing CQ explainer:** the plain text card is now a visual strip — the four pillars (Earn / Manage / Grow / Survive) with mini progress bars feeding a CQ dial (742 · Strong · +12 this month) and a note on how XP and CQ differ. Responsive down to phone width. - **Phase 17 prep (non-visible):** `pg` dependency and `tools/apply-postgres.mjs` (one-command transactional Postgres migration apply, 0001–0019) added; `docs/PRODUCTION_PERSISTENCE.md` updated with the exact apply command and owner hand-off values. - **Verification:** lint/typecheck/build/all suites/E2E green; live tour re-audited after deploy with zero errors.

Build 24 — 15 Aug 2026 (Brand art package)

**Why:** give MoneyCQ a real identity and a first-class landing page — logo, icons, hero art and social cards that match the game's dusk-city mood.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Logo:** new gold-coin "CQ" mark (`public/logo.svg`) shown on the landing page and in the game topbar; favicon (`app/icon.svg`) and Apple touch icon (`public/icon-180.png`) rebuilt to match. - **Landing hero:** an illustrated dusk-city scene (`public/landing/hero.svg`) — skyline, warm windows, bank, market stall, houses, street lamps, a walker with a satchel — sits between the headline and the create-life form. - **Social card:** `public/moneycq-og.png` re-rendered at 1200×630 from the hero art + logo + headline (Open Graph + Twitter share). - **City landmarks:** ten line/duotone hotspot icons (`public/city-icons/*.svg` — office, business district, business, school, stock exchange, home, property, bank, shopping, industrial) now render on the city viewport instead of single-letter markers, with the letter as a graceful fallback. - **Verification:** lint/typecheck/build/all suites/E2E green; live tour re-audited after deploy with zero errors.

Build 23 — 15 Aug 2026 (QA sweep: clean build + verified live)

**Why:** eliminate the last build warning and re-verify the whole app end-to-end against the live site.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Clean build:** `themeColor` moved from `metadata` to the `viewport` export (Next 15's supported location), removing the build warnings for every route. - **Verification:** local CI (lint, typecheck, build, six suites, E2E 10/10) green; live tour audit 18/18 with zero 4xx/5xx and zero page errors; deep API checks (CQ derivation + history, class rollup with median CQ 498, net-worth delta truth, single loan ledger row, GM rewind rejection, forward jump, week-104 completion, leaderboard GET) all pass on the production server.

Build 22 — 15 Aug 2026 (Polish: city art + social metadata)

**Why:** make the app feel finished — real visual depth and shareable pages.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **City scene:** the placeholder backdrop is replaced with a layered dusk-city illustration (skyline, warm lit windows, road with street lamps) that stays crisp at any size and keeps the hotspot layer readable. - **Social metadata:** Open Graph + Twitter cards with a branded 1200×630 image, apple-touch icon, theme colour, `robots.txt` (game/city routes excluded from indexing) and a sitemap. - **Verification:** lint/typecheck/build/all suites/E2E green; the full live tour (landing, onboarding, every screen, city, mobile, challenge leaderboard, user world) shows zero errors.

Build 21 — 15 Aug 2026 (Balance pass)

**Why:** loans should read as an expensive lesson, not a hidden trap; the fresh-start calibration is confirmed.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Loan APR tuned:** weekly interest margin 150bp → 100bp. Effective APR drops from ~126% to ~75% (normal economy); a $250 loan now costs ~$283 back instead of ~$303 — still clearly expensive, no longer trap-like. - **Fresh-start CQ confirmed:** a brand-new retail worker still lands at CQ 498 (Stable) after all Batch 1–10 engine changes — no recalibration needed. - **Band labels confirmed:** canonical Ruined → Mogul remains the in-game catalog (the site's "Strong" placeholder is still pending the CQ-8 sync). - **Verification:** loan disclosure test updated to the tuned range (APR 50–100%); all suites + E2E green, build clean.

Build 20 — 15 Aug 2026 (App rebrand to MoneyCQ)

**Why:** the game's own surfaces should carry the product name.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- Landing page brand: **MoneyCQ** with the "What's your CQ?" tagline. - In-game topbar: **MoneyCQ** (world name alongside). - Browser metadata: title "MoneyCQ — What's your CQ?" and a CQ-focused description; styleguide header and README title updated. - The WordPress marketing site is a separate sync (CQ-8, pending site access).

Build 19 — 15 Aug 2026 (Hotfix: secondary screens after partial state)

**Why:** Batch 10's home-partial state broke the Money/Business/Market/ Property screens — their client panels read fields the partial response omits, crashing with a client-side exception.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- New `GET /api/worlds/[worldId]/state` returns the FULL snapshot; the interactive screen components (`MoneyServices`, `BusinessManager`, `MarketTrading`, `MarketExtra`, `PropertyManager`) now request it, while the home page keeps the cheaper partial state. - E2E now visits money/market/property screens and asserts zero client errors (10/10).

Build 18 — 15 Aug 2026 (Batch 10 — QA and performance infrastructure)

**Why:** regressions should be caught by a machine, not a human refresh.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **E2E smoke suite** (`tests/e2e/smoke.mjs`, `npm run test:e2e`): onboarding, business→hire→profit, the net-worth-delta regression, SET_WEEK rewind rejection, week-104 completion, challenge leaderboards, 390px overflow, and zero 4xx/5xx + zero page errors on load. 9/9 passing. - **Lint + typecheck + CI:** `npm run lint` (ESLint 8 + eslint-config-next 15, two pre-existing issues fixed), `npm run typecheck`, and a GitHub Actions workflow running lint → typecheck → build → test → e2e (with Chromium). `npm run verify` chains the whole gate locally. - **Performance:** per-world state snapshot cache with invalidation on every write path (commands, GM actions, week rolls, ledger posts, and the exported mutators); partial "home" state that skips policies/claims/auctions/ marketplace/legal/disasters and property cashflow entirely (home payload ~8% smaller on a typical world, policies/auctions absent); ledger and notification indexes (migration 0019, SQLite + Postgres). - **Verification:** the full CI chain passes locally; the E2E suite covers the Batch 1 (net-worth delta), Batch 2 (SET_WEEK rewind), and Batch 3 (zero 4xx/5xx) regressions.

Build 17 — 15 Aug 2026 (Batch 9 — failure states and the difficulty curve)

**Why:** a player should never sit at −$86,700 forever — bad play should end in an educational failure — and rewards/wages should be honest and visible.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Overdraft consequence ladder:** fees escalate with depth ($35 → $100 → $250/wk); 25% of weekly gross income is garnished while overdrawn (`GARNISHMENT` ledger type); a derived credit rating (0–100) drops with overdrafts/loan defaults and recovers in clean weeks, and loan rates scale with it (visible as "Credit" on the Money screen); deep overdraft (−$1,000+) for four consecutive weeks ends the life in **BANKRUPT** with a final CQ score and an educational notification. - **Meaningful missions:** cash rewards scaled to goals (emergency-fund missions now pay 10%), reputation rewards added (`rewardReputation`), and previews show XP/cash/reputation on the mission card and panel. - **Predictable NPC wages:** the expectation spread tightened to $15–$30/hr, the hiring board shows each candidate's fair range (expectation ±10%), and declined offers explain the exact gap ("declined your offer of $X — they expect at least $Y"). A fair offer always succeeds. - **Verification:** `tests/content.test.ts` 9–11 (ladder → bankruptcy with a final score, escalated fees + garnishment + credit damage, scaled mission rewards, tightened NPC spread + fair-range + gap explanation); all suites green, build clean.

Build 16 — 15 Aug 2026 (Batch 8 — leaderboard and API contracts)

**Why:** challenge boards should show real rows, and command responses should return the IDs they create.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Real leaderboard endpoint:** `GET /api/worlds/[worldId]/leaderboard` returns derived rows (CQ primary, net worth secondary) for the world's challenge. `LeaderboardCard` now fetches it with a single GET — the per-page-load GM POST is gone, and challenge boards show actual challengers. - **Entity IDs from the command route:** every creating/mutating player command now returns `result.data` IDs — `assetId`, `propertyId`, `policyId`, `contractId`, `auctionId`, `offerId`, `tradeId`, `claimId`, `locationId` — matching what the GM route already returned. - **Verification:** headless-browser pass — two challenge worlds render real rows (no "No challengers yet"), the network shows a single GET with no LEADERBOARD POST, and purchases return IDs in the same response. All previous gate walkthroughs still pass.

Build 15 — 15 Aug 2026 (Batch 7 — unlock the engine behind the UI)

**Why:** everything the engine could already do should be reachable with a mouse, not a console.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Business chooser:** `START_BUSINESS` accepts a `businessKey`; setup and the Business screen present all five ventures. - **Trading screen:** live prices, buy/sell with quantity, holdings with derived P/L. - **Property manager:** purchase form with an engine mortgage calculator (`GET /api/worlds/[worldId]/mortgage-quote`) and sell actions. - **Money services:** insurance broker (products, eligible entities, policies, claims), assets store (buy/sell), NPC hiring board. - **Market extra:** auctions (create/bid) and the class marketplace (list/purchase). - **World management:** rename, archive, and delete on the landing page, plus sorting by week/status and challenge creation. - **GM quick actions:** "Give $1,000" and "Trigger severe storm" (disaster gate). - **Verification:** `tests/content.test.ts` covers the business chooser, world management cascade-delete, and the mortgage quote; a headless-browser walkthrough completed all four handoff gates through the UI alone and confirmed 8/8 nav targets return 200 with zero page errors.

Build 14 — 15 Aug 2026 (Batch 6 — content and copy)

**Why:** no event reruns within weeks of itself, copy that matches the real game length, and borrow buttons that disclose the true cost.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Per-event cooldowns:** random events respect an 8-week default cooldown (`cooldownWeeks`, data-driven); wedding and promotion are `oncePerLife`. GM `TRIGGER_EVENT` remains a deliberate override and bypasses the filter. Verified by a seeded 60-week run with no event repeating within 8 weeks. - **Copy:** landing page, README, and onboarding now say "two years (104 weeks)" instead of "twelve weeks". - **Loan disclosure:** the snapshot exposes `content.loanRules.weeklyInterestBp`, `aprPct` (effective annual rate), and per-amount `examples` (payment, total repayment, weeks) computed by the same amortisation rules the engine uses. Borrow buttons now read e.g. "Borrow $250 · ~104% APR · back ~$295". - **Verification:** `tests/content.test.ts` (cooldowns, once-per-life, seeded long-run, copy consistency, disclosure honesty); all six suites green, build clean.

Build 13 — 15 Aug 2026 (Batch 5 — dashboards must not misrepresent state)

**Why:** screens should show the state as it is — no phantom debts, no fake pay, no anonymous grants.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Active-only dashboards:** `liabilities`, `policies`, and `claims` in the snapshot now contain only live state; paid-off liabilities, expired policies, and denied claims move to `liabilitiesHistory`/`policiesHistory`/ `claimsHistory`. The Money screen shows a clearly labelled "History" section for them instead of listing them as current debt. - **Career effective pay:** the snapshot exposes `effectiveWeeklyPayCents` (base × economy factor × reputation factor), and the Career page shows Base pay + Effective pay — the number that actually lands in the salary ledger. - **Accurate grants:** GM grant notifications now name the target account ("Game Master granted $500.00 to SAVINGS" / "... to EVERYDAY"). - **Verification:** new money tests (6–8) cover history filtering, pay-ledger parity under a weak economy, and account-named notifications; all suites green, build clean.

Build 12 — 15 Aug 2026 (Batch 4 — mobile and layout hardening)

**Why:** no horizontal overflow on phones, honest wages, and one keyboard-accessible decision surface at a time.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **Tool dock wraps** on narrow screens (`flex-wrap`, centered, capped width) — the 559px dock no longer pushes a 375px viewport sideways. - **Hire wage is derived:** the engine now exposes the economy-adjusted hourly wage (`content.business.hiredWageCents`), and the hire button renders it instead of the hardcoded "$18/hr". - **One decision surface:** a pending event renders only in the modal — the GM rail and drawer hide their copies while it's open. The modal is a proper dialog (`role="dialog"`, `aria-modal`, labelled/described), traps Tab focus, restores focus on close, and handles Escape (decisions are mandatory). - **Verification:** headless-browser pass at 375/430/480px — zero horizontal overflow, real wage on the button, one event title on the page, focus stays inside the dialog through Tab and Escape.

Build 11 — 15 Aug 2026 (Batch 3 — city routing, art, and error states)

**Why:** kill the asset/route collision and the 404 noise, and give bad city IDs the styled error card.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **City art moved** out of `/city/*` to `/city-assets/base.svg` — it no longer routes into the `/city/[worldId]` page (the old source of the 500); the PNG attempt was dropped so there is no fallback 404 either. - **Real art shipped:** 8 navigation icons (`/icons/*.svg`), a player avatar (`/avatar/player.svg`, monogram fallback retained), and a favicon (`app/icon.svg`). Zero 4xx/5xx on real page loads. - **Styled error state:** `/city/<bad-id>` now renders the shared "World not found" card (same as the game layout) with a proper 404 status. - **Verification:** headless-browser pass — game page loads 8 icons and 10 hotspots with zero bad responses/page errors; city page renders; bad city ID shows the styled card at 404.

Build 10 — 15 Aug 2026 (Batch 2 — time controls and the end of life)

**Why:** the clock must never run ahead of its own ledger, and a life should end cleanly at week 104.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **SET_WEEK is forward-only:** targets below the current week are rejected (rewinds would re-process weeks and double-post salary/food). Forward jumps run every week through the real weekly pipeline (advanceWeek) inside a capped, transactional loop — the clock is never ahead of its ledger, economy history, or CQ snapshots. The SET_WEEK notification is stamped with the target week. - **End of life:** week 104 is processed normally, then the world is set to COMPLETED and the "your story comes to a close" notification is written — no failed 105th advance. - **Verification:** new `tests/time.test.ts` (contiguous ledger + economy history after a jump, exactly one salary row per week, target-week notification stamping, 103 → 104 COMPLETED); all suites green, build clean.

Build 9 — 15 Aug 2026 (Batch 1 — money reporting tells the truth)

**Why:** the reported numbers should never disagree with the real state.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026).

What changed

- **One shared net-worth formula** (`netWorthFromParts` + `computeNetWorthCents`): cash + savings + business + assets + property + investments − loans − liabilities, used by `advanceWeek` (before/after), `getState`, the weekly summary, and CQ derivation. Buying a $20k van can no longer narrate a +$20k net-worth jump. - **Week attribution:** every successful command (and GM action) re-snapshots the current week's net-worth history, so grants, purchases, and event choices land in the week they happened — not the next week's summary. - **Loan rows:** the loan's liability leg gets its own `LOAN_LIABILITY` ledger type ("Loan liability") and is hidden from the money log; the cash leg shows once per loan. Both legs still recorded for audit. - **Financial freedom:** counts only genuinely passive income (savings interest + property rents); an owner-run business is work, not passive. - **Weekly summary completed:** new categories — Game Master, Fines, Insurance payouts, Dividends, Property, Assets, Other — signed from the player's cash direction; the categories sum to the week's real cash delta (verified by ledger). - **Verification:** new `tests/money.test.ts` (net-worth truth, week attribution, single loan row, passive-only freedom, summary-sums-to-ledger); all suites green, build clean.

Build 8 — 15 Aug 2026 (CQ — Build CQ-D: brand & launch)

**Why:** bring the MoneyCQ brand in line with the shipped game and walk the release gates.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). Build CQ-D complete; full playable-gate demo run. moneycq.com WordPress copy sync awaits site access (prepared checklist + screenshots); defensive domain registrations await CEO decision.

What changed

- **Brand sync (prepared):** moneycq.com currently says "MoneyCQ is coming/development", uses the placeholder "Strong" band label, and lacks the 0–1000 scale, canonical Ruined → Mogul bands, and month-delta language. Replacement copy + screenshots prepared for the WordPress site (site access required to apply). - **Defensive domains:** re-verified all 8 backups AVAILABLE on 15 Aug 2026 (cqhero, cqsims, cqville, cqtown, cqfactor, cqtrack, cashcq, getcashq). - **Playable-gate demo:** full end-to-end walk (business→hire→profit, asset→insure→disaster→claim, mortgage→property→rent→sell, invest→recession→respond) with CQ reacting throughout (bands, perks, missions, leaderboard); screenshots captured.

Build 7 — 15 Aug 2026 (CQ — Build CQ-D: production hardening)

**Why:** harden CQ for production: dedicated derived APIs, concurrency-safe rollover, and documented bounded-cost behaviour.

**Status:** API + guard live at https://app.moneycq.com (15 Aug 2026). The live Supabase/Postgres RLS verification pass remains blocked on infrastructure (see `docs/PRODUCTION_PERSISTENCE.md`).

What changed

- **CQ API:** `GET /api/worlds/[worldId]/cq` (live CQ + weekly timeline with top movers) and `GET /api/worlds/[worldId]/cq/class` (derived class rollup: averages, distribution, pillar means) — both auth-guarded and purely derived. Timeline/rollup logic extracted for reuse by the GM console. - **Concurrency:** week rollover now updates the world with an optimistic `WHERE week = <read value>` guard, so a concurrent advance fails cleanly instead of losing an update; weekly snapshots upsert via unique keys. - **Bounded cost:** 52-week history windows, weekly snapshots, 104-week timeline cap — documented in `PRODUCTION_PERSISTENCE.md` and the spec. - **Verification:** full suite green (29 CQ groups), build clean; new routes exercised in the production build.

Build 6 — 15 Aug 2026 (CQ — Build CQ-C: content pack + classroom safety)

**Why:** make every CQ factor playable through shipped events and enforce classroom safety on abstract risk content, per the locked spec.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). **Build CQ-C complete.** Build CQ-D (production hardening + brand/launch) remains.

What changed

- **Event pack (one event per factor):** Shopping Spree → spending habits, Savings Match Day → saving discipline (+ resilience), Loan Payment Trouble → debt management, Market Opportunity → investment behaviour, Insurance Agent Visit → risk tolerance, Hailstorm Damage → resilience/risk, Health Kick → lifestyle choices; promotion already covered income streams. Three new effect types: `SAVINGS`, `INVEST`, `PURCHASE_POLICY` (all through engine paths; events change state, never CQ). - **Classroom safety:** abstract risk events (A Night at the Tables, The Crypto Craze) are consequence-focused and OFF by default in classroom worlds (`classroomMode`), teacher-enabled via GM `CQ_SET_CONFIG` (`riskCategoriesEnabled`); random selection and GM triggering both enforce the gate. Content reviewed against `features.txt` §36–39 (abstract, no operational detail). - **Verification:** tests 27–28 (each factor moved by its shipped event, classroom gate + teacher re-enable); full suite green, build clean.

Build 5 — 15 Aug 2026 (CQ — Build CQ-C: bands & perks)

**Why:** make the 9-band catalog live identity with derived, exactly-once, audited perk effects — no free money, per the locked spec.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). Perk catalog is PROPOSED and awaiting CEO sign-off (`CASH_QUOTIENT.md` §16); CQ-6 (content pack + classroom safety gate) remains.

What changed

- **Band crossings:** band-up/band-down events notify the life feed (and toast in-session) and record APPLY/REMOVE exactly once per perk threshold in `band_perk_applications` (migration 0018, SQLite + Postgres/RLS). - **Derived perk effects** (never grants, applied through engine paths): Preferred Rates (loan margin −20bp at band 6), Savings Boost (×1.2 at 6), Steady Hand (negative-event odds ×0.85 at 7), Harder Path (mission XP ×1.25 at 7), Mogul Touch (−40bp / ×1.3 at 9). Band-down removes perks because effects derive from the current band. - **UI:** perk badges on the player card; GM console shows active perks and the audited application history. - **Verification:** tests 22–26 (catalog boundaries, exactly-once application, loan-rate effect, band-down removal, GM views); full suite green, build clean.

Build 4 — 15 Aug 2026 (CQ — Build CQ-B: player UI + GM console)

**Why:** let players and teachers see CQ everywhere it matters, per the locked spec (`docs/CASH_QUOTIENT.md`) and integration plan.

**Status:** deployed live at https://app.moneycq.com (15 Aug 2026). Build CQ-C (bands/perks, content pack + classroom safety) remains.

What changed

- **CQ-3 — Player UI:** CQ card on the player profile (score, band, month delta, 4 pillar mini-bars); weekly summary "what moved CQ" section driven by derived factor deltas (`StateSnapshot.cq.factorDeltas`); city-viewport CQ chip; CQ mission targets (`cqTarget` metadata); CQ impact hints on event choices (modal + GM rail). Contract v1.3. - **CQ-4 — GM console + class analytics:** audited GM actions `CQ_VIEW`, `CQ_CLASS_ANALYTICS`, `CQ_SET_CONFIG` (weights, band labels, classroom/risk toggles, history windows — validated), and `CQ_RESET` (recompute from state). GM screen "CQ console" panel: breakdown with factor drill-down, "what moved CQ" timeline, class averages/distribution/pillar averages, and teacher config. - **Fixes:** `/city/[worldId]` now returns a proper 404 for unknown worlds (was a 500). GM grant cap respected in tests. Audit pass: disabled CQ remains re-enableable from the GM console, string booleans coerce safely in `CQ_SET_CONFIG`, and CQ surfaces are hidden until week 1. - **Verification:** `tests/cq.test.ts` grows to 20 groups (view/analytics/ config/reset all audited); `npm test` green across all suites; production build clean; headless-browser audits (fresh + tycoon worlds, player and GM screens at 1440/1366/1024px) show zero overflow and no page errors.

Build 3 — 14 Aug 2026 (CQ — Cash Quotient, Build CQ-A)

**Why:** introduce MoneyCQ's primary financial-health metric as a derived, deterministic engine feature, per the locked spec (`docs/CASH_QUOTIENT.md`).

**Status:** deployed live at https://app.moneycq.com (14 Aug 2026). Player/GM CQ UI surfaces remain in Build CQ-B; production persistence (Phases 17/18) still awaits live infrastructure.

What changed

- **CQ-0 — Canon + data contract:** `CqScore`/`CqPillar`/`CqFactor`/`CqBand`/ `CqSnapshot`/`CqConfig` types in `lib/cq.ts`; `CqSnapshotRow` + `WorldConfigRow` in `lib/schema.ts`; migration 0017 (`cq_snapshots` + `world_config`, SQLite + Postgres/RLS); per-world config defaults seeded at creation; `CqState` DTO in `docs/DOMAIN_UI_CONTRACT.md` (v1.2). - **CQ-1 — Derivation engine:** pure `computeCq(state, history)` with 8 factor scorers (income streams, spending habits, saving discipline, debt management, investment behaviour, risk tolerance, financial resilience, lifestyle choices), 4-pillar aggregation, 9-tier data-driven bands (Ruined → Mogul), bounded 52-week history windows, idempotent weekly snapshotting at week rollover, month delta vs the 4-week-earlier snapshot. - **CQ-2 — Engine integration:** events move state only (choice buttons carry derived CQ impact hints from projected state); economy wired into scorers (inflation → spending baselines, employment → income stability, base rates → debt health, market environment → investment behaviour); CQ missions (`cq_band_6`, `cq_factor_raise_10`); leaderboard sorts by CQ first, net worth second; XP-vs-CQ split explained in player-facing landing help. - **Verification:** `tests/cq.test.ts` (13 groups: bounds, determinism, direction per factor, idempotency, isolation, delta, leaderboard, missions, event auditing, economy wiring, GM VIEW_STATE); `npm test` green across all suites; production build clean; live smoke tests passed.

Build 2 — 13 Aug 2026 (Phases 13–14, 16–24, working tree)

**Why:** turn the Build 1 vertical slice into a deep financial-life strategy game: economy, tools, hiring, wealth, risk, markets and production foundations — each phase gated by tests and a clean build before the next.

**Status:** this entry records the implemented working-tree work shipped in one change cycle. Remaining gates (still open): GUI milestone passes A–N, QA sign-off, and live production verification for Phases 17/18 (requires a Supabase/PostgreSQL project). All Dev phases for Build 2A and the Build 2B wealth/risk group (21–26) are done; their playable gates are testable end-to-end.

What changed

- **Phase 13 — Economy V0:** per-world economy state (inflation, employment strength, consumer demand, base interest rate) with bounds validation; business revenue × demand, economy-driven loan/savings rates, employment-market pay factors, inflation-indexed living costs. - **Phase 14 — GM Console V0:** `runGmCommand` + `POST/GET /api/worlds/[worldId]/gm`; ADVANCE_WEEK, GIVE_MONEY, ADD_EXPENSE, CHANGE_JOB, SET_FATIGUE, TRIGGER_EVENT, RESET_EVENT, VIEW_STATE; every action audited in `gm_actions`; ledger-backed grants/expenses. - **Phase 15 — NPC Employees:** deterministic per-world candidate pool (`npcs` table, migration 0007); hire through the contract framework (accept at/above expected wage); skills scale labour; managers add bonus labour and buy back owner time; deterministic morale/raise/resignation employee events. - **Phase 16 — Employment Contract Framework:** generic contracts (`employee_type = NPC | PLAYER`) with a strict lifecycle, overlap prevention, exactly-once payroll, and labour-supply integration. - **Phase 17 — Production Persistence (foundation):** versioned migrations (`lib/migrations.ts`, `migrations/sqlite`, `migrations/postgres` with RLS); Supabase-compatible JWT auth gating API routes in supabase mode; world membership with OWNER/MEMBER roles; `withTransaction` around world creation and the weekly pipeline; UUID v4 production ids. Live provisioning + async data-layer conversion remain. - **Phase 18 — Multiplayer Hiring (mechanics):** `addPlayerToWorld`/`listPlayers`; player payroll routed into the employee's own account; player contract commands; serialized acceptance. Presence/invitations await Phase 17 infra. - **Phase 19 — Generic Assets + Debt:** `assets` + `liabilities` tables; derived asset values; exactly-once maintenance and liability interest/repayment; richer statements (net worth includes assets and debt). - **Phase 20 — Insurance Core:** data-driven products; `policies` + `claims`; exactly-once premiums; claim engine with no-double-payout and min(loss, limit) − deductible payouts; timing/eligibility enforcement. - **Phase 21 — Disasters V1:** deterministic, severity-based disaster damage; exactly-once resolution; insurance interaction (paid claims repair, uninsured losses stay damaged); business interruption with correct duration; GM disaster controls. - **Phase 22 — Property:** HOME/INVESTMENT/RENTAL ownership; mortgages as Phase 19 liabilities; rent + maintenance exactly once per week; derived market value; atomic sales with mortgage settlement; ledger-derived cashflow. - **Phase 23 — Property Insurance Extension:** Homeowners/Contents/Landlord products, property-specific risks, subtype eligibility, policies bound to their property — no insurance-core rebuild. - **Phase 24 — Auctions:** `auctions` + `auction_bids`; validated bidding, exactly one winner, atomic settlement for property/business, weekly auto-close. - **Phase 25 — Investment Market:** five data-driven instruments; seeded deterministic prices scaled by market environment; idempotent portfolio trades (refId), weighted-average cost, derived gains/losses; net worth + snapshot integration. - **Phase 26 — Economy V1:** market/property/business environments on the per-world economy row; deterministic, audited weekly drift (`economy_history`); business, property, market, salaries, expenses and rates all respond to the same economy state; GM `SET_ECONOMY` for scenarios like recessions. - **Phase 27 — External Market Adapter (ahead of schedule):** `MarketDataProvider` abstraction (internal deterministic + external REST providers); `market_snapshots` (migration 0009) so domain reads are snapshot-or-internal with no live-provider dependency; no real money — trades remain simulated; GM `SNAPSHOT_MARKET`. - **Phase 28 — GM Console V1 (ahead of schedule):** scheduled events (SCHEDULE_EVENT / CANCEL_SCHEDULED_EVENT), bounded reversible time control (SET_WEEK), mission controls (COMPLETE_MISSION), WORLD_OVERVIEW and CLASS_ANALYTICS — all audited, world-scoped, engine-validated. - **Phase 29 — Hybrid AI Game Master (ahead of schedule):** AI proposes / teacher approves (with edits) or rejects; proposals stored in `ai_proposals` (migration 0010) and applied only through engine paths; rule-based deterministic provider + optional LLM provider (fallback); fully audited. - **Phase 30 — Legal + Reputation (ahead of schedule):** reputation derived from audited `reputation_history` (migration 0011); abstract legal dilemma events + investigations; legal rulings with exactly-once fines; fixed- duration imprisonment while mortgages/loans/expenses keep processing; reputation-based pay restrictions; GM LEGAL_RULING / LIST_LEGAL. - **Phase 31 — Advanced Businesses (ahead of schedule):** share-based ownership (`business_shares`, total always 100), exactly-once pro-rata dividends from available profit, atomic acquisitions (100% share transfer), and `business_locations` as distinct entities with their own financials (migration 0012); commands + GM actions TRANSFER_SHARES / OPEN_LOCATION. - **Phase 32 — Class Marketplace (ahead of schedule):** per-world permitted-trade rules, offer listings, atomic + idempotent purchases (refId) with exactly-once service delivery/charge (migration 0013); commands + GM actions LIST_OFFER / CANCEL_OFFER / PURCHASE_OFFER / SET_MARKET_RULES / LIST_MARKET_OFFERS. - **Phase 33 — Shared City (ahead of schedule):** derived visual city state (`lib/city.ts`) from the authoritative engine snapshot — homes, businesses + locations, vehicles/assets, workers, damage and interruption statuses; per-world isolation; always consistent with the simulation; `GET /api/worlds/[worldId]/city`, `/city/[worldId]` page, GM CITY_VIEW. - **Phase 34 — Historical Worlds (ahead of schedule):** data-driven scenarios (Great Recession 2008, Tech Boom 1999) with packaged economy configuration + fixed price history; immutable `historical_prices` snapshots (migration 0014); deterministic replay; price lookups clamped to the current week (no future prices); `createHistoricalWorld` + `POST /api/worlds` (`scenarioKey`). - **Phase 35 — Public Challenges & Seasons (ahead of schedule, final roadmap phase):** standardized challenge worlds (identical starting cash + economy), derived leaderboards from authoritative net worth, seasons with atomic audited resets (migration 0015); GM actions LEADERBOARD / SEASON_RESET / LIST_CHALLENGES / LIST_SEASONS. - **GUI milestone A–D + Phase O:** persistent game shell with top metrics bar and left navigation (`GameShell` + game layout), plus the Money, Career, Business, Property, Market, and World/GM secondary screens — all rendered from the authoritative state snapshot, with a quick audited GM action panel. - **GUI milestone E–H:** City V1 viewport (drop-in art base + ten hotspots with real-state overlays), player profile + time card, GM decision panel, and weekly summary / mission / leaderboard cards — powered by a new `net_worth_history` table and a ledger-derived `weeklySummary` in the state snapshot (migration 0016). - **GUI milestone I–J:** floating economy widget with a real inflation sparkline (`economyHistory` in the snapshot), a rotating world ticker from real state (prefers-reduced-motion aware), and a bottom tool dock with real badge counts. - **Standing requirement §5.1:** the app now displays the live version (`v2`) in the top-right of every page, matching the `VERSION` file.

Who did it

Project Manager-led implementation of the Build 2A/2B phase plan, with worker ownership per the master plan (Worker 1 engine/data, Worker 3 content, Worker 5 QA). Bookkeeping compiled by the PM from phase reports; approved by the CEO (13 Aug 2026).

How to verify

- `npm test` — all simulation + persistence tests pass (sections 8e–8j, 9a–9h, 10a–10i, 11a–11e, 12a–12i, 13a–13h, 14a–14f, 15a–15h, 16a–16f, 17a–17i, plus migration/auth/membership/transaction/id tests). - `npm run build` — production build compiles clean. - Run the app (`npm start`); `v2` is visible in the top-right corner. Use the GM console at `/api/worlds/[worldId]/gm` to trigger events, disasters and auctions; verify economy-driven revenue, insurance payouts, property rent, and auction settlement against the ledger.

Shipped files (primary)

`lib/engine.ts`, `lib/schema.ts`, `lib/db.ts`, `lib/content.ts`, `lib/migrations.ts`, `lib/auth.ts`, `lib/config.ts`, `lib/transactions.ts`, `lib/ids.ts`, `lib/http.ts`, `lib/narrator.ts`, `app/api/*`, `app/layout.tsx`, `components/VersionBadge.tsx`, `migrations/sqlite/*`, `migrations/postgres/*`, `tests/simulation.test.ts`, `tests/persistence.test.ts`, `docs/*`, `README.md`.


Build 1 — 13 Aug 2026 (Phases 0–1, COMPLETE)

**Why:** establish the foundation (Phase 0) and prove the core loop with a playable vertical slice (Phase 1) before any feature expansion begins.

What changed

- **Project foundation:** Next.js 15 + strict TypeScript + SQLite persistence, npm scripts for dev/build/start/test, and a production build that compiles. - **Simulation engine** (`lib/engine.ts`): persistent worlds and players; an immutable money ledger with integer minor units (balances are derived from ledger entries, never mutated in place); deterministic seeded randomness per world and week; a weekly processing pipeline covering salary, business revenue/expenses/wages/profit draw, rent, food, transport, subscriptions, loan interest and repayments, savings interest, fatigue/health, burnout, events, missions, XP/levels and overdraft fees; audited commands (choose job/housing, transfers, savings goals, start/hire/fire business, loans, advance week, event choices). - **Persistence** (`lib/schema.ts`, `lib/db.ts`): SQLite schema with worlds, players, accounts, ledger, employment, housing, businesses, loans, goals, events, mission progress, notifications and command log. - **Data-driven content** (`lib/content.ts`): three jobs, three housing options, weekly expenses, a side business with worker hiring, loan rules, twelve life events with choices and delayed consequences, nine missions and an XP/level curve. - **Supporting modules:** seeded RNG (`lib/rng.ts`), integer money formatting (`lib/money.ts`), and the weekly Game Master narrator (`lib/narrator.ts`). - **API:** world creation/listing, full state snapshots, and a single command endpoint (`app/api/`). - **GUI:** landing page with life creation and world list; the game dashboard (life setup, resource metrics, missions, actions, savings goals, loans, business management, life feed, money log, event choice modal); a styleguide route (`/styleguide`). - **GUI design system (build guide Prompt 1):** design tokens and thirteen reusable primitives in `components/ui/` (cards, metrics, progress, circular meter, buttons, choices, chips, tooltips, skeletons) with hover, focus, disabled, loading and reduced-motion states. - **Tests** (`tests/simulation.test.ts`): automated 12-week simulation runs covering determinism, ledger integrity, single-payroll-per-week, savings missions, overwork fatigue and burnout mechanics.

Who did it

Project Manager-led build (pre-charter), with the GUI design system delivered as the first pass of the build guide's Prompt sequence.

How to verify

- `npm test` — all simulation tests pass. - `npm run build` — production build compiles clean. - Run the app (`npm start`), create a life, choose a job and housing, and advance weeks; verify money, fatigue, events, missions and the ledger all update. `/styleguide` shows the design system.

Shipped files (primary)

`lib/engine.ts`, `lib/schema.ts`, `lib/db.ts`, `lib/content.ts`, `lib/rng.ts`, `lib/money.ts`, `lib/narrator.ts`, `app/api/*`, `app/page.tsx`, `app/game/[worldId]/page.tsx`, `app/styleguide/page.tsx`, `components/ui/*`, `tests/simulation.test.ts`, `README.md`.

v77 · ChangelogChangelog | MoneyCQ