An update that goes wrong is no longer the end of it

Two things the audit found, both about the archive path every shipped .app
uses.

**Settings could be wiped.** The update kept config/modules.json and
config/layouts/ by name, but not config/proddash.json — which holds the admin
PIN, the theme and the forge pointer. On an install whose data directory IS
the app's own config/ (an unwritable Application Support, or PRODDASH_DATA_DIR
aimed inside the app), an update wrote the repo's shipped defaults over it:
the theme went, and admin silently unlocked. Nothing inside the data
directory is written now, wherever it happens to sit, and the two legacy
names stay listed for an install whose state never moved out.

**A bad update was unrecoverable.** No rollback, and a fresh .app would not
help: seeding only replaces an *older* copy, and a broken one carries a
higher version — so the fix was deleting a folder nothing told you about.
Three changes, in the order they catch things:

- The download must parse before anything is swapped in. `node --check`
  against the new server.js, and a failure is reported with the syntax error
  and leaves the running copy untouched.
- Past that, the copy being replaced is set aside as `app.previous`, and
  dropped once the new version has stayed up ninety seconds — so that folder
  existing means "the last update has not proven itself yet", and never
  anything older.
- The launcher, which already gives up after four stops in two minutes, now
  looks for that folder before it does and puts the old copy back. Once: if
  the old one will not run either, the update was not the problem.

The launcher half only reaches a machine with a new .app; the server half
travels by the normal update.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Waters Church
2026-09-17 16:16:46 -04:00
co-authored by Claude Opus 5
parent 5025e12b71
commit 12f6e22187
5 changed files with 151 additions and 8 deletions
+12 -1
View File
@@ -200,7 +200,18 @@ below. Nothing is installed without someone clicking.
no local changes — otherwise the banner says why and you update with git).
A plain folder (no `.git`) has the repo archive unpacked over it; files
removed upstream are left behind but harmless. Settings and layouts are
never touched. **What changed** opens the commit comparison on GitHub.
never touched — nothing inside the data directory is written, even on an
install where that directory *is* the app's own `config/`. **What changed**
opens the commit comparison on the forge.
- **If an update goes wrong**: the download has to parse before anything is
swapped in, so a truncated or mangled `server.js` is refused with the
reason and the running copy is left exactly as it was. Past that, the copy
being replaced is set aside as `app.previous` next to the app folder, and
dropped once the new version has stayed up for ninety seconds — so that
folder existing means "the last update has not proven itself yet". The
macOS app watches for a version that will not stay up (four stops in two
minutes) and puts the old one back by itself, once, with a notification.
Running some other way, the way back is a rename: `mv app.previous app`.
- **Restarting**: after an update the server exits with code 75 and starts
its own replacement, which waits for the port to free up. If you supervise
ProdDash with your own launcher, set `PRODDASH_LAUNCHER=1` so the server