Skip to content

Code cleanup audit, post-1.0 (2026-09-28)

Read-only audit of main at 4a418a6 (BUILD 206 = store build 37). Nothing was edited. The test suite was run once, on a copy of the repo in a scratch directory so the real checkout wasn’t touched: 320 scripts, 3151 tests, 3147 passing, 4 risky, 0 failing, 80.8 s.

Method: symbol-reference scans over the tracked .gd/.tscn/.json/.sh files, leaving out addons/, platform/ (symlinks) and _archive/; per-column read/write scans of EnemyPool; an argument-count check on every enemies.add( call; per-test timings from GUT’s JUnit output; git branch, worktree and size checks; and matching function names cited in the docs against the code.

Confidence tags: [Certain] checked directly in the code or by running it. [Likely] strong evidence with one unchecked assumption. [Guessing] an inference. Det. risk means removing or changing it could move the seed-1234 baselines in tests/test_determinism_survival.gd, tests/test_determinism.gd or tests/test_determinism_coop.gd. state_checksum() hashes pilot pos/hp/xp/level; enemy pos/HP/aura_element/stacks/aura_remaining; projectile, enemy-projectile and gem positions; and drones. Anything outside that set, and anything that draws no RNG, is safe to delete.


# Finding Why it matters Effort Det. risk
1 Halo Chain kills pay 0 XP and add 0 wave biomass. HaloChainDirector.spawn_pack calls enemies.add() with 11 args, so biomass_v falls back to 0. The bible says biomass: 2. This is the same bug class as the 2026-08 story-mode zero-XP bug, live in Survival (spawn_table.gd:29,77). Splitter children (sim.gd:2682) have the same problem, and may be intended to. A real gameplay bug, not cleanup. It also means the wave-pressure maths never counts Halo packs. S yes (spawn pacing; Halo unlocks late, so it is probably outside the 600-tick window, but re-run the baselines)
2 Remote config advertises boss stats that nothing reads. build-206.json manifests enemies.funzo.hp/armor/speed/contact_damage (and warden/graviton) as patchable. FunZo.spawn uses FUNZO_HP etc., and _enemy_types[TYPE_FUNZO] = {}. Only the Eye reads the bible. FunZo is the only survival boss (V01_FUNZO_ONLY). A balance patch to FunZo HP would publish “successfully” and do nothing. S (add to EXCLUDED_FIELDS), or M (make the boss directors read the bible) no, if excluded. Reading the bible is also no while the values match (they do today).
3 Delete the 5 stale agent worktrees and review 3 unmerged commits. .claude/worktrees/* is about 385 MB. worktree-agent-a0a9… (+ 2 uncommitted files) and -a46b… hold 3 commits that are not on main (2f7dc25 stats-sheet redesign, 4895303 death-screen damage breakdown, 4c57fba WIP TestFlight features). networked-multiplayer-mb-mc is 54 commits ahead and dates from July. Housekeeping, but check the 3 commits before deleting anything. S no
4 Dead Sim pacing and state. _next_boss_time/BOSS_FIRST_TIME/BOSS_INTERVAL are write-only. _spawn_swarm_burst + SWARM_BURST_* + _swarm_burst_fired have no live caller. _boss_spawn_count is write-only (5 increments, 0 reads). _spawn_accum and other_area() are unused. 4 boss tests assert on _next_boss_time. This is already on NEXT_TASKS. Misleading knobs, and tests of behaviour that no longer exists. S no (none of it is in the checksum, and none of it draws RNG)
5 Reactions-mode residue in EnemyPool and the render path. primed is only ever written 0, but main.gd:2222-2234 reads it per enemy per frame. react_cd is decremented every tick (elemental_system.gd:389) and never set or read. xp_val is written and never read. Elemental.apply() + ContentDB.reaction() are reachable from tests only. On NEXT_TASKS. Per-frame and per-tick waste. The 13-positional-arg add() is the trap behind finding 1. M no (aura_element/stacks/aura_remaining ARE in the checksum; leave those alone)
6 Retire the A/B look switches that have been decided. VisualLook.glass_ui (true) keeps the 631-line LegacyLevelUpPanel + its 168-line test + non-glass branches in pause_menu/level_up_base. VisualLook.nova, plasma_nova and ThreatRadar.radar_v2 each keep an old path alive (about 40 branch sites in about 15 files). Roughly 1,000+ lines removable once Chris confirms each pick. M no (render/UI only)
7 Consolidate the main.gd dev-only const flags. PERF_BENCH, AUTO_SHOWCASE, MEASURE_FULL_QUALITY, SHIP3D_MEASURE and RECORD_REPLAY are all false. Four of the five are “never ship true” benches. The MEASURE_FULL_QUALITY comment says “adaptive quality runs”, but ADAPTIVE_QUALITY := false. About 150 lines of main.gd, plus one misleading comment. Move them to a DevBench helper or a single BuildConfig dev flag. S–M no
8 Split sim.gd: 3,053 lines, not “~2,400”. Since the July split it has gained +1,881/−650 lines. Carve out SpawnSystem, StorySpawner, DimensionSystem, SimDevSeams and per-boss on_death() (see §3). The biggest structural win. It also fixes the CLAUDE.md drift. L yes, only if RNG draw order changes. Pure relocation is safe; gate each step on the 3 determinism tests.
9 main.gd._new_run() is 545 lines, _process 348, _physics_process 215. Extract EnemyColorizer (pure, about 200 lines), MainDevCommands (about 200), and a render-rig builder. Already on NEXT_TASKS for _new_run. Makes main.gd testable in slices. That unblocks the “no e2e test of _new_run order” item on NEXT_TASKS. M–L no
10 Beacon’s flank-jitter buff is documented but never wired. BeaconDirector.BEACON_FLANK_MULT is defined and referenced nowhere. The class header says Sim._move_enemies reads it, but EnemyBehaviors.step_walk only uses flank[i]. Only the telegraph buff is live. A feature gap, or a doc lie: decide which, then wire it or delete it. S wiring it: yes (Beacon is the last unlock, so probably outside the window). Deleting it: no.

Also cheap and worth doing in the same pass: menu_theme.mp3 and survival_loop.mp3 are byte-identical, 3.7 MB each, both shipped (§7). Upgrades.roll_choices() is a test-only RNG trap (§1). scripts/verify-sim-refactor.sh has a stale baseline (180 scripts vs 320) (§6).


Finding Evidence Conf. Effort Det. risk Suggested action
EnemyPool.xp_val written, never read enemy_pool.gd:102,261,320,376. The only non-pool mention is a comment at sim.gd:1127. bible_overlay.gd:35 already labels it dead Certain S no Remove the column + add()’s xp_v param. Doing so means updating all 22 add() call sites, so do it together with an add() redesign that takes a spec dict or named-arg builder, to kill the positional trap
EnemyPool.primed is never set to 1, but is read every frame enemy_pool.gd:95,256,315,371; main.gd:2222-2234 lerps colour when primed[i]==1 Certain S no Remove the column and the main.gd branch (NEXT_TASKS 2026-08-12)
EnemyPool.react_cd decremented each tick, never set or read elemental_system.gd:389 is the only use Certain S no Remove (NEXT_TASKS)
EnemyPool.shape_id: only TYPE_CUSTOM (dev tool) sets it sim.gd:1833 (dev_spawn_custom), read in archetype_renderer.gd:787 Certain — no Keep while the custom-enemy dev tool exists; note it as dev-only
Sim._next_boss_time, BOSS_FIRST_TIME, BOSS_INTERVAL write-only sim.gd:14-15,614, 5 writes at 2645-2676, no reads. Tests test_boss.gd:225, test_eye.gd:414, test_funzo.gd:383, test_graviton.gd:392 assert on it Certain S no Delete, plus the 4 tests. BOSS_FIRST_TIME is also used as a convenient “late enough” time in 4 tests; replace it there with a literal
Sim._spawn_swarm_burst, SWARM_BURST_TIME, SWARM_BURST_COUNT, _swarm_burst_fired sim.gd:82-83,616,1777. Only caller is tests/test_areas.gd Certain S no Delete (NEXT_TASKS)
Sim._boss_spawn_count write-only Incremented in all 5 boss spawn()s. Its declaration comment at sim.gd:615 (“5-way rotation counter”) describes the removed rotation. No reads anywhere, tests included Certain S no Delete
Sim._spawn_accum, Sim.other_area() sim.gd:519, sim.gd:1413: zero references Certain S no Delete
Upgrades.roll_choices(rng, …): test-only, and a determinism trap sim/upgrades.gd:7; only tests/test_upgrades.gd. Takes a raw rng. CLAUDE.md says to roll via upgrade_system.roll_upgrade_choices Certain S no Delete, so nobody calls it with sim.rng
Elemental.apply() + ContentDB.reaction() (reactions archive) Only tests/test_elemental.gd, test_mods_in_sim.gd, test_content_db.gd Certain S–M no Move to _archive/ or delete, along with its tests (NEXT_TASKS)
Sim.RULESET_REACTIONS / ruleset field sim.gd:382-391. Only SURVIVAL is ever set; 4 ruleset ==/!= guards Certain S no Collapse the guards and drop the field
Dead consts BeaconDirector.BEACON_FLANK_MULT (beacon_director.gd:30, see summary #10); EliteKit.WEB_SLOW_MULT (elite_kit.gd:87, “PlayerState.BEAM_SLOW_MULT mirrors this”, so a duplicate source of truth); ThreatRadar.V2_TOP_K/V2_SIZE/V2_EDGE_INSET (threat_radar.gd:26-29); ElementPalette.PLAYER_CORE; FunzoTreatments.TREATMENT_COUNT; QualityManager.TARGET_FPS; UiTokens.BG_PANEL Certain (0 refs) S no Delete. For WEB_SLOW_MULT, make PlayerState.BEAM_SLOW_MULT reference it, or delete one of the two
Dead functions (0 refs anywhere) Ship3DRenderer.tilt_idle (ship3d_renderer.gd:195), BossEdgeIndicator.arrow_direction (:100), ButtonPrompt.style_for_device (:44), MetaShopPanel._rebuild_current (:905, comment says “for tools”, but no tool calls it), UpgradeCopy.leech_cap_per_tick (:21) Certain S no Delete
Test-only production functions (69 found) Most are legitimate test accessors (hp_fill_width, active_count, …). Notable non-accessors: SpawnDirector.spawn_count_for, DroneDirector.drone_kinds_for, StoryState.tutorial_locked, MetaState.has_seen, UpgradeSystem.upgrade_choice_display, UpgradeSystem.live_dps (the last is read by test_results_panel only; check whether the results panel was meant to show it) Likely S no Review the non-accessor ones. Accessors stay
Ship3DRenderer (244 lines) + ShipClasses Only live-code user is main.gd, behind SHIP3D_MEASURE := false (“DISABLED 2026-07-01, live SubViewport-3D broken on tvOS”). Also used by tools/ship_preview Certain S no Keep for the tool; drop the main.gd wiring (see §2)
Power-ups (gated off by POWERUPS_ENABLED := false) sim.gd:97-114 consts, _collect_powerups/_apply_powerup (sim.gd:2858-2893), render/powerup_renderer.gd (52 lines), 5 main.gd refs Certain S yes: the skirmisher death must keep rng.randi_range(0, POWERUP_KINDS-1) (sim.gd:2691) or the spawn stream shifts Park until Chris decides. If deleted, keep a bare rng.randi_range(0, 3) with a comment, or re-pin via bh-determinism-repin
Boss2 (gated by BOSS2_ENABLED := false) sim/boss2.gd (245), boss2_state, renderer, 2 tests (232 lines), elite path sim.gd:2030 Certain M no (the elite path is behind the const and draws nothing) Chris’s call: archive it like reactions, or keep it for revival
Warden elite path only reachable in Aurora/Ember Reach sim.gd:2023 (current_area != HOME). NEXT_TASKS says real play never enters them Likely S no Fold into the NEXT_TASKS decision
_archive/ (1,168 lines) duplicates git tags Tags pre-reactions-archive-2026-07-09 and pre-portal-popup-archive-2026-07-10 exist. _archive/ has no .gdignore, so Godot still parses its .gd files. The memory note records a class_name collision from this Certain S no Delete _archive/ (the tags keep the history), or at least add _archive/.gdignore
Teaser wormhole (V01_FUNZO_ONLY gate) _spawn_teaser_wormhole (sim.gd:2819) has no live caller (retired 2026-07-07, per the comment at sim.gd:2698-2702). But _update_teaser_wormhole() still runs every tick (sim.gd:922) on an always-empty dict, and main.gd still drives WormholeRenderer + _check_teaser_event for it Certain S no (it draws no RNG and isn’t hashed) Delete the spawn/update/consume trio, WORMHOLE_RADIUS, V01_FUNZO_ONLY, WormholeRenderer, main._check_teaser_event, test_teaser_wormhole.gd, test_wormhole_renderer.gd, test_v01_funzo_only.gd
Orphan .uid files (untracked, on disk) 17, for example ui/crystals_levelup_panel.gd.uid, ui/control_hint.gd.uid, sim/decoy_state.gd.uid, tests/test_zzz_verify_TEMP.gd.uid Certain S no find . -name '*.gd.uid' for files with no matching .gd → delete

Other enemies.add() calls that drop biomass_v

Section titled “Other enemies.add() calls that drop biomass_v”
Call site Args Intended? Conf.
halo_chain_director.gd:80 (Halo Chain packs, live in Survival) 11 No. The bible has biomass: 2, and the code passes xp_value Likely (bug)
sim.gd:2682 (splitter children) 10 Probably not: it passes sw["xp_value"], which suggests XP was intended. 0 XP since the XP→biomass switch Likely
boss2.gd:219 (Boss2 summons) 10 Unclear. Boss2 is disabled Guessing
funzo.gd:252 (jesters), enemy_attacks.gd:99 (tank missiles) 11/12 Yes (commented “no XP farming”) Certain
5 boss spawn()s 11 Yes (_xp_worth falls back to BOSS_XP_BIOMASS) Certain

Suggested action: a regression test per spawn path, on the real spawn→kill→_sweep_dead path. Then make biomass_v required: move it before the defaulted params, or have add() take a spec.


Every const X := true/false outside tests (23), plus the runtime static var switches.

Flag Value Gates Dead? Conf. Suggested action
main.gd:158 MEASURE_FULL_QUALITY false fps overlay + pin L0 (main.gd:1347-1360,1756) Dead path. Its comment (“adaptive quality runs”) contradicts ADAPTIVE_QUALITY := false Certain Delete, with the measure_label/_fps_* vars
main.gd:162 ADAPTIVE_QUALITY false QualityManager.tick (main.gd:1754). Memory says “re-enable at release”, but 1.0 shipped with it off Off in shipping Certain Chris’s call: re-enable, or accept “always L0” and strip the auto-degrade half of QualityManager (Debug Settings still sets tiers manually)
main.gd:167 PERF_BENCH (+_DWELL_S, _MAX_LEVEL, _RUN_S) false tier-cycling bench (main.gd:475,749,1326,1744) Dev-only, “never ship true” Certain Move to a DevBench RefCounted helper, or behind BuildConfig.dev_tools() + a Debug Settings row instead of a const edit
main.gd:176 AUTO_SHOWCASE (+SHOWCASE_*) false hands-free attract/warp showcase (main.gd:444-472,1326,1734) Dev-only Certain Same as PERF_BENCH
main.gd:187 V01_LOCK_AREAS false sim.areas_enabled=false (main.gd:908) False branch dead Certain Delete (Dimensions are live)
main.gd:196 V01_LOCK_COOP false P2 join (main.gd:848) False branch dead Certain Delete, or keep as a documented kill switch
main.gd:203 SHIP3D_MEASURE false Ship3DRenderer spike (main.gd:9,1198) Dead (“DISABLED 2026-07-01”) Certain Delete the main.gd wiring
main.gd:207 RECORD_REPLAY false ReplayRecorder (main.gd:906,1607) Dev-only, but feeds tools/story_board Certain Keep; make it runtime (dev console/Debug Settings) instead of a const
main.gd:254 ENEMY_HIT_FLASH true hit-flash tint (3 sites) Decided (“GRAPHICS CANDIDATE 1”) Likely Inline, drop the flag
render/archetype_renderer.gd:146 USE_BAKED_GLOW false baked-glow path (:353) Dead path. Its outputs (ghost_glow_baked.png, orbiter_glow_baked.png) were never committed Certain Delete the branch + tools/glow_bake/bake_{ghost,orbiter}_glow.gd
render/player_renderer.gd:52 USE_LIT_HULL true lit normal-mapped hull Decided Likely Inline; drop the 3 pass_test branches in test_player_renderer.gd
render/player_renderer.gd:60 USE_BAKED_HULL true baked 3D hull sprite Decided Likely Inline; drop 6 pass_test branches
render/warp_effect.gd:25 BLUR_V2 true warp afterimages (10 sites across 3 files) Decided Likely Inline, delete the V1 streak code
render/warp_effect.gd:32 SPEED_LINES false streak lines Dead path Certain Delete
sim/boss_rotation.gd:10 V01_FUNZO_ONLY true now only the teaser-wormhole spawn guard (sim.gd:2820), and that spawn function has no caller Dead Certain Delete with the teaser machinery (§1)
sim/enemy_behaviors.gd:168 CHARGER_CRUISE_WHILE_CHARGING false Charger movement during charge Dead path Certain Delete the branch (det: no, elites are absent from the baseline)
sim/enemy_behaviors.gd:250 ELITE_SPIDER_RAY_USE_MOVING_EMITTER true legacy ray path “kept for an easy revert” (:280+) + test_elite_powers.gd:126 legacy tests Legacy path dead Certain Delete the legacy path + its tests
sim/sim.gd:68 BOSS2_ENABLED false Boss2 elite see §1 Certain Chris’s call
sim/sim.gd:101 POWERUPS_ENABLED false power-up drops see §1 (keep the RNG draw) Certain Chris’s call
sim/sim.gd:224 AUTO_COLLECT_XP true gem-drop XP path (sim.gd:2545) Gem-XP branch dead Certain Delete the gem branch only if physical gems are gone for good (det: no; with the flag true, kills spawn no gems)
ui/start_menu.gd:17 V01_CRYSTALS_ONLY true hides Story mode Live gate, misnamed (there is no “Crystals” mode any more) Certain Rename to STORY_HIDDEN or similar; keep
ui/touch_controls.gd:27 SYS_SLOT_IS_FEEDBACK true touch sys-slot = feedback vs HUD toggle Decided Likely Inline
fx/damage_numbers.gd:17 MERGE true number merging Decided Likely Inline
Runtime static var: VisualLook.nova/nova_ground/glass_ui/plasma_nova, ThreatRadar.radar_v2, Ship3DRenderer.topdown_override, TouchControls.slide_abilities mixed A/B switches exposed in Debug Settings Old paths are alive only for A/B Certain Once Chris confirms each pick, delete the losing path (see summary #6). LegacyLevelUpPanel is the biggest single deletion

sim/sim.gd: 3,053 lines (CLAUDE.md says “~2,400”), 94 funcs, 165 vars, 119 consts, 33% comments

Section titled “sim/sim.gd: 3,053 lines (CLAUDE.md says “~2,400”), 94 funcs, 165 vars, 119 consts, 33% comments”

Growth since the 2026-07-02 split: +1,881 / −650 lines. Almost all of it went back into the conductor instead of into modules.

Responsibility (still in Sim) Functions (line) ~Lines Proposed module
Spawn pipeline _spawn_one 1486 (136), _spawn_wyrm 1622 (82), _spawn_wave 1924, _spawn_enemies, _pick_extra_variety, _spawn_point, _spawn_due_elites, _spawn_boss_adds, _spawn_elite_swarmer_brood, _vary_stats, _element_for_spawn, _dim_buff, _update_spawn_phase, _set_spawn_phase, spawn_banner, total_biomass, _count_of_type, _build_enemy_types 710 (74) ~650 SpawnSystem (sim.spawn_system). RNG draw order is load-bearing: move bodies verbatim and gate on all 3 determinism tests
Story/tutorial spawns + rewards enable_story, spawn_story_boss (46), spawn_story_enemy (78), _spawn_story_wyrm (50), grant_story_reward, _build_weapon_remap, drop_weapon_pickup, _collect_weapon_pickups, tutorial_locks ~330 StorySpawner. Also dedupe _spawn_story_wyrm against _spawn_wyrm (near-parallel, both set _wyrm_biomass)
Dimensions / areas enter_area, _dimension_allowed_types, _remap_to_dimension, _update_dimension_hazard, _spawn_fire_hazard, _spawn_void_hazard, _award_dimension_crystals, _roll_dimension_choice, teaser wormhole trio, _spawn_phase_boss, _spawn_dimension_boss, _update_chalice_zones ~330 DimensionSystem (next to the existing dimension_hazards.gd)
Boss death rewards _sweep_dead 2565 (144): 5 near-identical elif dead_type == TYPE_X branches (gold + crystals + reset + “BOSS DOWN”) ~60 A on_death(sim, pos) on each boss director; _sweep_dead dispatches through boss_rotation
Pilot survival _update_dash, _apply_regen, stand_heal_rate, _hurt_player (49), _check_pilot_hit (39), _armor_reduction, armor_reduction_for, is_invulnerable, _all_pilots_down ~220 PilotSystem
Dev/playtest seams dev_set_player_stat, dev_set_funzo_hp_frac, dev_clear_enemies, dev_spawn_custom, dev_force_grant_weapon, dev_remove_weapon, dev_reset_upgrades ~120 SimDevSeams. Keeps dev-only code out of the shipping conductor
Power-ups consts + _collect_powerups, _apply_powerup ~60 Delete or PowerupSystem (§1)
Conductor proper _init, tick (173), tick_single, movement of projectiles, XP/level-ups, checksum/snapshot ~900 stays

The end state is about 1,000 lines. Also: sim.gd:808 has the only TODO in the codebase (“integrate() still hardcoded to player/player2”). Solve that when co-op goes past 2 pilots, not in this pass.

main.gd: 2,896 lines, 93 funcs, 164 vars, 21% comments

Section titled “main.gd: 2,896 lines, 93 funcs, 164 vars, 21% comments”
Responsibility Functions ~Lines Proposal
Run bootstrap _new_run (545 lines, 79 .new() calls) 545 Split per NEXT_TASKS: _setup_sim_and_content, _setup_renderers (→ a RenderRig RefCounted that owns the ~40 renderer refs, which also drops ~40 vars from main), _setup_ui_and_hud, _setup_dev_overlays. That makes the run-start order unit-testable (the NEXT_TASKS remote-config item 3)
Per-frame render sync _process (348), _physics_process (215) 560 Pull out the render-sync block (drain fx events → renderer syncs) into RenderRig.sync(sim, delta). The incident-narrative comments (e.g. the 25-line “corpse bug” story at _process +21..+81) belong in docs/architecture/rendering-and-performance.md
Enemy/projectile colouring (pure) _build_enemy_type_colors (48), _base_color_for_type (32), _swarmer_color, _enemy_colors (44), _enemy_proj_colors, _proj_colors, _sync_aim_lance, + 6 colour buffers ~220 render/enemy_colorizer.gd (RefCounted, takes sim). Pure, so it’s headless-testable. Removes the dead primed branch
Dev console apply_dev_command (53), _set_funzo_treatment, _dev_spawn_boss, _dev_spawn_positions, build_status, build_caps (47), save-debug label ~220 MainDevCommands (RefCounted, takes main)
Dev benches _setup_showcase, _update_showcase_label, _showcase_dash_due + PERF_BENCH/MEASURE blocks ~150 Delete or DevBench (§2)
Level-up/dimension flow _open_levelup (45), _next_leveling_pilot, _leveling_pilot_idx/_device, _await_drawn_frame, _on_upgrade_chosen, _open_dimension_choice, _on_dimension_chosen ~180 LevelUpFlow
Tutorial UI gating tutorial_pause_hidden, tutorial_hotkey_blocked, tutorial_tip_for, _objective_panel_blocked, _touch_controls_blocked, _stage_tutorial_hud, _update_objective_panel ~120 TutorialUiGate
Menus/pause/bay/shop routing _toggle_pause (69), _show_start_menu, _return_to_menu, bay, shop ~300 stays (this is main’s real job)

ui/meta_shop_panel.gd: 1,739 lines, 81 funcs

Section titled “ui/meta_shop_panel.gd: 1,739 lines, 81 funcs”
Responsibility Functions ~Lines Proposal
Pure layout maths (already static and tested) layout_for, column_count, card_metrics, sort_for_grid, affordable_count, badge_count/text, content_width, sparse_row_x, tab_sections, fit_font_size, wrapped_line_count ~170 ShopLayout (static RefCounted). No behaviour change
Card factory + skins _make_upgrade_card (65), _set_upgrade_card_content (59), _level_pips, _make_card, card_skin, _text_button_skin, _glass_pill, _cat_color, _cat_icon, _label, _header_button ~260 ShopCardFactory
Reset-shop dialog _build_reset_dialog (72), _handle_reset_dialog_input, highlight/open/close/confirm ~130 ShopResetDialog (Control)
Tip overlay _build_tip (52), _fill_tip_advice, _show_tip, _dismiss_tip, _handle_tip_input ~130 ShopTipOverlay (Control)
Grid/rail/nav/input _ready (116), _input (101), _build_rail (92), _rebuild_grid, _move, focus ~800 stays

Finding Evidence Conf. Effort Det. risk Action
cooldown_frac() identical in 11 weapons (+1 near-identical) clampf(1.0 - _timer / maxf(cooldown, 0.001), 0.0, 1.0) in 11 of 16 sim/weapon_*.gd that define it Certain S no WeaponCooldown.frac(timer, cd) (NEXT_TASKS 2026-08-12)
"power" mod-preview case 32 "power": sites across sim/weapon_*.gd Likely S–M no WeaponModDisplay.power_now_after() (NEXT_TASKS)
Menu nav debounce hand-rolled in 11 panels 11 separate NAV_DEBOUNCE_MS consts (150/160/180/200), 41 debounce-timestamp sites. MenuNav only centralises the direction predicates. 7 separate _ui_nav() sound helpers Certain M no Add MenuNav.Debouncer (or a static accept(ms)), with one tvOS value and per-panel override only where it’s justified (the shop’s 150 ms)
Boss death rewards ×5 sim.gd:2635-2677 (see §3) Certain S no (keep the append order of fx_events/run_gold; neither is hashed) on_death() per director
Boss spawn/enrage boilerplate ×5 Each spawn() does add() → state.reset() → max_hp → _boss_spawn_count += 1 → a name fx event. hp_frac + “latch ENRAGED” repeated in eye.gd:81-87, graviton.gd:69-77, funzo Certain M no, if the call order is kept A small BossCommon.spawn_pooled(sim, spec) + BossCommon.check_enrage(state, hp, frac)
Boss stats: two sources of truth Warden/Boss2/FunZo/Graviton use code consts (BOSS_HP etc.), Eye reads content.enemy("eye"). The bible values match today, but nothing enforces it Certain S–M no, while the values match Pick one. Reading the bible also fixes summary #2
_spawn_story_wyrm vs _spawn_wyrm sim.gd:1162 (50) vs 1622 (82), same segment-building shape Likely S yes, if _spawn_wyrm’s draw order changes Share a builder; the story variant just skips scaling
Legacy vs glass level-up panels level_up_panel.gd (788) + level_up_panel_legacy.gd (631) both implement nav/confirm/cards Certain — no Delete legacy (§2) rather than dedupe
6 enemy-attack timer passes rebuild dicts each tick enemy_attacks.gd vs update_lancers (NEXT_TASKS 2026-08-12 perf) Likely S no (dictionary iteration order: check that nothing iterates these for RNG) Mirror update_lancers
Duplicate sprite assets render/ship_sprites/nova/hull_b_{body,glow}.png = manta_{body,glow}.png (same md5) Certain S no Keep one and point both hull ids at it

Measured run: 80.8 s total, 3151 tests, 0 failing, 4 risky, 163 orphans. The suite is healthy and fast. The findings are about dead coverage, not speed.

Finding Evidence Conf. Effort Det. risk Action
Slowest scripts test_soak_run 18.4 s (29 tests), test_economy_career 11.3 s (4 tests, 3.8 s each), test_profiled_auto_player 8.9 s, test_main 7.1 s, test_testflight_build33 4.5 s. The top 3 are 48% of the suite Certain S no Acceptable. If gate time matters, shorten the career tests’ run count, or tag them “slow” and run them in gate.sh only
Tests of dead behaviour 4× *_death_advances_next_boss_time (boss, eye, funzo, graviton); test_areas swarm-burst case; test_elemental.gd (whole file, Elemental.apply); reaction cases in test_mods_in_sim/test_content_db; test_threat_radar.gd (V1 radar, flips radar_v2 off); test_level_up_panel_legacy.gd (168); legacy spider-ray tests (test_elite_powers.gd:126+); Boss2 tests (test_boss2*.gd, 232 lines, feature disabled) Certain S no Delete alongside the code they cover
Flag-conditional pass_test escapes 15+ sites where a test passes trivially depending on a const: test_player_renderer.gd:143-195 (6), test_main.gd:1184,1202 (legacy panel), test_survival_ruleset.gd:119,165, test_upgrade_effects.gd:97,103 (“no reaction_damage_mult mod in content”) Certain S no Once the flags are inlined these become real asserts or get deleted. Today they can hide regressions
4 risky (no-assert) tests test_debug_settings_panel: test_apply_background_variant_is_null_safe, test_apply_graphics_toggle_is_null_safe, test_apply_tilt_mode_is_null_safe; test_player_renderer: test_set_tilt_is_safe_to_call_in_every_mode_without_crashing Certain S no Add pass_test("no crash") or a real assert
163 orphan nodes spread over about 40 scripts, 1–4 each Certain M no Low priority; autofree/add_child_autofree
Build-numbered / naming-drift tests test_testflight_build33.gd (fine as regression, but name it by behaviour); test_crystal_state.gd, test_crystal_endless_tuning.gd, test_dud_crystal_filter.gd; the determinism test’s assert messages say “crystals mode” / “crystals snapshot hash baseline” (test_determinism_survival.gd) Certain S no (messages only, don’t touch the pinned numbers) Rename files and messages
Test files larger than their subject test_dimension_hazards 1106 vs 723; test_debug_settings_panel 824 vs 746; test_funzo 531 vs 316; test_graviton 484 vs 224; test_eye 514 vs 306; test_main 1497 Certain — no Not a problem in itself; the boss tests shrink when the dead _next_boss_time tests go

Item Status Evidence Conf. Action
scripts/verify-sim-refactor.sh Dead: hardcoded BASELINE_SCRIPTS=180, BASELINE_TESTS=1231 (the suite is 320/3151), one-off from the July split last touched 2026-07-02, 1 ref Certain Delete (gate.sh + check-test-count.sh replace it)
scripts/deploy-demo.sh Live (bh-deploy skill uses it) last touched 2026-06-23 Likely Keep
gate.sh, check-test-count.sh, soak.sh, ui-sweep.sh, economy-careers.sh, publish-config.mjs, release/, fix-tvos-appstore-icons.py, test/ Live 5–72 refs each, touched Sep Certain Keep. Note that gate.sh runs git checkout -- project.godot on exit, which silently discards any intended project.godot edit in the working tree
tools/glow_bake/ (32 files) Mostly one-off 2026-07-22 experiments. bake_ghost_glow/bake_orbiter_glow/compare_ghost_glow/bake_hires write outputs that were never committed. live_check_warden_enraged.tscn, live_check_warden_untinted.tscn have 0 refs; verify_start_menu_carousel.tscn has nothing to do with glow USE_BAKED_GLOW := false Likely Keep bake_shape_glows (its output is live in the renderer) and preview; delete the rest, or move them to a tools/_experiments/ with .gdignore
tools/glow_compare, nova_vfx, nova_units, look_metrics, warp_capture, glass_preview One-off A/B harnesses from the 2026-09-23/24 look goal (1–6 refs, mostly docs). bh-vfx-iteration references the pattern Likely Keep glow_compare (the skill uses it); archive the rest once the look A/Bs are retired (§2)
tools/app_icon One-off, but reusable for icon refreshes Likely Keep
tools/economy_sim/ablate.gd, calibrate_runner.gd, tools/sim_bench/sim_bench.gd Entry points run via godot -s, not referenced by other code. Fine; documented in docs/research/2026-09-27-* and rendering-and-performance.md Certain Keep
tools/shop_lab Last touched 2026-07-02; the shop was rebuilt on liquid glass on 2026-09-24 Guessing Check that it still boots. If not, delete
tools/story_board Live (dev-tools doc), tutorial-only (NEXT_TASKS) Certain Keep
Missing paths referenced Only tool output paths (.godot/imported/*, tools/*/out*.png, the two unbaked glow PNGs). No live-code res:// path is missing Certain None needed

