From 49b8843821001088920bb9c794c0fa53b52eee16 Mon Sep 17 00:00:00 2001 From: otivm Date: Mon, 27 Apr 2026 09:28:33 +0000 Subject: [PATCH] Replace game dev handover with corrected and complete version --- docs/handover-game-dev.md | 260 ++++++++++++++++++++++++++------------ 1 file changed, 177 insertions(+), 83 deletions(-) diff --git a/docs/handover-game-dev.md b/docs/handover-game-dev.md index 60a6dce..1872eca 100644 --- a/docs/handover-game-dev.md +++ b/docs/handover-game-dev.md @@ -1,5 +1,5 @@ # Handover — OTIVM Game Development -### Date: 2026-04-26 +### Date: 2026-04-27 ### For: Incoming assistant (game development track) ### Read this completely before doing anything @@ -13,7 +13,7 @@ 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`). +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 @@ -26,13 +26,14 @@ to real users within seconds of `pm2 restart otivm`. 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. `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 --- @@ -41,13 +42,20 @@ project owner instruction. ### 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` +- 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` @@ -56,27 +64,33 @@ project owner instruction. ### 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 +- 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) +- `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. +- 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 +- 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"`) +- Ecosystem file: `ecosystem.config.cjs` (must be `.cjs` — Vite sets + `"type": "module"`) --- -## 4. Current game state — as of 2026-04-26 +## 4. Current game state — as of 2026-04-27 ### OTIVM-I — complete - Fastify backend serving `dist/` and save API on port 3000 @@ -84,7 +98,8 @@ project owner instruction. - 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 +- Token displayed in UI — player can record it to resume on another + device - 128 concurrent players supported ### Navigation scaffold — complete @@ -95,98 +110,168 @@ project owner instruction. ### 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 +- 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 four routes: +- 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 H3 IDs today — become live TESSERA API queries in OTIVM-III + These are stub values today — become live TESSERA 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 + - `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` + 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` + - `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 -- Mediterranean map to be replaced in OTIVM-III (moved up from OTIVM-VII) -- Two-polygon land outline (not one) — avoids cross-sea lines +- 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. This note exists in the project owner's memory. +- 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. OTIVM-III — defined, not yet started +## 5. The roadmap — needs rewriting ⚠ -OTIVM-III moves two items forward from their original roadmap positions: +**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. **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. +**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. **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. +**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. -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. +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. -OTIVM-III scope must be confirmed with the project owner before code is written. +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. What the dataset assistant is doing in parallel +## 6. The database — what the game can and cannot do -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 +`data/otivm.sqlite3` is present on the container. It is read-only +from the game's perspective. The dataset assistant owns it. -The output will be `data/otivm.sqlite3` — a SQLite database with TESSERA -physical-world data for the five OTIVM waypoint H5 hexes. +### 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 -**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 +### Five waypoints +| City | H5 TEXT | H9 cells | +|---|---|---| +| Ostia | `851e805bfffffff` | 2401 | +| Capua | `851e8333fffffff` | 2401 | +| Brundisium | `851e8ba3fffffff` | 2401 | +| Carthago | `85386e23fffffff` | 2401 | +| Alexandria | `853f5ba7fffffff` | 2401 | -You do not run extraction scripts. You do not touch pipeline files. -When `otivm.sqlite3` arrives on the container, you will be told. +### 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. Workflow — one file, one step, one confirmation +## 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) +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) +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 @@ -198,25 +283,34 @@ Every change follows this sequence without exception: --- -## 8. Hard rules +## 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 (`data/saves/`) -- H3 IDs on every location — never a coordinate pair or string name alone +- 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 +- 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 --- -## 9. Commit messages +## 10. 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* +*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.*