Skip to content

v1.7.1 — emergency update fix

Choose a tag to compare

@avcode-exe avcode-exe released this 24 Jul 07:58
· 16 commits to main since this release

Release v1.7.1 — Emergency Update Fix

This emergency patch release fixes critical auto-update issues that could silently prevent users from receiving updates, and removes the "skip this version" feature to ensure reliable update notifications on every startup.

1,885 tests · 49 files · 92.93% branch coverage · 98.38% statement coverage


🐛 Critical Bug Fixes

Stale skipped version blocking updates — When a version was previously skipped (e.g. clicking "Skip" on an update notification), the skipped version was persisted to settings.json. If the user later downgraded to an older version (e.g. for testing or reinstalling), the stale skipped version would prevent the app from ever notifying them about the same update again — because shouldAnnounceToUser() immediately returned false for any version in the skippedVersions list. This could cause users to silently miss updates indefinitely.

Fix: Removed the "Skip this version" feature entirely. The "Skip" button has been replaced with "Cancel" — clicking Cancel simply dismisses the notification without persisting any state. The update prompt will re-appear on every startup until the user updates.

Double startup update check — Both the main process (did-finish-load handler in electron-main.js) and the renderer (updateManager.init() with a 3-second setTimeout) were independently triggering update checks on every app launch. This caused two identical "Update available: v1.7.0" notifications to appear simultaneously.

Fix: Removed the main process startup check. The renderer's delayed check is now the sole trigger, eliminating duplicate notifications.

Update notification "not-available" despite newer version existing — The shouldAnnounceToUser() function was filtering out valid updates because of the stale skippedVersions list combined with channel and release-type checks. Now that the skip feature is removed, shouldAnnounceToUser is simplified and always reports available updates that match the user's channel preference.

Files affected: electron-main.js, preload.cjs, src/updateManager.js, src/main.js, src/config/settingsDefaults.js


🎉 Features & Improvements

  • Sidebars expanded on startup — The left (HUD) and right (shop) sidebars now always expand on app launch regardless of the previously persisted collapsed state. This ensures full UI visibility immediately after starting the game.

  • Update banner smooth fade-out — The persistent update banner now uses a smooth CSS animation that slides it upward and fades it out of the canvas when dismissed, instead of abruptly disappearing.

  • Dev console support (F12) — A developer console has been added to help debug issues in production builds.


⚙️ Performance

  • Auto-save debounce_stepWaveCompletion() now calls _autoSave() every 5 waves instead of every wave, reducing disk I/O during long sessions.
  • Cached DPS/HPS — Troop getDps() and getHps() return cached values computed in _recomputeStats(), avoiding recomputation on every render frame.
  • Cached stat lines — Shop _buildStatLines() caches its result on the troop object, invalidated on upgrade.
  • Optimized troop tile index — Removed redundant full rebuilds from sellTroop() and killTroop(); the index is rebuilt only in _cleanupDead().
  • Optimized monster tile index — Rewrote from full clear-and-rebuild to incremental updates tracking _prevTileIdx on each monster, only moving entries when monsters cross tile boundaries.
  • Dynamic particle cap — Particle pool scales with navigator.hardwareConcurrency (100–300 particles based on core count) instead of a hardcoded 300.

🧪 Testing & Quality

  • Toast.js branch coverage: 83.33% → 95.83% — Added test for showToast() without a type parameter, covering the TYPE_ICONS[type] || '' fallback and icon ? falsy ternary branches.
  • preload.cjs excluded from v8 coverage — v8 cannot instrument CommonJS files, so preload.cjs always reported 0%. Removed from the coverage include list. The file still has 36 active tests via tests/preload.test.js.
  • All test references to removed skip features cleaned up — Removed skipUpdate, skip-update, and skippedVersions test coverage from tests/preload.test.js, tests/electronMain.test.js, tests/updateManager.test.js, and tests/smoke.test.js.
  • 1,885 tests across 49 files (up from 1,710 tests across 47 files).
  • Full coverage compliance: Every source file now meets ≥90% on all coverage metrics.
  • Lint: 0 errors, 0 warnings.
  • Format: All source files use consistent Prettier formatting.

Coverage Summary (vs v1.7.0)

Metric v1.7.0 v1.7.1 Change
Statements 98.47% 98.38% -0.09pp
Branches 92.15% 92.93% +0.78pp
Functions 93.75% 98.30% +4.55pp
Lines 99.64% 99.30% -0.34pp

Branch coverage improved significantly (+0.78pp). The slight changes in statements/lines are due to the exclusion of preload.cjs from coverage measurement.


⚙️ Configuration

  • Magic numbers extracted — Added named constants to config.js: MAX_SPAWNS_PER_FRAME, HIT_TROOPS_CAP, PARTICLE_POOL_SIZE, DEV_MODE_CLICK_THRESHOLD, DEV_MODE_CLICK_WINDOW_MS, WAVE_TRANSITION_DURATION, AUTO_SAVE_DEBOUNCE_MS, AUTO_SAVE_DEBOUNCE_WAVES, REVIVE_REWARD_HP_RATIO, POPUP_ANIM_MS.
  • Version bump — 1.7.0 → 1.7.1 (patch release).

💾 Persistence

  • Save migration pipeline — Added SaveMigrator to src/gamePersistence.js with versioned migration system and sensible defaults for legacy saves. Integrated into GameSnapshotRestorer.apply().

📝 Documentation

  • All references to skipUpdate, skip-update, and skippedVersions removed from API docs, notification system descriptions, and contributing guidelines.
  • Test stats and coverage metrics updated across README and CONTRIBUTING to reflect current project state.
  • Full CHANGELOG entry for v1.7.1.