Skip to content

Remote patchability roadmap (batches 8+)

Goal: after BUILD 259 ships (632 tunables + the gold-economy branch), close the remaining balance levers a store build can’t patch, in order of player impact, without breaking the numbers-only App Store stance (guideline 2.5.2) or the seed-1234 determinism baselines.

Source: a full inventory of sim/, ai/, content/, meta/, input/ at 66630181 (2026-10-04). Conversion rules, liveness probe and bounds are in docs/architecture/remote-config.md; every batch below follows them unchanged.

Area Balance knobs left Blocked by data shape
Player base / armor regen 1.0, first-level XP 100, armor curve 0.06/pt cap 0.75, enemy armor floor 0.25, knockback decay hull ShipBonuses.TABLE (base HP/speed/headline magnitudes)
Upgrades / crystals crystal grant amount 2..5 and types 1..3, CRYSTAL_REROLLS WEAPON_MODS, AIM_MODS, WeaponThresholds.TABLE
Evolutions ~40 inline evolve multipliers across 16 weapons (only Nova’s are tunable); evolve copy hardcodes them —
Weapons misc Thunder Wake root 0.6 s, Scar Tissue MAX_STACKS 5, ZONE_RADIUS/DURATION/DPS (Firestorm + Nova remnant) —
Elites / spawns stat-variance variant roll (8%, x1.5 HP, x1.4 speed), elite Wyrm x2 radius / x3 segments, Dimension unlock pick_wave * 2 spawn table weights, UNLOCK_ORDER, boss rotation match
Dimensions Electricity strike (dmg 16, radius 60, delay 1.2, dist 80-220) has no knobs at all; Ice hitbox frac 0.85 per-dimension rosters / weapon lists
Drones Disruptor pulse cadence 0.5 (two inline copies) Bomber/targeting kind lists; chain/payload/suppress per-level semantics
Bible enemies.armor bundled 0 on 16/31 enemies, so armor can’t be ADDED remotely —
Story / tutorial tutorial pacing consts, story TEACH_LOW_FRAC, BOSS_ADD_INTERVAL data/story.json (outside the overlay), tutorial LESSONS

Not levers (nothing to patch): survival is endless (no run timer), no difficulty modes, materials drops unbuilt, archetype tags are presentation-only. Offer counts (3 level-up cards, 3 dimension cards) are UI-layout-bound: leave as code.

Phase 0 — hygiene (ship in 259, ~1 hour)

Section titled “Phase 0 — hygiene (ship in 259, ~1 hour)”
  1. Add the 13 phantom meta_upgrades.*.magnitude fields to BibleOverlay.EXCLUDED_FIELDS (drone-slots, 4x unlock-drone-*, 9 novel drone attributes): today a patch to them validates and does nothing.
  2. Greed (Chris’s call): the shop sells meta_upgrades.greed (+12% pickup radius x5, 40g) but survival auto-collects XP and powerups are off, so it does nothing. Hide it (as Fuchsia and the pickup mod already are) or give it a live effect. Refund owned levels either way (the ledger handles it).
  3. DISRUPTOR_CD tunable replacing both inline 0.5s (drone_director.gd:101, :224).
  4. Delete dead consts found (BEACON_FLANK_MULT, SpawnDirector.pick_type() table, ELITE_XP_MULT) or list them as dead in remote-config.md, so nobody patches them later.

Phase 1 — batch 8: scalar statics (one session, same mechanics as batches 1-7)

Section titled “Phase 1 — batch 8: scalar statics (one session, same mechanics as batches 1-7)”

All plain const → static var + registry entry + liveness probe + safety-bounds test.

Key(s) Where Bounds note
PlayerState.BASE_REGEN player_state.gd:29 0..10 explicit (0 legal)
Sim.XP_FIRST_LEVEL player_state.gd:12 xp_to_next tutorial keeps its own const
Sim.ARMOR_PER_POINT, Sim.ARMOR_CAP sim.gd:3156 cap <= 0.95 (never invulnerable); stats sheet already calls the function
ElementalSystem.ARMOR_DMG_FLOOR elemental_system.gd:237 0.05..1.0
UpgradeSystem.CRYSTAL_AMT_MIN/MAX, CRYSTAL_TYPES_MIN/MAX upgrade_system.gd:201,205 CROSS_RULES lo <= hi; same upgrade_rng draw count, so baselines hold
Sim.VARIANT_CHANCE, VARIANT_HP_MULT, VARIANT_SPEED_MULT sim.gd:1383-1387 speed mult capped by the tunnelling rule (see SPEED_MULT_CEILING)
Sim.ELITE_WYRM_RADIUS_MULT, ELITE_WYRM_SEG_MULT sim.gd:1206/1679/1684 radius must keep within MAX_ENEMY_RADIUS
Sim.DIM_UNLOCK_RATE (int) sim.gd:2149 1..4
DimensionHazards.ELEC_DMG/RADIUS/DELAY/DIST_MIN/DIST_MAX sim.gd:2361-2362 dist pair CROSS_RULE
ElementalSystem.ZONE_RADIUS/DURATION/DPS elemental_system.gd:42-44 radius <= 80 if it feeds the hash query
WeaponThunderWake.ROOT_S, WeaponScarTissue.MAX_STACKS :171, :13 —
DimensionHazards.ICE_HITBOX_FRAC, Sim.KNOCKBACK_DECAY :68, constants.gd:10 0.5..1.0

