docs: add OTIVM-V roadmap
This commit is contained in:
353
docs/Roadmap-OTIVM-V.md
Normal file
353
docs/Roadmap-OTIVM-V.md
Normal 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.*
|
||||||
Reference in New Issue
Block a user