games/kaintuck: two-vector commodity pricing + rumor/reality banter

games/kaintuck: two-vector commodity pricing + rumor/reality banter

#38 in Riparion/riparion-retro — merged 2026-06-12

Why

Kaintuck's market was a one-dimensional downstream gradient — a single base_ranks per town, prices base_ranks/2 · (1–3 band). That captured "cheap upstream, dear at Natchez" but flattened the real economic geography: it couldn't say a town is cheap because it produces a good (Cincinnati pork, Monongahela rye) or dear because it lacks one (the provision-hungry lower landings), and it posted a single quote with no bid/ask.

What

Two-vector model + spread. Each town gets a sparse market: Vec<MarketBias> (supply discount / demand premium / extra spread, with a cause note) layered on the existing base_ranks gradient:

mid  = base_ranks/2 · (1−supply)(1+demand) · band
buy  = mid · (1 + spread/2)            // ask
sell = mid · (1 − spread/2) · (1 + reputation/200)   // bid

An 8% scenario base_spread applies to every quote; base_ranks is untouched (Natchez's premium stays in the distance gradient — no double-counting).

Historical first pass: Monongahela rye (Pittsburgh), Porkopolis pork + hides demand (Cincinnati), Kentucky tobacco/livestock (Maysville), bourbon (Louisville), and demand premiums + wider spreads at Shawneetown / Cairo / Memphis.

Rumor & reality banter. Reuses the existing banter system: hand-written rumors on the approach legs (the "every town's its own market" thesis early on the upper Ohio, plus Porkopolis/Kentucky-leaf/bourbon/hungry-landings color) and an engine-derived "wharf factor" reality line at each dock — composed from the same market data, so the spoken truth can never drift from the prices.

UI quotes actionable prices: the Trade screen and town-hub table show ask/sell, and the Natchez cash-out values cargo at the realizable bid (cargo_sale_value) rather than the mid.

Tests

  • Reworked the price-band test to fold in the local factor.
  • New reality_banter_matches_the_market (banter == schema invariant) and buy_ask_never_below_sell_bid (ask ≥ bid > 0 against the live buy_price/sell_price).
  • Market-bias range validation in the scenario consistency test.
  • Re-pinned the golden trace (0x4702_3407_a369_986e) — a deliberate retune (every quote moves).
  • Bumped trail-kit 0.1.6→0.1.7, kaintuck 0.1.11→0.1.12.

🤖 Generated with Claude Code

Last updated 2026-06-13