Assemble Run Pipeline
assembleRunDef is the single canonical assembly path that merges every metagame selection into one RunDefinition — the engine’s run-config contract. The engine itself does not know where any field came from; everything funnels through this function.
Inputs
AssembleParams carries the player’s selections from the hub:
shipId— hull class to fly (v4 bare hull name, e.g.'Bulwark'). Star is derived from inventory XP viauseInventoryStore.currentStar(shipId), defaulting to1.node— optional partial overrides for the mission/node config, merged ontoDEFAULT_RUN.node.unlockPools— progression-gated content pools fromderiveUnlockedContent(). When omitted, no gating is applied.planetIndex— index intoPLANETS. Drives biome, level preset, and enemy-count multiplier.isChallenge— Challenge Mode flag (10-level run, 2× rewards, 1.5× enemy difficulty).
Merge order
The pipeline assembles these contributions in order:
- Ship spec —
getShipDef(shipId, star)resolves the rarity-banded hull. Direct stats convert to engine combat stats viatoShipCombatStats()and meta stats viatoShipMetaStats(). - Node overrides —
params.nodepartial spreads ontoDEFAULT_RUN.node. - Planet preset —
PLANETS[planetIndex]suppliesbiomeandlevelPreset(resolved throughLEVEL_PRESETS) when the caller did not override them onnode. - World knob multipliers — base
worldKnobsare multiplied by:planet.enemyCountMult(per-planet, e.g. Voidstar = 2×)rarityScalefromRARITY_SCALE[shipDef.rarity](common 0.5 → legendary 1.0) — applied to enemy count, HP, and damage so the whole run scales with hull raritychallengeDiffMult(1.5× on Challenge Mode) — applied to count, HP, and damagechallengeRewardMult(2.0× on Challenge Mode) — applied torewardMultrarityScaleis also stored onworldKnobsso hardcoded melee/charger damage call sites can read it.
- Facilities + supply — buildings are disabled;
facilitiesstays atDEFAULT_RUN.context.facilitieszeros andsupplyLevel = 0. - Codex / artifact context — content gating fields (
weaponPool,upgradePool,levelupRarityCap,weaponCacheRarityCap) are allnull(no gating).eventsUnlocked,starsUnlocked, andeventTier = 3are forced on.startingArtifactIdis alwaysnull(Tick 67 removed the starting-artifact grant). - Identity —
planetIdandisChallengewritten through to context.
Output
A complete RunDefinition (version: 2) with:
node— merged node config (biome + level preset from planet, plus overrides).ship— id, color, accent,combatStats,metaStats,weaponSlotCount,nonWeaponSlotCount,startingWeapons(copied).context— gated/forced content flags,facilities,planetId,isChallenge,supplyLevel,worldKnobs,startingArtifactId.spawn,player,timing— passthrough fromDEFAULT_RUN.
Invariant
There is exactly one assembly path. The engine’s run loop never reads from the hub, inventory store, or planet table directly — it only reads RunDefinition. Any new metagame input (new ship dimension, new planet field, new unlock) must be folded into assembleRunDef before it can influence a run.
Throws if shipId is not found in the roster.