Update in place, without taking plugins away from running colonies - #112
Merged
Merged
Conversation
Closes #45. #110 did the check; this applies it. It runs scripts/install-release.sh from inside the app rather than reimplementing the download, the checksum and the swap. That installer already unpacks beside the running app and moves the symlink with one rename, so a failure part-way leaves the running version exactly as it was — which is the "a build that fails leaves the running version untouched" line, for free. The proposal said to fetch the tag into a clone the mothership owns and build it. Prebuilt releases landed since (#74), so there is a verified archive to install and no cargo, npm or node needed on the machine. install.sh now ships the installer into dist/ so an installed mothership has a local copy, instead of downloading a script to execute. The part that would have lost work: colonies mount vendored plugins straight out of the app directory the mothership started from, because resolve_assets canonicalises the symlink away — and the installer deletes the slot it replaces. Applying an update under a running colony would take its plugins with it. So the installer learned COLONIZER_KEEP_PREVIOUS=1, each session records the directory its mounts resolved through, and a kept directory is swept at the next start once no live colony still names it. A person running the installer by hand keeps today's behaviour. Publishing colonies hold the update, and are named in the refusal: the microVM is already gone and the host is committing and pushing, so interrupting it leaves the colony failed with its pull request unopened. A colony that is only working does not hold it — it is detached, and recover reconnects it, which is the whole reason this can be done at all. The restart is an exec of the app symlink's binary, after the live map is told this mothership is going and the mesh children are killed so the new process can take their ports. Checked by driving the real installer on this machine with fake releases: with KEEP_PREVIOUS the previous slot survives an update and its plugin file is still readable, and without it the slot is removed exactly as before. The UI was driven against the mock: Update to v0.1.4 goes to Installing, then Restarting with "colonies keep their microVMs and reconnect" and a line per colony. Not exercised: a real release installed by a running mothership, and the exec itself. Both need two real releases and an installed app.
The pane showed a version and a date. It now also says how old the build is relative to the release being offered — "Released 9/18/2026, 12 days after the build you are running" — because a version number alone does not tell you whether you are a day or a season behind. The commit is shown beside the build time, and a development build says which release it came after. The gap is computed from the build time and the release date, so it is honest about the build rather than about the tag: someone running a build from a checkout sees how far that checkout has fallen behind.
This was referenced Sep 18, 2026
ParallelEntrepreneur
added a commit
that referenced
this pull request
Sep 23, 2026
) * Update in place, without taking plugins away from running colonies Closes #45. #110 did the check; this applies it. It runs scripts/install-release.sh from inside the app rather than reimplementing the download, the checksum and the swap. That installer already unpacks beside the running app and moves the symlink with one rename, so a failure part-way leaves the running version exactly as it was — which is the "a build that fails leaves the running version untouched" line, for free. The proposal said to fetch the tag into a clone the mothership owns and build it. Prebuilt releases landed since (#74), so there is a verified archive to install and no cargo, npm or node needed on the machine. install.sh now ships the installer into dist/ so an installed mothership has a local copy, instead of downloading a script to execute. The part that would have lost work: colonies mount vendored plugins straight out of the app directory the mothership started from, because resolve_assets canonicalises the symlink away — and the installer deletes the slot it replaces. Applying an update under a running colony would take its plugins with it. So the installer learned COLONIZER_KEEP_PREVIOUS=1, each session records the directory its mounts resolved through, and a kept directory is swept at the next start once no live colony still names it. A person running the installer by hand keeps today's behaviour. Publishing colonies hold the update, and are named in the refusal: the microVM is already gone and the host is committing and pushing, so interrupting it leaves the colony failed with its pull request unopened. A colony that is only working does not hold it — it is detached, and recover reconnects it, which is the whole reason this can be done at all. The restart is an exec of the app symlink's binary, after the live map is told this mothership is going and the mesh children are killed so the new process can take their ports. Checked by driving the real installer on this machine with fake releases: with KEEP_PREVIOUS the previous slot survives an update and its plugin file is still readable, and without it the slot is removed exactly as before. The UI was driven against the mock: Update to v0.1.4 goes to Installing, then Restarting with "colonies keep their microVMs and reconnect" and a line per colony. Not exercised: a real release installed by a running mothership, and the exec itself. Both need two real releases and an installed app. * Say how far behind the running build is, and which commit it is The pane showed a version and a date. It now also says how old the build is relative to the release being offered — "Released 9/18/2026, 12 days after the build you are running" — because a version number alone does not tell you whether you are a day or a season behind. The commit is shown beside the build time, and a development build says which release it came after. The gap is computed from the build time and the release date, so it is honest about the build rather than about the tag: someone running a build from a checkout sees how far that checkout has fallen behind. --------- Co-authored-by: Nick <40026523+Nick-CHI@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #45. #110 did the check; this applies it.
It reuses the installer rather than reimplementing it
scripts/install-release.sh, from inside the app. That installer already unpacks beside the running app and moves the symlink with one rename, so a failure part-way leaves the running version exactly as it was — one of the acceptance lines, for free.The proposal said to fetch the tag into a clone and build it. Prebuilt releases landed since (#74), so there is a verified archive to install and no cargo/npm/node needed on the machine.
install.shnow ships the installer intodist/, so an installed mothership has a local copy instead of downloading a script to execute.The part that would have lost work
Colonies mount vendored plugins straight out of the app directory the mothership started from —
resolve_assetscanonicalises the symlink away — and the installer deletes the slot it replaces. Applying an update under a running colony would take its plugins with it.COLONIZER_KEEP_PREVIOUS=1Session.app_slotupdate::sweep_slotsA person running the installer by hand keeps today's behaviour.
What holds an update, and what does not
Publishing colonies hold it, and are named in the refusal: the microVM is already gone and the host is committing and pushing, so interrupting leaves the colony failed with its PR unopened.
A working colony does not. It is detached, and
recoverreconnects it — which is the whole reason this is possible. Blocking on it would mean never updating while anything runs.The restart is an
execof the app symlink's binary, after the live map is told this mothership is going and the mesh children are killed so the new process can take their ports.Verified
The real installer, on this machine, with fake releases:
The UI, against the mock:
Update to v0.1.4→Installing…→Restarting…with "colonies keep their microVMs and reconnect" and a line per colony. The pane also now says how far behind the build is — "Released 9/18/2026, 12 days after the build you are running" — and shows the commit.Not exercised: a real release installed by a running mothership, and the
execitself. Both need two real releases and an installed app, which I do not have here.Acceptance in #45
KEEP_PREVIOUSand the sweep