# Handover — OTIVM Game Development ### Date: 2026-04-26 ### For: Incoming assistant (game development track) ### Read this completely before doing anything --- ## 0. Your role 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. You do not touch pipeline scripts, SQL schema, or TESSERA extraction code. That work belongs to the dataset assistant (see `docs/handover-seed-extraction.md`). 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`. --- ## 1. Read these files before writing any code In order: 1. `CLAUDE.md` — workflow, three-shell model, ground rules, deployment facts 2. `docs/roadmap.md` — where the game is going through OTIVM-X 3. `docs/RFC-TESSERA-4.0-001.md` — the data schema that OTIVM-III onward depends on 4. This file The roadmap is the product plan. The RFC is the data contract. CLAUDE.md is the operational contract. Do not deviate from any of them without explicit project owner instruction. --- ## 2. Infrastructure ### OTIVM container (otium-dev, 10.0.0.23) - 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` - PM2 home: `/home/otivm/.pm2` - Node: `/usr/bin/node` (v22) - App port: 3000 - WireGuard: 10.110.0.18 ### Nginx proxy - Lives on wg-pk (198.58.111.109) — not on this container - Proxies `otium.civicus.us` → `10.110.0.18:3000` - Do not look for a vhost on the container ### 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 ### Backups - `vzdump 1105 --compress zstd --storage local --mode snapshot` on srv-a (root shell) - Document every backup in `docs/archives.md` immediately after - Never take a backup without documenting it. Never document one not taken. --- ## 3. Stack - React 19 + Vite 8 frontend (`src/`) - Fastify backend (`server/index.js`) — serves `dist/` and save API on port 3000 - No database for player state — JSON flat files in `data/saves/` - `data/otivm.sqlite3` — TESSERA physical-world data, read-only by the game server - PM2 under `otivm` user (never root) - Ecosystem file: `ecosystem.config.cjs` (must be `.cjs` — Vite sets `"type": "module"`) --- ## 4. Current game state — as of 2026-04-26 ### OTIVM-I — complete - Fastify backend serving `dist/` and save API on port 3000 - Five trade routes, Ostia → Alexandria, all working - Journal entries firing on dispatch milestones - Otium/negotium mechanic working - Per-player save files in `data/saves/` via 8-char hex token - Token displayed in UI — player can record it to resume on another device - 128 concurrent players supported ### Navigation scaffold — complete - `src/screens/` directory established - Game.jsx renamed to `src/screens/Ledger.jsx` - `App.jsx` manages screen state — ledger and map - Both screens stay mounted — no state lost on switch ### OTIVM-II — complete and live - `src/screens/Map.jsx` — Mediterranean SVG map - Two-polygon land outline (Europe + Asia Minor, North Africa) — accurate mainland coastline - Bounding box: 5°E–38°E / 28°N–48°N, equirectangular projection, 800×460 canvas - Five waypoints plotted at hardcoded H3 res-5 cell centres - Route lines between waypoints — gold when unlocked, muted dashed when locked - Current chapter waypoint highlighted in gold, reached waypoints in green - `src/constants.js` — provenance fields added to all four routes: `origin_h3_r5`, `origin_region`, `cultural_note` These are stub H3 IDs today — become live TESSERA API queries in OTIVM-III - `src/gameState.js` — structural additions: - `active_dispatch: null` in `INITIAL_STATE` — records in-progress dispatch for position tracking and real-time duration (OTIVM-IV) - `events: []` in `INITIAL_STATE` — append-only event log Each entry: `{ type, route_id, timestamp_utc }` Types: `dispatch_start`, `dispatch_complete`, `otium`, `chapter_advance`, `journal_unlock` This is the sequencing substrate for OTIVM-IX attestation - `galleyProgress(active_dispatch, now_ms)` — pure function, returns 0–1 progress float for a dispatched galley. Returns null if no dispatch active. OTIVM-IV plugs real durations in. OTIVM-VII plugs H3 waypoints in. - All apply* functions now append to `events` and set/clear `active_dispatch` ### Architecture decisions locked - H3 IDs on all waypoints — permanent, TESSERA-compatible - `constants.js` / `gameState.js` / `api.js` separation — permanent - Virtual screens via `display:none` — state preserved in browser - Save on meaningful events only — not on every tick - H3 cell centre coordinates hardcoded in `Map.jsx` — h3-js is server-side only - Mediterranean map to be replaced in OTIVM-III (moved up from OTIVM-VII) - Two-polygon land outline (not one) — avoids cross-sea lines ### Known issue — recorded - Claude Code collapsed `INITIAL_STATE` onto one line during a prior session, causing a Vite build failure. Fixed in commit 34176dc. - Going forward: Claude Code writes content exactly as received, regardless of how it arrives. This note exists in the project owner's memory. --- ## 5. OTIVM-III — defined, not yet started OTIVM-III moves two items forward from their original roadmap positions: 1. **SQLite integration** — `data/otivm.sqlite3` arrives on the container from the dataset assistant. The Fastify server gets a read-only SQLite connection (better-sqlite3). A `/api/cell/:h9` endpoint exposes TESSERA data for individual H9 cells. The game UI does not yet surface this data directly — the plumbing is established and verified working. 2. **Accurate map** — the placeholder two-polygon coastline is replaced with a Natural Earth or equivalent accurate coastline, including major islands (Sicily, Sardinia, Crete, Cyprus). The map remains SVG, equirectangular, same bounding box and canvas size. These two items belong together in OTIVM-III because the database arrival on the container is the trigger for both — once `otivm.sqlite3` is present, the map replacement and server plumbing happen in the same release. OTIVM-III scope must be confirmed with the project owner before code is written. --- ## 6. What the dataset assistant is doing in parallel The dataset assistant is working on TESSERA 4.0 seed extraction: - `data/create_otivm_db.sql` — schema for `otium.sqlite3` ✅ committed - `pipeline/seed_extract.py` — extracts five waypoint H3 cells from tessera.db ✅ committed - `pipeline/seed_promote.py` — promotes draft rows to current ✅ committed - `docs/RFC-TESSERA-4.0-001.md` — normative schema ✅ committed - `docs/handover-seed-extraction.md` — dataset track orientation ✅ committed The output will be `data/otivm.sqlite3` — a SQLite database with TESSERA physical-world data for the five OTIVM waypoint H5 hexes. **Verified row counts (from `data/create_otivm_db.sql` and confirmed by dataset assistant):** - H3 resolution hierarchy res-5 → res-9: 7⁴ = 2,401 H9 cells per H5 hex - Five waypoints × 2,401 = **12,005 total H9 rows** - All five H5 hexes are within the completed portion of tessera.db (Mediterranean is fully populated through stage 04) - `occ_flag` is 0 for all seed rows — stage 06 (occupation evidence) not yet run You do not run extraction scripts. You do not touch pipeline files. When `otivm.sqlite3` arrives on the container, you will be told. --- ## 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. The file header contains the Claude Code instruction (path, commit message) 3. The file body contains the exact content to write to disk 4. Human downloads from Claude chat and pastes into Claude Code (Shell 1) 5. Claude Code writes to the specified path, commits, pushes 6. Human runs `npm run build` in Shell 2 (otivm shell) 7. Human runs `pm2 restart otivm` in Shell 2 8. Human confirms in browser at https://otium.civicus.us 9. Human reports result back to Claude chat 10. Claude chat proceeds to the next step **One file. One step. One confirmation. Never batch.** --- ## 8. Hard rules - Never run PM2 as root — always as otivm user - Never commit secrets — no tokens, no keys, no passwords in any file - Never push to main without building — `npm run build` must pass first - No database for player state — JSON flat files only (`data/saves/`) - H3 IDs on every location — never a coordinate pair or string name alone - One change confirmed before the next — no batching steps - Never print file contents or code blocks in chat — always downloadable attachments - Never make assumptions about what is on disk — always read from Gitea MCP first --- ## 9. Commit messages Imperative mood, present tense, under 72 characters. Example: `Add Mediterranean SVG map to Map screen` not `Added map`. --- *Handover 2026-04-26 — game development track* *Claude chat designs. Claude Code implements. The human decides.*