ADR 0022: Application Update Delivery
- Status: Accepted (amended by D364 / D603 / ADR 0197, D450 / ADR 0289)
- Date: 2026-07-26
- Deciders: PI-Desktop core
- Related: D120, D126, D364, D603, D010, D450, ADR 0021, ADR 0197, ADR 0289
Context
PI-Desktop needs a release-update path that preserves the renderer sandbox, does not expose feed configuration to untrusted UI code, and reflects each platform's actual installer capabilities. A single automatic-install policy is not appropriate: unsigned macOS packages cannot provide a qualified in-app upgrade lane, while Windows NSIS and Linux AppImage support electron-updater's download-and-install flow.
Decision
- Electron Main exclusively owns
electron-updater, the fixed GitHub Releases feed, update polling, and install lifecycle. Renderer IPC exposes only allowlisted check, state, release-link, and install operations; callers cannot supply a feed URL. - Development builds keep updates disabled. Packaged macOS, Windows NSIS, and Linux AppImage use in-app download and quit-and-install delivery. Non-AppImage Linux (deb/rpm) and Windows ZIP builds (
piDistribution = "zip") use notify-and-link delivery so an NSIS installer cannot replace a no-install run. Legacy portable executables remain manual whenPORTABLE_EXECUTABLE_FILEis present. (Packaged macOS was notify-and-link until D450 / ADR 0289 qualified the signed in-app channel.) - The updater always sets
allowPrerelease = false. electron-updater would otherwise pin prerelease installs (for example0.2.0-rc.6) to the same custom channel (rc) and never offer a newer stable GitHub latest release. Prerelease-channel policy remains an operational follow-up if a dedicated RC feed is needed later. - Automatic checks run after startup and periodically. Automatic failures remain ambient; explicit checks expose status and errors through the menu and Settings -> Info. A downloaded update remains actionable until install or normal shutdown.
- Feed manifests and artifact hashes are generated by electron-builder. The client ships no GitHub credential and fails closed when the feed or package cannot be validated.
- D126 later lifts D010's macOS-only publication scope and publishes all platform artifacts and update manifests produced by the release matrix. D450 / ADR 0289 qualifies the signed macOS in-app channel on that same feed.
- Dual-locale product "what's new" text (D164) is maintained in
packages/sharedas EN + zh-CN catalogs. Main formats notes for the discovered version using the product UI locale and attaches them as optionalUpdateState.releaseNoteson the existing updates path. GitHub auto-generated release bodies remain web-only; the renderer never supplies a notes URL.
Consequences
- Update state is process-owned and consistent across the application menu, Settings, and the ambient banner.
- The sandboxed renderer cannot redirect update traffic or install arbitrary packages.
- Windows NSIS, Linux AppImage, and packaged macOS can update in-app from published tag feeds; Linux deb and Windows ZIP users install from the release page after extracting the archive.
- Prerelease installs graduate to newer stable releases through the same latest feed; a dedicated RC channel is not active.
- In-app bilingual release highlights ship with the build and follow the product locale without a second network surface.
- Rollback, staged rollout, and optional prerelease-channel policy remain operational follow-ups rather than renderer capabilities.
Alternatives
- Renderer-owned updater: rejected because it violates the process and sandbox boundary.
- Caller-provided feed URLs: rejected because it creates an arbitrary package installation path.
- Force one delivery mode on every platform: rejected because installer and signing guarantees differ by target.
Amendment (D450 / ADR 0289)
Official GitHub tag macOS artifacts are Developer ID-signed, notarized, and stapled. Packaged macOS therefore uses the same in-app electron-updater lane as Windows NSIS and Linux AppImage. Local unsigned packaging without a certificate remains available (D078).
Amendment (D603)
The Windows no-install lane now publishes a normal ZIP archive instead of electron-builder's self-extracting portable executable. The release helper builds NSIS and ZIP separately and stamps the ZIP app metadata with piDistribution = "zip"; the updater uses that marker to keep the ZIP manual even though ordinary ZIP launches do not set PORTABLE_EXECUTABLE_FILE. Users extract the archive and run PI-Desktop.exe; the NSIS lane and existing data directory remain unchanged.