Remote patchability roadmap (batches 8+)
Remote patchability roadmap (batches 8+)
Section titled “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.
What is still not patchable (summary)
Section titled “What is still not patchable (summary)”| 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)”- Add the 13 phantom
meta_upgrades.*.magnitudefields toBibleOverlay.EXCLUDED_FIELDS(drone-slots, 4xunlock-drone-*, 9 novel drone attributes): today a patch to them validates and does nothing. - 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 thepickupmod already are) or give it a live effect. Refund owned levels either way (the ledger handles it). DISRUPTOR_CDtunable replacing both inline0.5s (drone_director.gd:101,:224).- 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— hullbase_hp,base_speed, headlinemagnitude(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.mjsmirror).
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.
Every batch (unchanged process)
Section titled “Every batch (unchanged process)”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.
Suggested order and size
Section titled “Suggested order and size”| 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 | — |
Execution handoff
Section titled “Execution handoff”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 biblegold,Sim.GOLD_MULT, floatCRYSTAL_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,macOSpreset 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 fromstore-255vs 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/andtests/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.