OverviewFilesCommitsIssuesDocsReleasesPeers

favela-surface-android commits / 175de3a

0.0.23: a refused bundle older than the one running is not news
⛔ SEEN ON THE HANDSET, and it is my own previous change reporting too much. After installing 0.0.22 the page showed "this update cannot be applied — staged bundle previously failed at boot" while running 0.0.22. Both halves true: the condemned bundle was 0.0.21, which failed on the old 0.0.18 shell because that shell had no way to stage addons. But it is older than what booted and permanently dead, so there is nothing anyone can do with the sentence. Noise in the update line is how a real notice gets ignored. A refusal is now reported only when the staged bundle WOULD have been an update — newer than the bundle that actually booted. A condemned bundle that is newer is still announced, because "this release cannot run" is worth knowing; one that is older is history. This also corrects a test I wrote an hour ago asserting the opposite: that an APK-superseded bundle should be reported with its reason. It should not — that is exactly the case that put an unactionable line on the screen. Suite 99/99, 321/321. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
175de3a82852a03270c1c3664e9a8ad5b898418d
by plankatron <fleeky@gmail.com> · 2026-09-11T01:54:07.000Z

Changed files (4) +57 -8

lib/host/boot-plan.js +9 -1
……@@ -84,7 +84,15 @@ export async function planBoot ({ storage, io }) {
8484 // Something IS staged but was not used: name it and say why, so the page can stop offering a
8585 // restart that cannot help and show the reason instead.
8686 const cur = await io.readJson(bdir + '/current.json')
87 if (cur && cur.treeHash) refused = { hash: cur.treeHash, reason: choice.reason }
87 // ⛔ ONLY IF IT WOULD HAVE BEEN AN UPDATE. Seen on the handset: after installing 0.0.22 the page
88 // said "this update cannot be applied — staged bundle previously failed at boot" while running
89 // 0.0.22. True, and useless — the condemned bundle was 0.0.21, older than what booted and
90 // permanently dead. Nobody can act on that, and noise in the update line is how a real notice
91 // gets ignored. A staged bundle older than the running one is history, not a pending update.
92 const stagedAt = Number(cur && cur.builtAt) || 0
93 const bootedAt = Number(assetBuiltAt) || 0
94 const wouldHaveBeenAnUpdate = !stagedAt || !bootedAt || stagedAt > bootedAt
95 if (cur && cur.treeHash && wouldHaveBeenAnUpdate) refused = { hash: cur.treeHash, reason: choice.reason }
8896 }
8997
9098 if (choice.use === 'staged' && await io.exists(bdir + '/' + choice.file)) {
lib/version.js +2 -2
……@@ -1,4 +1,4 @@
11// GENERATED by scripts/gen-version.mjs — do not edit.
2export const VERSION = "0.0.22"
3export const BUILT_AT = 1789090294391
2export const VERSION = "0.0.23"
3export const BUILT_AT = 1789091628615
44export default { VERSION, BUILT_AT }
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-surface-android",
3 "version": "0.0.22",
3 "version": "0.0.23",
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,
test/boot-plan.test.js +45 -4
……@@ -163,8 +163,11 @@ test('a staged bundle that WILL boot is reported as applicable', async (t) => {
163163 t.is(shell.refused, null, 'nothing refused')
164164})
165165
166test('a staged bundle the APK supersedes is reported REFUSED, with the reason', async (t) => {
167 // The 0.0.17-staged / 0.0.18-APK case exactly: legitimately un-appliable, for ever.
166test('a staged bundle the APK supersedes is SILENT, not reported', async (t) => {
167 // ⛔ CORRECTED FROM MY OWN EARLIER EXPECTATION. I first had this report the refusal with its reason.
168 // On the handset that produced "this update cannot be applied" for a bundle older than the one
169 // running — accurate and unactionable. An APK newer than the staged bundle means that bundle was
170 // never a pending update; there is nothing to tell anyone.
168171 const staged = { treeHash: 'b'.repeat(64), file: 'y.bundle', builtAt: 1000 }
169172 const d = device({
170173 assets: { ...BASE, 'worklet.bundle.built': '9999' },
……@@ -174,8 +177,7 @@ test('a staged bundle the APK supersedes is reported REFUSED, with the reason',
174177 const plan = await planBoot({ storage: STORAGE, io: d.io })
175178 const shell = JSON.parse(d.written[STORAGE + '/shell.json'])
176179 t.is(shell.bundle, null, 'the APK bundle booted')
177 t.is(shell.refused.hash, 'b'.repeat(64), 'and the staged one is named as refused')
178 t.ok(shell.refused.reason.includes('more recently'), 'with the reason: ' + shell.refused.reason)
180 t.is(shell.refused, null, 'and nothing is said about a bundle that was never a candidate')
179181})
180182
181183test('a CONDEMNED staged bundle is reported refused too', async (t) => {
……@@ -201,3 +203,42 @@ test('nothing staged means nothing refused', async (t) => {
201203 await planBoot({ storage: STORAGE, io: d.io })
202204 t.is(JSON.parse(d.written[STORAGE + '/shell.json']).refused, null)
203205})
206
207test('a refused bundle OLDER than what booted is not reported at all', async (t) => {
208 // ⛔ SEEN ON THE HANDSET. After installing 0.0.22 the page said "this update cannot be applied —
209 // staged bundle previously failed at boot" while running 0.0.22. True, and useless: the condemned
210 // bundle was 0.0.21, older than what booted and permanently dead. A notice nobody can act on is
211 // noise, and noise in the update line is how a real one gets ignored.
212 //
213 // A refusal is only worth reporting when the staged bundle WOULD have been an update.
214 const staged = { treeHash: 'a'.repeat(64), file: 'x.bundle', builtAt: 1000 }
215 const d = device({
216 assets: { ...BASE, 'worklet.bundle.built': '9000' },
217 sizes: { [STORAGE + '/worklet.bundle']: 100 },
218 files: {
219 [BDIR + '/current.json']: JSON.stringify(staged),
220 [BDIR + '/failed.json']: JSON.stringify(['a'.repeat(64)]),
221 [BDIR + '/x.bundle']: 'S'
222 }
223 })
224 await planBoot({ storage: STORAGE, io: d.io })
225 t.is(JSON.parse(d.written[STORAGE + '/shell.json']).refused, null, 'silent — it is history, not a pending update')
226})
227
228test('a refused bundle NEWER than what booted IS reported', async (t) => {
229 // The case worth saying out loud: a genuinely new release that cannot run.
230 const staged = { treeHash: 'b'.repeat(64), file: 'y.bundle', builtAt: 9000 }
231 const d = device({
232 assets: { ...BASE, 'worklet.bundle.built': '1000' },
233 sizes: { [STORAGE + '/worklet.bundle']: 100 },
234 files: {
235 [BDIR + '/current.json']: JSON.stringify(staged),
236 [BDIR + '/failed.json']: JSON.stringify(['b'.repeat(64)]),
237 [BDIR + '/y.bundle']: 'S'
238 }
239 })
240 await planBoot({ storage: STORAGE, io: d.io })
241 const r = JSON.parse(d.written[STORAGE + '/shell.json']).refused
242 t.is(r.hash, 'b'.repeat(64))
243 t.ok(r.reason.includes('failed to boot'), r.reason)
244})