Plus bible bounds for zero-bundled fields: give BibleOverlay explicit per-field min/max rules (like the registry’s) so enemies.*.armor can be raised from 0 (e.g. 0..20). Same mechanism then covers any other legitimately-zero column.

Phase 2 — batch 9: evolution multipliers + live copy

Section titled “Phase 2 — batch 9: evolution multipliers + live copy”

~40 per-weapon EVOLVE_* statics (weapon_aim, beam, blaster, chalice, chronowell, melee, momentum_core, orbit, pulse, railgun, scar_tissue, scatter, scythe, thunder_wake, turret, wildfire). The blocker is copy, not code: WeaponEvolutions.TABLE descriptions hardcode “x1.8 damage”; they must format from the live statics in the same commit (standing rule: copy that states a tunable’s value reads it live). One liveness scenario per weapon via liveness_probe.gd --start-upgrades=<weapon> past its 18-crystal rung.

Phase 3 — record-shaped data moves into the bible

Section titled “Phase 3 — record-shaped data moves into the bible”

New bible categories so the existing overlay (validation, hash, manifest, console) covers them with no new machinery beyond per-category rules:

  • ships — hull base_hp, base_speed, headline magnitude (slots stay structural/excluded). Hull labels format from data.
  • weapon_mods / aim_mods — the ~56 per-kind magnitudes.
  • weapon_thresholds — per-weapon rung amounts. New validator: amounts strictly increasing per weapon (publish-config.mjs mirror).

Risk: this is a content-pipeline change (bible.json ↔ game, design-bible tool). Read docs/architecture/content-and-elemental.md first; determinism must not move at bundled values.

Phase 4 — keyed-row tunables (new registry type)

Section titled “Phase 4 — keyed-row tunables (new registry type)”

For per-type number tables: SpawnTable._table (7 time rows of weights), Warden deck WEIGHTS_* + PREFERRED_RANGE, EnemyChipFire.SPEED_BY_TYPE, FunZo THRESHOLD_SUMMONS. Design: a registry entry of type "row" = Dictionary of id → float with a fixed key set (unknown/missing keys rejected) and optional sum rule (spawn rows sum to 1). Needs: Tunables.apply support, publish-config.mjs mirror, manifest typing, a console editor, and a liveness test. This is the biggest pacing lever and the biggest change: spec it first (brainstorm → spec → plan).

Phase 5 — decisions, not batches (Chris’s calls)

Section titled “Phase 5 — decisions, not batches (Chris’s calls)”
  • Membership lists (UNLOCK_ORDER, dimension rosters/weapon lists, boss rotation, drone kind lists, elite exclusions, story pools): an “enum-array of known ids” overlay is buildable, but it changes what content appears, which is closer to the 2.5.2 line than a number. Recommendation: keep in code; revisit only if a real patch need appears.
  • Story/tutorial (story.json, LESSONS): low value (fixed authored content, played once). Recommendation: skip unless the story becomes a live-ops surface.

Liveness probe per key (NO-DIFF → trace or revert), safety bounds pinned in tests/test_tunable_safety_bounds.gd, hot-loop hoists, control/src/tunable_docs.js tooltips, What’s new item, manifest regenerated at the BUILD bump (keys reach players only from that build on), determinism baselines untouched, bh-reviewer before merge, and the ATV frame-time gate before publishing any patch that raises spawn/elite/boss pressure.

Phase Size Ships in
0 hygiene ~1 h 259 with gold economy
1 batch 8 scalars 1 session (~25 keys) 260
2 evolutions 1 session (~40 keys + copy) 260/261
3 bible categories 1-2 sessions 261
4 keyed rows spec + 2 sessions 262+
5 decision only —

State on 2026-10-04 (written at the end of the planning session):

  • Chris asked for this plan (“mak a plan for making more of the game patchable”) right after asking for the whole gold economy to be patchable. He has NOT yet approved any phase; present Phase 0 + Phase 1 for a go-ahead before implementing, and get his two calls: greed (hide vs make it live) and the Phase 5 recommendations.
  • In flight, separate branch gold-economy (bh-implementer subagent, worktree .claude/worktrees/gold-economy): fractional gold accumulator, per-enemy bible gold, Sim.GOLD_MULT, float CRYSTAL_GOLD_BONUS. Not merged; needs bh-reviewer + Chris’s look at the Nebula/Aurora before/after gold numbers. Phase 0 here should land on top of it (both target 259).
  • Also unmerged: branch mac-app-store (this plan file is committed there): native Mac App Store pipeline (scripts/release/build-macos.sh, macOS preset in platform/tvos). bh-reviewer said DO NOT MERGE for 2 plist issues; both fixed in 6eed590b but not re-reviewed; the classifier blocked the fast-forward to main as “merge without review”. Chris must still: run the signing script he was given (Mac Installer cert + MAC_APP_STORE profile, classifier-blocked for Claude), add the macOS platform in App Store Connect, and pick Mac content (recommendation: release/ branch from store-255 vs BUILD 258/259 with unreviewed exponential scaling).
  • Release context: store build 255 (1.0.1) is WAITING_FOR_REVIEW on iOS; tvOS 1.0.1 is live. Store 255 carries 494 tunables; main’s next bump (259) carries 632 + whatever merges first.
  • Main checkout has another session’s uncommitted edits under tools/economy_sim/ and tests/test_economy_career.gd: never touch or stash them.
  • Next action: wait for / review the gold-economy result, then ask Chris for the Phase 0 calls and the go-ahead on Phase 1 (batch 8). Execute via bh-implementer in its own worktree, one batch per branch, bh-reviewer before each merge.