perf-test-mode
PURPOSE
Hidden stress-test gauntlet activated by ?perftest URL param. Boots the full engine under cranked entity counts and an indefinite auto-restart loop, then ships periodic perf snapshots to Supabase player_events for overnight soak testing, A/B render-config comparison, and memory-leak / context-loss detection.
OWNS
- Module-scoped session state:
_sessionId,_snapshotIdx,_intervalHandle,_runCount,_runStartMs,_deviceCtx,_activeFlags. SNAPSHOT_INTERVAL_MSconstant (telemetry cadence).DeviceContextinterface (UA, screen, dpr, effectiveDpr, cores, memGB, isMobile).- The stress-tuned
RunDefinitionfactorybuildPerfTestRunDef(). - Internal helpers
captureDeviceContext(),captureActiveFlags(),sendSnapshot().
READS FROM
../engine/core/config—PERF_FLAGS(incl.perftest,isMobile,dprOverride, render-disable toggles),PERF_VERSION_TAG,BUILD_VERSION.../engine/core/render-diag—diagGetPerfSnapshot(),diagDrainSpikes().../data/run-config—RunDefinitiontype,DEFAULT_RUNbaseline (spread + overridden).- Browser globals:
navigator.userAgent,navigator.hardwareConcurrency,(navigator as any).deviceMemory,window.innerWidth/innerHeight,window.devicePixelRatio,performance.now(),(performance as any).memory(Chrome/Edge only).
PUSHES TO
../../metagame/services/analytics—trackEvent()with three event types:perftest_start— once at session boot; includes device + active flags snapshot.perftest_snapshot— every 30 s; includessessionId,snapshotIdx,runNumber,runElapsedSec, version tags, device, flags, fullperfsnapshot,spikeCount, top-5worstSpikesbyframeMs, and JS heap stats when available.perftest_end— onstopPerfTestSession(); includes totals + a final snapshot flush.
DOES NOT
- Does not read or write game state directly (no engine ECS, no Zustand stores).
- Does not own the auto-restart loop — that lives in the screen/runner that calls
notifyPerfTestRunStart(). - Does not own the URL-param parsing —
PERF_FLAGS.perftestis set elsewhere inengine/core/config. - Does not gate itself:
isPerfTestMode()only reports the flag; callers decide whether to wire start/stop. - Does not retry, batch, or buffer telemetry — pure fire-and-forget through
trackEvent. - Does not throttle or cap session length; runs indefinitely until
stopPerfTestSession(). - Does not pin or tag the run with a player/user id (Supabase wiring is upstream of
trackEvent).
Signals
_intervalHandleis the re-entrancy guard forstartPerfTestSession()— second call is a no-op.- Memory block under
(performance as any).memoryis Chrome/Edge-only; the snapshot shipsmemory: nullon other engines (no try/catch — the guard is the truthy check). - Spike sort is destructive (mutates the array returned by
diagDrainSpikes()); drain semantics mean spikes are consumed per snapshot. worstSpikesis sliced to 5 entries to keep payload size bounded.runElapsedSecis per-run (resets onnotifyPerfTestRunStart()), not per-session; session age must be derived fromsnapshotIdx * 30._sessionIdformat:perftest_<epoch-ms>_<6-char-base36>— groups all snapshots from one boot.
Entry points
startPerfTestSession(): void— boots session id, device/flag capture, firesperftest_start, starts 30 s interval. Idempotent via_intervalHandleguard.notifyPerfTestRunStart(): void— increments_runCount, resets_runStartMs. Caller invokes on each auto-restart after death.stopPerfTestSession(): void— clears interval, flushes a finalsendSnapshot(), emitsperftest_end. Component-unmount hook.isPerfTestMode(): boolean— thin wrapper overPERF_FLAGS.perftest.buildPerfTestRunDef(): RunDefinition— returns aDEFAULT_RUN-spreadRunDefinitionwith stress overrides (enemy multiplier, fast spawn ramp, infinite survive timer, beefed ship). Callers feed this into the normal run pipeline instead of a real mission def.
Pattern notes
- Module-singleton state pattern: all session state is file-scoped
letvariables, not a class. Reflects single-active-session assumption — only one perftest runs per tab. - Snapshot is the unit of telemetry; the device + flag context is captured once at session start and re-attached to every snapshot for A/B grouping at query time.
RunDefinitionoverrides use the spread-merge pattern (...DEFAULT_RUN,...DEFAULT_RUN.node, etc.) — depends onDEFAULT_RUNshape staying stable; adding new required fields toRunDefinitionrequires no change here, removing or renaming does.versionandversionTagare stamped on every event so cross-build comparisons survive aBUILD_VERSIONbump mid-session in the dataset.- Curve shape (quantity/quality) is hand-tuned for fast stress ramp, not balance — kept in code, not the data tables, because perftest is a diagnostic surface, not a player-facing mission.
EXTRACT-CANDIDATE
- The capture-once / attach-per-event pattern (device context + active flags stamped on every telemetry event in a session) recurs anywhere a long-running diagnostic stream needs grouping. If a second long-soak telemetry surface appears, lift
captureDeviceContext()+captureActiveFlags()into a sharedengine/core/diag-context.ts. - The
(performance as any).memoryJS-heap probe is a generic Chrome-only diagnostic; if any other module starts shipping heap stats, extract intoengine/core/render-diagalongside the existing perf snapshot helpers.