Skip to content

0079 — Haggling numerical model

Status

Folded into FEATURES/economy/haggling.md (rollup 2026-06-21) — the seven numbers + the band engine now live canonically in haggling.md § Numerical Haggling; this ADR is retained as the decision record.

Accepted (Max 2026-06-14). Resolves the seven open haggling numbers in one consolidating ADR (the contradictions span haggling.mdjsonb-schema.md); all numbers below are blessed. Supersedes haggling-numerical-v1 in DECISIONS.md. Single source of truth for haggling math.

Context

The round skeleton is solid (4-round limit, accept/counter/reject band table, reject-locks-commodity, final clamp [0.80, 1.20]), but seven numeric gaps / cross-doc contradictions block the build. Each is resolved below.

Decision

  1. Counter formula. When the player's offer is outside the acceptance band but not a reject, the NPC counters at the midpoint between the player's offer and the NPC's current fair price (split-the-difference, converging toward fair each round).
  2. Per-round band narrowing. The acceptance band narrows 20% per round (round 1 widest → round 4 tightest): early rounds forgive, late rounds demand near-fair.
  3. Rank modifier (resolves the 0–5% vs +1%/tier contradiction). Adopt the richer model: +1% effective price per rank tier, capped at +12%; the 0–5% figure is retired.
  4. Reputation-tier multipliers (pins the ranges). Faction rep linear from hostile ×1.05 → allied ×0.97 across the named tiers; personal rep linear from disliked ×1.05 → trusted ×0.95.
  5. Difficulty authority (resolves archetype-bands vs int 1–10). haggling_difficulty int 1–10 is the single source; archetype only sets that int. Map linearly: difficulty 1 → band-multiplier ×0.85 (easy/generous) … difficulty 10 → ×1.25 (hard/tight). The stray ×1.20 cap is raised to ×1.25 to match; the final realized price is still clamped to [0.80, 1.20].
  6. Perceived-fair-price model. Haggling modifiers adjust the acceptance band only, never the displayed/perceived fair price — this prevents double-applying the trading.md price-stacking modifiers that already set the base price.
  7. Session re-entry. After a non-reject close (accept or round-timeout), re-entry is allowed only after a cooldown (the :331-337 table becomes real — draft 5 min) to defeat accept-threshold binary search; a reject still hard-locks the commodity for the session. Reputation deltas are zero in numerical mode (it is pure price negotiation; the "optional reputation deltas" are off here).

Schema reconciliation (required before build): align Station.trader_personality to jsonb-schema.mdmemory_duration_days (not memory_duration) and trust in [−1000, 1000] (not a 50 default). NB: 100% of live stations carry the BORDER default, so archetype-driven difficulty is a no-op until a bang/seed pass derives real personalities — flagged as a prerequisite, not part of this ADR.

Consequences

  • Numerical haggling becomes buildable against a single, internally-consistent number set; haggling.md and jsonb-schema.md both defer to this ADR.
  • Build follow-up (player/gameserver lane): implement the band math, plus the prerequisite Station.trader_personality schema reconcile and the archetype difficulty seeding pass.

FEATURES/economy/haggling.md, DATA_MODELS/jsonb-schema.md, FEATURES/economy/trading.md (price-stacking order).