diff --git a/docs/handover-game-dev.md b/docs/handover-game-dev.md index 0e13e85..e890704 100644 --- a/docs/handover-game-dev.md +++ b/docs/handover-game-dev.md @@ -9,8 +9,8 @@ You are the game development assistant. You design and build the OTIVM browser game at `otium.civicus.us`. You work in Claude chat (claude.ai), -produce one file at a time as a downloadable attachment, and Claude Code -on the container commits and pushes. +produce one file at a time as a downloadable attachment, and the human +commits and pushes from the otivm shell. You do not touch pipeline scripts, SQL schema, or TESSERA extraction code. That work belongs to the dataset assistant (see `docs/handover-dataset.md`). @@ -19,13 +19,19 @@ You share the OTIVM Gitea repo but work on different files. The game is live. The server is running. Every change you make is visible to real users within seconds of `pm2 restart otivm`. +**Workflow — files you produce go to the human, not Claude Code.** +Claude Code is expensive. The human writes files to disk directly from +the otivm shell and runs git commands copy-pasted from chat. Always +provide the exact git commands in chat, ready to copy-paste. Never +require manual editing or renaming. + --- ## 1. Read these files before writing any code In order: -1. `CLAUDE.md` — workflow, three-shell model, ground rules, deployment facts +1. `CLAUDE.md` — workflow, ground rules, deployment facts 2. `docs/architecture/infrastructure.md` — container topology, API protocol 3. `docs/architecture/terminology.md` — three-layer vocabulary, naming convention 4. `docs/architecture/latin-bridge.md` — Latin terms, admission standard, semantic entries @@ -35,8 +41,9 @@ In order: 8. `docs/scenarios/SCENARIO-MERCHANT-0000.md` — the BALNEA prologue, background selection 9. `docs/scenarios/SCENARIO-MERCHANT-0001.md` through `0003.md` — the founding trilogy 10. `docs/cities/CITY-OSTIA-0001.md` — Ostia as pressure field, not backdrop -11. `docs/roadmap.md` — where the game is going -12. This file +11. `docs/Roadmap-OTIVM-IV.md` — OTIVM-IV scope and file inventory (approved) +12. `docs/roadmap.md` — where the game is going +13. This file The parameter registry is the bridge between the design documents and the schema. Read it before touching any database code. @@ -48,7 +55,6 @@ schema. Read it before touching any database code. ### OTIVM container (otivm-dev, CT 1105) - App user: `otivm` - Repo at `/home/otivm/OTIVM` -- Claude Code runs here as `otivm` user via `work` alias (`cd ~/OTIVM && claude`) - Python venv: `/home/otivm/venv` - Pipeline venv: `/home/otivm/pipeline-venv` - PM2 home: `/home/otivm/.pm2` @@ -57,9 +63,6 @@ schema. Read it before touching any database code. - WireGuard: 10.110.0.18 ### Five containers on srv-a (10.0.0.11) -See `docs/architecture/infrastructure.md` for the full topology. -The architecture is settled: REST over HTTPS on the WireGuard mesh, -one write domain per container, no shared filesystems between containers. | CT | Role | |---|---| @@ -70,13 +73,13 @@ one write domain per container, no shared filesystems between containers. | 1105 | otivm-dev (this container) | ### Nginx proxy -- Lives on wg-pk (198.58.111.109) — not on this container +- Lives on wg-pk (198.58.111.109) - Proxies `otium.civicus.us` → `10.110.0.18:3000` ### Gitea - Repo: `https://gitea.barternetwork.us/TheRON/OTIVM` -- Branch: `main` (direct push, Claude Code handles this) -- MCP: connected via `mcp.civicus.us` — Claude chat reads any file directly +- Branch: `main` (direct push) +- MCP: connected via `mcp.civicus.us` ### Git protocol — mandatory, non-negotiable Before touching any file: @@ -91,11 +94,10 @@ git commit -m "scope: description" git push origin main ``` NEVER: `--rebase`, `--force`, `git stash`, `git reset --hard`, `git add .` -NEVER: commit without fetching and merging first. ### Backups - Command: `vzdump 1105 --compress zstd --storage local --mode snapshot` on srv-a (root shell) -- Document every backup in `docs/archives.md` immediately after — see existing entries for format +- Document every backup in `docs/archives.md` immediately after - Download each dump to workstation cold storage - Never take a backup without documenting it. Never document one not taken. @@ -104,18 +106,42 @@ NEVER: commit without fetching and merging first. ## 3. Stack - React 19 + Vite 8 frontend (`src/`) -- Fastify backend (`server/index.js`) — serves `dist/`, save API, TESSERA map endpoint -- `data/otivm.sqlite3` — TESSERA physical data, read-only by game server (`better-sqlite3`) +- Fastify backend (`server/index.js`) +- Bootstrap 5.3.3 (vendored, MIT, pinned) — layout and components +- Bootstrap Icons 1.11.3 (vendored, MIT, pinned) +- `data/otivm.sqlite3` — TESSERA physical data, read-only (`better-sqlite3`) - `data/saves/` — per-player save files (gitignored) - OTIVM-I/II: `{token}.json` - OTIVM-III+: `{token}.sqlite3` (created from `data/create_player_db.sql`) - - Both formats coexist during migration. JSON files are never deleted. -- `data/create_otivm_db.sql` — TESSERA world schema (read-only reference) -- `data/create_player_db.sql` — per-player schema (schema version 5, committed at `b1de03f`) -- `data/repair_player_db_fk.sql` — repair script for pre-v5 player databases -- `better-sqlite3` installed — used by server for TESSERA queries and player databases + - Both formats coexist. JSON files are never deleted. +- `data/create_player_db.sql` — per-player schema (schema version 5) +- `data/repair_player_db_fk.sql` — repair script for pre-v5 databases - PM2 under `otivm` user (never root) -- Ecosystem file: `ecosystem.config.cjs` + +### Frontend file structure (OTIVM-IV) +``` +src/ + config/ + contexts.json ← dropdown definition + context-actor.json ← ACTOR layout and section config + context-forum.json ← FORUM layout and section config + context-map.json ← MAP layout and section config + components/ + Shell.jsx ← sidebar + dropdown + layout grid (built once) + Section.jsx ← generic panel renderer (built once) + ParameterRow.jsx ← one parameter row + CostRow.jsx ← one cost line + DriftEntry.jsx ← one drift log entry + screens/ + Actor.jsx ← ACTOR context screen + Forum.jsx ← FORUM context screen + Map.jsx ← MAP context (unchanged from OTIVM-II) + App.jsx ← Shell wired, three contexts + App.css ← project overrides only (Bootstrap handles layout) + constants.js ← routes, waypoints, BACKGROUNDS, MS_PER_SIM_DAY + gameState.js ← frontend game state logic + api.js ← save API calls +``` --- @@ -126,202 +152,162 @@ Five trade routes Ostia → Alexandria, journal, otium/negotium mechanic, per-player saves via 8-char hex token, 128 concurrent players supported. ### OTIVM-II — complete and live -**The map is live and rendering from real TESSERA data.** +Map live and rendering from real TESSERA data. Fog-of-war SVG, H7 land +cells at real geographic positions, progressive reveal by chapter. -- `src/screens/Map.jsx` — fog-of-war SVG map -- H7 land cells rendered at real geographic positions (lat/lon from API) -- Progressive reveal by chapter — only visited waypoints are visible -- Sea = permanent darkness — no data needed, no storage needed -- `/api/map/:h5/:epoch` endpoint — H7 land/sea classification with centroids -- Epoch parameterised — default `roman_14bce` (sl_offset_cm = -10) -- `data/otivm.sqlite3` — 12,005 H9 rows, five H5 waypoints, `paleo_epochs` table live -- Session lifecycle — `session_abandoned` event written on new game, old saves preserved -- `active_dispatch`, `events[]` in save state — sequencing substrate for future releases -- `galleyProgress()` utility in gameState.js -- Provenance fields on all routes (`origin_h3_r5`, `origin_region`, `cultural_note`) +### OTIVM-III — complete and live +Per-player SQLite live. Schema version 5. Background selection, parameter +seeding, ventures, venture_legs, parameter_drift_log all recording correctly. -### Architecture decisions locked in OTIVM-II -- H3 IDs on all waypoints — permanent, TESSERA-compatible -- Sea hexes are dark by definition — no data, no storage -- `session_abandoned` event — saves are never deleted, they receive a terminal event -- REST API for all inter-container data flows — no shared filesystems -- Per-player SQLite replacing JSON saves — schema committed, wiring is OTIVM-III +### OTIVM-IV — complete and live at `3700f5a` -### OTIVM-III — complete and live at `d1e1b98` +**The situation instrument is live.** -**The sub-trace is live. The behavioral record is real.** +Server startup message: `OTIVM server running on port 3000 — OTIVM-IV` -Current HEAD: `d1e1b98`. Server startup message: `OTIVM-III complete`. +**What was built:** -**What was built, in order:** +1. **Bootstrap 5.3.3 + Bootstrap Icons 1.11.3** — vendored, pinned. -1. **Schema** (`data/create_player_db.sql`) — schema version 5. Eight tables: - `actor_profile`, `actor_parameters`, `parameter_drift_log`, `ventures`, - `venture_legs`, `scenario_state`, `events`, `background_starting_values`. - Pre-seeded with 72 rows (12 parameters × 6 backgrounds). `UNIQUE(actor_id)` - on `actor_profile` — required for FK references from child tables. - `data/repair_player_db_fk.sql` provided for pre-v5 database repair. +2. **`App.css`** — reduced to project overrides. Roman palette as CSS custom + properties. All classes prefixed `otivm-`. -2. **Background selection** (`src/screens/Prologue.jsx`, `src/App.jsx`, - `src/constants.js`) — Prologue tab added as a third tab alongside Ledger - and Map. Player chooses one of six backgrounds before first dispatch. - `BACKGROUNDS` constant in `constants.js` — six entries with canonical IDs, - display names, Latin names, summaries, and starting den values. - `MS_PER_SIM_DAY = 3_000` defined in `constants.js` (1 simulated day = 3 - real seconds). `INITIAL_STATE.background_id = null` — gates the Prologue. +3. **Shell architecture** — `Shell.jsx` and `Section.jsx` built once. + Sidebar with context dropdown replaces tab navigation. Four layout types: + `single`, `two-col`, `three-col`, `map`. Nine panel types in Section.jsx. -3. **Backend wiring** (`server/index.js`) — per-player SQLite live. On new - player creation, seeds `actor_parameters` from `background_starting_values` - for the chosen background. Profile patch: if `actor_profile` has - `background_id = 'unknown'` and a subsequent POST arrives with a real - background, the profile is patched and parameters are seeded. JSON migration - retained per roadmap — JSON files are never deleted. +4. **Context JSON files** — four files in `src/config/`. Adding a new context + requires one JSON file + one thin screen file. No shell changes. -4. **Ventures and venture legs** — on `dispatch_start`, creates a `ventures` - row (`status='active'`) and a `venture_legs` row. Cost split applied: - `cost_vectura = 60%`, `cost_portoria = 25%`, `cost_other = 15%` — placeholder - pending a real cost model. `duration_days` stored as INTEGER (never REAL), - derived from `duration_ms / MS_PER_SIM_DAY`. On `dispatch_complete`, closes - both rows with `outcome_net` and `completed_at`. +5. **Sub-components** — `ParameterRow.jsx`, `CostRow.jsx`, `DriftEntry.jsx`. -5. **Parameter drift log** — `parameter_drift_log` writes on every parameter - change with correct trigger types: - - `dispatch_cost` — den decreases at dispatch start (cost deducted) - - `venture_complete` — den increases at dispatch return (profit received) - - `interval_complete` — auctoritas band changes after otium - No drift log entry fires during initial seeding (null-check guard). +6. **`Actor.jsx`** — background selection (when `background_id = null`) or + full parameter instrument view (three-col: identity/liquiditas, auctoritas + three faces/parameters, obligations/drift log). -**Known schema state for new players:** -- `actor_profile.background_id` — correct canonical identifier -- `actor_parameters` — all 12 parameters seeded from `background_starting_values` -- `ventures`, `venture_legs` — one row per dispatch cycle -- `parameter_drift_log` — one row per parameter change, with venture_id refs -- `events` — append-only, correct event_type sequence +7. **`Forum.jsx`** — dispatch and otium decisions. Full cost breakdown + (vectura/portoria/other) visible on route cards. Periodic expenditures + panel. Journal collapsible. -**Cost split — placeholder values (change only in `server/index.js` constants block):** +8. **`App.jsx`** — Shell wired. Three contexts: ACTOR, FORUM, MAP. + +9. **`server/index.js`** — three named otium expenditure trigger types: + `otium_access_fee` (2 dn), `personal_maintenance` (4 dn), + `officia_obligation` (2 dn). Each writes a separate drift log entry. + +10. **Retired** — `Prologue.jsx` and `Ledger.jsx` deleted. + +**Otium expenditure constants — source: `docs/economy/cost-calibration-model.md`:** ```javascript -const COST_VECTURA_RATIO = 0.60 // VECTVRA — freight charge -const COST_PORTORIA_RATIO = 0.25 // PORTORIUM — customs duty -// cost_other = remainder = 0.15 // horreum, incidentals +const OTIUM_ACCESS_FEE_DN = 2.00 // LOW confidence +const PERSONAL_MAINTENANCE_DN = 4.00 // MEDIUM confidence +const OFFICIA_OBLIGATION_DN = 2.00 // LOW confidence +const OTIUM_CYCLE_TOTAL_DN = 8.00 ``` +Change only in `server/index.js` constants block and `Forum.jsx`. -**Known deferred items from OTIVM-III:** -- Cost model: 60/25/15 split is a placeholder. A real model based on route - distance, cargo type, and epoch should be designed before OTIVM-IV touches - economics. -- Journal local state does not reset on new game (React state issue, low priority) -- H7 cells rendered as circles — hex geometry deferred pending client-side h3-js -- Map coastline is five isolated H5 clusters — route corridor coverage deferred -- Terrain in `data/otivm.sqlite3` is modern WorldCover — restoration layer - (HYDE 3.3 + KK10) not yet built. No release may present terrain as - historically accurate. +**Economic calibration documents in `docs/economy/`:** +- `cost-calibration-model.md` — ceramic cup baseline, reference wages +- `cost-calibration-additional-goods.md` — garum, grain, amber, marble capital -### What OTIVM-IV is -Per the roadmap: **The Seasons** — dispatches take real hours, weather affects -routes, DWD data drives conditions. This is a significant scope change. -The project owner decides whether to proceed with OTIVM-IV as defined in the -roadmap or redefine the scope before development begins. +**Five good patterns:** +`batch_craft` · `perishable_batch` · `bulk_staple` · `import_luxury` · `commission_heavy` -Before OTIVM-IV begins: take a backup (`vzdump 1105`) and document it in -`docs/archives.md`. +**Market architectural constraints (deferred — must not be violated):** +- `observable_level` on every `actor_parameters` row is the Market visibility gate +- `value_true` = server ground truth. `value_perceived` = ledger truth. Never conflate. +- Every drift log entry must be meaningful to an external reader. + +**Known deferred items:** +- Real cost model — 60/25/15 split is a placeholder +- Transformation routes (grain→bread) and barter — architecture defined, not built +- Market reader — deferred, constraints documented +- H7 cells as circles — hex geometry deferred pending h3-js +- Map coastline — five isolated H5 clusters +- Terrain — modern WorldCover, restoration layer not yet built + +### What OTIVM-V is +Not yet defined. Project owner decides scope before development begins. +Take a backup and document it before OTIVM-V begins. --- ## 5. Design corpus -The following documents are the design substrate for OTIVM-III and beyond. - **Scenarios** (`docs/scenarios/`): -- `SCENARIO-MERCHANT-0000.md` — The BALNEA Conversation (prologue, background selection) -- `SCENARIO-MERCHANT-0001.md` — The Bronze Forge Fire (second-order market logic) -- `SCENARIO-MERCHANT-0002.md` — The Capuan Timber Yard Fire (upstream choke-point logic) -- `SCENARIO-MERCHANT-0003.md` — The FAENUS Offer (capital without cargo) +- `SCENARIO-MERCHANT-0000.md` — The BALNEA Conversation +- `SCENARIO-MERCHANT-0001.md` — The Bronze Forge Fire +- `SCENARIO-MERCHANT-0002.md` — The Capuan Timber Yard Fire +- `SCENARIO-MERCHANT-0003.md` — The FAENUS Offer **Actors** (`docs/actors/`): - `CHARACTER-FRAMEWORK.md` — twelve parameters, hidden traits, background rules - `BACKGROUND-0001` through `BACKGROUND-0006` — six asymmetric starting lives **Cities** (`docs/cities/`): -- `CITY-OSTIA-0001.md` — Ostia substrate: urban zones, population model, - infrastructure parameters, social nodes, daily and seasonal rhythm +- `CITY-OSTIA-0001.md` — Ostia substrate **Architecture** (`docs/architecture/`): -- `infrastructure.md` — settled container topology and API protocol -- `terminology.md` — three-layer vocabulary, rejected terms, naming rules -- `latin-bridge.md` — Latin term admission standard and full semantic entries -- `parameter-registry.md` — all parameters, scope, layer, maturity -- `parameter-registry-additions.md` — 44 additional tokens from corpus review -- `simulation-clock.md` — integer time constraints, `MS_PER_SIM_DAY = 3_000` +- `infrastructure.md`, `terminology.md`, `latin-bridge.md` +- `parameter-registry.md`, `parameter-registry-additions.md` +- `simulation-clock.md` — `MS_PER_SIM_DAY = 3_000` -**Corpus** (`docs/training/corpus/`): -- 20 Layer 0 primitive facts (commerce domain) -- 5 Layer 1 worked examples -- 1 sketch awaiting promotion -- `commerce_chunks.jsonl` — 230 training chunks, 5 layers - -**Law and commerce dialogues** (`docs/law/`, `docs/commerce/`, `docs/economy/`): -- 37 dialogues reviewed, sanitized, and cleared for use -- Source material for the parameter registry additions +**Economic calibration** (`docs/economy/`): +- `cost-calibration-model.md` +- `cost-calibration-additional-goods.md` --- ## 6. The SVCCINUM thread -The amber (`SVCCINUM`) in the grain route cargo is not merely a goods label. -It is the first explicit connection between OTIVM and CIVICVS. The amber -originated in Maglemoisian forests in approximately 8000 BCE — the same -territory and period that CIVICVS models. When both simulations share a -TESSERA substrate, the amber in the MERCATOR's hold will be traceable to a -specific H3 cell where a CIVICVS Constructor gathered or traded it. +The amber (`SVCCINUM`) in the grain route cargo is the first explicit +connection between OTIVM and CIVICVS. It originated in Maglemoisian forests +in approximately 8000 BCE. When both simulations share a TESSERA substrate, +the amber in the MERCATOR's hold will be traceable to a specific H3 cell +where a CIVICVS Constructor gathered or traded it. -This thread runs through the `origin_h3_r5` provenance stub in `constants.js`, -through the SVCCINUM entry in `latin-bridge.md`, through the `occ_flag` stub -parameter in the registry, through to OTIVM-VIII and OTIVM-IX. - -Do not lose this thread. It is the architectural consequence of building -both systems on the same physical reality layer from the start. +This thread runs through `origin_h3_r5` in `constants.js`, through the +SVCCINUM entry in `latin-bridge.md`, through `occ_flag` in the registry, +through to OTIVM-VIII and OTIVM-IX. Do not lose it. --- ## 7. Workflow — one file, one step, one confirmation -Every change follows this sequence without exception: - -1. Claude chat discusses the change and produces one downloadable file -2. Human uploads to Gitea manually, or pastes into Claude Code -3. If code: `npm run build && pm2 restart otivm` -4. Human confirms result -5. Claude chat proceeds to next step +1. Claude chat produces one downloadable file +2. Human writes to disk: `cp filename src/path/filename` +3. If code: `npm run build` (then `pm2 restart otivm` if server or frontend) +4. Human runs the exact git commands provided in chat — copy-paste, no editing +5. Human confirms +6. Claude chat proceeds **One file. One step. One confirmation. Never batch.** -When a commit requires two files (e.g. paired .jsx and .css), both files must -carry their full content in the instruction header, or the instruction must -include an explicit STOP — do not proceed until the human pastes the second -file. Claude Code must never generate content for a missing file. +**Git add rule:** Always name the exact file. Never `git add .` +**File naming rule:** Downloaded filename = destination filename. No renaming. --- ## 8. Hard rules - Never run PM2 as root — always as otivm user -- Never commit secrets — no tokens, no keys, no passwords -- Never push to main without building — `npm run build` must pass first -- Per-player SQLite for player state — `data/saves/{token}.sqlite3` from `data/create_player_db.sql` -- JSON saves coexist during migration — never deleted, never overwritten -- H3 IDs on every location — never a coordinate pair or string name alone -- Never make assumptions about disk state — always read from Gitea MCP first -- Uncertainty is a first-class record, not a comment — applies to all schema work +- Never commit secrets +- Never push without building +- Per-player SQLite for player state +- JSON saves coexist — never deleted, never overwritten +- H3 IDs on every location — never a coordinate pair alone +- Never assume disk state — always read from Gitea MCP first +- Uncertainty is a first-class record, not a comment - The data warehouse is the product — the game is the public interface -- Real weather only in CIVICVS — DWD data always, no simulation -- Design one step ahead — no release planned beyond the next confirmed step +- Real weather only in CIVICVS — DWD data always +- Design one step ahead +- Bootstrap is vendored and pinned — never use a CDN reference --- ## 9. Commit message convention Imperative mood, present tense, under 72 characters. -`Add Mediterranean SVG map to Map screen` not `Added map`. --- @@ -330,16 +316,13 @@ Imperative mood, present tense, under 72 characters. See `docs/handover-dataset.md` for full detail. Current state: - `data/otivm.sqlite3` live — 12,005 rows, `paleo_epochs` populated, FK clean -- `staging_otivm.sqlite3` in sync -- Pipeline venv provisioned at `/home/otivm/pipeline-venv` -- Four datasets pending download to Drive 1 (BGR IGME5000, HYDE 3.3, KK10, HydroRivers) -- Per-H5 pipeline architecture designed (RFC-TESSERA-4.0-001), not yet coded +- Four datasets pending download (BGR IGME5000, HYDE 3.3, KK10, HydroRivers) +- Per-H5 pipeline designed (RFC-TESSERA-4.0-001), not yet coded -When `otivm.sqlite3` is expanded with new H5 hexes (OTIVM-III first new -waypoint), the game development assistant will be told. The `/api/map/:h5/:epoch` -endpoint requires no changes — it is already parameterised by H5 ID. +When `otivm.sqlite3` is expanded with new H5 hexes, the game development +assistant will be told. The `/api/map/:h5/:epoch` endpoint needs no changes. --- *Handover 2026-05-03 — game development track* -*Claude chat designs. Claude Code implements. The human decides.* +*Claude chat designs. Claude Code implements. The human decides.* \ No newline at end of file