Fix compute utilization bug and add subscriber saturation cap
CI / build-and-push (push) Successful in 34s

Three intertwined fixes:

1. Zero-capacity utilization: when inference allocation was 0%, the
   guard clause returned 0% utilization instead of 100%, so the market
   system never penalized satisfaction and subscribers never churned.

2. Stale compute in market: restructured tick order so capacity is
   computed before market runs, giving satisfaction calculations
   current-tick demand/capacity ratio instead of previous tick's.

3. Subscriber growth: replaced pure compound growth (reached billions
   in minutes) with logistic saturation curve. Era-based market caps:
   startup 10K, scaleup 1M, bigtech 20M, agi 100M. Quality and
   reputation expand the effective cap.

Also tuned FLOPS-to-tokens multiplier (10 → 26) for balanced
demand/capacity feel across all eras, and added market saturation
indicator to the Market page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 20:50:26 -04:00
parent a36617f9e3
commit 900d1d5190
5 changed files with 134 additions and 41 deletions
+4 -7
View File
@@ -1,7 +1,7 @@
import type { GameState, AchievementDefinition } from '@ai-tycoon/shared';
import { processEconomy } from './systems/economySystem';
import { processInfrastructure } from './systems/infrastructureSystem';
import { processCompute } from './systems/computeSystem';
import { computeCapacity, finalizeCompute } from './systems/computeSystem';
import { processResearch } from './systems/researchSystem';
import { processModels } from './systems/modelSystem';
import { processMarket } from './systems/marketSystem';
@@ -49,13 +49,10 @@ export function processTick(state: GameState): Partial<GameState> {
}
const stateWithModels = { ...stateWithInfra, models: modelResult.modelsState };
const market = processMarket(stateWithModels, state.compute);
const compute = processCompute(state, infrastructure);
compute.tokensPerSecondDemand = market.totalTokenDemand;
compute.inferenceUtilization = compute.tokensPerSecondCapacity > 0
? Math.min(1, market.totalTokenDemand / compute.tokensPerSecondCapacity)
: 0;
const capacity = computeCapacity(state, infrastructure);
const market = processMarket(stateWithModels, capacity.tokensPerSecondCapacity);
const compute = finalizeCompute(capacity, market.totalTokenDemand);
const talent = processTalent(stateWithModels);
const stateWithTalent = { ...stateWithModels, talent };