Skip to content

Improvement punch list

Improvement punch list — rolling polish-audit log

Section titled “Improvement punch list — rolling polish-audit log”

Staging area for the 2026-10-02 improvement loop (one investigation every 10 min for 6 h). Nothing here gets fixed by the loop itself — Chris triages items onto docs/RELEASE-1.0.1.md before any fix, per project rules.

Run protocol (each loop run follows this):

  1. Read the newest run section below to learn the last category covered.
  2. Pick the NEXT category in this cycle:
    1. Asset-fiction mismatch (marketing/icon vs real in-game assets)
    2. Snap-vs-ramp effects (boolean/threshold-driven feedback for continuous quantities)
    3. UI pattern inconsistency (same job, different pattern across screens)
    4. Invisible progression / undifferentiated abilities (upgrade tiers the player can’t perceive)
    5. Render ignores sim data (unread fx_event fields, undrawn sim state, hardcoded colours)
    6. Telemetry-driven improvement (real death/hitch/behaviour data suggests a fix)
  3. Run the sweep per the polish categories in .claude/skills/bh-overnight-audit-loop/references/polish-categories.md. Investigation only — no code changes without sign-off. Dedupe against every previous section below.
  4. Append a new ## Run N — <category> — <timestamp> section: concrete findings with file:line evidence, or “no new findings” plus exactly what ground was covered (so later runs don’t repeat it).
  5. Commit just this file (docs(polish): loop run N — <category> — <n> findings), git pull --rebase then push; if push is blocked, leave the commit local.
  6. If it is past 2026-10-02 06:50 BST, do not run a sweep — cancel this loop (Loop tool → list → cancel) and post a closing summary of total findings.

Run 1 — Asset-fiction mismatch — 2026-10-02 01:00 BST

Section titled “Run 1 — Asset-fiction mismatch — 2026-10-02 01:00 BST”

