From 38097478dae0ddbc325b3c2b648b984984ea2d8e Mon Sep 17 00:00:00 2001 From: josh Date: Fri, 24 Apr 2026 20:00:06 -0400 Subject: [PATCH] Fix price elasticity and inference utilization bugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Price elasticity: subscribers ignored price entirely — a $50k/month subscription still grew. Replaced naive price/100 formula with a fair price model (based on model quality). Overpriced subscriptions now kill growth and drive churn at 3x the overprice ratio. Inference utilization: was always pinned at 100% because organic API token demand (10M base) and per-subscriber demand (100 tokens/tick) massively exceeded any realistic compute capacity. Reduced to 500 base organic tokens and 0.5 per subscriber so scaling compute meaningfully reduces utilization. Co-Authored-By: Claude Opus 4.6 --- packages/game-engine/src/systems/marketSystem.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/game-engine/src/systems/marketSystem.ts b/packages/game-engine/src/systems/marketSystem.ts index 773bf75..89af9a5 100644 --- a/packages/game-engine/src/systems/marketSystem.ts +++ b/packages/game-engine/src/systems/marketSystem.ts @@ -29,9 +29,13 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi let subscriptionRevenue = 0; if (chatProduct?.isActive && bestModel) { - const priceAttractiveness = Math.max(0, 1 - chatProduct.pricing.subscriptionPrice / 100); - const growthRate = (CONSUMER_BASE_GROWTH + modelQuality * CONSUMER_QUALITY_GROWTH_MULTIPLIER) * (0.5 + priceAttractiveness * 0.5); - const churnRate = CONSUMER_BASE_CHURN * (1 + (1 - consumers.satisfaction) * 2); + const price = chatProduct.pricing.subscriptionPrice; + const fairPrice = 20 + modelQuality * 80; + const priceRatio = price / Math.max(1, fairPrice); + const priceAttractiveness = Math.max(0, Math.min(1, 1 - (priceRatio - 1) * 0.8)); + const growthRate = (CONSUMER_BASE_GROWTH + modelQuality * CONSUMER_QUALITY_GROWTH_MULTIPLIER) * priceAttractiveness; + const priceChurnMultiplier = priceRatio > 1 ? 1 + (priceRatio - 1) * 3 : 1; + const churnRate = CONSUMER_BASE_CHURN * (1 + (1 - consumers.satisfaction) * 2) * priceChurnMultiplier; consumers.growthRatePerTick = growthRate; consumers.churnRatePerTick = churnRate; @@ -40,7 +44,7 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi const lostSubs = consumers.totalSubscribers * churnRate; consumers.totalSubscribers = Math.max(0, consumers.totalSubscribers + newSubs - lostSubs); - if (consumers.totalSubscribers < 100 && modelQuality > 0.1) { + if (consumers.totalSubscribers < 100 && modelQuality > 0.1 && priceRatio < 3) { consumers.totalSubscribers += 5 + modelQuality * 20; } @@ -67,7 +71,7 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi const priceFactor = Math.max(0.1, 1 - (textApi.pricing.outputTokenPrice / 20)); organicApiTokens = Math.floor( - qualityFactor * reputationFactor * priceFactor * 10_000_000 * (1 + state.meta.tickCount * 0.0001), + qualityFactor * reputationFactor * priceFactor * 500 * (1 + state.meta.tickCount * 0.0001), ); let contractTokens = 0; @@ -83,7 +87,7 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi } const totalTokenDemand = organicApiTokens + - consumers.totalSubscribers * 100 + + consumers.totalSubscribers * 0.5 + enterprise.activeContracts.reduce((s, c) => s + c.tokensPerTick, 0); const openSourceCount = state.market.openSourcedModels.length;