Release checklist: verifying the updater

The auto-updater ships across a version hop, so the code in a release is only exercised by the NEXT release. A build's own updater is proven by whether the build after it lands, not by the build itself. This checklist is how a release runner confirms it, because the paths that matter most are the ones a clean, successful release never touches.

Before the tag: mechanical gates (run these first)

The proving hop (rehearse on prereleases, before the real release)

0.4.6 is delivered by 0.4.5's updater, so 0.4.6 arriving proves the OLD code worked. Only a hop that STARTS on our new code proves it. So rehearse on prereleases first: publish 0.4.6-rc.1, then a no-op 0.4.7-rc.1, and drive the hop 0.4.6-rc.1 -> 0.4.7-rc.1 on a test machine BEFORE the real 0.4.6 exists. Same evidence, earlier, with any failure landing on a throwaway.

Why it is safe: a -rc.1 tag publishes as a GitHub pre-release (release.yml, prerelease: contains(ref_name, '-')), and electron-updater only offers a pre-release to a client whose OWN version is a pre-release (allowPrerelease defaults to that, verified in 6.8.9). So a stable 0.4.5 client sees neither rc, on the native path or the notify-only fallback. Only a machine already on 0.4.6-rc.1 sees 0.4.7-rc.1.

Two things to hold: a tester must MANUALLY install 0.4.6-rc.1 first (a 0.4.5 machine sees nothing, which is the point); and a machine left on 0.4.7-rc.1 stays AHEAD of the real 0.4.6 (0.4.7-rc.1 > 0.4.6 and we do not allow downgrade), so reset rehearsal machines by reinstalling manually afterward. A 0.4.6-rc.1 machine that does nothing self-heals to the real 0.4.6 when it ships, because a release outranks its own pre-release.

If the rehearsal passes, the real 0.4.6 is that SAME tree with only package.json's version bumped from 0.4.6-rc.1 to 0.4.6 (the build reads the version from package.json, not the tag), nothing else. Any CODE change between the rehearsal and the release means re-rehearse.

Release gate (hard): each rc (and the real release) must be a COMPLETE signed, notarized, stapled run of the real pipeline, not a git tag and not a version bump. macOS updates through Squirrel.Mac, which needs mac-universal.zip + its .blockmap + latest-mac.yml (whose path: must point at the zip, not the dmg). A release missing those silently falls back to manual and proves nothing.

What a clean 0.4.7 proves on its own (the happy path)

Install 0.4.6-rc.1, publish a complete 0.4.7-rc.1, then watch that client:

What a clean release CANNOT reach (inject these by hand)

These only run when a user is already in trouble, so a healthy release never exercises them. A skipped check here means they ship unwitnessed.

Tested vs rc-only (keep this split in every report)

  • Verified without a release (unit tests, typecheck, and dev update:simulate): badge state-rendering and click-wiring for every state, and the no-update acknowledgement.
  • Only a real signed release can exercise: downloadUpdate, quitAndInstall, and the Squirrel install itself. Do not let this half borrow the tested half's confidence: report which is which.