# Handover — OTIVM Game Development ### Date: 2026-04-27 ### 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-dataset.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` — **read with the warnings in Section 5 of this document in mind. The roadmap needs rewriting. Do not treat it as current.** 3. `docs/RFC-TESSERA-4.0-001.md` — the database schema all future releases depend on 4. `docs/TESSERA-dataset-registry.md` — what data exists, what is pending, and critically: the restoration layer concept 5. This file --- ## 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 (game): `/home/otivm/venv` - Python venv (pipeline — do not use): `/home/otivm/pipeline-venv` - PM2 home: `/home/otivm/.pm2` - Node: `/usr/bin/node` (v22) - App port: 3000 - WireGuard: 10.110.0.18 ### Three Proxmox boxes - **proliant-dev (srv-a, 10.0.0.11)** — development work happens here - **staging box** — validation before production - **production box** — live game served from here ### 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 - Player state: JSON flat files in `data/saves/` — no database - TESSERA data: `data/otivm.sqlite3` — read-only by game server, owned and populated by dataset assistant - 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-27 ### 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) — placeholder coastline, accurate mainland only - 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 routes: `origin_h3_r5`, `origin_region`, `cultural_note` These are stub values today — become live TESSERA queries in OTIVM-III - `src/gameState.js` — structural additions: - `active_dispatch: null` — records in-progress dispatch - `events: []` — 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. Returns null if no dispatch active. - 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 - Two-polygon land outline — to be replaced in OTIVM-III - Two polygons not one — avoids cross-sea rendering 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. --- ## 5. The roadmap — needs rewriting ⚠ **Read `docs/roadmap.md` but do not treat it as authoritative.** The roadmap was written before the TESSERA 4.0 architecture was decided. The following assumptions in the current roadmap are now wrong: **1. It assumes a completed global TESSERA database.** The global database (tessera.db) no longer exists on a reachable server. `data/otivm.sqlite3` is a purpose-built per-waypoint database (TESSERA 4.0 model). New hexes are added one H5 at a time by the dataset assistant as the game expands. The roadmap must reflect this. **2. It does not mention the restoration layer.** `terrain` in `otivm.sqlite3` is modern WorldCover 2021 data. It is wrong for any historical period. The Mediterranean was 60–70% forested in Roman times and Mesolithic times. Today the same cells are classified as built-up, cropland, or drained wetland. The restoration layer (HYDE 3.3 + KK10 datasets, not yet on drives) will correct `terrain` to historically appropriate values. Until that layer is active, the game must not present terrain data as historically accurate. This affects the roadmap significantly — terrain-dependent features (city physical character, environmental hazard, resource availability) cannot be implemented correctly until the restoration layer is in place. **3. Release numbering is out of date.** OTIVM-III in the current roadmap describes "The Factor" (NPC model). The actual next release should establish the SQLite server connection and replace the map coastline — both triggered by the database arriving on the container. Discuss scope with the project owner before any code. **The roadmap rewrite is the first task for the game development assistant.** Do not write code until the roadmap is current. The project owner will direct the rewrite. --- ## 6. The database — what the game can and cannot do `data/otivm.sqlite3` is present on the container. It is read-only from the game's perspective. The dataset assistant owns it. ### What is in the database - 12,005 H9 rows across five waypoints, all `status=2` (current) - `paleo_epochs` table — 9 epochs from Eemian to present with sea level offsets ### Five waypoints | City | H5 TEXT | H9 cells | |---|---|---| | Ostia | `851e805bfffffff` | 2401 | | Capua | `851e8333fffffff` | 2401 | | Brundisium | `851e8ba3fffffff` | 2401 | | Carthago | `85386e23fffffff` | 2401 | | Alexandria | `853f5ba7fffffff` | 2401 | ### The canonical game query Only use cells from complete, current H5 hexes: ```sql SELECT tc.* FROM tessera_cells tc JOIN h5_coverage h5c ON tc.h5 = h5c.h5 WHERE h5c.status = 2 AND tc.status = 2 AND tc.h5 = ? ``` ### Field status — what the game can trust | Field | Trust level | Reason | |---|---|---| | `elev_cm` | ✅ Use — with epoch offset | GEBCO 2025, modern MSL. Apply `sl_offset_cm` from `paleo_epochs` for historical periods. | | `terrain` | ⚠ Modern only | WorldCover 2021. Wrong for Roman/Mesolithic. Do not present as historical until restoration layer is active. | | `hydro` | ✅ Use with caution | HydroSHEDS v1.1. Rivers have migrated — major drainage correct, fine detail approximate. | | `geo_dep` | ✅ Use | USGS MRDS. Sparse in places but correct where present. | | `geo_flag` | ✅ Use | BGR IGME5000. European coverage only. | | `occ_flag` | ❌ Do not use | Placeholder 0x00 everywhere. Stage 06 not written. | ### H3 conversion in JavaScript H3 IDs are stored as INTEGER (64-bit) in the database. In JavaScript: `h3.indexToCell(BigInt(row.h9))` to convert to string. Server-side only — h3-js is not available in the browser bundle. --- ## 7. Dataset assistant — what they are doing in parallel The dataset assistant owns the pipeline. Current status: - `data/otivm.sqlite3` — production database, 12,005 rows ✅ - `data/staging_otivm.sqlite3` — their working copy, not in git - `pipeline/seed_extract.py` — old extractor, do not re-run ✅ - `pipeline/seed_promote.py` — old promotion script, do not re-run ✅ - `docs/TESSERA-dataset-registry.md` — full dataset inventory ✅ - `docs/handover-dataset.md` — their track orientation ✅ **Next dataset work:** 1. Four datasets to be added to USB Drive 1 (project owner action) 2. Per-H5 pipeline to be designed and built 3. Restoration layer — HYDE 3.3 + KK10 integration You will be told when the database is updated. You do not run pipeline scripts. You do not touch `pipeline/` or `data/create_otivm_db.sql`. --- ## 8. 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.** --- ## 9. 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 - 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 - Do not query `otivm.sqlite3` with raw coordinates — always H3 IDs - Do not present `terrain` as historically accurate until the restoration layer is confirmed active by the dataset assistant --- ## 10. Commit messages Imperative mood, present tense, under 72 characters. Example: `Add Mediterranean SVG map to Map screen` not `Added map`. --- *Handover 2026-04-27 — game development track* *Database present, paleo_epochs added, 12,005 current rows.* *Roadmap needs rewriting — first task before any code.* *terrain field is modern WorldCover — not historically accurate yet.* *Claude chat designs. Claude Code implements. The human decides.*