6 findings. Method: git-history freshness audit of every player-facing static asset vs the overhaul dates that changed its subject (2026-07-03 HUD polish, 2026-07-22 glow rework, 2026-09-24 icon re-bake, 2026-09-28 weapon FX v2). No pixels judged — evidence is last-modified commits.

  1. marketing/appstore/{iphone,ipad,tv}/*.png — last touched 2026-09-24 (b44d4d1e): live App Store 1.0 screenshots show pre-FX-v2 flat weapon visuals.
  2. marketing/appstore/mac/01–06_*.png — 2026-06-30 (731a1c79): stalest set, predates the HUD polish pass, glow rework AND FX v2 (3 overhauls behind).
  3. marketing/appstore/icon/icon_60.png/icon_120.png — 2026-06-30 (0210374c), sourced from the OLD generic icon.png; the real icon re-bake (bdc7122b, 2026-09-24, real Nova hull) never flowed into these thumbs.
  4. marketing/appstore/press/hero.png, one-sheet.png — 2026-06-30: press key art predates every visual overhaul.
  5. marketing/trailer/cards/*.png — 2026-06-30: trailer frames predate glow rework + FX v2.
  6. docs-site/public/images/** — all 2026-07-05 (69175d91/fca91eaa): every “real game frame” on the docs site shows the pre-rework look; weapon-icon set covers only 7 of bible’s 16 weapons.

Ground covered / FRESH (don’t re-audit): platform/tvos/icon* + xcassets (2026-09-24 re-bake, real hull); marketing site repo ~/Claude/bullet-heaven-site (rebuilt 2026-10-01 f3d156b, post-FX-v2 images, 16-weapon table matches data/bible.json, roster gap already documented in its AUDIT-2026-10-01.md); concept-art/ (labelled concept); marketing/raw/ (untracked).

Suggested triage order: device screenshot sets (1) → Mac set (2) → icon thumbs (3) → press kit (4) → trailer cards (5) → docs-site images (6). All are re-captures/re-bakes, not code changes.

Run 2 — Snap-vs-ramp effects — 2026-10-02 01:10 BST

Section titled “Run 2 — Snap-vs-ramp effects — 2026-10-02 01:10 BST”

5 findings. Method: grep of render/fx/ui/main.gd for boolean setters + hard-threshold call sites gating feedback whose underlying quantity is continuous; the fixed ScreenFeedback.set_hp_fraction case is the fix template.

  1. HUD HP-bar danger pulse snaps at 30% — ui/hud.gd:232 (P1) / :285 (P2): pulse depth is a frac < 0.3 ternary while colour ramps continuously; also out of sync with ScreenFeedback.LOW_HP_START_FRAC = 0.5 (fx/screen_feedback.gd:36). Fix: amplitude = eased low-HP ramp, start 0.5.
  2. HUD HP-block visibility two-steps at 50% — ui/hud.gd:251-254 / :296: above_half_hp bool switches baseline alpha between hard 1.0 and the hit-flash curve. Fix: continuous floor maxf(flash, ramp(frac)).
  3. Warden boss colour flips WHITE→full crimson in one frame — main.gd:2257-2258: if enraged: return vivid; return WHITE; enrage latches at 40% HP (sim/boss_warden.gd:100). Fix: continuous lerp like other boss renderers’ hurt = 1 - hp_frac; keep the latch only for cadence.
  4. Graviton lens enrage term is a +0.25 step — main.gd:2718-2722: enr := 1.0 if enraged jumps the swirl instantly at the latch (sim/graviton.gd:74) while pull ramps. Fix: drive from the hp_frac already exposed at sim/graviton.gd:71.
  5. Boss2 enrage aura snaps on at fixed intensity — render/boss2_renderer.gd:73 (if enraged:; latch sim/boss2.gd:115). Fix: alpha-ramp with 1 - hp_frac. (Same-shaped branches in render/eye_renderer.gd:80, render/graviton_renderer.gd:73, render/funzo_renderer.gd:76 already carry a continuous hurt ramp alongside — borderline, lower priority.)

Ground covered / fine (don’t re-sweep): set_hp_fraction + eased ramp (fx/screen_feedback.gd:185, fed main.gd:2065); player heal/tilt, weapon_fx_layer.set_dim(d) (main.gd:2686), screen_punch damage scaling (main.gd:2054), audio_manager.set_weapon_load (audio/audio_manager.gd:394), touch-ability charge fractions, gold/shop-affordability glows (binary facts), graviton/eye/funzo sim-side escalation already continuous.

Run 3 — UI pattern inconsistency — 2026-10-02 01:20 BST

Section titled “Run 3 — UI pattern inconsistency — 2026-10-02 01:20 BST”

4 findings — all design-judgment calls for Chris, no clear defects. Key discovery: the convention itself has forked. The full start_menu carousel no longer exists (replaced 2026-09-24 by a vertical glass row list, ui/start_menu.gd:1-10), so the game now has FOUR picker idioms: hero-card carousel, all-visible card strip, vertical list, confirm-to-cycle rows.

  1. Start-menu mode picker vs ship picker — modes/actions are a vertical VBoxContainer of GlassPanel rows with up/down nav (ui/start_menu.gd:80-88, :447-448) while the equivalent ship picker uses the hero-card carousel (ui/ship_config_panel.gd). Same job, two patterns — but appears deliberate (2026-09-24 redesign).
  2. Death Results vs Pause menu action lists — Results: horizontal 3-button row, LEFT/RIGHT nav (ui/results_panel.gd:36-37, :529-533); Pause: vertical button column, UP/DOWN (ui/pause_menu.gd:32, :505-509). Two orientations/nav axes for the same “pick 1 of N actions” job. Carousel removal on Results was Chris-directed 2026-09-26 (phone paging hid options).
  3. Drone Bay third idiom — per-slot “pick 1 of N” via confirm-to-cycle rows (ui/drone_bay_panel.gd:118, :140, :279). Arguably right for slot-fitting, but confirms the fork.
  4. Stale exemplar in our own docs — skill bh-polish-audit + DESIGN.md conventions still cite start_menu.gd’s drag-physics carousel as the pattern exemplar; it’s gone. LevelUpPanel + DimensionChoice now form a consistent all-visible card-strip pair (ui/level_up_panel.gd:244-248, ui/dimension_choice_panel.gd:157-200) that just doesn’t match the doc. Doc should record which idiom is canonical going forward.

Decision needed from Chris: which picker idiom is canonical (hero-card carousel / all-visible card strip / list / cycle-rows), then re-align docs + outliers. Past confirmed cases (Dimension Choice, Results actions) were deliberately redesigned away — not defects.

Ground covered / fine: codex (browse), debug settings (toggles), stats sheet, meta shop (tabs+grid, hulls delegated to SHIP panel :67), all HUD/overlay panels, dialogue box, level_up_panel_legacy (retained variant).

Run 4 — Invisible progression — 2026-10-02 01:30 BST

Section titled “Run 4 — Invisible progression — 2026-10-02 01:30 BST”

3 grouped findings (17 items). Method: FX v2 coverage cross-ref of all 17 weapons vs V2_LOOKS; manifest 0-score cards; threshold/evolution table completeness; meta-upgrade render consumers.

  1. 11 weapons still have NO progression visual — pulse, beam, turret, scatter, chalice, railgun, scar_tissue, momentum_core, chronowell, thunder_wake, wildfire. FX v2 is 6-of-17 merged (batches 1-2 at 4ebccfcc/50ca79b5); notably batch 2 shipped Beam/Railgun mechanics under the v1 look — no V2_LOOKS entry (fx/fx_manager.gd:38), Railgun v2 look still unpromoted in fx/weapons/candidates/. Fix pattern: entry + look reading WeaponVfx.power/rungs/evolved (as fx/weapons/blade_slash_look.gd:22-28). Beam width bug was fixed but beam still has no per-level/per-evolve look; wildfire/thunder_wake zones drawn but binary, not tiered.
  2. 5 sim states confirmed still invisible (manifest 0-score MISSING cards, tools/vfx_library/library_manifest.gd:124-136): elemental_aura (stack counts affect damage, no renderer), railgun_mark (damage-amplifying mark invisible), disruptor_field (slow/suppress field has no visible radius), wisp_phase (untargetable phase looks solid), scar_tissue_meter (stack buildup invisible until discharge).
  3. Meta-shop upgrades apply stats with no in-run perception — data/bible.json .data.meta_upgrades tiers (armor, fire_rate, pickup_radius, move_speed, e.g. vitality lvl 5) applied stat-only via sim/meta_run_setup.gd:24; only max_hp is perceivable (HP bar). Needs a call: add visual_tier()-style consumers (pickup ring, thruster intensity) or accept menu-only.

Table completeness fine (don’t re-sweep): sim/weapon_thresholds.gd (16) + sim/weapon_evolutions.gd:15-31 (17) cover the full roster, no gap rows; drones have no tier table by design.

Run 5 — Render ignores sim data — 2026-10-02 01:40 BST

Section titled “Run 5 — Render ignores sim data — 2026-10-02 01:40 BST”

10 new findings across the 3 mechanical sweeps (ignored event fields / undrawn sim state / hardcoded colour). Prior confirmed cases verified: blade arc FIXED (fx/fx_manager.gd:696); wildfire/thunder_wake zones now drawn (render/zone_renderer.gd:166-174); beam width still ignored by the legacy path (fx/fx_manager.gd:662-668, only v2 candidate looks read it) — partial fix.

  1. Halo-chain tethers + their buffs are completely invisible — sim/halo_chain_director.gd:53 _active_tethers (explicitly “for render/debug”) has zero render readers; the +15%/member damage mult (sim/sim.gd:3110) and knockback immunity (sim/elemental_system.gd:147) mean enemies near packs hit up to +45% harder with no visual cue. Highest-impact finding of the run.
  2. beam.hits (sim/weapon_beam.gd:66) — no consumer in fx/ at all.
  3. mark_pop ignores hits + element (sim/weapon_railgun.gd:144 → fx/fx_manager.gd:678-684 reads only pos/radius).
  4. reaction slam ignores radius — elite brute slam sends ELITE_BRUTE_SLAM_RADIUS (sim/enemy_attacks.gd:598) but fx draws fixed REACTION_BURST_RING = 120.0 (fx/fx_manager.gd:42, :769).
  5. ignite carries element (sim/weapon_wildfire.gd:66) but fx hardcodes orange (fx/fx_manager.gd:756).
  6. turret_fire hardcodes amber + producer stamps no element (fx/fx_manager.gd:715, sim/weapon_turret.gd:65) — turret is element-selectable.
  7. scatter_fire same pattern (fx/fx_manager.gd:717, sim/weapon_scatter.gd:57).
  8. wildfire_pop same pattern (fx/fx_manager.gd:729, sim/weapon_wildfire.gd:104).
  9. MARK_POP_COL fixed light-gold ignores railgun’s selectable element_idx (fx/fx_manager.gd:26) — overlaps finding 3.
  10. momentum_charged_fire hardcodes (fx/fx_manager.gd:748) on an element-bearing weapon — borderline; chronowell’s pale cyan is fixed zone identity by design (fine).

Fix pattern for all: read the field / derive from ElementPalette, then pin with a GUT test. Ground covered clean: death.type_id (audio-consumed), accum_warn.radius, dmgnum.big, thunder_wake from/radius, turret positions, eye laser targets, elite beams/warps.

Run 6 — Telemetry-driven improvement — 2026-10-02 01:50 BST

Section titled “Run 6 — Telemetry-driven improvement — 2026-10-02 01:50 BST”

4 findings from live D1 (human runs n≈308, ATV samples build≥235, hitches build≥235). Method: death-cause + run-length funnel from runs (is_auto=0/NULL, charger label merged), hitch/fps from hitches/samples.

  1. The first 2 minutes are a cliff: 63% of human runs (193/346) end <2m, and swarmer alone causes 44% of all human deaths (136 deaths, avg level 3.9, avg 81s). The early swarm wall dominates everything else; charger is the secondary wall (73 deaths, lvl 12.4, 226s). Improvement candidate: early-game pacing audit (spawn curve/forgiveness in the first 90s) — docs/RELEASE-1.0.1.md early-game items should be weighed against this.
  2. 12 runs flagged human have weapons_list NULL and absurd dps (1,858,568 avg — attract/dev sessions predating or bypassing is_auto), plus 12 NULL + 11 empty death_cause rows — the funnel/death numbers above include this contamination (~7%). Improvement: fix the run-report path so is_auto/weapons_list are always set, or exclude these from future queries.
  3. A build id 9001 session is writing ATV samples at 46.4 fps (n=254) — an out-of-range build id (dev-spoofed?) polluting per-build perf stats. Hygiene: make DevFlags builds report a distinguishable real BUILD.
  4. Perf verified healthy on current builds — no new work needed: builds 236-240 averaged 105-181ms play hitches (243 peaked at ~1.5s with pipeline compiles), but 244-246 show no play-state hitches in the top rows and hold ~59 fps / 16.9-17.1ms with sim_ms 1.2-3.0 — the shader-bake/PSO-prewarm arc reads as landed. 238’s 38.7 fps low is the known late-run collapse already triaged in RELEASE-1.0.1 §1.

Weapon diversity (Q5): blade-only 64 runs (starter/tutorial-heavy), blaster-centric lists dominate after — consistent with the funnel, not a separate finding. Ghost/accumulator deaths occur late (lvl 20-36) = healthy curve.

Run 7 — Asset-fiction mismatch (deep: data + copy) — 2026-10-02 02:00 BST

Section titled “Run 7 — Asset-fiction mismatch (deep: data + copy) — 2026-10-02 02:00 BST”

3 findings. Cycle 2 went past run 1’s image-freshness pass into data/copy that claims to describe the game: bestiary vs bible, App Store copy, web-demo build. Tutorial/help-text sweep came back clean (token-driven, matches real bindings).

  1. sentinel bestiary stats block is dead-stale — data/bestiary.json entries.sentinel.stats: hp 1800 vs bible 3400, speed 45 vs 60, contact_damage 44 vs 22, armor 0 vs 5, element kinetic vs void. Not player-visible today (BestiaryLoader _merge_one prefers live bible stats, content/bestiary_loader.gd:66-80), but it’s a fallback that silently becomes the displayed source if the bible entry is removed. Warden block (concurrent fix) verified correct; all 30 keys have bible entries; codex has no hardcoded copy.
  2. App Store copy version framing + feature gaps — marketing/appstore/copy.md “What’s New (v0.1): First release…” while the store build is 1.0/37 (SUBMIT.md §3 still points at the v0.1 label); description never mentions Story mode (“Ascent: The Spectrum”), the codex/bestiary, or gold-shop meta-unlocks. No FALSE claims found (elemental/dimension/boss/drone claims all verified 2026-09-23, 30b6ffd8).
  3. Public web demo is 1.0-era and docs say otherwise — live bullet-heaven-play.lumara.digital index.pck = 2026-09-28 21:23 GMT export (byte-identical to last local export), predating the Warden rebuild/FX v2-era main (BUILD 242+); docs/architecture/dev-tools.md:82 still claims the demo is “CURRENT at build 78”. Re-deploy scripts/deploy-demo.sh after the next merge and fix the doc line.

Ground covered clean (don’t re-sweep): bestiary↔bible full 30-key diff + codex render path; store copy claims vs sim (2026-09-23 pass held); tutorial/help/dialogue control tokens vs input/input_router.gd and touch UI — no drift.

Run 8 — Snap-vs-ramp (cycle 2) — 2026-10-02 02:10 BST

Section titled “Run 8 — Snap-vs-ramp (cycle 2) — 2026-10-02 02:10 BST”

3 new findings; all 5 run-2 findings re-checked — NONE fixed. Warden enrage snap NOT fixed by the rebuild, just MOVED: now fx/boss/warden_fx.gd:101, :182 (_tint = HOSTILE_BODY.lightened(0.2) if enraged else HOSTILE_BODY — still a binary lightening at the 40% latch; supersede run-2 finding 3’s old main.gd:2257 location). HP pulse (ui/hud.gd:238/:290), above_half_hp (:251-252/:296-297), graviton enr step (main.gd:2749, :2752-2754), boss2 aura (render/boss2_renderer.gd:73-75) all still live.

  1. Area warp is a frozen 1.2s beat with no VFX, then an instant background swap — main.gd:2780-2787 _begin_warp→_finish_warp; comment says “Streak/fade VFX is a noted polish follow-up”. Fix: drive dim/flash off the _warp_timer / WARP_DURATION fraction — the warp-dash path (main.gd:2697-2717, set_dim(t), set_warp_smear) already shows the pattern.
  2. Damage numbers are binary big/small — fx/damage_numbers.gd:81-82: font_size 36 if big else 20 + gold-vs-white on the big bool (dealt >= DMGNUM_BIG), hiding the continuous amount. Fix: remap font 20→36 and lerp colour toward gold. Same two-state split in the fx_manager dmgnum spark.
  3. Boss enrage audio is a one-shot sting, never a swelling state — audio/audio_manager.gd:63-64 maps ENRAGED → a shared graviton_singularity one-shot; below the latch nothing escalates. Fix: low-intensity looping enrage bed on the boss voice with pitch/volume ramped from boss HP frac, sting as latch accent.

Ground covered clean (don’t re-sweep): zone renderers (render/zone_renderer.gd — all fades + radii continuous, incl. funzo growth); boss telegraphs (bomb/lancer/graviton rings + warden tele/fire_charge 0..1 looks, fx/boss/warden_charge_look.gd:5-9); drone dock cooldowns, touch ability rings, decoy durability fade; warden rebuild FX beyond the enrage tint (charge convergence, missile flicker, body spin 1→4x flare).

Run 9 — UI pattern inconsistency (cycle 2: DESIGN.md conventions) — 2026-10-02 02:20 BST

Section titled “Run 9 — UI pattern inconsistency (cycle 2: DESIGN.md conventions) — 2026-10-02 02:20 BST”

4 drift findings. This pass swept the non-picker DESIGN.md conventions across ui/ (anchoring, typography, glass family, bars, colour discipline, MenuNav, motion). Run 3’s picker-idiom fork not re-swept.

  1. Glass spec has drifted codebase-wide — DESIGN.md says translucent bg alpha 0.6-0.66; the only literal complier is ui/weapon_panel.gd:203 (0.6). Every other panel sits at 0.82-0.97 opaque: ui/level_up_panel.gd:608 (0.82), ui/ship_config_panel.gd:441 (0.85), ui/codex_overlay.gd:71 + ui/meta_shop_panel.gd:249 (0.92), ui/dialogue_box.gd:92 (0.95), ui/pause_menu.gd:459 + ui/debug_settings_panel.gd:882 (0.97). Doc or panels need re-pinning — Chris’s call which direction (the Nova look at 0.94 was Chris-requested, so “opaque” may be the real convention now).
  2. Dialogue box glass outlier — ui/dialogue_box.gd:92-94: 2px border at full-strength cyan (family: 1-2px at ~0.22-0.42 alpha) + shadow_size 10 (family: 3-7).
  3. Meta-shop tab chrome breaks the single-cyan pillar — ui/meta_shop_panel.gd:1723-1728 _cat_color(): purple/orange/green/pink per category. Categories aren’t weapons/elements, so this reads as decorative multi-hue chrome — unless Chris calls it category identity (drone class colours in drone_dock.gd:26 ARE identity and fine).
  4. Stats sheet hand-rolls the only non-family bar-like style — ui/stats_sheet.gd:585-590 scrollbar (white 0.06 track, accent 0.55 grab, corner_radius 2) unrelated to hud.gd:365-384 _bar_* family. Borderline (it’s a scrollbar).

Verified compliant (don’t re-sweep): anchoring (no hardcoded-position bug class anywhere), typography (all via NeonTheme fonts), bars (HP+boss share _bar_*), MenuNav (raw keycodes found are additive keyboard shortcuts, not parity breaks), motion timings (idle breaths 0.55-1.4s, level-up 0.22s + 0.8s failsafe, low-HP pulse reuses the semantic ramp).

Deliberate outliers (confirm, don’t fix): ui/debug_overlay.gd:25 absolute positioning (dev-only); ui/ship_config_panel.gd:363-429 viewport-math layout inside FULL_RECT root (resize-safe, not the bug class); Nova dual style family (Chris-requested, VisualLook.nova); level_up_panel_legacy.gd retained variant.

Run 10 — Invisible progression (cycle 2: non-weapon systems) — 2026-10-02 02:30 BST

Section titled “Run 10 — Invisible progression (cycle 2: non-weapon systems) — 2026-10-02 02:30 BST”

4 new findings. Pass-1 re-checks post-warden-merge: ALL still open — V2_LOOKS still only 5 weapons (fx/fx_manager.gd:38), the 5 invisible states still score 0 in tools/vfx_library/library_manifest.gd:30-31, meta-shop stats still consumer-less. This pass swept drones/abilities/hulls/elites/mods/career/audio.

  1. Weapon dock draws NO progression at all — no level, no mod, no evolve state — sim/upgrade_system.gd:323 apply_weapon_mod() alters power/rate but ui/weapon_icon.gd reads none of it; evolved names only appear on the end-run results panel (ui/results_panel.gd:396). Fix: level pips + mod ring segment on the dock icon from pilot.arsenal.
  2. Drone class-upgrade tiers invisible — sim/meta_state.gd:149 _apply_class_upgrades() scales dmg/durability/radius/speed per drone-<class>-<attr> level, but sim/drone_director.gd:523-528 drones_render_info() exposes no tier/power field and render/decoy_renderer.gd:38 uses a fixed render size. Fix: add power to render info, scale size/glow.
  3. Weapon audio never escalates — audio/audio_manager.gd:213 play() takes only key/volume/pitch; no level/evolved parameter anywhere (only per-shot random pitch :102 and load density :394). An evolved weapon sounds identical to level 1. Fix: pass a tier/pitchMult from the fx event weapons already emit.
  4. Warp-cooldown upgrade tier invisible — sim/sim.gd:2437 (dash_cd *= pilot.dash_cooldown_mult); HUD ring shows fill fraction only, so a faster warp is perceivable only by timing it. Fix: tier pip/rim brightness from dash_cooldown_mult.

Borderline: career/meta has end-run reflection only (banked gold + shop pulse, ui/results_panel.gd:250, :258-270), zero mid-run.

Fine (don’t re-sweep): ship hulls — render/player_renderer.gd:20-58 renders 5 per-tier bands, hue ascent, ascension ring pop; elites — distinct shapes (render/archetype_renderer.gd:14, :56), dedicated HP bars + attack FX.

Run 11 — Render ignores sim data (cycle 2: render-info dicts + player-side state) — 2026-10-02 02:40 BST

Section titled “Run 11 — Render ignores sim data (cycle 2: render-info dicts + player-side state) — 2026-10-02 02:40 BST”

6 new findings. Pass-1 re-checks: all 10 still open (one partial: mark_pop now reads radius at fx/fx_manager.gd:684 but still hardcodes MARK_POP_COL, ignores hits/element; beam legacy still drops width at :674). This pass swept render-info dicts, player-side statuses, HUD ambient state, armour/element identity, audio.

  1. Player-side DoT and slows are completely invisible — the most damaging class (changes player decisions, not just polish): pilot.burn_timer (elite burn, set sim/elite_kit.gd:341, ticked :351) has zero render/HUD/fx consumers — the player takes ticking damage with no on-ship visual; pilot.kite_slow_timer (sim/elite_kit.gd:343/345, sim/sim.gd:3127) and pilot.beam_slow_timer (:298) slow with no status visual; player.move_mult (sim/sim.gd:816) sources render but the slowed state itself is unread. Fix: ship-heat tint/sparks for burn, vignette/tint for slow keyed on move_mult < 1. Good precedent exists: warp_scramble_timer IS drawn (render/elite_fx_renderer.gd:54).
  2. Active Dimension is invisible after the choice popup — main.gd:681-689 _apply_area_change only retints bg/border; nothing in ui/render reads AreaDefs during play. Hidden: dimension name + its modifier (reward ×, enemy buff, element override). Fix: HUD chip on arrival.
  3. Warden render_info()["strafing"] (sim/boss_warden.gd:542) has zero render/fx consumers — the rebuild spec (2026-10-01-warden-rebuild.md:296) named it as a render contract. No lean/thrust cue while the boss orbits. Fix: warden_fx reads it, adds drift thrust.
  4. boss2.render_info()["charge_pos"] (sim/boss2.gd:253) unread — renderer uses charge_dir only (minor; boss2 is dev-only today).
  5. Post-warp invulnerability frames render nothing — RESUME_IFRAMES grant (main.gd:684); minor (short window) but free forgiveness the player can’t exploit knowingly.
  6. Audio is purely event-driven — zero sim-state reads in audio/ (no boss-proximity or swarm-density ambient layering); verdict logged, overlaps run 10’s weapon-tier finding.

Ground covered clean (don’t re-sweep): eye/graviton/funzo/elite/lancer render-info dicts fully consumed (only the known drone power gap remains); wave pressure (spawn_banner + threat_radar); boss bar name+HP; enemy element tint (render/archetype_renderer.gd:296) + armour silhouettes.

Run 12 — Telemetry (cycle 2: encounters, picks, iOS, quality ladder) — 2026-10-02 02:50 BST

Section titled “Run 12 — Telemetry (cycle 2: encounters, picks, iOS, quality ladder) — 2026-10-02 02:50 BST”

4 new findings from live D1. New ground vs run 6: encounters table (n=2,274), build_picks weapon-token aggregation, iOS session coverage, adaptive-quality engagement.

  1. Warp dash is a panic button, not a skill tool — on CLEARED dash encounters players dashed only 5-11% of the time (charger 0.11, spider 0.05, accumulator 0.07); on CONTACT (hit) outcomes dash_rate jumps to 0.26-0.42. Players clear telegraphs by walking and only dash once it’s too late. Accumulator has the worst clear rate (79% vs charger 89%, spider 95%) and longest contact duration (0.96s). Improvement candidates: dash teaching/incentive, accumulator telegraph readability.
  2. Weapon picks are heavily concentrated on the visible-progression weapons — nova 134, beam 108, orbit 102, turret 93, pulse 90 vs chalice 5, scythe 5, thunder_wake 5, momentum_core 5, scar_tissue 6, scatter 14, railgun 4, wildfire 3, chronowell 0 (blade/blaster are starters, excluded). The near-zero weapons are exactly run 4’s no-progression-visual list — telemetry now supports the invisible-progression suppresses-picks hypothesis.
  3. Adaptive quality ladder engagement looks broken/threshold-mismatched — build 238 averaged 40.4 fps / 33.8 ms across 750 sample windows with ZERO degraded windows (quality=0 throughout); build 9001 (the anomalous dev-id build from run 6 finding 3) engaged the ladder in 189/254 windows (avg_q 1.49) at similar-or-better fps (46.4 avg, min 28). Either the ladder is DevFlags-gated, or its engage threshold sits below 238’s collapse. Needs a code-level threshold audit (render/ QualityManager).
  4. Zero iOS device sessions in the recent build range — last iPad sample build 230, last iPhone 206 (the store 1.0 build); everything since (236-246, incl. the warden rebuild + PSO-prewarm arc) has no iPhone/iPad validation at all. Install a dev build on both before the next release.

Ground covered: death-cause funnel/run-length/hitch/fps (run 6, not re-queried); encounters outcome/dash/duration per type; per-weapon pick frequency; iOS session coverage; quality-tier engagement per build.

Run 13 — Asset-fiction mismatch (cycle 3: player-facing strings + audio) — 2026-10-02 03:00 BST

Section titled “Run 13 — Asset-fiction mismatch (cycle 3: player-facing strings + audio) — 2026-10-02 03:00 BST”

4 findings. Cycles 1-2 covered images and data; this pass swept naming consistency, the Decoy/Sentinel rule, audio↔content match, and privacy labels. Name chain (project.godot, CFBundleDisplayName, ASC, marketing site) fully CLEAN — zero player-facing “Bullet Heaven”; Decoy/Sentinel rule fully CLEAN (only code comments + legit boss name).

  1. Warden lunge telegraph is silent and untracked — boss_swing_start fx (sim/boss_warden.gd:285, :321, :395) has no audio_manager case AND no audio/sound_map.json entry (swing hit + missiles are mapped); every other silent thing is honestly catalogued with "status": "silent" (sound_map.json:179-249 — chalice, chronowell, momentum, scar_tissue).
  2. Elemental Dimension hazard rifts emit nothing at all — sim/dimension_hazards.gd:259, :696-703 (drawn by render/dimension_hazard_renderer.gd) produce no fx_events → no possible audio, no sound_map row. Rift appearance is silent and untracked.
  3. Privacy page’s “No other third party receives it” has a dormant exception — the iOS build embeds the Sentry SDK (no DSN, dormant; declared to ASC in marketing/appstore/compliance.md). True today, but unlike compliance.md, the site privacy page (~/Claude/bullet-heaven-site/privacy/index.html) has no note that a DSN-config change must update the page in the same change.
  4. Privacy page omits the build-channel probe (App Store/TestFlight receipt existence check) that compliance.md lists — minor, arguably covered by “app build number”.

Borderline (internal convention, Chris’s call): project.godot:6 custom_user_dir_name keeps “Bullet Heaven” in macOS Finder save paths. Chalice/chronowell/momentum/scar_tissue weapon silence is PRE-TRACKED (sound_map “silent”) — not new.

Run 14 — Snap-vs-ramp (cycle 3: spawn/despawn, bars, focus, transitions) — 2026-10-02 03:10 BST

Section titled “Run 14 — Snap-vs-ramp (cycle 3: spawn/despawn, bars, focus, transitions) — 2026-10-02 03:10 BST”

6 new findings. Pass 3 swept snap classes passes 1-2 didn’t touch. (The 8 prior findings not re-checked; all were open at last check.)

  1. Enemy death: corpse vanishes in one frame — _sweep_dead end-of-tick removal leaves only a 0.16s additive spark (fx/fx_manager.gd death case); no dissolve/shrink. Fix: render-side dying-ghost pass (last-known pos/colour, scale+alpha out ~0.12s), mirroring render/funzo_dash_afterimage.gd’s pooled-ghost pattern.
  2. No lagging damage chip on HP/boss bars — ui/hud.gd:222 and :337: fill width tracks HP exactly each frame; damage drops instantly, healing pops. Fix: ghost-fill lerp toward frac at fixed rate (classic chip), both bars.
  3. Focus glow snaps between rows — ui/theme/glass_panel.gd:35 focus setter + ui/results_panel.gd:245-246, ui/drone_bay_panel.gd:234-235: focus = 1.0/0.0 assigned directly. Fix: ~0.10s ease-out tween.
  4. Element override recolours everything in one frame — main.gd:2403 _proj_colors() + render/zone_renderer.gd:326-327: when a dimension/mod flips the active element, all in-flight projectiles and live zones snap to the new colour; no lerp on the path. Fix: per-instance colour lerp ~0.15s or fade old-colour instances out.
  5. Pause/codex/panel opens are instant — main.gd:405,565,573,594 visible = true, ui/codex_overlay.gd:111,124; no modulate fade. Fix: 0.15s alpha fade-in/out, consistent with level-up’s entry.
  6. Enemy spawn pop-in at full size — render/archetype_renderer.gd:765-833: drawn at radius[i] with no spawn-age. Fix: spawn-time column + 0.1s scale ramp.

Ground covered clean: FxManager primitives (rings/beams/slashes fade+grow via tick()); level-up card stagger; ship-config slide+crossfade; start-menu staggered reveal. No combo/streak system exists (F — nothing to ramp).

Run 15 — UI pattern inconsistency (cycle 3: formatting, empty states, settings, hints) — 2026-10-02 03:20 BST

Section titled “Run 15 — UI pattern inconsistency (cycle 3: formatting, empty states, settings, hints) — 2026-10-02 03:20 BST”

6 findings. Pass 3 swept number/time/gold formatting, empty/locked states, player-facing settings, hint conventions, iconography. (Picker idioms and DESIGN.md styling already covered.)

  1. Store players cannot mute the game — no shipped volume/audio control: mute exists only in ui/debug_settings_panel.gd:396-445, which is DevFlags dev-only. Meanwhile the telemetry opt-out IS player-facing (ui/pause_menu.gd:22, :30, :156-165). Asymmetric settings surface — a shipped game needs at least volume in pause/start menu.
  2. Headline DPS isn’t compacted while sibling rows are — ui/results_panel.gd:258 raw %.0f (e.g. 12400 DPS) vs the same panel’s _short() compaction (12.4k, :432-435, :400). Also two time idioms coexist (M:SS at :257 vs raw %ds in ui/hud.gd:323, ui/drone_bay_panel.gd:164 — minor) and gold casing drifts (%d GOLD/GOLD vs "0 gold" in ui/meta_shop_panel.gd:225).
  3. All-maxed shop category has no designed state — only fully-empty categories auto-hide (ui/shop_categories.gd:16-20); a category with everything maxed just sorts last (meta_shop_panel.gd:12), showing a wall of grey MAXED pills. Needs an “all maxed” empty-state treatment.
  4. Zero-kill/zero-gold death run renders bare zeros — results_panel.gd:257, :267 (0 KILLS · 0 GOLD); only the zero-damage case has designed copy (:447).
  5. Run tips violate DESIGN.md twice — objective-panel tips sit top-center (ui/objective_panel.gd:46-48, fed main.gd:2592-2644) where the convention is bottom-center transient; and they re-show EVERY run (main.gd:51, reset :1261) instead of being seen-once onboarding. Either the doc or the tips need re-pinning (Chris’s call — tips re-showing may be intentional teaching).
  6. Mixed separators inside one stat string — ui/stats_sheet.gd:494-503 mixes →, /, · in single value lines. Micro.

Handled well (don’t re-sweep): codex locked ??? entries (ui/codex_overlay.gd:153-158), drone bay — empty —, stats sheet +N empty slots, empty-category auto-hide, LOCKED ships; iconography is one clean procedural family (ui/shop_icons.gd, ui/weapon_icon.gd, ui/drone_panel.gd:57, codex live previews — no font-glyph/emoji strays). Damage numbers raw vs _short() — acceptable (live hits), noted only.

Run 16 — Invisible progression (cycle 3: decision-time readability) — 2026-10-02 03:30 BST

Section titled “Run 16 — Invisible progression (cycle 3: decision-time readability) — 2026-10-02 03:30 BST”

4 findings. Pass 3 swept readability at the moment of choice (level-up cards, evolution readiness, crystal wallet, story progress) rather than render consumers. Prior items unchanged (one-line re-checks in the log below).

  1. Evolution fires with zero announcement — _apply_weapon_thresholds (sim/sim.gd:991-1008) applies crystal rungs including a full evolve with no fx_events push anywhere (grep: no evolve/threshold fx event). The only tell is the weapon’s look changing. Fix: push an fx_event (banner + sound) per newly-met rung; minimal version = pickup blip on card confirm. (Crystals are never field pickups — the wallet only changes at card-pick time, silently; same fix covers it.)
  2. Crystal wallet is invisible outside the level-up sheet — only ui/stats_sheet.gd:58-96 reads sim.crystals.counts; no HUD counter, no dock rung/evolve-ready indicator (run 10’s dock gap still holds). Between level-ups the player can’t see holdings or evolve-readiness. Fix: HUD wallet row or evolve-ready glow on the dock slot.
  3. No LV n → n+1 on upgrade cards — weapon_levels tracked (sim/upgrade_system.gd:407-412) but read only by can_evolve/dev tools; a wm: card shows “+50% damage” but not how many Power picks you’ve stacked or that the weapon is 1 pick from evolve-eligible (REQUIRES_LEVEL). Fix: “LV n → n+1” sub-line from weapon_level().
  4. Story mode has no chapter/beat number — ui/hud.gd:261-263, :318-336 renders “Region — objective” live (good) but never chapter n-of-m; story.current_room + region list exist unsurfaced. Fix: add n/m to _story_objective.

Clean (don’t re-sweep): upgrade-vs-new card distinction (why-tag pills ui/level_up_panel.gd:383-402), real stat deltas (ui/upgrade_copy.gd:31-126, upgrade_preview sim/upgrade_system.gd:479-516), crystal-card rung progress (“EVOLVE → name”, 3/5 rows :487-491), no wasted MAXED picks (wm: mods uncapped by design, capped ones pre-filtered :107-112, mod_eligible:247, one-pick Fork :256), no reroll/ban mechanic exists.

Run 17 — Render ignores sim data (cycle 3: coverage + capacity + attribution) — 2026-10-02 03:40 BST

Section titled “Run 17 — Render ignores sim data (cycle 3: coverage + capacity + attribution) — 2026-10-02 03:40 BST”

3 findings. Pass 3 swept entity-type→renderer coverage completeness, projectile→fx consumer coverage, MultiMesh/LUT capacity vs telemetry max, mid-run UI staleness, kill attribution.

  1. Death recap mis-categorizes dimension-hazard damage as melee — hazards damage with source "hazard" (sim/dimension_hazards.gd:409,414,422,475,574,631) but ui/death_recap.gd:13-16 _ZONE list is only ["funzo","orbiter","burn"], so suggest_counters tells players to buy armor/kite the swarm for what was a fire/poison zone. Fix: add "hazard". Minor sibling: "funzo_dash"/"brute_slam" also fall to melee — switch to prefix match.
  2. No completeness-guard test for enemy shape coverage — all 32 TYPE_ constants have _TYPE_SHAPE rows today (render/archetype_renderer.gd:87-141) but shape_for (:722-727) silently falls back to a generic triangle for any type_id beyond the table, and no GUT test pins _TYPE_SHAPE.size() == TYPE count (only Nova buckets are pinned, tests/test_nova_units.gd:45). This is exactly the bh-add-content invisible-entity trap, unpinned. Fix: one-line assert.
  3. Boss bar shows one boss via priority chain — main.gd:2007-2021 (Warden→Boss2→Funzo→Graviton→Eye); directors are mutually exclusive in practice and Boss2 dev-only, so noting as design intent — confirm only.

Ground covered clean (don’t re-sweep): every emitted fx kind has a consumer (~30 in fx/fx_manager.gd:640-871, warden kinds in fx/boss/warden_fx.gd, funzo/eye from sim-state readers, audio-only kinds intentional); capacity — ENEMY_CAP 6000 with EntityPool.add() returning -1 at cap + grow-only SwarmRenderer.fit_capacity (render/swarm_renderer.gd:70-76), telemetry max 5246 < cap, no type-indexed colour LUT; pause genuinely freezes sim.tick (main.gd:1415-1425) so mid-run panels can’t go stale; death-recap damage contract otherwise holds (all _hurt_player sites pass a source).

Run 18 — Telemetry (cycle 3: v2 events table) — 2026-10-02 03:50 BST

Section titled “Run 18 — Telemetry (cycle 3: v2 events table) — 2026-10-02 03:50 BST”

4 findings. New ground: the v2 events table (now LIVE and populated — 26,720 samples, 3,150 hitches, 476 shop_buys; the bh-telemetry skill’s “events does not exist live” note is stale). Death funnel/fps/encounters/picks already covered in runs 6+12.

  1. 80% of recorded exits are reason=“crash” (48 of 60 prev_exit events) — builds 211-228, mixed states incl. mid-play at run_time 0.25s and post-gameover at 359s. CAVEAT: Chris’s devicectl-terminate fresh-process test recipe likely masquerades as crash, so some/many of these are test kills. Action: make the client distinguish a dev-kill/SIGTERM from a real crash (or cross-check MetricKit) before treating this as a stability signal — right now the exit-health metric is unusable.
  2. Tutorial lesson “wake” started 5× and never advanced past step 0; “riftbolt” also stalls at step 0 — every other lesson shows symmetric step 0→2/3 progression (n small: 51 events, mostly one clean completion). Candidate stuck lesson-gate — exactly the harness/gate class CLAUDE.md warns about. Watch/verify with a story_trace run before trusting.
  3. The legacy runs table is nearly dead on recent builds — only 1 row (attract) for build ≥236 while 84 run_end events exist; death-cause/build analysis must move to events or it silently reads an empty set (run 6’s funnel queries predate this and still work on old builds, but any build-236+ analysis on runs returns nothing).
  4. Shop purchases: 80% from the results screen (381) vs 20% from menu (95), all out-of-run (in_run: 0) — the death→shop funnel is where spending happens; recent id mix is drone-upgrade-heavy (decoy-power, drone-disruptor-*, unlock-drone-bomber). Informational; economy-sim calibration input.

Payload gotchas logged for future queries: event keys are $.id/$.from/$.reason/$.lesson (not item/build/dev); ts is not a usable date column (use marker_ts in data).

Run 19 — Asset-fiction mismatch (cycle 4: prose claims) — 2026-10-02 04:00 BST

Section titled “Run 19 — Asset-fiction mismatch (cycle 4: prose claims) — 2026-10-02 04:00 BST”

5 findings. Pass 4 audited prose that claims to describe behavior: bestiary descriptions/counters vs sim, docs-site “current” claims, ASC metadata, display-name consistency.

  1. Codex tells players skirmishers “drop a powerup when killed” — powerups are disabled — data/bestiary.json:22-24 desc + counter advise chasing a drop that can’t spawn (sim/sim.gd:93 POWERUPS_ENABLED := false, off since 2026-09-27). The drop roll happens, nothing spawns. Player-facing fiction in the codex.
  2. Tank’s “armored fire wall… wear the armor down” counter is fiction — data/bestiary.json:8-9 vs data/bible.json:859 "armor": 0; no armor special-case exists in sim/. Sustained-fire advice is moot.
  3. Two stale “current” claims in live public docs — docs/architecture/enemies-bosses-survival.md:12 says Sim_Const.BUILD “currently 14” (it’s 242); docs/architecture/art-asset-pipeline.md:130 describes ADAPTIVE_QUALITY := false gated on the v0.1 release — the const moved to QualityManager.ENABLED (render/quality_manager.gd:16), v0.1 shipped, and it’s now remote-tunable. (docs/ symlinks into the live docs site, so these are public pages.)
  4. Tank missile name mismatch — bible data/bible.json calls it “Fireball”, bestiary/codex shows “Tank Missile” (desc says “fired by Tanks” so the bestiary side reads intentional — the bible name looks stale).
  5. VFX library labels the weapon “Pulse” where the player-facing name is “Electricity” — tools/vfx_library/library_manifest.gd; dev tool only, but it’s the polish-audit reference surface.

Verified accurate (don’t re-check): fleet_kite slow bolt, glass_wisp phase-negate, coil ring-reset, leech knockbreak, accumulator growth, warden range-banded deck + 40% enrage, swarmer fragility. ASC metadata clean (keywords/subtitle/age-rating all match shipped reality). Dialogue only names Blaster/Nova, both accurate.

Run 20 — Snap-vs-ramp (cycle 4: big moments + hit feedback) — 2026-10-02 04:10 BST

Section titled “Run 20 — Snap-vs-ramp (cycle 4: big moments + hit feedback) — 2026-10-02 04:10 BST”

6 findings. Pass 4 swept the moments no prior pass touched: boss death, player death, enemy hit feedback, gem magnet, thruster, XP anticipation.

  1. Boss death pops into a ~54px generic disc — the biggest moment in the game reads small: body removal + all fx are same-tick (sim/sim.gd:2825-2863), and the dissolve is a FIXED size — fx/death_dissolve.gd:12 SIZE := 0.85 (~54px), consume() (:39-46) ignores the type_id the sim already sends (sim.gd:2772). A screen-filling boss becomes a small disc in one frame. Fix: scale the dissolve (or multi-burst) from type_id, 3-4× for bosses. Surrounding layers (shockwave main.gd:1802, hero lights, victory sting) are fine.
  2. Player death is a hard cut to the results card — main.gd:1606-1621 → _show_results_when_drawn() (:1630-1635) awaits ONE drawn frame then shows results: no slowdown, desaturation, zoom, or fade — in sharp contrast to the ramped level-up convention. Fix: ~1s _time_scale lerp to 0 + fullscreen desat/fade, then results.
  3. Thruster ignores actual speed — render/player_renderer.gd:199 takes no velocity param; the plume (:212-222) varies only with the binary dash_ready (16/9 Hz, ×1.2/×0.8). Identical at full speed and a dead stop. Fix: plume size+alpha 0→1 eased from move magnitude.
  4. Gem magnet is flat 520 px/s — sim/sim.gd:2929 constant velocity inside the fixed 240px radius (:222-223); no acceleration as it closes. Fix: lerp(speed, speed*2.5, 1 - d/RADIUS).
  5. Zero anticipation moment at XP-full — pending_levelups opens the panel the same tick (main.gd:1596-1601); no HUD charge pulse, dock flash, or beat before it appears (and the live HUD has no run timer in survival — pause menu only, ui/pause_menu.gd:324-327 — design choice, noted).
  6. Enemy hit: colour flash only, no scale pulse — whitening is good (main.gd:233-237, render/hit_flash_tracker.gd:11, 0.09s); body is otherwise rigid. Optional polish: ~1.05 scale pulse riding the same tracker (knockback would be sim-side, out of scope).

Clean: enemy hit-flash system; story countdown cadence (ui/hud.gd:323 re-derived per frame); boss-death supporting layers.

Run 21 — UI pattern inconsistency (cycle 4: interaction behavior) — 2026-10-02 04:20 BST

Section titled “Run 21 — UI pattern inconsistency (cycle 4: interaction behavior) — 2026-10-02 04:20 BST”

5 findings. Pass 4 swept how panels BEHAVE: transient messages, back handling, selection memory, confirms, touch parity, death flow.

  1. “Quit to menu” is the only unconfirmed destructive action — abandons the whole run instantly (ui/pause_menu.gd:183) while harmless-ish RESET PROGRESS gets a full confirm dialog (ui/meta_shop_panel.gd:136, :1530-1617) and shop buys are deliberately no-confirm (:20). The most destructive action in the game is the only unconfirmed one. Fix: reuse the reset-dialog pattern.
  2. Four ad-hoc transient-message systems — wave banner (ui/hud.gd:163-176, :266-277, top-center gold 40px, sim-driven seconds, no fade), objective tip (ui/objective_panel.gd:14, top-center gold 14px, hard 6s cutoff), shop toast (ui/meta_shop_panel.gd:34, :364-376, centered glass plate, 3s + 0.4s fade — the only one that fades), damage numbers (own system). Same job, four lifetimes/positions/styles. Fix: one shared helper (text, position, lifetime, fade).
  3. Dimension choice swallows the universal “back” — ui/dimension_choice_panel.gd:216-231 has no ui_cancel/B branch; every other panel closes on B. (Results panel :508-541 also ignores B — minor, nothing to go back to.)
  4. Codex browse rows are nav-only — Labels with no per-row tap handler (ui/codex_overlay.gd:145-163, :205); tapping anywhere just closes, so touch players can’t tap to inspect. Fix: row gui_input → select+show. All other panels have proper tap targets.
  5. Selection-memory policy is split and undocumented — shop/codex/results/dimension all reset to index 0 on reopen; pause menu alone remembers (ui/pause_menu.gd:415, :460). Pick one policy (remember-last is friendlier for shop/codex) and apply uniformly.

Clean: ui_cancel/B/ESC consistent on drone bay, ship config, shop, stats sheet; forced-choice panels (level-up, dimension) intentionally non-cancellable and consistent with each other; death flow is one family by construction (DeathRecap renders inside ResultsPanel).

Run 22 — Invisible progression (cycle 4: value/identity perception) — 2026-10-02 04:30 BST

Section titled “Run 22 — Invisible progression (cycle 4: value/identity perception) — 2026-10-02 04:30 BST”

4 findings. Pass 4 swept perception of VALUE differences the sim computes: gem worth, enemy elemental states, reward multipliers, time-based enemy tanking. (Player-burn overlap with run 11 noted, not re-reported.)

  1. Gem values are pixel-identical — a 400-XP boss gem and a 5-XP swarmer gem look the same: main.gd:1971 gem_renderer.sync passes one fixed colour and NO scale array, though render/swarm_renderer.gd:103-142 supports per-instance colours/scales; boss biomass 400 vs ~5 land in the same pool (sim/sim.gd:2724-2730, :228). Gold has no entity at all (awarded invisibly at sim.gd:2810-2858). Fix: per-gem colour+scale keyed to value tiers, distinct boss-gem colour.
  2. Burning/shocked enemies have no element-specific tell — main.gd:2317 _enemy_colors() reads base_element/is_elite/hit-flash but never aura_element/aura_remaining/stacks (sim/elemental_system.gd:280-281, :249, :449); a burning enemy shows no flame tint, a shocked one no arcs. Only tell is the element-agnostic white flash. Fix: lerp instance colour toward the element palette in _enemy_colors() (enemy-side; the PLAYER burn DoT was run 11’s finding).
  3. Reward multipliers are invisible once the run starts — area_reward_mult 1.25-1.5 (sim/area_defs.gd:68-147, applied sim.gd:2724, :2810-2858) has exactly one consumer: the pre-run choice panel (ui/dimension_choice_panel.gd:173). In-run, boosted gems look identical and gold just increments faster with no blip. Fix: warm gold-shift tint on boosted-area gems + gold-counter pulse.
  4. Late-run enemy tanking is invisible — difficulty_mult() +50% HP/contact per minute (sim/spawn_director.gd:25-31, applied sim.gd:1538, :1658) never reaches render: render/archetype_renderer.gd:135 sizes by radius[i] only. A minute-15 swarmer with 10× HP is pixel-identical to a minute-2 one. Fix: per-enemy spawn-diff scale/tint lerp.

Common fix shape: the per-instance colour/scale channels SwarmRenderer.sync/ArchetypeRenderer.sync already support, but nothing populates from the sim data. Verified fine: drone class identity (distinct tints render/decoy_renderer.gd:26-32 + per-class Nova sprites render/drone_sprites.gd:20).

Run 23 — Render ignores sim data (cycle 4: hitbox vs visual) — 2026-10-02 04:40 BST

Section titled “Run 23 — Render ignores sim data (cycle 4: hitbox vs visual) — 2026-10-02 04:40 BST”

5 findings (3 in the harmful direction). Pass 4 compared every damage radius against its drawn radius. Correction to run 22 finding 1: AUTO_COLLECT_XP = true (sim/sim.gd:226) banks XP on kill — no physical gems spawn in the shipped config, so the “pixel-identical gem values” gap is config-mooted (fix stays valid if physical gems return).

  1. Eye boss hitbox 28% bigger than its drawn body — contact at full enemies.radius (sim/sim.gd:3129) vs body disc drawn at erad * 0.78 (render/eye_renderer.gd:65, erad full at :45). You get hit standing clear of the drawn eye. Fix: draw at ≥1.0× or shrink the pool radius.
  2. Boss2 artillery blast 25% bigger than its telegraph — damages within full BOSS2_ARTILLERY_BLAST_RADIUS = 80 (sim/boss2.gd:34, :96); telegraph circle drawn at *0.8 = 64 (render/boss2_renderer.gd:142). Hits land inside the unmarked ring. Fix: draw telegraph at 1.0×.
  3. Boss2 body hitbox 12% bigger than visual — full brad contact (sim.gd:3129) vs brad*0.88 disc / 0.92 ring (render/boss2_renderer.gd:59-60). Same class, milder.
  4. Graviton satellites: visual 40-60% BIGGER than hitbox (forgiving) — collision GRAVITON_SAT_HIT_R = 8 (sim/graviton.gd:39, :175) vs drawn 11.2/12.8 (render/graviton_renderer.gd:115-116). Cosmetic only.
  5. Web capsule hitbox leads its visual by 0.25s — sim tests the full capsule on landing (sim/elemental_system.gd:314-321); renderer grows drawn length over WEB_GROW_S = 0.25 (render/zone_renderer.gd:96-99). Far end slows you before it’s drawn. Minor — plausibly intended landing animation.

Clean (don’t re-sweep): swarm contact vs draw (scale by construction, render/archetype_renderer.gd:135); every drawn zone radius = damage radius (webs, weapon zones, funzo, chalice, chronowell, reaction); bomb telegraphs at full radius; warden body; arena bounds fully rendered (glowing edge at exactly ±ARENA_HALF, render/arena_border.gd:20-22, :49-56; story walls via StoryMapRenderer); elite-kit status scan — all four pilot fields have consumers; pause/attract render behaviour clean.

Run 24 — Telemetry (cycle 4: v2 run lifecycle) — 2026-10-02 04:50 BST

Section titled “Run 24 — Telemetry (cycle 4: v2 run lifecycle) — 2026-10-02 04:50 BST”

4 findings. New ground: run_start/run_end lifecycle analysis on the events table (119 starts vs 84 ends), level-at-death distribution, quit behaviour, perf_seg rows.

  1. Death-cause data is being LOST going forward — v2 run_end payloads carry kills/level/mode/reason/run_time but NO cause (verified across all 84 rows); the legacy runs table that had death_cause is dead on build ≥236. Run 6’s funnel (44% swarmer, charger wall) is the LAST measurement of its kind — the 1.0.1 early-death work is flying blind on new builds. Fix: add cause to the run_end payload (and a build/dev key — run_start has neither, so per-build lifecycle analysis on events currently can’t group).
  2. Level-at-death is bimodal — the wall is real — 0-9: 22, 10-19: 22, 20-29: 10, 30-39: 5, 40+: 14. Players either die early (avg lvl 10.1 for quitters) or break through and run long (survival deaths avg lvl 22.5 / 438s; several lvl-40+ runs 490-1049s). Get past the mid-game and you thrive. Corroborates run 6’s early-pacing finding from a different angle.
  3. 29% of started runs never record an end (119 starts vs 84 ends) — with 48-of-60 exits reading “crash”, most of the gap is probably the devicectl-kill masquerade (run 18 finding 1), not rage-quit. Direct quit data that DOES exist: 8 survival quits (avg lvl 10.1, 320s) + one 2-second tutorial quit. Fix path remains: distinguish dev-kill from crash.
  4. The soak/perf A-B harness writes to the production DB — 21 perf_seg rows (scenario ids, A/B sides, presets like “nova_shockwave” vs “webs”, p50/p95) are harness-generated test data in prod, same contamination class as the build-9001 rows (run 6 finding 3). Minor hygiene: tag harness rows or route them elsewhere.

Ground covered: run_end/run_start payload schemas; level-at-death buckets; quit vs death split; tutorial_cap (2 completions); no new device samples landed during the loop itself (no sessions since ~21:23 UTC 2026-09-28 era beyond the ones already counted).

Run 25 — Asset-fiction mismatch (cycle 5: preview reality + store media) — 2026-10-02 05:00 BST

Section titled “Run 25 — Asset-fiction mismatch (cycle 5: preview reality + store media) — 2026-10-02 05:00 BST”

3 findings. Pass 5 traced preview-vs-reality pipelines and store media. Hull preview verified CLEAN — config screen and in-run renderer load the identical baked PNGs via the identical PlayerRenderer.nova_hull_base() helper (ui/ship_config_panel.gd:221-225 = render/player_renderer.gd:181-190); no bake-vs-live divergence class exists there (cosmetic only: preview shows body PNG without glow/tilt). Console deployment current, no drift signal.

  1. Trailer videos are 3 months stale while SUBMIT.md says “still being produced” — marketing/appstore/previews/{iphone,ipad,tv}.mp4 (12-17MB each) last changed 2026-06-30 (0210374c), predating the glow rework, Nova look, and 1.0 content freeze — yet SUBMIT.md §5 claims trailers are still being produced. Fiction both ways. Fix: recapture via marketing/trailer/build_trailer.sh + update §5 to reference the existing files.
  2. No TestFlight what-to-test text exists — grep of marketing/docs/copy finds none; SUBMIT.md has no TestFlight section at all. Gap (not drift): write a marketing/appstore/testflight.md matched to 1.0.1’s real scope.
  3. Mac screenshots are 2880×1800, not the required 2560×1600 — marketing/appstore/mac/ (dead weight: never uploaded, Mac listing uses the iPad set as “Designed for iPad”, per SUBMIT.md §4). Delete or regenerate only if a native Mac submit ever happens. iPhone 6.9“ (2868×1320), iPad 13“, tvOS sizes all correct.

Run 26 — Snap-vs-ramp (cycle 5: readiness + transitions) — 2026-10-02 05:10 BST

Section titled “Run 26 — Snap-vs-ramp (cycle 5: readiness + transitions) — 2026-10-02 05:10 BST”

6 findings. Pass 5 swept readiness transitions, boss entrances, music switches, counters, banner text.

  1. Bosses spawn with no entrance ceremony — every boss emits a spawn reaction (name + ring + sting: sim/sim.gd:1086, sim/graviton.gd:64, sim/eye.gd:70, sim/boss2.gd:51, sim/funzo.gd:94) but the BODY pops in via the generic pooled spawn, in plain sight under the BOSS APPROACHING banner. Fix: a boss_spawn fx event driving a 0.5-1s materialize ramp/telegraph ring.
  2. Music switches are hard cuts — audio/audio_manager.gd:423-436 play_music() swaps the stream on one player, stop_music() (:456-459) hard-stops (gameover → abrupt silence); no tween exists anywhere in the file. Fix: twin-player crossfade ~0.8s.
  3. Warp readiness is diegetic-only AND discontinuous — no HUD indicator exists (the old icon was removed; stale comment ui/touch_controls.gd:148), and the thruster pulse hard-flips rate 9→16 Hz / amp at the ready edge (render/player_renderer.gd:213-219). Fix: lerp dash_ready strength over ~200ms + a one-shot ready ring (mirroring touch’s READY_PULSE_MS, ui/touch_controls.gd:530-533).
  4. Drone dock ready-state snaps 14% scale — ui/drone_dock.gd:76-77 _apply_ready_state() sets scale 1.0→1.14 instantly; glow pulse starts abruptly. Fix: ~150ms tween on the ready edge.
  5. Boss bar pops at full size — ui/hud.gd:311 _boss_group.visible = true. Fix: modulate+fill tween ~300ms on first sight.
  6. Gold counters show final numbers instantly — results tiles (ui/results_panel.gd:267-270) and shop header (ui/meta_shop_panel.gd:610) set the final int directly; no count-up on the payoff moment. Fix: 0.6s count-up tween (results at minimum). Banner/reaction text also snap in at full size (ui/hud.gd:275, fx/fx_manager.gd:343-352 — out-fade only).

Clean: touch ability ready pulse (expanding ring + halo, ui/touch_controls.gd:530-533); codex/stats scrolling reads fine linear for tvOS (nit: codex row-highlight rebuild is instant where ship-config tweens EASE_OUT — same family, different motion language, low priority).

Run 27 — UI pattern inconsistency (cycle 5: text + token discipline) — 2026-10-02 05:20 BST

Section titled “Run 27 — UI pattern inconsistency (cycle 5: text + token discipline) — 2026-10-02 05:20 BST”

4 grouped findings. Pass 5 swept casing, safe-area coverage, colour-token discipline, scaling mechanisms.

  1. Safe-area insets ignored on four live HUD surfaces (shared helper Platform.safe_insets_units exists, platform.gd:42-64, and most panels use it): ui/hud.gd:72-73 HP group at hardcoded y=22 (inside TV-overscan/Dynamic-Island band), ui/objective_panel.gd:46-48 fixed TOP_Y, ui/level_up_panel.gd:123-126,338-340,175-177 bottom strip/hint/STATS (home-indicator band), ui/dimension_choice_panel.gd:193 bottom hint. Real device bug class. Fix: add insets on all four.
  2. Button/hint casing is three-way mixed — titles are reliably ALL-CAPS, but buttons: start-menu CAPS (“SHIP”, “SHOP”, ui/start_menu.gd:75-86) vs pause Title Case (“Ship stats”, “Shop”, ui/pause_menu.gd:142-155) on back-to-back screens; “STATS” CAPS vs Title siblings (ui/level_up_panel.gd:174); hints three-way (“TAP A RIFT TO ENTER” vs “Tap to select · swipe to browse” vs “tap to continue”). Fix: one button casing + one hint casing.
  3. Colour tokens exist but five semantic roles drift — TEXT_DIM has 6 variants (ui/tokens.gd vs ui/results_panel.gd:129, ui/codex_card.gd:8, ui/weapon_detail_view.gd:11, ui/stats_sheet.gd:131, + ui/dimension_choice_panel.gd:24 shadows the token); GOLD has 5 values (ui/results_panel.gd:180 vs ui/theme/gold_pulse.gd:10 etc.); SUCCESS 4 variants; ui/feedback_panel.gd:22 redefines ACCENT as a hue-drifted cyan; Tokens.BG (0,0,0,0.55) matches neither DESIGN.md’s (0.02,0.03,0.06,0.6-0.66) nor the 0.9+ panels actually use (ties to run 9’s glass-drift finding — the token itself needs re-pinning). Fix: migrate to tokens, retokenize BG per the real convention.
  4. start_menu runs its own second scaling mechanism — ui/start_menu.gd:29-31, :201-204 _scale() against a 1280×720 DESIGN basis, duplicating Tokens.ui_scale()/content-scale (can compound with the touch 1.3 CSF). Other families: meta_shop’s layout_for, measured 720p fitting with tests. Fix: collapse to the shared model or document why it’s separate.

Clean: identity-colour tables (weapon/drone/codex) by design; death_recap, boss_edge_indicator, region_title.

Run 28 — Invisible progression (cycle 5: long-horizon meta) — 2026-10-02 05:30 BST

Section titled “Run 28 — Invisible progression (cycle 5: long-horizon meta) — 2026-10-02 05:30 BST”

4 findings. Pass 5 swept cross-run progression visibility: personal bests, collection counters, account numbers.

  1. Personal-best records don’t exist — sim/meta_state.gd persists only banked_gold/gold_spent/levels/flags/loadout/seen_enemies — no best time/kills/level/gold field anywhere; ui/results_panel.gd:251-270 shows this run’s tiles with no comparison and no NEW RECORD moment; nothing in the start menu either. The retention lever is absent entirely. Fix: best_* fields in MetaState + BEST tile + record flash in results.
  2. Codex completion is tracked but never shown — ui/codex_overlay.gd:96-104 has entry_count()/seen_count() used only by a test, never rendered; title is just “BESTIARY” with per-entry ??? but no “12 / 30 discovered”. Fix: title counter. Players can’t chase what they can’t count. ✅ DONE (COMMIT, branch codex-counter): claim verified accurate. BROWSE mode now renders a right-aligned “n / m DISCOVERED” counter (JetBrains Mono 24, soft blue-grey so the cyan BESTIARY title keeps the accent) on the title row; hidden on the NEW ENEMY card. Lives inside the full-screen overlay (layer 24, 56px margins), so no HUD collision. Tests: test_codex_overlay.gd ×2. Windowed look at Apple TV distance not checked here; codex.png in the UI sweep will drift and needs a bless.
  3. No account-level career numbers at all — no career level, total runs, or lifetime kills field exists in meta_state; the only account number ever rendered is banked_gold (ui/meta_shop_panel.gd:610, ui/results_panel.gd:259-270); the start menu shows no gold readout either (ui/start_menu.gd:40-44, :71-83). Fix: persist runs_played/lifetime_kills, surface a line on the start menu.
  4. Ship collection has no count framing — LOCKED tag + dim treatment per hull exists (ui/ship_config_panel.gd:82, :226-228) but no “n of m hulls owned”. Fix: header counter from ShipBonuses roster vs meta.owns_ship.

Clean (don’t re-sweep): empty weapon/drone slots DO render as visible empty boxes (ui/weapon_panel.gd:218-222, max slots always built; ship config renders “Empty slot / not yet owned” cards) — progression space is readable; locked abilities hide entirely but are tutorial-stage gates only — nothing unowned to tease.

Run 29 — Render ignores sim data (cycle 5: overflow + z-order) — 2026-10-02 05:40 BST

Section titled “Run 29 — Render ignores sim data (cycle 5: overflow + z-order) — 2026-10-02 05:40 BST”

3 findings. Pass 5 audited load behavior and layering. The fx queue itself is clean (plain arrays, no cap, drained per frame); damage numbers clean (fixed 72-pool + merge); aim indicators clean (Rift Bolt is stick-directed, no reticle needed).

  1. Boss reaction events can be silently dropped under a hitch backlog — per-consume caps count in event order (fx/fx_manager.gd:12-47: REACTION_CAP=6, ring pool 24, global JUICE_FRAME_CAP=48); reaction (shared by boss ENRAGED/SUMMON/BLAST rings+labels from sim/graviton.gd/sim/eye.gd/sim/boss2.gd) and accum_warn (accumulator kill-priority warning) appended after weapon spam can vanish. Boss telegraph SHAPES are safe (state-reading renderers, not events). Fix: exempt named reactions + accum_warn like ESSENTIAL_KINDS.
  2. Bomb telegraphs render UNDER the swarm (z=-1) while lancer/ghost telegraphs sit at z=1 — render/bomb_renderer.gd z=-1 vs render/dash_telegraph_renderer.gd z=-1 and ghost/lancer at z=1 (deliberately promoted “visible over enemies”). A dense horde can bury the bomb blast zone the player must dodge. Fix: raise bomb telegraph to z=1. (DoT/web zones at z=-1 are deliberate large translucent fields — acceptable, but worth one eyeball check under a 5000-enemy swarm in the vfx harness.)
  3. Audio PER_FRAME_CAP=4 drops priority cues — the cap is checked BEFORE priority in audio/audio_manager.gd (~:25 + mapped-sound gate), so a boss_missile_launch/eye_laser arriving after 4 ordinary sounds in the same consume is dropped despite the BOSS_RESERVED_VOICES=3 steal protection existing. Fix: let PRIORITY_FX_KINDS past the cap (or reserve a cap slot).

Run 30 — Telemetry (cycle 5: economy + prewarm verification) — 2026-10-02 05:50 BST

Section titled “Run 30 — Telemetry (cycle 5: economy + prewarm verification) — 2026-10-02 05:50 BST”

3 findings. New ground: shop-economy health from shop_buy payloads, gold accumulation, first-use-stall verification on current builds.

  1. Gold over-accumulates — sinks are far too weak vs income — 476 shop_buys across 62 distinct items: avg cost only 112 gold, avg gold_after 14,115, only 28/476 buys left the player under 200 gold, 234 left them over 5k; and 65 of 119 runs START with 5k+ banked (26 start under 100). Players are hoarding with nothing meaningful to spend on. Data-backed economy imbalance — feed into the economy-sim calibration (bh-economy-sim / docs/RELEASE-1.0.1.md pricing items): prices need scaling or new sinks for 1.0.1.
  2. First-use shader stalls: ZERO on builds 244-246 — no pipelines > 0 hitch rows exist for any build ≥244 (hardest cut). The shader-bake/PSO-prewarm arc is fully verified — run 6 finding 4’s “reads as landed” is now confirmed; no further work.
  3. Launch events carry no timestamp — marker_ts exists only on prev_exit payloads; launch/run_start/run_end/shop_buy have no time key, so play-frequency/retention-over-time analysis is impossible (and the events table’s ts column isn’t a usable date). Fold a marker_ts (or fix ts) into the same payload-keys fix as run 24 finding 1.

Run 31 — Asset-fiction mismatch (cycle 6: long-tail prose) — 2026-10-02 06:00 BST

Section titled “Run 31 — Asset-fiction mismatch (cycle 6: long-tail prose) — 2026-10-02 06:00 BST”

6 findings. Pass 6 verified the remaining ~20 bestiary prose entries, unverified story dialogue, credits, and export metadata.

  1. Sentinel boss “five attacks” claim includes a removed attack — data/bestiary.json:41 lists “a sweeping cutter beam”; the cutter was removed (sim/boss2_state.gd:14, ATTACK_COUNT := 4 at :19-23). Player-facing fiction. Fix: “four attacks — artillery, rings, slam, summons”.
  2. Story dialogue tells players to aim the Beam manually — it auto-targets — data/story.json:475-477 “hold a line and sweep it” vs sim/weapon_beam.gd:40-52, :92-106 (auto-targets nearest + self-slews; player never aims). Fix: “It seeks the nearest foe on its own…”.
  3. Zapper “fires a bolt mid-charge” is wrong — data/bestiary.json:27 vs sim/enemy_attacks.gd:221-246: bolts fire on an independent timer in any phase. Fix: “fires aimed bolts while it rushes”.
  4. Halo-chain “Dash through a tether to break it… collapsing the buff” is doubly wrong — data/bestiary.json:93 vs sim/halo_chain_director.gd:171-175 (any crossing breaks it) + :31 (TETHER_BREAK_COOLDOWN — re-forms in 1.0s, buff only pauses). Fix: “Cross a tether to break it for a moment”.
  5. No credits screen exists anywhere — grep of ui/ clean; start menu has no Credits row. Gap for a shipped store game (not a defect).
  6. Copyright string inconsistent — root export_presets.cfg:68 copyright="Lumara" (bare, no year); platform/tvos/export_presets.cfg has NO copyright field at all. Fix: consistent © 2026 Lumara in both, single-writer style.

Omissions (minor, not fiction): charger entry omits the 0.6s post-lunge recovery (sim/enemy_behaviors.gd:166) + elite chained dash; funzo entry omits jester/confetti mechanics. Support/Marketing/Privacy URLs verified live and real (SUBMIT.md:75-77 → darkcosmos.lumara.digital, deploys confirmed). Checked clean this pass: ghost, rusher, brute, scatterer, bomber, orbiter, spider/weaver, wyrm (shared HP pool real), beacon, mite, tank_missile, graviton, eye, centurion; story: riftbolt, decoy 8s, warp invuln, stand-still regen, homing-missiles-target-drones, crystals, orbit shards, scatter pellets, ember Blaster auto-aim.

Run 32 — Snap-vs-ramp (cycle 6: final corners) — 2026-10-02 06:10 BST

Section titled “Run 32 — Snap-vs-ramp (cycle 6: final corners) — 2026-10-02 06:10 BST”

2 findings; category nearing exhaustion. Pass 6 checked the last untouched corners.

  1. “HOLD %ds” countdown sits flat until zero — ui/hud.gd:263, :322-323: plain text, no colour shift/pulse/audio tick in the final ~5s, and completion swaps to the next objective with no beat (only incidental mass-kill dissolves, sim/story_director.gd:218-224). Fix: final-5s urgency ramp + completion flash.
  2. Choice-panel confirmations have zero visual animation — level-up _confirm() (ui/level_up_panel.gd:565-583) plays a nav sound and vanishes: no chosen-card pop, no sibling fade; dimension choice _confirm() (ui/dimension_choice_panel.gd:208-212) the same instant swap. One family fix: chosen-card scale/burst + sibling fade (~0.2s).

Verified clean (don’t re-sweep): drone deploy materializes over ~0.45s (render/decoy_renderer.gd:23-26); shop purchase flash tweens (ui/meta_shop_panel.gd:905-910); all fx/ pooled classes ramp from life/max_life, no sibling inconsistencies.

Run 33 — UI pattern inconsistency (cycle 6: final corners) — 2026-10-02 06:20 BST

Section titled “Run 33 — UI pattern inconsistency (cycle 6: final corners) — 2026-10-02 06:20 BST”

2 mild findings; category exhausted. Pass 6 swept layer stacking, modal dim, focus treatments, hint footers, onboarding tips.

  1. Level-up and dimension choice dim differently for the same job — both are mid-run freeze-and-pick-card modals, but level-up ramps a vertical 0→0.88 veil (ui/level_up_panel.gd:102) while dimension choice is flat 0.9 (ui/dimension_choice_panel.gd:23). Level-up’s ramp is the odd one out among card modals (unless deliberate — Chris’s call).
  2. Ship config has no hint footer, no first-open tip, nothing — while every sibling has at least one: drone bay a full contextual hint bar (ui/drone_bay_panel.gd:114), shop a persisted first-3-opens tip (ui/meta_shop_panel.gd:1492-1509); ship config only has a top-left BACK + ‹/› glyphs (ui/ship_config_panel.gd:91,95,110). Results panel likewise has no exit hint (weaker case — buttons self-labelled).

Verified clean (don’t re-sweep): CanvasLayer stacking fully consistent and documented (HUD 5 < modals 10 < codex 24 < touch 30 < menus 60-82 < toast 200; the one same-layer pair feedback/shop at 80 never co-opens; touch suppressed while codex open, main.gd:2660); focus treatments are ONE GlassPanel family across level-up/dimension/drone/results/shop; dim tiers otherwise consistent (0.55 light veil, 0.86-0.9 heavy, 1.0 opaque-HDR).

Run 34 — Invisible progression (cycle 6: unlock discoverability) — 2026-10-02 06:30 BST

Section titled “Run 34 — Invisible progression (cycle 6: unlock discoverability) — 2026-10-02 06:30 BST”

No new findings — category exhausted. Pass 6 swept unlock discoverability and all four corners came back clean or deliberate:

  • Shop shows unowned items (priced unlock cards render, just sort first — ui/meta_shop_panel.gd:468, :1251-1286; no ownership filtering anywhere). No invisibility.
  • Tutorial progress IS visible — “LESSON %d OF %d” + per-step progress line (ui/objective_panel.gd:92, :97-102).
  • Dimension choice has no silent gating — exclusions are only already-visited rifts (sim/sim.gd:2976, :2995), with a failsafe re-admit; card count is honest.
  • Borderline design choice (Chris’s call, not a defect): the drone-bay slot cycle filters to owned classes only (ui/drone_bay_panel.gd:133-138 _options()), so a new player cycling the bay never sees that Bomber/Interceptor/Disruptor/Logistics exist — discoverability rests entirely on the shop’s Drones tab blurbs (ui/shop_categories.gd:67-86). Locked placeholders in the cycle would close it if wanted.

Run 35 — Render ignores sim data (cycle 6: interpolation + final corners) — 2026-10-02 06:40 BST

Section titled “Run 35 — Render ignores sim data (cycle 6: interpolation + final corners) — 2026-10-02 06:40 BST”

1 finding. Pass 6 audited sim→render temporal smoothing, camera, shader uniforms, and “for render” fields.

  1. No sim-to-render interpolation — 60Hz stepping is visible on 120Hz ProMotion displays — sim ticks in _physics_process (main.gd:1412, tick at :1506), renderers draw raw pos per _process frame (main.gd:1725); no prev-position columns in any pool, no tick-fraction lerp anywhere (grep-verified). On iPhone/iPad Pro/Mac 120Hz displays, fast movers step at 2-render-frames-per-tick. Partially masked by the rigid player-follow camera (fixed-offset child of the player, main.gd:1231-1233) — whether interpolation is warranted is a design call, but the mechanism doesn’t exist today.

Verified clean (don’t re-sweep): camera responds only to player transform by design; live-game shaders’ only uniforms (dim, accent_codes) are both set live; the “for render” comment census found only graviton satellites (consumed, render/graviton_renderer.gd:112) and the KNOWN still-open halo-chain tethers (sim/halo_chain_director.gd:53 — punch-list run 5 finding 1, still zero consumers at HEAD).

Run 36 — Telemetry (cycle 6: confirmations) — 2026-10-02 06:40 BST

Section titled “Run 36 — Telemetry (cycle 6: confirmations) — 2026-10-02 06:40 BST”

2 findings, both confirmations of earlier candidates. New ground: hitch-free verification on current builds, dash-rate trend, wake-lesson recheck, purchase spread.

  1. Tutorial “wake” lesson stall CONFIRMED — still 5× step 0 with zero progressions (riftbolt 2× step 0 likewise), no new completions since run 18’s flag. Upgrade from “candidate”: worth a story_trace verification pass before trusting, but the stall is stable in the data.
  2. Builds 244+ are hitch-free in event data — zero rows of ANY kind (no pipeline stalls per run 30, now no non-pipeline stalls either on this cut). Combined with 244-246 holding ~59fps: the perf thread from runs 6/12/30 is fully closed. No action.

Trend note (no action beyond run 12’s finding): dash rate on cleared encounters roughly DOUBLED across builds — 0.04-0.07 on builds 207-212 vs 0.17-0.18 on 230/243/244 (encounter tuning or tester skill; still ≤0.18, so “dash as panic button” holds). Purchase spread: all 476 buys are 1-2 per item across 62 items — no must-buy concentration; consistent with run 30’s cheap-prices/hoarding picture (players buy a bit of everything, bank the rest).


Closing summary — 2026-10-02 06:50 BST — loop complete

Section titled “Closing summary — 2026-10-02 06:50 BST — loop complete”

36 runs over 6 hours, 148 logged findings, all committed and pushed. Six audit categories × 6 passes each; nothing was fixed (per protocol) — everything above awaits triage onto docs/RELEASE-1.0.1.md.

Triage guide — highest-value first:

  1. Gameplay fairness (player getting hit by invisible things): eye hitbox +28% vs drawn body (r23), boss2 artillery +25% past telegraph (r23), player burn/slow DoT invisibility (r11), halo-chain +45% damage buff with zero visual (r5), bomb telegraph buried under swarm (r29), audio priority cues dropped by PER_FRAME_CAP (r29), boss reaction events dropped under load (r29).
  2. Retention + economy (data-backed): first-2-minutes cliff — 63% of runs die <2m, swarmers cause 44% of deaths (r6, r12, r24 bimodal); gold over-accumulation — avg 14k banked vs 112 avg cost (r30); personal bests don’t exist (r28); tutorial “wake” lesson stalled 5× (r18, r36 confirmed); death-cause no longer captured on new builds (r24).
  3. Store hygiene for 1.0.1: screenshots/trailers/press kit 3 overhauls behind (r1, r25), “What’s New” still v0.1-framed + missing Story/codex/gold-shop mention (r7), no TestFlight text (r25), privacy-page Sentry note (r13), copyright fields missing/inconsistent (r31), no credits screen (r31), stale docs claims (r7, r19).
  4. In-fiction fictions (player-told lies): skirmisher “drops a powerup” (disabled) (r19), sentinel “five attacks” (cutter removed) (r31), story “hold a line” Beam (auto-aims) (r31), zapper/halo-chain prose (r31), death recap calls hazard damage “melee” (r17).
  5. Juice for the big moments: boss death = 54px disc (r20), player death hard cut (r20), bosses spawn with no entrance (r26), music hard cuts (r26), HP/boss bars no damage chip (r14), gold count-up absent (r26), card-confirm animations absent (r32), 60Hz stepping on 120Hz displays (r35).
  6. UI hygiene: store players can’t mute (r15), quit-run unconfirmed (r21), HUD safe-area gaps on TV/iPhone (r27), save-area + colour-token + casing cleanups (r27), run tips violate DESIGN.md placement (r15), 4 ad-hoc transient-message systems (r21).
  7. Progression visibility (supports r12’s pick-concentration data): 11 weapons without progression visuals — and they’re exactly the unpicked ones (r4, r12), weapon dock shows no level/mod/evolve (r10), crystal wallet + evolve announcement invisible (r16), meta-stat upgrades imperceptible (r4).
  8. Guard rails to add: shape-coverage GUT test (r17), death-cause/build keys in run_end (r24), devicectl-kill vs real-crash distinction (r18), codex counter render (r28).

Verified healthy (no action): ATV perf fully landed (zero hitches, ~59fps on 244-246), arena bounds rendered, drone class identity, hull pipeline, enemy shape coverage today, tutorial progress + codex locked states, back handling, glass focus family, layer stacking, privacy labels vs reality, Dark Cosmos naming chain, Decoy naming rule.