Pitfall Preferences jobs-apply

Electron Stale Bundle Version Drift

pitfallelectronversioningdesktop

What Happened

The Electron desktop app ran stale engine code for two days without any indication. 33 Greenhouse jobs were submitted on Apr 13 using code from Apr 12 that was missing five fixes committed that same day: Direct smart picker, Lever board postings, auto-skip rules, resume quality gates, and match threshold changes. The Lever channel had zero discoveries across every session since the DB wipe. Direct was silently skipping all Fortune 500 companies. The user troubleshot for over an hour before we traced it to the installed app bundle being 2 days old.

Three independent failures aligned to make this invisible:

  1. pnpm run pack built to release/mac-arm64/ but never installed to /Applications/. The user had to manually drag the DMG. Nobody remembered to do this after code changes.
  2. /api/version had a hardcoded LATEST_VERSION constant that was manually maintained separately from package.json. When YYMMDD versioning was adopted on Apr 13, package.json changed to 260413 but the API route still returned 0.1.1. The Electron version checker compared 0.1.1 <= 0.1.1 and said “up to date.”
  3. The app existed in two locations (/Applications/ and ~/Applications/). The install script only updated one.

Root Cause

No automated path from code change to running app. The build pipeline had a gap: git commit -> pnpm build -> pnpm run pack -> (manual DMG install) -> app launches. The manual step was invisible. The version checker that was supposed to catch this had its own manual step (bumping a hardcoded constant) that also got skipped. Two manual gates, both failed silently, both in the same pipeline.

How to Avoid

  1. pnpm run pack auto-installs. Added install-app.cjs as the final step of the pack script. It kills running instances, removes the old app, copies the fresh build to both /Applications/ and ~/Applications/. No manual drag needed.
  2. /api/version reads from package.json. The route now reads version from the monorepo root package.json at module load time. Bump package.json, deploy, done. No second file to remember.
  3. Version badge in the dashboard sidebar. A v26.4.14 pill in the nav turns yellow when the remote API reports a newer version. Always visible, no dialog to dismiss.

The principle: every manual gate in a deployment pipeline is a gate that will eventually be skipped. Automate the gate or remove the step.