OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface-android commits / ec744ee

0.0.14: OTA errors carry the stack, because guessing the call site has failed three times
⛔ THREE SEPARATE HOMEDIR DEFAULTS HAVE PRODUCED THE SAME ENOENT on a handset, each masked by the one before it: `resolveRelease`'s registry store, then `NetworkFetcher`'s local registry — and 0.0.12 carries overrides for both, verified in the published bundle, and the device still reports it. So there is a third, and `err.message` cannot distinguish them: it names the PATH and not the CALLER, and all three build the same path. Every grep I ran found only the two already fixed. pgh-runtime has no homedir and no stat at all. I have guessed wrong three times and the fourth guess is not worth another build-and-sideload cycle. So the device carries the frame now. Three sites — the fetcher catch, the watch catch, and `runtime.on('error')` — append the first stack frames to the message `/status` already shows verbatim. ⚠ This ships no fix. It is an instrument, and it exists because the last one paid for itself immediately: surfacing the daemon's own last OTA line is what turned "check now does nothing" into a named cause within one boot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ec744ee9beabd6e89d2bcdc068060e4de8d47f82
by plankatron <fleeky@gmail.com> · 2026-09-10T18:05:49.000Z

Changed files (3) +16 -6

lib/host/ota.js +13 -3
……@@ -50,6 +50,16 @@ const DEFAULT_INTERVAL = 6 * 60 * 60 * 1000 // 6h — a phone is not a server; d
5050const COLD_SETTLE_MS = 30000
5151const BUNDLE_NAME = 'worklet.bundle'
5252
53// ⛔ THE STACK, NOT JUST THE MESSAGE. Three separate homedir defaults have now produced the SAME
54// ENOENT on a handset, each masked by the one before it, and each cost a build-and-sideload cycle to
55// guess at. `err.message` names the path and not the caller, so it cannot distinguish them. A device
56// with no log anyone can read has to carry the frame itself.
57const frame = (err) => {
58 const st = (err && err.stack) || ''
59 const lines = String(st).split('\n').slice(1, 4).map((l) => l.trim().replace(/^at\s+/, ''))
60 return lines.length ? ' @ ' + lines.join(' < ') : ''
61}
62
5363const hashOf = (bytes) => crypto.data(Buffer.from(bytes)).toString('hex')
5464
5565// The running bundle's hash, if the environment happens to say. Guarded because `process` is a shim in
……@@ -438,7 +448,7 @@ export async function startOta ({ storage, say = () => {}, repo = DEFAULT_REPO,
438448 registryKeyHex, repo, destDir: path.join(dir, '.fetch'), swarm, latest: entry
439449 }))
440450 } catch (err) {
441 say('ota: no swarm fetcher (' + ((err && err.message) || err) + ')')
451 say('ota: no swarm fetcher (' + ((err && err.message) || err) + ')' + frame(err))
442452 return
443453 }
444454 }
……@@ -454,7 +464,7 @@ export async function startOta ({ storage, say = () => {}, repo = DEFAULT_REPO,
454464 })
455465 runtime.on('updating', (r) => { store.noteRelease(r); say('ota: downloading ' + (r && r.version)) })
456466 runtime.on('updated', (i) => say('ota: staged ' + i.newTreeHash + ' — active on next start'))
457 runtime.on('error', (e) => say('ota: ' + ((e && e.message) || e)))
467 runtime.on('error', (e) => say('ota: ' + ((e && e.message) || e) + frame(e)))
458468 started = runtime.start()
459469 await started
460470 }
……@@ -473,7 +483,7 @@ export async function startOta ({ storage, say = () => {}, repo = DEFAULT_REPO,
473483 })
474484 say('ota: watching ' + repo + ' — releases arrive as events, not on a timer')
475485 } catch (err) {
476 say('ota: cannot watch the registry (' + ((err && err.message) || err) + ')')
486 say('ota: cannot watch the registry (' + ((err && err.message) || err) + ')' + frame(err))
477487 return null
478488 }
479489 }
lib/version.js +2 -2
……@@ -1,4 +1,4 @@
11// GENERATED by scripts/gen-version.mjs — do not edit.
2export const VERSION = "0.0.13"
3export const BUILT_AT = 1789062715193
2export const VERSION = "0.0.14"
3export const BUILT_AT = 1789063540261
44export default { VERSION, BUILT_AT }
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-surface-android",
3 "version": "0.0.13",
3 "version": "0.0.14",
44 "description": "favela-surface-android \u2014 a React Native shell over a bare-kit worklet running a full favela-peer node (markdown records, no atproto) with favela-surface rendering its pages in a WebView.",
55 "type": "module",
66 "private": true,