OverviewFilesCommitsIssuesDocsReleasesPeers

pgh commits / 85168db

0.1.130: `pgh app bootstrap-serve` — cross-arch serving is now opt-in, default off
Only a forge backend answers a cold-start HTTPS /bootstrap fetch. Every other peer installs over hyper-deploy/overlay and never serves one, so holding another arch's ~150MB tarball is pure cost to it. 0.1.125 promoted every vendored arch on every machine; now it's an admin setting. pgh app bootstrap-serve pgh-sidecar on Writes apps.json `bootstrapServeAllArches`, mirroring `pgh app autostart`. Read by pgh-sidecar (_isBootstrapServeEnabled) and passed as { serveAllArches }. Defaults FALSE — unlike autoupdate, which defaults true — because the useful case is the minority one. Toggling off actually stops serving: the prune pass drops any tarball no longer in wantTarballs, so opt-out removes what opt-in promoted. Tested both directions. NOTE this does not shrink any download on its own — promotion is a hardlink. The bytes still ride in the dep tree (~275MB of dist/*.tar.gz under node_modules/pgh), so every peer still fetches them. Removing that needs publishIgnore on dist/ plus an oid manifest so opted-in backends fetch arches over the overlay instead. This is the control surface for that, not the saving. test: 286/286 (846 asserts) under bare. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
85168db98747d4dd6f15eeb39231b80d964f3b7b
by plankatron <fleeky@gmail.com> · 2026-07-30T01:59:29.000Z

Changed files (4) +101 -32

lib/bootstrap-artifacts.js +32 -20
……@@ -179,6 +179,14 @@ export async function reconcileBootstrapArtifacts (store, o = {}) {
179179 }
180180
181181 // ── Cross-arch promotion pass ───────────────────────────────────
182 // OPT-IN (admin setting). Only a forge backend actually serves /bootstrap over
183 // HTTPS, so only a backend needs the foreign-arch tarballs. Ordinary peers pull
184 // over hyper-deploy/overlay and never answer a cold-start HTTP fetch — holding
185 // another arch's 150MB would be pure cost to them.
186 // pgh app bootstrap-serve pgh-sidecar on
187 // sets apps.json `bootstrapServeAllArches`, which the sidecar reads and passes
188 // here. Default OFF: build your own arch, promote nothing.
189 //
182190 // Deliberately over ALL app trees, not just pgh.bootstrap ones: a vendored
183191 // bootstrap tarball is arch-portable BYTES, and it does not live in the tree
184192 // of the app it bootstraps. Measured on tabertron:
……@@ -188,27 +196,31 @@ export async function reconcileBootstrapArtifacts (store, o = {}) {
188196 // apps would serve pgh for arm64 and still fail at the sidecar step.
189197 // Anything already in wantTarballs was tarred locally for the host arch and
190198 // wins — promotion only ever fills arches we cannot build here.
191 for (const name of appNames) {
192 if (name.startsWith('.') || /\.new-\d+$/.test(name)) continue
193 for (const v of vendoredBootstraps(path.join(appsDir, name))) {
194 if (wantTarballs.has(v.name)) continue
195 wantTarballs.add(v.name)
196 nextState[v.name] = 'vendored'
197 const vdest = path.join(dir, v.name)
198 // Same-inode means it's already the promoted hardlink — nothing to do.
199 // A DIFFERENT inode means the vendored artifact was updated underneath us,
200 // so re-link rather than serving stale bytes forever.
201 let linked = false
202 try { linked = fs.statSync(vdest).ino === fs.statSync(v.src).ino } catch {}
203 if (linked) { out.kept.push(v.name); continue }
204 try { fs.rmSync(vdest, { force: true }) } catch {}
205 try {
206 fs.linkSync(v.src, vdest) // hardlink: zero extra bytes
207 } catch {
208 try { fs.copyFileSync(v.src, vdest) } catch { continue }
199 if (!o.serveAllArches) {
200 if (log) log('[bootstrap] cross-arch promotion off (enable: pgh app bootstrap-serve <app> on)')
201 } else {
202 for (const name of appNames) {
203 if (name.startsWith('.') || /\.new-\d+$/.test(name)) continue
204 for (const v of vendoredBootstraps(path.join(appsDir, name))) {
205 if (wantTarballs.has(v.name)) continue
206 wantTarballs.add(v.name)
207 nextState[v.name] = 'vendored'
208 const vdest = path.join(dir, v.name)
209 // Same-inode means it's already the promoted hardlink — nothing to do.
210 // A DIFFERENT inode means the vendored artifact was updated underneath us,
211 // so re-link rather than serving stale bytes forever.
212 let linked = false
213 try { linked = fs.statSync(vdest).ino === fs.statSync(v.src).ino } catch {}
214 if (linked) { out.kept.push(v.name); continue }
215 try { fs.rmSync(vdest, { force: true }) } catch {}
216 try {
217 fs.linkSync(v.src, vdest) // hardlink: zero extra bytes
218 } catch {
219 try { fs.copyFileSync(v.src, vdest) } catch { continue }
220 }
221 out.tarred.push(v.name)
222 if (log) log('[bootstrap] promoted vendored ' + v.name + ' (cross-arch, from ' + name + ')')
209223 }
210 out.tarred.push(v.name)
211 if (log) log('[bootstrap] promoted vendored ' + v.name + ' (cross-arch, from ' + name + ')')
212224 }
213225 }
214226
lib/commands/app.js +22 -0
……@@ -58,6 +58,8 @@ export const usage = `pgh app — install and run pgh-managed apps
5858 pgh app stale [--all] installed-vs-RUNNING check for every app on this host
5959 pgh app log <name> [-f] [--lines N]
6060 pgh app autostart <name> on|off
61 pgh app bootstrap-serve <name> on|off Serve bootstrap tarballs for arches this
62 machine cannot build (forge backends only)
6163 pgh app boot | shutdown
6264 pgh app adopt <path> [--name <name>] [--bin <name>]
6365
……@@ -393,6 +395,7 @@ export async function run (client, args) {
393395 if (sub === 'stale') return cmdStale(args)
394396 if (sub === 'log') return await cmdLog(args)
395397 if (sub === 'autostart') return cmdAutostart(args)
398 if (sub === 'bootstrap-serve') return cmdBootstrapServe(args)
396399 if (sub === 'boot') return await cmdBoot(args)
397400 if (sub === 'shutdown') return await cmdShutdown(args)
398401 if (sub === 'adopt') return cmdAdopt(args)
……@@ -1724,6 +1727,25 @@ async function cmdLog (args) {
17241727 })
17251728}
17261729
1730// Admin setting: does THIS machine serve bootstrap tarballs for arches it cannot
1731// build? Only a forge backend answers a cold-start HTTPS /bootstrap fetch; every
1732// other peer installs over hyper-deploy/overlay and never needs a foreign arch's
1733// ~150MB. Off by default — turn it on for the backends behind the public endpoint.
1734// Read by pgh-sidecar (_isBootstrapServeEnabled) and passed to
1735// reconcileBootstrapArtifacts as { serveAllArches }.
1736function cmdBootstrapServe (args) {
1737 const name = args[1]
1738 const state = args[2]
1739 if (!name || (state !== 'on' && state !== 'off')) {
1740 throw new Error('usage: pgh app bootstrap-serve <name> on|off')
1741 }
1742 const cfg = readUserConfig()
1743 if (!cfg[name]) cfg[name] = {}
1744 cfg[name].bootstrapServeAllArches = state === 'on'
1745 writeUserConfig(cfg)
1746 return { name, bootstrapServeAllArches: cfg[name].bootstrapServeAllArches }
1747}
1748
17271749function cmdAutostart (args) {
17281750 const name = args[1]
17291751 const state = args[2]
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "pgh",
3 "version": "0.1.129",
3 "version": "0.1.130",
44 "description": "pgh — P2P content-addressed package manager and app launcher",
55 "type": "module",
66 "main": "index.js",
test/bootstrap-artifacts.test.js +46 -11
……@@ -41,7 +41,7 @@ test('reconcileBootstrapArtifacts tars bootstrap apps, symlinks install.sh, skip
4141 mkAppTree(store.appsDir, 'hyper-tps', { bootstrap: false, treeHash: 'ccc' })
4242
4343 const calls = []
44 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar(calls), log: () => {} })
44 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar(calls), log: () => {}, serveAllArches: true })
4545
4646 const dir = bootstrapDir(store)
4747 t.is(res.tarred.length, 2, 'tarred the 2 bootstrap apps')
……@@ -115,7 +115,7 @@ test('reconcileBootstrapArtifacts guards a malformed pghBootstrap.label (no doub
115115 // a tree whose label is corrupted (baked-in stage name)
116116 mkAppTree(store.appsDir, 'pgh-sidecar', { label: 'bootstrap-bare-linux-x64', treeHash: 'h1' })
117117
118 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
118 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
119119 t.alike(res.tarred, ['pgh-sidecar-bootstrap-bare-linux-x64.tar.gz'], 'falls back to host label — no double infix')
120120})
121121
……@@ -172,7 +172,7 @@ test('reconcileBootstrapArtifacts promotes a vendored cross-arch tarball into th
172172 const appDir = mkAppTree(store.appsDir, 'pgh', { label: 'linux-x64', treeHash: 'h1', installSh: true })
173173 const src = mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'ARM64BYTES')
174174
175 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
175 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
176176
177177 const dir = bootstrapDir(store)
178178 const arm = join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz')
……@@ -191,11 +191,11 @@ test('a promoted cross-arch tarball survives the prune pass', async (t) => {
191191 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz')
192192
193193 const dir = bootstrapDir(store)
194 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
194 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
195195 t.ok(existsSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz')), 'present after first reconcile')
196196
197197 // Second pass is where a non-wanted artifact would get pruned.
198 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
198 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
199199 t.absent(res.pruned.includes('pgh-bootstrap-bare-linux-arm64.tar.gz'), 'not pruned')
200200 t.ok(existsSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz')), 'still served after re-reconcile')
201201})
……@@ -207,7 +207,7 @@ test('local tar wins for the host arch — a vendored same-label tarball never o
207207 // a stale vendored tarball for OUR arch — must not shadow the fresh local tar
208208 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-x64.tar.gz', 'STALE')
209209
210 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
210 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
211211
212212 const hostTb = join(bootstrapDir(store), 'pgh-bootstrap-bare-linux-x64.tar.gz')
213213 t.not(readFileSync(hostTb, 'utf8'), 'STALE', 'host-arch tarball came from local tar, not the vendored copy')
……@@ -225,7 +225,7 @@ test('promotes a vendored tarball carried by a NON-bootstrap app tree', async (t
225225 const pgv3 = mkAppTree(store.appsDir, 'pear-git-v3', { bootstrap: false, treeHash: 'h2' })
226226 mkVendored(pgv3, 'pgh-sidecar', 'pgh-sidecar-bootstrap-bare-linux-arm64.tar.gz', 'SIDECAR-ARM64')
227227
228 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
228 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
229229
230230 const sc = join(bootstrapDir(store), 'pgh-sidecar-bootstrap-bare-linux-arm64.tar.gz')
231231 t.ok(existsSync(sc), 'sidecar arm64 tarball served despite carrier not being a bootstrap app')
……@@ -242,12 +242,12 @@ test('re-promotes when the vendored artifact is replaced underneath us', async (
242242 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'V1')
243243
244244 const dir = bootstrapDir(store)
245 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
245 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
246246 t.is(readFileSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'utf8'), 'V1', 'v1 served')
247247
248248 // new upstream version replaces the vendored file (new inode)
249249 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'V2')
250 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
250 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
251251 t.is(readFileSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'utf8'), 'V2', 're-promoted, not stale')
252252})
253253
……@@ -260,7 +260,7 @@ test('promotes from the app\'s OWN dist/, which is where these artifacts really
260260 writeFileSync(join(appDir, 'dist', 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'OWN-DIST')
261261 writeFileSync(join(appDir, 'dist', 'pgh-bootstrap-bare-linux-arm64.tar.gz.sha256'), 'deadbeef')
262262
263 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
263 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
264264
265265 const dir = bootstrapDir(store)
266266 t.is(readFileSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'utf8'), 'OWN-DIST', 'promoted from own dist/')
……@@ -275,7 +275,7 @@ test('own dist/ wins over a vendored copy of the same tarball', async (t) => {
275275 writeFileSync(join(appDir, 'dist', 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'CANONICAL')
276276 mkVendored(appDir, 'somedep', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'STALE-VENDORED')
277277
278 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
278 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
279279
280280 const served = readFileSync(join(bootstrapDir(store), 'pgh-bootstrap-bare-linux-arm64.tar.gz'), 'utf8')
281281 t.is(served, 'CANONICAL', 'own dist/ took precedence, not the vendored copy')
……@@ -284,3 +284,38 @@ test('own dist/ wins over a vendored copy of the same tarball', async (t) => {
284284test('hostLabel returns os-arch', (t) => {
285285 t.ok(/^[a-z0-9]+-[a-z0-9]+$/.test(hostLabel()), 'looks like <os>-<arch>')
286286})
287
288// The opt-in itself. Promotion is a hardlink (no bytes), but SERVING a foreign
289// arch is only useful on a machine that answers cold-start HTTPS /bootstrap
290// fetches — a forge backend. Everyone else installs over hyper-deploy/overlay.
291test('cross-arch promotion is OFF by default', async (t) => {
292 const root = mkdtempSync(join(tmpdir(), 'pgh-ba-optout-'))
293 const store = fakeStore(root); store.init()
294 const appDir = mkAppTree(store.appsDir, 'pgh', { label: 'linux-x64', treeHash: 'h1', installSh: true })
295 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'ARM64')
296
297 // no serveAllArches
298 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
299
300 const dir = bootstrapDir(store)
301 t.absent(existsSync(join(dir, 'pgh-bootstrap-bare-linux-arm64.tar.gz')), 'arm64 NOT promoted without opt-in')
302 t.ok(existsSync(join(dir, 'pgh-bootstrap-bare-linux-x64.tar.gz')), 'own arch still built')
303 t.absent(res.tarred.includes('pgh-bootstrap-bare-linux-arm64.tar.gz'), 'not reported as produced')
304})
305
306test('opting in promotes, and opting back out prunes what it promoted', async (t) => {
307 const root = mkdtempSync(join(tmpdir(), 'pgh-ba-toggle-'))
308 const store = fakeStore(root); store.init()
309 const appDir = mkAppTree(store.appsDir, 'pgh', { label: 'linux-x64', treeHash: 'h1', installSh: true })
310 mkVendored(appDir, 'pgh', 'pgh-bootstrap-bare-linux-arm64.tar.gz', 'ARM64')
311 const arm = join(bootstrapDir(store), 'pgh-bootstrap-bare-linux-arm64.tar.gz')
312
313 await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64', serveAllArches: true })
314 t.ok(existsSync(arm), 'promoted while opted in')
315
316 // Turning it off must actually stop serving it — the prune pass drops any
317 // tarball no longer in wantTarballs, which is what makes the toggle real.
318 const res = await reconcileBootstrapArtifacts(store, { tarTree: fakeTar([]), label: 'linux-x64' })
319 t.ok(res.pruned.includes('pgh-bootstrap-bare-linux-arm64.tar.gz'), 'pruned on opt-out')
320 t.absent(existsSync(arm), 'no longer served')
321})