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 <noreply@anthropic.com>
This commit is contained in:
@@ -29,9 +29,13 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi
|
|||||||
let subscriptionRevenue = 0;
|
let subscriptionRevenue = 0;
|
||||||
|
|
||||||
if (chatProduct?.isActive && bestModel) {
|
if (chatProduct?.isActive && bestModel) {
|
||||||
const priceAttractiveness = Math.max(0, 1 - chatProduct.pricing.subscriptionPrice / 100);
|
const price = chatProduct.pricing.subscriptionPrice;
|
||||||
const growthRate = (CONSUMER_BASE_GROWTH + modelQuality * CONSUMER_QUALITY_GROWTH_MULTIPLIER) * (0.5 + priceAttractiveness * 0.5);
|
const fairPrice = 20 + modelQuality * 80;
|
||||||
const churnRate = CONSUMER_BASE_CHURN * (1 + (1 - consumers.satisfaction) * 2);
|
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.growthRatePerTick = growthRate;
|
||||||
consumers.churnRatePerTick = churnRate;
|
consumers.churnRatePerTick = churnRate;
|
||||||
@@ -40,7 +44,7 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi
|
|||||||
const lostSubs = consumers.totalSubscribers * churnRate;
|
const lostSubs = consumers.totalSubscribers * churnRate;
|
||||||
consumers.totalSubscribers = Math.max(0, consumers.totalSubscribers + newSubs - lostSubs);
|
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;
|
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));
|
const priceFactor = Math.max(0.1, 1 - (textApi.pricing.outputTokenPrice / 20));
|
||||||
|
|
||||||
organicApiTokens = Math.floor(
|
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;
|
let contractTokens = 0;
|
||||||
@@ -83,7 +87,7 @@ export function processMarket(state: GameState, compute: ComputeState): MarketTi
|
|||||||
}
|
}
|
||||||
|
|
||||||
const totalTokenDemand = organicApiTokens +
|
const totalTokenDemand = organicApiTokens +
|
||||||
consumers.totalSubscribers * 100 +
|
consumers.totalSubscribers * 0.5 +
|
||||||
enterprise.activeContracts.reduce((s, c) => s + c.tokensPerTick, 0);
|
enterprise.activeContracts.reduce((s, c) => s + c.tokensPerTick, 0);
|
||||||
|
|
||||||
const openSourceCount = state.market.openSourcedModels.length;
|
const openSourceCount = state.market.openSourcedModels.length;
|
||||||
|
|||||||
Reference in New Issue
Block a user