Finding Evidence Conf. Effort Action
Byte-identical music shipped twice audio/menu_theme.mp3 and audio/survival_loop.mp3, both 3,737,616 B, same md5. Both are played (main.gd:478,728) Certain S Either one file for both events (saves 3.7 MB of bundle), or the survival loop was meant to be different music: ask Chris
Stale worktrees 5 under .claude/worktrees/ (about 385 MB). See summary #3: 3 unmerged commits on worktree-agent-a0a9… (+2 dirty files: main.gd, ui/stats_sheet.gd) and -a46b…; networked-multiplayer-mb-mc is 54 commits ahead (2026-07-03, netcode work; probably belongs with ~/Claude/sovereign or an archive tag) Certain S Diff each unmerged commit against main. Tag networked-multiplayer-mb-mc as archive/netcode-mb-mc before removing it. Then git worktree remove + git branch -D
Stale branches tutorial-lessons and origin/feature/8-dimensions-full are both fully merged into main Certain S git branch -d tutorial-lessons; git push origin --delete feature/8-dimensions-full (outward-facing, so it needs a same-day OK)
_archive/ see §1 Certain S Delete (tags exist) or .gdignore it
Important gitignored files .claude/skills/* (19 project skills incl. bh-deploy, bh-appstore-release, bh-determinism-repin) are ignored by the global ~/.gitignore_global:13 .claude/, so Toby doesn’t get them and they have no history. .claude/hooks/, the root export_presets.cfg (ignored at .gitignore:6; the tvOS one is tracked). .claude/skills/bh-deploy-mac-dev.md is tracked but is a flat .md, not a <name>/SKILL.md dir, so it isn’t a loadable skill Certain S–M Chris’s call: force-add the skills dir (the rescue-gitignored-content pattern), which matters now there are two devs
Largest tracked binaries marketing/audio/dark_cosmos_theme.wav 4.9 MB, 3 × music mp3 ~3.7 MB, audio/orbit_ambience.wav 0.9 MB, App Store PNGs 0.4–1 MB. Pack is 57 MB total, so it’s fine Certain — Optionally convert orbit_ambience.wav to ogg
audio/candidates/ (12 files, 264 KB) tracked Sound-map audition candidates; blaster_fire.wav = candidates/weapon.blaster.fire/c1.wav. The tvOS export doesn’t exclude audio/candidates/* Likely S Add to the export exclude_filter, or untrack
Export filters The tvOS preset excludes tests/*, telemetry/*, tools/* but not _archive/*, docs/*, audio/candidates/*. The root presets exclude only marketing/*, so tests and tools may ship in the web/mac export Likely S Align the exclude filters across presets
Orphan .uid files on disk 17 (§1) Certain S Delete
TODO/FIXME/HACK 1 in all of .gd (sim.gd:808). Legacy/temporary markers: main.gd 7, meta_store.gd 3, level_up_base.gd 2, pause_menu.gd 2, shop_categories.gd 2 Certain — Deferred work is tracked in NEXT_TASKS rather than in inline TODOs; the “TEMPORARY”/“SPIKE” markers in main.gd line up with §2

Doc Says Reality Conf. Action
CLAUDE.md sim.gd is “~2,400-line conductor” 3,053 lines Certain Update after the §3 split (or now)
CLAUDE.md RNG streams at sim/sim.gd:245-248 sim.gd:273-276 Certain Replace the line numbers with the symbol names
CLAUDE.md _damage_enemy/_resolve_collisions/_apply_element live in elemental_system.gd They’re damage_enemy/resolve_collisions/apply_element (no underscore) Certain Fix the names
CLAUDE.md boss_rotation.gd = “boss-index lookups + survival rotation dispatch” Rotation dispatch removed 2026-07-09 (boss_rotation.gd:5) Certain Fix
CLAUDE.md “the seed-1234 600-tick baseline is pinned in tests/test_determinism_survival.gd” There are 3 determinism files (test_determinism.gd, _survival, _coop) Certain List all three
docs/architecture/enemies-bosses-survival.md:51 _maybe_spawn_survival_boss() dispatches a 5-boss rotation Removed; FunZo only (V01_FUNZO_ONLY) Certain Rewrite as current state
…enemies-bosses-survival.md:70-72 Swarm crescendo at 3:00; first boss at BOSS_FIRST_TIME 210 s, BOSS_INTERVAL 80 s cadence Burst has no caller; boss timing is phase-driven (WAVE_PHASE_S → BOSS_PREP_S), so both consts are dead (remote-config.md:169-171 already says this, so the two docs contradict each other) Certain Rewrite
…enemies-bosses-survival.md:48,72 _spawn_suppressed, _any_boss_alive() Neither function exists Certain Remove
docs/architecture/dev-tools.md:18 _spawn_boss() has no positioned overload No _spawn_boss() exists Certain Update to _dev_spawn_boss → director spawn()
docs/architecture/rendering-and-performance.md main.gd._enemy_scales Doesn’t exist Certain Update
sim/beacon_director.gd:8-9 header aura “shrink[s] its flank/backstab jitter (Sim._move_enemies)” Not implemented (summary #10) Certain Wire it or fix the comment
sim.gd:2698-2702 comment _spawn_teaser_wormhole “retired”, its machinery “left in place” Accurate, but the leftover machinery still ticks every frame (§1) Certain Delete the machinery
main.gd:158 comment “adaptive quality runs” ADAPTIVE_QUALITY := false Certain Fix/delete
sim.gd:615 comment “5-way rotation counter” Write-only counter, no rotation Certain Delete the field
NEXT_TASKS.md (co-op Leech, 2026-08-12) “Leech heal (sim/sim.gd:2450) always targets player.hp (P1)” Fixed 2026-09-23: heals every living pilot (sim.gd:2567-2570, main.gd:196 comment) Certain Mark the heal half DONE; the shared-ModState design question stays open
NEXT_TASKS.md (playtest batch 2) dimension-choice spec “is currently UNTRACKED” It’s tracked (git ls-files shows docs/superpowers/specs/2026-07-09-dimension-choice-popup-design.md) Certain Strike that sentence
NEXT_TASKS.md (2026-07-16) snapshot_string() at sim/sim.gd:2800 sim.gd:3035 Certain Use the symbol name
Memory bullet-heaven-measurement-open-loop “ADAPTIVE_QUALITY off; re-enable at release” 1.0 submitted with it off Certain Update memory / make the decision

NEXT_TASKS item Overlap with this audit
2026-09-27 dead sim pacing fields Same as §1 / summary #4. This audit adds _boss_spawn_count (write-only), _spawn_accum and other_area()
2026-09-27 dead bible fields Same as §1 xp_val. This audit adds boss HP/speed/contact for warden/funzo/graviton/boss2, which are unread yet patchable (summary #2)
2026-08-12 primed/react_cd + main.gd tint branch Same as §1 / summary #5
2026-08-12 Elemental.apply() + ContentDB.reaction() Same as §1
2026-08-12 _new_run 510-line split Same as §3 main.gd (now 545 lines)
2026-08-12 cooldown_frac / power preview duplication Same as §4
2026-08-12 perf: enemy_attacks dict rebuild, fx_manager._spawn dicts, weapon_panel views §4 lists the enemy_attacks one. The others are perf, outside this audit’s scope
2026-08-12 co-op SimMods/Leech §8: the heal half is now stale (fixed); the design half is open
2026-09-27 remote-config item 3 (no e2e test of _new_run order) Unblocked by the §3 _new_run extraction
2026-09-27 remote-config “unverified-dead meta magnitudes” Same class as summary #2. Add the boss-stat fields to that check
2026-07-09/10 dimension-choice spec “untracked” §8: stale, it’s committed
2026-07-16 per-tick determinism trace tool Would de-risk the §3 SpawnSystem extraction. Worth building first
Everything else (ui-sweep guard, sweep sRGB, MetaState.from_dict, P2 meta stats, story_board, Toby-era tvOS flake) No overlap

  1. Bugs first (not cleanup): Halo Chain/splitter biomass (#1) and the unread boss-stat remote-config fields (#2).
  2. Zero-risk deletions in one PR: §1 dead symbols, dead const-flag branches (§2 rows marked “Dead path”), the dead tests in §5, verify-sim-refactor.sh, orphan .uids, _archive/. Gate: scripts/gate.sh. All three determinism tests must stay green without a re-pin. If one moves, something wasn’t dead.
  3. Chris’s calls, batched into one question list: power-ups, Boss2, ADAPTIVE_QUALITY, each VisualLook/radar_v2 A/B pick, the duplicate music file, committing .claude/skills.
  4. Structural: the EnemyColorizer/MainDevCommands/ShopLayout extractions (low risk), then the sim.gd split one module per PR, with the per-tick trace tool built first.