Update handover-game-dev.md

OTIVM-II complete, OTIVM-III defined, full design corpus documented
This commit is contained in:
2026-04-28 11:56:16 -04:00
parent 890cc8e303
commit e199f88d4a

View File

@@ -1,5 +1,5 @@
# Handover — OTIVM Game Development
### Date: 2026-04-27
### Date: 2026-04-28
### For: Incoming assistant (game development track)
### Read this completely before doing anything
@@ -26,239 +26,205 @@ 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` — **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. `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
5. `docs/architecture/parameter-registry.md` — all simulation parameters, scope, layer, maturity
6. `docs/actors/CHARACTER-FRAMEWORK.md` — six backgrounds, twelve starting parameters
7. `docs/scenarios/SCENARIO-MERCHANT-0000.md` — the BALNEA prologue, background selection
8. `docs/scenarios/SCENARIO-MERCHANT-0001.md` through `0003.md` — the founding trilogy
9. `docs/cities/CITY-OSTIA-0001.md` — Ostia as pressure field, not backdrop
10. `docs/roadmap.md` — where the game is going (warning: body is stale, vision and principles still valid)
11. This file
The parameter registry is the bridge between the design documents and the
schema. Read it before touching any database code.
---
## 2. Infrastructure
### OTIVM container (otium-dev, 10.0.0.23)
### 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 (game): `/home/otivm/venv`
- Python venv (pipeline — do not use): `/home/otivm/pipeline-venv`
- 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`
- 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
### 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 |
|---|---|
| 1101 | tessera-pipeline |
| 1102 | tessera-store (master database) |
| 1103 | tessera-dev (aggregation) |
| 1104 | apt-cache |
| 1105 | otivm-dev (this container) |
### 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
- 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.
- 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
- Download each dump to workstation cold storage
- 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
- Fastify backend (`server/index.js`) — serves `dist/`, save API, TESSERA map endpoint
- `data/otivm.sqlite3` — TESSERA physical data, read-only by game server
- `data/saves/` — per-player JSON save files (gitignored)
- `better-sqlite3` installed — used by server for TESSERA queries
- PM2 under `otivm` user (never root)
- Ecosystem file: `ecosystem.config.cjs` (must be `.cjs` — Vite sets
`"type": "module"`)
- Ecosystem file: `ecosystem.config.cjs`
---
## 4. Current game state — as of 2026-04-27
## 4. Current game state — as of 2026-04-28
### 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
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
- `src/screens/Map.jsx` — Mediterranean SVG map
- Two-polygon land outline (Europe + Asia Minor, North Africa) —
placeholder coastline, accurate mainland only
- Bounding box: 5°E38°E / 28°N48°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 01 progress float. Returns null if no dispatch active.
- All apply* functions now append to `events` and set/clear
`active_dispatch`
**The map is live and rendering from real TESSERA data.**
### Architecture decisions locked
- `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`)
### Architecture decisions locked in OTIVM-II
- 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
- 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 (128 files) replacing JSON saves — planned for OTIVM-III
### 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.
### Known deferred items
- 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 to OTIVM-III+
- Roadmap body is stale — rewrite planned under project owner direction
---
## 5. The roadmap — needs rewriting ⚠
## 5. OTIVM-III — defined, not yet started
**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:
OTIVM-III is the data plumbing release. Three things:
**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.
**1. Per-player SQLite — 128 pre-provisioned databases**
**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 6070% forested
in Roman times and Mesolithic times. Today the same cells are
classified as built-up, cropland, or drained wetland.
Replace JSON save files in `data/saves/` with SQLite databases in
`data/players/`. Pre-provision all 128 at container setup — no database
created on demand under player load. The schema is defined by the parameter
registry and the SQLite schema document (pending — this is the next
document to be produced).
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.
The atomic unit is **time**. The database is a time-series of events.
Current parameter values are derived from event history. The schema must
treat uncertainty, confidence, and perceived-vs-true values as first-class
records, not comments.
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.
**2. RATIONES tab — the third screen**
**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.
Add a third tab alongside Ledger and Map. This is the disaggregated
accounts — the line items of every NEGOTIVM. Not a dashboard. A Roman
merchant's RATIONES: what was spent at each ITER, on what, at what rate.
**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.
The player sees a historically authentic accounting surface. The system
records parameters beneath it. Raw parameter values remain hidden or
available only in advanced view.
**3. Internal API for aggregation (1103)**
1105 exposes an internal endpoint that 1103 can call on a schedule to
collect player event snapshots for aggregation. Anonymised behavioral
data only — no save file contents transferred raw.
**Before any OTIVM-III code is written:**
Read `docs/architecture/parameter-registry.md` in full. The schema
must not flatten AVCTORITAS into an integer. Uncertainty, observability,
and perceived-vs-true are structural requirements, not optional features.
---
## 6. The database — what the game can and cannot do
## 6. Design corpus — what ChatGPT produced this session
`data/otivm.sqlite3` is present on the container. It is read-only
from the game's perspective. The dataset assistant owns it.
The following documents were produced in collaboration with ChatGPT and
represent the design substrate for OTIVM-III and beyond. Read them in order.
### 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
**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)
### Five waypoints
| City | H5 TEXT | H9 cells |
|---|---|---|
| Ostia | `851e805bfffffff` | 2401 |
| Capua | `851e8333fffffff` | 2401 |
| Brundisium | `851e8ba3fffffff` | 2401 |
| Carthago | `85386e23fffffff` | 2401 |
| Alexandria | `853f5ba7fffffff` | 2401 |
These form a trilogy with a prologue. Each success condition is sharper
than the last. The trilogy teaches: event → dependencies → price → capital.
### 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 = ?
```
**Actors** (`docs/actors/`):
- `CHARACTER-FRAMEWORK.md` — twelve parameters, hidden traits, background rules
- `BACKGROUND-0001` through `BACKGROUND-0006` — six asymmetric starting lives
### 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. |
These are not classes. They are starting parameter profiles that drift
toward decision history over time (`background_drift` parameter).
### 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.
**Cities** (`docs/cities/`):
- `CITY-OSTIA-0001.md` — Ostia substrate: urban zones, population model,
infrastructure parameters, social nodes, daily and seasonal rhythm
Ostia functions as a pressure field. It is not scenery. Every parameter
in the city document connects to actor parameters and scenario triggers.
**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
- `research-brief-roman-venture.md` — ChatGPT research instructions
- `parameter-registry.md` — all parameters, scope, layer, maturity
---
## 7. Dataset assistant — what they are doing in parallel
## 7. The SVCCINUM thread
The dataset assistant owns the pipeline. Current status:
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.
- `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 ✅
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.
**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`.
Do not lose this thread. It is the architectural consequence of building
both systems on the same physical reality layer from the start.
---
@@ -267,17 +233,10 @@ pipeline scripts. You do not touch `pipeline/` or `data/create_otivm_db.sql`.
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
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
**One file. One step. One confirmation. Never batch.**
@@ -286,31 +245,39 @@ Every change follows this sequence without exception:
## 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 commit secrets — no tokens, no keys, no passwords
- 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
- JSON flat files for player state — until OTIVM-III replaces them with SQLite
- 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
- The data warehouse is the product — the game is the public interface
- Real weather only in CIVICVS — DWD data always, no simulation
---
## 10. Commit messages
## 10. Commit message convention
Imperative mood, present tense, under 72 characters.
Example: `Add Mediterranean SVG map to Map screen` not `Added map`.
`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.*
## 11. What the dataset assistant is doing in parallel
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 not yet designed — next dataset session task
When `otium.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.
---
*Handover 2026-04-28 — game development track*
*Claude chat designs. Claude Code implements. The human decides.*