OverviewFilesCommitsIssuesDocsReleasesPeers

favela-bridge commits / c5b2996

0.0.12: select a level rather than withholding the picture
SOCIAL-MODEL 6.6.1: bridges SELECT, they do not downsample. The pyramid was built once at authoring; this picks the rung nearest bskys ceiling. Re-encoding here would do the work per delivery on every bridge AND produce bytes the author never made. The peer does the arithmetic against a ceiling we supply, so there is one ladder rather than one per bridge. The chosen level is REPORTED even when everything worked — a bridge that quietly serves a smaller picture has altered what was published. And when nothing fits it says so, because "no level fits your ceiling" and "the fetch failed" are different facts. 29/29. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
c5b2996c9e50eaeac2ec5cef337e2d03117a6f35
by plankatron <fleeky@gmail.com> · 2026-09-10T00:03:19.000Z

Changed files (2) +26 -4

index.js +25 -3
……@@ -21,7 +21,7 @@
2121import process from 'bare-process'
2222import os from 'bare-os'
2323import { join } from 'bare-path'
24import { planRecord, selectImages, samePost } from './lib/plan.js'
24import { planRecord, selectImages, samePost, MAX_IMAGE_BYTES } from './lib/plan.js'
2525import { planProfile, sameProfile } from './lib/profile.js'
2626import { FavelaPeer } from './lib/peer.js'
2727import { BskySink, POST_COLLECTION } from './lib/bsky.js'
……@@ -202,15 +202,37 @@ const blobCache = new Map() // oid -> blob ref. Content-addressed, so this can n
202202 */
203203async function buildEmbed (peer, bsky, imgs) {
204204 if (!imgs || !imgs.length) return { embed: null, losses: [] }
205 const losses0 = []
205206
207 // ⛔ SELECT, NEVER DOWNSAMPLE (SOCIAL-MODEL §6.6.1). The pyramid was built once at authoring; a
208 // bridge picks the level nearest its ceiling. Re-encoding here would do the work per delivery on
209 // every bridge AND produce bytes the author never made — §8's rule, applied to pixels.
210 //
211 // ⚠ The peer does the arithmetic against a ceiling WE supply, so there is one ladder rather than
212 // one per bridge. A blob with no pointer answers with its single level, which is every blob
213 // written before today.
206214 const described = []
207215 for (const im of imgs) {
216 let chosen = null
217 try { chosen = await peer.call('blob-level', { oid: im.oid, maxBytes: MAX_IMAGE_BYTES }) } catch { chosen = null }
218 if (!chosen || !chosen.level) {
219 // ⛔ A CLEAR ABSENCE, not a silent drop: "no level fits" and "the fetch failed" are different
220 // facts and the author is entitled to know which happened.
221 losses0.push('image omitted — ' + ((chosen && chosen.reason) || 'no level could be chosen'))
222 continue
223 }
224 // ★ THE HONESTY REQUIREMENT. A bridge that quietly serves a smaller picture has altered what
225 // was published, so the level it chose is reported even when everything worked.
226 if (chosen.reason && chosen.reason !== 'full size' && chosen.reason !== 'single level') {
227 losses0.push('image: ' + chosen.reason)
228 }
208229 let f = null
209 try { f = await peer.call('file-get', { oid: im.oid }) } catch { f = null }
230 try { f = await peer.call('file-get', { oid: chosen.level.oid }) } catch { f = null }
210231 described.push({ ...im, path: (f && f.path) || null, mimeType: f && f.mimeType, size: f && f.size })
211232 }
212233
213 const { images, losses } = selectImages(described)
234 const { images, losses: sizeLosses } = selectImages(described)
235 const losses = losses0.concat(sizeLosses)
214236 const out = []
215237 for (const d of images) {
216238 let ref = blobCache.get(d.oid)
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-bridge",
3 "version": "0.0.11",
3 "version": "0.0.12",
44 "description": "Projects favela records onto the networks a room may reach. One reader, one reach decision, one projection per network.",
55 "type": "module",
66 "main": "index.js",