Files
otivm/docs/Roadmap-OTIVM-V.md
2026-05-06 12:56:06 -04:00

14 KiB
Raw Permalink Blame History

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):

// 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:

{
  "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:

{
  "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.jsxgoods-list panel type added. This is the only shell change. Build and confirm renders before proceeding.

Step 4 — Context config src/config/context-actor.jsongoods-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.jsexchange_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.

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.