ADR 0022: Application Update Delivery
- Status: Accepted
- Date: 2026-07-26
- Deciders: PI-Desktop core
- Related: D120, D126, D010, ADR 0021
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 and non-AppImage Linux use manual delivery: discovery stops at
availableand opens the fixed releases page. Windows NSIS and Linux AppImage use in-app download and quit-and-install delivery. - 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. macOS remains notify-and-link until a signed in-app channel is separately qualified.
- 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 and Linux AppImage can update in-app from published tag feeds; macOS and Linux deb users install from the release page.
- 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.
- Signing, 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.