OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-bridge commits / e487cfa

0.9.39: OTA — respawn on release-ready
The app half of the push contract. The sidecar already does the FULL install (tree fetch + dep closure + materialize + symlink swap) and then calls `release-ready`; nothing was listening, so the bridge stayed on the old code until someone ran stop/start by hand. That is the INSTALLED != RUNNING trap, and it bit repeatedly today. ⚠ DELIBERATELY NOT pgh-runtime's fetch path, despite the request being "add pgh-runtime". pear-git-v3's implementation says why in as many words: pgh-runtime only fetches ROOT trees, not dep closures, so an app pulling its own update produces a BROKEN install — which is precisely the missing-dependency MODULE_NOT_FOUND that took this membrane down for ~20 minutes on 2026-07-31. The sidecar already does it correctly; duplicating half of it is how you get half of it. So the dependency is not added and the handler is 15 lines. Exits 75 AFTER responding to the RPC, so the caller sees ok rather than a dropped connection, and after a clean shutdown so no store is left locked for the process that replaces us. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
e487cfa5cdc90edaee77e6dbcd93ba935ab2d75d
by plankatron <fleeky@gmail.com> · 2026-08-01T01:35:38.000Z

Changed files (2) +22 -1

package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "atproto-bridge",
3 "version": "0.9.38",
3 "version": "0.9.39",
44 "description": "Stateless keyless atproto MEMBRANE \u2014 fronts self-custody hyper-proto-peers to bluesky over HTTP/WS, holds no keys and never signs. Bare-runnable. Deploy root / flat closure over the identity+repo+store+pds packages.",
55 "type": "module",
66 "main": "index.js",
pds/bin/pds-serve.js +21 -0
……@@ -96,6 +96,27 @@ await new Promise((r) => server.listen(cfg.port, cfg.bind, r))
9696// 2. UDS control plane + pgh-sidecar registration.
9797const control = await startControl({ uds: cfg.uds, name: process.env.PGH_APP_NAME || 'atproto-bridge', version, peers })
9898
99// OTA — the app half of the push contract. The sidecar does the FULL install (tree fetch + dep closure +
100// materialize + symlink swap) and THEN calls this; our only job is to exit cleanly so the supervisor
101// respawns against the new tree. Same shape as pear-git-v3/server.js.
102//
103// ⚠ DELIBERATELY NOT pgh-runtime's fetch path. pgh-runtime only fetches ROOT trees, not dep closures, so
104// having the app pull its own update produces a BROKEN install — the exact failure that took the
105// membrane down on 2026-07-31 (a missing dep, MODULE_NOT_FOUND, respawn loop). The sidecar already did
106// the work correctly; duplicating it is how you get half of it.
107//
108// Exit 75 AFTER responding, so the caller sees ok rather than a dropped connection, and after a clean
109// shutdown so no store is left locked for the process that replaces us.
110if (control && control.svc && !control.svc.hasHandler('release-ready')) {
111 control.svc.handle('release-ready', async (ctx, params = {}) => {
112 const ver = (params && params.version) || '?'
113 console.log(JSON.stringify({ msg: 'ota: release-ready — sidecar installed; exiting 75 for supervisor respawn', version: ver }))
114 setImmediate(() => { shutdown().catch(() => {}).then(() => process.exit(75)).catch(() => process.exit(75)) })
115 return { ok: true, willRespawn: true }
116 })
117 console.log(JSON.stringify({ msg: 'ota: release-ready handler armed (push-based; sidecar installs, we respawn)' }))
118}
119
99120// 3. Warm the fronts in the BACKGROUND — never block the HTTP/UDS listen or the readiness probe.
100121// A peer offline at boot (or one that hasn't signed its first commit yet) must not delay the bridge
101122// coming up: awaiting fronts here blew past the 30s UDS readiness window → supervisor restart loop.