You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
distribution: extract the shared updater state machine (check → select → download → snapshot) — three apps now duplicate it #220
Follow-up to #212's progress reporting (PR#219). With movebit's updater shipped this week, the family now has three near-identical ~400-line update.rkt modules (taskly, fulcrum, movebit) layering the same orchestration on rivet/distribution primitives:
a state box (phase / percent / message / available-version) that background download threads publish and the UI polls through an RPC, because RVT1 events are thread-local;
perform-check! (reset → fetch → verify → select → map to a result hash) and start-download! (guard against a running worker, spawn the thread, publish progress/downloaded/error);
platform/arch symbols matching the release manifest vocabulary.
The duplication has already cost real bugs twice: the redirect-following fix (#153) had to be hand-applied to each app's downloader, and fulcrum's DER-key contract violation (#165) would have bitten any copier. Movebit additionally hit an Optional-encoding class error (#f vs (void)) that a shared encoder would have prevented.
Proposal
rivet/distribution/updater.rkt grows the orchestration, parameterized by the app's identity:
(make-updater #:application-id...#:public-key...#:key-id...#:base-url...#:data-dir...#:maximum-bytes...)
(updater-check! updater) ; → (hash status available-version ...)
(updater-download! updater) ; background thread, progress into the state
(updater-state updater) ; phase / percent / message snapshot
Apps keep what is genuinely theirs: the embedded key, the base URL, the install step (which stays host-owned — movebit's staged-swap, fulcrum's open-the-installer, taskly's restart flow), and the auto-check policy.
Out of scope here
Install mechanics: movebit's Windows staged-swap helper (tar + detached cmd + robocopy) works but needs real-time-AV robustness work before it is a blessed pattern; the install-plan framework already in updater.rkt is the right landing zone once it matures.
Manifest contents (e.g. adding MSI artifacts for Windows silent upgrades) — release-pipeline side.
Audit finding: this extraction must also absorb bounded-worker behavior instead of copying the weakest of the three implementations. Taskly already carries a 120-second no-progress watchdog and 30-minute total bound because get-pure-port / read-bytes-avail! can wait forever when a server stalls or never closes after the advertised bytes. Fulcrum and MoveBit remain vulnerable to a permanent downloading phase.
I am treating these as part of the upstream contract:
One synchronized check/download operation per updater.
Deeply immutable state snapshots.
Cumulative progress from the first-party download-update.
Explicit cancellation.
Configurable check, no-progress, and total deadlines using monotonic time.
Terminal cancelled/error states and guaranteed .partial cleanup.
Deterministic injected-transport tests with no live network.
Fail-closed platform and architecture validation and a stable per-installation rollout bucket.
Installation remains host/platform-owned as proposed.
Activity
turinglambdaai commentedon Oct 12, 2026
Audit finding: this extraction must also absorb bounded-worker behavior instead of copying the weakest of the three implementations. Taskly already carries a 120-second no-progress watchdog and 30-minute total bound because
get-pure-port/read-bytes-avail!can wait forever when a server stalls or never closes after the advertised bytes. Fulcrum and MoveBit remain vulnerable to a permanent downloading phase.I am treating these as part of the upstream contract:
download-update..partialcleanup.Installation remains host/platform-owned as proposed.