docs: add OTIVM-V roadmap

This commit is contained in:
2026-05-06 12:56:06 -04:00
parent 63b2f6cf7b
commit 915f0a285e

353
docs/Roadmap-OTIVM-V.md Normal file
View File

@@ -0,0 +1,353 @@
# OTIVM-V — Roadmap
### Date: 2026-05-03
### Status: DRAFT — awaiting project owner approval before any code is written
### Supersedes: nothing — OTIVM-IV is complete at Gitea HEAD 3700f5a
---
## 0. What OTIVM-V is, in one sentence
OTIVM-V makes goods real: the merchant holds physical inventory, transforms
raw goods into finished goods, barters goods for goods, and the Simulator
can read every transaction from the behavioral record.
---
## 1. Governing constraints — gates, not preferences
**No schema change to `data/create_player_db.sql` without explicit project
owner instruction.** All goods mechanics are expressed through existing
tables: `ventures`, `venture_legs`, `parameter_drift_log`, `events`.
**No artificial values.** Every constant is sourced from the calibration
documents or marked LOW confidence with a named revision trigger. The Market
will balance against real equations. Placeholders that cannot survive Market
pressure are not placeholders — they are errors deferred.
**JSON `delta_note` on every `exchange_complete` entry.** The
`parameter_drift_log.delta_note` column is TEXT and holds a JSON object
today without schema change. CT 1103 (aggregation / Market) parses this
JSON when it reads player databases. The player UI renders selected fields
as human-readable text. Consistency with `events.payload` is mandatory.
**CT 1103 is not constrained to SQLite.** The Market database may be
PostgreSQL, MySQL, or any engine that serves the aggregation workload.
The API boundary between CT 1105 and CT 1103 is REST over WireGuard —
what sits behind that endpoint is CT 1103's internal decision. OTIVM-V
does not touch CT 1103. It produces records that CT 1103 can read.
**The shell architecture is unchanged.** `Shell.jsx` and `Section.jsx`
are built once. One new section type (`goods-list`) is added to
`Section.jsx` only. No other shell changes.
**One file. One step. One confirmation. Never batch.**
---
## 2. What OTIVM-V builds
### 2.1 — Transformation route: grain→bread
The merchant dispatches the grain route (Brundisium → Carthago) with grain
cargo. At destination, instead of receiving raw coin profit, he contracts a
transformation: a baker converts the grain to bread at an agreed ratio. The
merchant receives bread as a tradeable good. He then sells the bread on the
next otium cycle or on a subsequent route.
**Transformation mechanics:**
- The dispatch and venture mechanics are unchanged. The merchant still
dispatches the grain route and waits for completion.
- On venture completion, instead of (or in addition to) the standard
`venture_complete` coin delta, a transformation may be applied if the
player selected a transformation route.
- The transformation is recorded as `trigger_type = 'exchange_complete'`
in `parameter_drift_log`.
- The coin-equivalent delta (bread value minus grain value minus baker fee)
is applied to `liquiditas`.
- The goods-on-hand state is derived from these records — no new table.
**Transformation constants** (to be added to `src/constants.js` and
documented in `docs/economy/otivm_v_transformation_goods.md`):
```javascript
// Grain → Bread transformation
// Source: docs/economy/otivm_v_transformation_goods.md
// Confidence: LOW — placeholder pending Market price signals
// Revision trigger: when CT 1103 provides real destination bread prices
const GRAIN_BREAD_TRANSFORMATION_RATIO = 1.15 // bread coin-value / grain coin-value at destination
const GRAIN_BREAD_BAKER_FEE_DN = 3.00 // per 100 modii, baker's transformation fee
// Net delta on 100 modii grain route:
// revenue_grain = 75.00 dn (GRAIN_DEST_WHOLESALE_100_DN)
// bread_value = 75.00 * 1.15 = 86.25 dn
// baker_fee = 3.00 dn
// net_delta = 86.25 - 75.00 - 3.00 = +8.25 dn above raw grain return
// Confidence: LOW. This is economically implausible at scale — the baker
// captures the real margin. Revision required when annona pressure and
// destination scarcity signals are available from the Market.
```
**Structured `delta_note` for grain→bread `exchange_complete`:**
```json
{
"event": "transformation",
"good_input": "grain",
"good_input_pattern": "bulk_staple",
"quantity_input_unit": "modius",
"quantity_input": 100,
"good_output": "bread",
"good_output_pattern": "bulk_staple",
"quantity_output_unit": "modius_equivalent",
"quantity_output_coin_dn": 86.25,
"baker_fee_dn": 3.00,
"transformation_ratio": 1.15,
"coin_delta_dn": 8.25,
"route": "grain",
"origin_h3": "851e8ba3fffffff",
"destination_h3": "853386e23fffffff",
"acquisition_ts": "<ISO>"
}
```
### 2.2 — Barter: grain for garum at Carthago
The merchant arrives at Carthago with grain. A counterparty holds garum.
No coin moves. The merchant surrenders grain and receives garum at an agreed
ratio. Both goods change hands. The coin-equivalent spread is the delta.
**Barter mechanics:**
- Same `exchange_complete` trigger type as transformation.
- Coin-equivalent delta: value of garum received minus value of grain
surrendered at calibration-document price anchors.
- Applied to `liquiditas` as a signed delta.
- Base exchange ratio: 50 modii grain : 4 amphorae garum (LOW confidence).
- Coin equivalent: 50 modii grain at 0.75 dn/modius = 37.50 dn.
4 amphorae garum at 9.00 dn/amphora wholesale = 36.00 dn.
Delta: 1.50 dn. The merchant accepts a slight loss for liquidity —
he holds a more portable, higher-margin good.
**Structured `delta_note` for barter `exchange_complete`:**
```json
{
"event": "barter",
"good_given": "grain",
"good_given_pattern": "bulk_staple",
"quantity_given_unit": "modius",
"quantity_given": 50,
"quantity_given_coin_dn": 37.50,
"good_received": "garum",
"good_received_pattern": "perishable_batch",
"quantity_received_unit": "amphora",
"quantity_received": 4,
"quantity_received_coin_dn": 36.00,
"coin_delta_dn": -1.50,
"exchange_ratio_note": "50 modii grain : 4 amphorae garum",
"route": "grain",
"location_h3": "853386e23fffffff",
"acquisition_ts": "<ISO>"
}
```
### 2.3 — Goods-on-hand panel in ACTOR context
A new panel appears in the right column of the ACTOR context, between
"Periodic obligations" and "Drift log". Title: "Goods on hand".
The panel shows the merchant's current physical inventory derived from
completed venture records and open `exchange_complete` events. It is a
derived view — no new table, no new parameter token.
**What the panel shows per good held:**
| Field | Source | Purpose |
|---|---|---|
| Good type | `delta_note.good_output` or `delta_note.good_received` | Player reads |
| Pattern | `delta_note.good_output_pattern` | CT 1103 reads |
| Quantity | derived from delta events | Player reads |
| Unit | `delta_note.quantity_output_unit` | Both read |
| Origin route | `delta_note.route` | CT 1103 reads |
| Origin H3 | `delta_note.origin_h3` | CT 1103 reads |
| Acquired at | `delta_note.acquisition_ts` | CT 1103 reads |
| Coin equivalent | derived from calibration constants | Player reads |
**What the panel does NOT show:**
- Any field not derivable from existing records.
- Speculative future prices.
- Market-side data (CT 1103 is not live in OTIVM-V).
**New section type:** `goods-list` added to `Section.jsx`. This is the
only change to the shell components.
---
## 3. Known architectural debt — named, not hidden
**No materialized inventory table.** Current holdings are reconstructed by
replaying `parameter_drift_log` exchange events. For a single player this
is fast. When CT 1103 reads 127 player databases on a polling schedule, this
becomes expensive if holdings are complex.
The correct solution — when the Market goes live — is an `actor_inventory`
table in the player schema: one row per good held, updated by the game server
on every `exchange_complete` event. That is a schema version 6 change,
justified by the Market requirement, made at the release when CT 1103 goes
live. Not now.
This debt is recorded here so the decision is deliberate.
---
## 4. What OTIVM-V explicitly does not include
- CT 1103 implementation — deferred
- The Roman Market itself — deferred
- Real destination price signals — deferred (Market provides these)
- New waypoints or map expansion — blocked on per-H5 pipeline
- Weather integration — blocked on restoration layer
- The Factor (NPC model) — deferred
- Scenario triggers — deferred
- Quality grade multipliers (garum luxury tier, fine vs common) — deferred
- Commission route pattern (marble) — deferred
- Any changes to the TESSERA map endpoint — unchanged
- H3 hex geometry on the map — deferred pending h3-js
- `actor_inventory` materialized table — deferred to Market release
---
## 5. New calibration document
`docs/economy/otivm_v_transformation_goods.md` — documents the grain→bread
transformation ratio and barter exchange rates as LOW confidence placeholders,
with explicit revision triggers keyed to Market price signal availability.
This document follows the same method as the existing calibration documents:
source-backed anchors where possible, explicit calibration flags where not.
---
## 6. File inventory — complete and authoritative
### Files added (new)
| File | Purpose |
|---|---|
| `docs/economy/otivm_v_transformation_goods.md` | Calibration document for transformation and barter constants |
| `docs/Roadmap-OTIVM-V.md` | This document |
### Files modified (existing)
| File | What changes |
|---|---|
| `src/constants.js` | Transformation ratio constants, baker fee, barter ratio constants added |
| `src/config/context-actor.json` | New `goods-list` section added to right column between obligations and drift log |
| `src/components/Section.jsx` | New `goods-list` panel type added |
| `src/screens/Actor.jsx` | Goods-on-hand data constructed and passed to Section |
| `src/screens/Forum.jsx` | Transformation and barter options added to route dispatch UI |
| `server/index.js` | `exchange_complete` handler added — writes structured JSON `delta_note`; goods-on-hand read endpoint added; server startup message updated to OTIVM-V |
### Files not touched
| File | Reason |
|---|---|
| `src/components/Shell.jsx` | Shell is built once — no changes |
| `src/screens/Map.jsx` | No map changes in OTIVM-V |
| `src/gameState.js` | Game state shape unchanged |
| `src/api.js` | API calls unchanged |
| `data/create_player_db.sql` | Schema unchanged — no modification without project owner instruction |
| `data/create_otivm_db.sql` | World schema unchanged |
| All TESSERA-related server code | Unchanged |
| `src/config/context-forum.json` | Forum layout JSON unchanged — Forum.jsx handles transformation/barter directly |
| `src/config/context-map.json` | Unchanged |
| `src/config/contexts.json` | No new contexts in OTIVM-V |
---
## 7. Implementation sequence
One file. One step. One confirmation. In this order:
**Step 1 — Calibration document**
`docs/economy/otivm_v_transformation_goods.md`
No rebuild needed. Commit and confirm before proceeding.
**Step 2 — Constants**
`src/constants.js` — transformation and barter constants added.
No rebuild needed for constants alone, but confirm file is committed.
**Step 3 — Section shell extension**
`src/components/Section.jsx``goods-list` panel type added.
This is the only shell change. Build and confirm renders before proceeding.
**Step 4 — Context config**
`src/config/context-actor.json``goods-list` section added to right
column. No rebuild needed for JSON alone. Confirm file is committed.
**Step 5 — Actor screen**
`src/screens/Actor.jsx` — goods-on-hand data construction added.
Build and confirm goods panel renders with placeholder data.
**Step 6 — Server**
`server/index.js``exchange_complete` handler, JSON `delta_note` writes,
goods-on-hand read endpoint, startup message updated to OTIVM-V.
`pm2 restart otivm` required. No npm build needed for server changes alone.
**Step 7 — Forum screen**
`src/screens/Forum.jsx` — transformation and barter route options added
to dispatch UI. Build and confirm full cycle: dispatch → transformation →
goods panel updates → barter available.
**Step 8 — Verify**
Play a full cycle: dispatch grain route with transformation selected →
verify `exchange_complete` entry in `parameter_drift_log` with correct JSON
`delta_note` → verify goods panel shows bread held → trigger barter →
verify second `exchange_complete` entry → verify goods panel updates.
Inspect player SQLite directly to confirm records are CT 1103-readable.
**Step 9 — Roadmap document**
`docs/Roadmap-OTIVM-V.md` — commit the approved version of this document.
---
## 8. Before OTIVM-V development begins
Per `CLAUDE.md` and the handover document:
**Take a backup before any OTIVM-V code is written.**
```bash
vzdump 1105 --compress zstd --storage local --mode snapshot
```
Run on srv-a as root. Document immediately in `docs/archives.md`.
A backup for OTIVM-IV completion already exists at
`vzdump-lxc-1105-2026_05_03-14_08_13.tar.zst`. Take a second backup
at the start of OTIVM-V work to capture any player data accumulated
between the two sessions.
---
## 9. Market architectural constraints — do not violate
These constraints govern every implementation decision in OTIVM-V, even
though the Market itself is not built here:
1. Every `exchange_complete` entry in `parameter_drift_log` writes a
structured JSON object as `delta_note`. This is the Market's read
target. A human-readable string is not acceptable.
2. `observable_level` on every `actor_parameters` row is the Market
visibility gate. Goods derived from `exchange_complete` events inherit
the `observable_level` of the `liquiditas` parameter they modify.
3. `value_true` is always server ground truth. `value_perceived` is what
the actor's ledger shows. Never conflate. Goods-on-hand is derived from
`value_true` — the server knows what the merchant actually holds.
4. The API boundary between CT 1105 and CT 1103 is REST over WireGuard.
CT 1103's internal database engine is CT 1103's decision. OTIVM-V
writes clean records. CT 1103 reads them.
---
*OTIVM-V Roadmap — draft 2026-05-03*
*Claude chat designs. Claude Code implements. The human decides.*