PURPOSE
Playground tab that drives the in-engine scenario-runner harness. Hosts three modes — Weapon Gauntlet, Artifact Matrix, and AABB — exposing buttons that kick off batched live-game test runs and renders their progress and result tables. Default mode on mount is the Weapon Gauntlet.
OWNS
- Default export
TestRunnerTab({ missionRef })— the tab’s root component. - Local component state:
runnerState(AABB),matrixState(full matrix),weaponGauntletState(weapon gauntlet),selectedArtifacts(Set<string>of artifact IDs),viewMode('aabb' | 'matrix' | 'weapons'). - Click handlers:
runWeaponGauntlet,toggleArtifact,selectAll,selectNone,runABAll,runABSelected,runTierSweep,runFullMatrix. - Derived flag
isRunning(true while runner status is'running'for either AABB or matrix). - Private subcomponents
WeaponGauntletPanel,WeaponMatrixGrid,MatrixGrid,MatrixRow. - Pure helpers
deltaPctColor(pct, triggered),fmtPct(pct, triggered), and theSCENARIO_LABELSrecord. - Module constants
SPEED_MULT = 4,WEAPON_GAUNTLET_LEVELS = [1, 5, 10, 15, 20],WEAPON_GAUNTLET_SPEED = 8,WEAPON_GAUNTLET_DURATION = 20.
READS FROM
./PlaygroundShared—BTN_STYLEfor all button styling.../../data/artifacts—ARTIFACT_DEFS(id, name, icon) for the selector grid and select-all action.../../testing/scenario-runner—scenarioRunnersingleton, plus typesWeaponGauntletStateandWeaponGauntletResult.../../testing/scenario-types—RunnerState,MatrixState,ScenarioType,ArtifactMatrixResult.../../testing/artifact-scenarios—SCENARIO_TEMPLATE_LIST(imported; not referenced at render time in this file).- Prop
missionRef: React.RefObject<any>— the live mission ref piped into the runner on mount.
PUSHES TO
scenarioRunner.setMissionRef(missionRef)— hands the runner the live mission handle.scenarioRunner.onUpdate(setRunnerState)— subscribes to AABB progress and results.scenarioRunner.onMatrixUpdate(setMatrixState)— subscribes to matrix progress and results.scenarioRunner.onWeaponGauntletUpdate(setWeaponGauntletState)— subscribes to weapon gauntlet progress and results.scenarioRunner.runWeaponGauntlet(WEAPON_GAUNTLET_SPEED, WEAPON_GAUNTLET_DURATION)from the WEAPONS panel.scenarioRunner.runABSuite(SPEED_MULT)from▶ AABB ALL.scenarioRunner.runABSelected([...selectedArtifacts], SPEED_MULT)from▶ AABB SELECTED.scenarioRunner.runTierSweep(id, SPEED_MULT)from▶ TIER SWEEP(exactly one artifact must be selected).scenarioRunner.runFullMatrix(SPEED_MULT)from▶ FULL MATRIX.scenarioRunner.cancel()from every mode’s✕ CANCELbutton while a run is in flight.
DOES NOT
- Does not own scenario logic, simulation stepping, weapon definitions, or artifact effects — only the runner orchestrates those.
- Does not persist results; everything lives in component state and disappears with the tab unmount.
- Does not write to telemetry, Supabase, Sentry, or any cloud surface.
- Does not mutate
selectedArtifactsafter a run completes; selection is independent of run lifecycle. - Does not validate that
missionRef.currentexists; passes the ref through to the runner unconditionally. - Does not gate buttons on each other across modes — switching tabs does not cancel an in-flight run.
Signals
runnerState.status === 'running'andmatrixState?.status === 'running'drive the sharedisRunninglockout for cross-mode buttons.weaponGauntletState?.status === 'running'additionally disables the weapon gauntlet button via theisRunningprop passed toWeaponGauntletPanel.- Tier sweep button is enabled only when
selectedArtifacts.size === 1. - AABB selected button is enabled only when
selectedArtifacts.size > 0. - Matrix progress block reads
matrixState.progress.{currentArtifact, currentTier, currentScenario, phase, current, total}. - AABB progress block reads
runnerState.{currentScenarioId, currentRun, currentStep, totalSteps}. - Weapon panel completion banner is gated on
state?.status === 'complete', showingstate.results.lengthandstate.wallTimeMs / 1000. - Result row color in AABB list: red when
r.reasonincludes'BROKEN', orange when it includes'NOISY', green onr.status === 'pass', otherwise red. - Matrix scaling-column color: red when
avgScaling > 3, yellow when> 2, otherwise green.
Entry points
- Imported and rendered by the Playground screen as one of the playground tabs (consumes
missionReffrom that parent). - Side-effect subscriptions registered once via
useEffect([missionRef])— re-subscribes if the parent ever swaps the ref.
Pattern notes
- Three orthogonal runner streams (AABB / matrix / weapon gauntlet) are kept in three independent useState slots, each fed by its own
onXxxUpdatecallback. The runner is treated as a singleton observable. - All run-triggering handlers are
asyncbut discard the resolved value; result rendering is driven entirely by the subscription callbacks, not by awaiting the promise. - Mode switching is purely visual — the conditional render blocks share no DOM and reset no state when toggled.
- The artifact selector grid is hidden in
'weapons'mode (viewMode !== 'weapons') because it is meaningless without an AABB or matrix run target. deltaPctColorthresholds (gray / green / yellow / orange / red at 0.20 / 0.05 / 0.0 / negative) andWeaponMatrixGridDPS thresholds (red / orange / yellow / green / purple at 5% / 15% / 40% / 75% / top) are inline magic numbers — not pulled from a constants module.WeaponMatrixGridpreserves weapon insertion order viaMapiteration, matching the order the runner emits results in.MatrixRowcomputesavgScalingper artifact as the mean ofscalingFactoracross the three scenario sweeps, defaulting missing sweeps to1.SCENARIO_TEMPLATE_LISTis imported but unused at render time; it is kept in the import graph alongside the other scenario-types imports.- Numeric formatting helper
fmtinsideWeaponMatrixGridcollapses values >= 1000 to1.2k-style strings; otherwise rounds to integer. - Tooltip on each weapon cell carries the full breakdown (
DPS, kills, total damage, durationSec) so the visual grid stays compact.