OverviewFilesCommitsIssuesDocsReleasesPeers

favela-peer commits / 354a856

favela-peer 0.0.47: the bio had no way in
`peer.setProfile` has taken `{name, avatar, bio}` since it was written; bin/favela.js only ever passed name and avatar. So the supported surface could not set a bio at all — the profile record's body stayed empty on every node, and every projection of it downstream read empty for a reason that looked like the projection was broken. ap-bridge's actor `summary` is null for exactly this: it was never reached. `--bio` now goes out in the SAME call as `--name`, so a name-and-bio change is one record write. The record is overwritten in place; two writes would briefly publish a profile with only half of it. `''` removes, matching how a blank name already behaves. 340/340 pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
354a8568c432cec04e1c88502ed6ab317c540a50
by plankatron <fleeky@gmail.com> · 2026-09-09T00:45:18.000Z

Changed files (3) +43 -63

.pgh-lock.json +23 -58
……@@ -1,9 +1,9 @@
11{
22 "name": "favela-peer",
3 "version": "0.0.44",
3 "version": "0.0.46",
44 "runtime": "bare",
5 "rootTreeHash": "c4f89bd25a183aeab4d047c0496d479dbd3c948142e069c62ee78f8df8e9e0cc",
6 "publishedAt": "2026-09-08T19:24:14.838Z",
5 "rootTreeHash": "83d403e7ecbb4ad299b588e76a51781a94f18d1a807750e934cc058612288b4a",
6 "publishedAt": "2026-09-08T22:09:42.828Z",
77 "deps": [
88 {
99 "name": "@hyperswarm/secret-stream",
……@@ -3017,7 +3017,7 @@
30173017 }
30183018 ],
30193019 "reason": "version-splits only: 0 code-differs",
3020 "acceptedAt": "2026-09-08T19:24:14.856Z"
3020 "acceptedAt": "2026-09-08T22:09:42.842Z"
30213021 },
30223022 {
30233023 "type": "VERSION_CONFLICT",
……@@ -3025,11 +3025,6 @@
30253025 "newVersion": "3.7.1",
30263026 "newTree": "5b662871145437a17e36c1dbebd64fc6e29be649b168ffb7638d3c5eaa781443",
30273027 "existing": [
3028 {
3029 "appName": "ap-bridge",
3030 "version": "3.6.1",
3031 "tree": "6bb5233025d1c30e4f181e29b6ab5af549d8909c7070c7b4438b30f1a4e76ce2"
3032 },
30333028 {
30343029 "appName": "atproto-bridge",
30353030 "version": "3.6.1",
……@@ -3067,7 +3062,7 @@
30673062 }
30683063 ],
30693064 "reason": "version-splits only: 0 code-differs",
3070 "acceptedAt": "2026-09-08T19:24:14.856Z"
3065 "acceptedAt": "2026-09-08T22:09:42.842Z"
30713066 },
30723067 {
30733068 "type": "VERSION_CONFLICT",
……@@ -3082,7 +3077,7 @@
30823077 }
30833078 ],
30843079 "reason": "version-splits only: 0 code-differs",
3085 "acceptedAt": "2026-09-08T19:24:14.856Z"
3080 "acceptedAt": "2026-09-08T22:09:42.842Z"
30863081 },
30873082 {
30883083 "type": "VERSION_CONFLICT",
……@@ -3107,7 +3102,7 @@
31073102 }
31083103 ],
31093104 "reason": "version-splits only: 0 code-differs",
3110 "acceptedAt": "2026-09-08T19:24:14.856Z"
3105 "acceptedAt": "2026-09-08T22:09:42.842Z"
31113106 },
31123107 {
31133108 "type": "VERSION_CONFLICT",
……@@ -3115,11 +3110,6 @@
31153110 "newVersion": "0.1.6",
31163111 "newTree": "4db5ae5fc0ad8552270405cd87877ac18d796bf082a05cb55e03a158af622290",
31173112 "existing": [
3118 {
3119 "appName": "ap-bridge",
3120 "version": "0.1.4",
3121 "tree": "b799e6ba8726aa951b45f12cc7ecffe5f4e9ee1e8adf09a34d026d9d5658828a"
3122 },
31233113 {
31243114 "appName": "atproto-bridge",
31253115 "version": "0.1.4",
……@@ -3142,7 +3132,7 @@
31423132 }
31433133 ],
31443134 "reason": "version-splits only: 0 code-differs",
3145 "acceptedAt": "2026-09-08T19:24:14.856Z"
3135 "acceptedAt": "2026-09-08T22:09:42.842Z"
31463136 },
31473137 {
31483138 "type": "VERSION_CONFLICT",
……@@ -3157,7 +3147,7 @@
31573147 }
31583148 ],
31593149 "reason": "version-splits only: 0 code-differs",
3160 "acceptedAt": "2026-09-08T19:24:14.856Z"
3150 "acceptedAt": "2026-09-08T22:09:42.842Z"
31613151 },
31623152 {
31633153 "type": "VERSION_CONFLICT",
……@@ -3172,7 +3162,7 @@
31723162 }
31733163 ],
31743164 "reason": "version-splits only: 0 code-differs",
3175 "acceptedAt": "2026-09-08T19:24:14.856Z"
3165 "acceptedAt": "2026-09-08T22:09:42.842Z"
31763166 },
31773167 {
31783168 "type": "VERSION_CONFLICT",
……@@ -3187,7 +3177,7 @@
31873177 }
31883178 ],
31893179 "reason": "version-splits only: 0 code-differs",
3190 "acceptedAt": "2026-09-08T19:24:14.856Z"
3180 "acceptedAt": "2026-09-08T22:09:42.842Z"
31913181 },
31923182 {
31933183 "type": "VERSION_CONFLICT",
……@@ -3202,7 +3192,7 @@
32023192 }
32033193 ],
32043194 "reason": "version-splits only: 0 code-differs",
3205 "acceptedAt": "2026-09-08T19:24:14.856Z"
3195 "acceptedAt": "2026-09-08T22:09:42.842Z"
32063196 },
32073197 {
32083198 "type": "VERSION_CONFLICT",
……@@ -3210,11 +3200,6 @@
32103200 "newVersion": "7.12.3",
32113201 "newTree": "955c2e26f31af120554761af5ea65e6773648f137083594bb888429432200344",
32123202 "existing": [
3213 {
3214 "appName": "ap-bridge",
3215 "version": "7.12.0",
3216 "tree": "272a04e0012c5aed2116ebd458d7c48b97f4bf5104cfa66225496ba1478a8fb8"
3217 },
32183203 {
32193204 "appName": "atproto-bridge",
32203205 "version": "7.11.1",
……@@ -3232,7 +3217,7 @@
32323217 }
32333218 ],
32343219 "reason": "version-splits only: 0 code-differs",
3235 "acceptedAt": "2026-09-08T19:24:14.856Z"
3220 "acceptedAt": "2026-09-08T22:09:42.842Z"
32363221 },
32373222 {
32383223 "type": "VERSION_CONFLICT",
……@@ -3247,7 +3232,7 @@
32473232 }
32483233 ],
32493234 "reason": "version-splits only: 0 code-differs",
3250 "acceptedAt": "2026-09-08T19:24:14.856Z"
3235 "acceptedAt": "2026-09-08T22:09:42.842Z"
32513236 },
32523237 {
32533238 "type": "VERSION_CONFLICT",
……@@ -3255,11 +3240,6 @@
32553240 "newVersion": "11.35.4",
32563241 "newTree": "a8699972843ff0e9e0b134447b71b055bbd8acd4a6ea3187624a7a52931ce10e",
32573242 "existing": [
3258 {
3259 "appName": "ap-bridge",
3260 "version": "11.35.1",
3261 "tree": "d163318f79d8aeea8054cdfc86f69823a80f3ec50b273e34f78ebde1b488d278"
3262 },
32633243 {
32643244 "appName": "atproto-bridge",
32653245 "version": "11.34.0",
……@@ -3277,7 +3257,7 @@
32773257 }
32783258 ],
32793259 "reason": "version-splits only: 0 code-differs",
3280 "acceptedAt": "2026-09-08T19:24:14.856Z"
3260 "acceptedAt": "2026-09-08T22:09:42.842Z"
32813261 },
32823262 {
32833263 "type": "VERSION_CONFLICT",
……@@ -3285,11 +3265,6 @@
32853265 "newVersion": "3.2.1",
32863266 "newTree": "46b1c3d46b4bf7703f0baf537ffbb80489394e28737a5c2e1641ca94ac115c4c",
32873267 "existing": [
3288 {
3289 "appName": "ap-bridge",
3290 "version": "3.2.0",
3291 "tree": "5fc49d698f6ddfd653b3cdaa72ec572d6804293e2e9c3e98303f69417115e903"
3292 },
32933268 {
32943269 "appName": "atproto-bridge",
32953270 "version": "3.2.0",
……@@ -3307,7 +3282,7 @@
33073282 }
33083283 ],
33093284 "reason": "version-splits only: 0 code-differs",
3310 "acceptedAt": "2026-09-08T19:24:14.856Z"
3285 "acceptedAt": "2026-09-08T22:09:42.842Z"
33113286 },
33123287 {
33133288 "type": "VERSION_CONFLICT",
……@@ -3322,7 +3297,7 @@
33223297 }
33233298 ],
33243299 "reason": "version-splits only: 0 code-differs",
3325 "acceptedAt": "2026-09-08T19:24:14.856Z"
3300 "acceptedAt": "2026-09-08T22:09:42.842Z"
33263301 },
33273302 {
33283303 "type": "VERSION_CONFLICT",
……@@ -3337,7 +3312,7 @@
33373312 }
33383313 ],
33393314 "reason": "version-splits only: 0 code-differs",
3340 "acceptedAt": "2026-09-08T19:24:14.856Z"
3315 "acceptedAt": "2026-09-08T22:09:42.842Z"
33413316 },
33423317 {
33433318 "type": "VERSION_CONFLICT",
……@@ -3345,11 +3320,6 @@
33453320 "newVersion": "3.17.4",
33463321 "newTree": "db9a29b3a3c27cca5ad561f21995e04945465c98d438579beff71e029e662776",
33473322 "existing": [
3348 {
3349 "appName": "ap-bridge",
3350 "version": "3.17.2",
3351 "tree": "6fc80ad1ccbfb046613f36299032f21a4752e2614ff8d88a7a5bd7ce66fc1293"
3352 },
33533323 {
33543324 "appName": "atproto-bridge",
33553325 "version": "3.17.2",
……@@ -3367,7 +3337,7 @@
33673337 }
33683338 ],
33693339 "reason": "version-splits only: 0 code-differs",
3370 "acceptedAt": "2026-09-08T19:24:14.856Z"
3340 "acceptedAt": "2026-09-08T22:09:42.842Z"
33713341 },
33723342 {
33733343 "type": "VERSION_CONFLICT",
……@@ -3387,7 +3357,7 @@
33873357 }
33883358 ],
33893359 "reason": "version-splits only: 0 code-differs",
3390 "acceptedAt": "2026-09-08T19:24:14.856Z"
3360 "acceptedAt": "2026-09-08T22:09:42.842Z"
33913361 },
33923362 {
33933363 "type": "VERSION_CONFLICT",
……@@ -3395,11 +3365,6 @@
33953365 "newVersion": "6.34.0",
33963366 "newTree": "f4e87130e4397b037b121356f2db0161fadd8f2c320f7042fa31f4b5308193ec",
33973367 "existing": [
3398 {
3399 "appName": "ap-bridge",
3400 "version": "6.33.0",
3401 "tree": "36d01631ddee74ac2ce62971abd7c0ac30562da8dfd6495480da56c534eb80b7"
3402 },
34033368 {
34043369 "appName": "hyperident",
34053370 "version": "6.30.0",
……@@ -3412,7 +3377,7 @@
34123377 }
34133378 ],
34143379 "reason": "version-splits only: 0 code-differs",
3415 "acceptedAt": "2026-09-08T19:24:14.856Z"
3380 "acceptedAt": "2026-09-08T22:09:42.842Z"
34163381 },
34173382 {
34183383 "type": "VERSION_CONFLICT",
……@@ -3427,7 +3392,7 @@
34273392 }
34283393 ],
34293394 "reason": "version-splits only: 0 code-differs",
3430 "acceptedAt": "2026-09-08T19:24:14.856Z"
3395 "acceptedAt": "2026-09-08T22:09:42.842Z"
34313396 },
34323397 {
34333398 "type": "VERSION_CONFLICT",
……@@ -3442,7 +3407,7 @@
34423407 }
34433408 ],
34443409 "reason": "version-splits only: 0 code-differs",
3445 "acceptedAt": "2026-09-08T19:24:14.856Z"
3410 "acceptedAt": "2026-09-08T22:09:42.842Z"
34463411 }
34473412 ]
34483413}
bin/favela.js +19 -4
……@@ -38,7 +38,7 @@ const USAGE = `favela — a p2p feed of markdown records
3838 favela handles [query] every handle in the namespace, or those matching
3939 favela resolve <handle> a handle -> feed, and whether the feed AGREES
4040 favela profile your display name and picture
41 favela set-profile --name X [--avatar <file>]
41 favela set-profile [--name X] [--bio "..."] [--avatar <file>]
4242 favela invite [--ttl <ms>] one-time invite for a browser
4343 favela browsers browsers you have admitted
4444 favela revoke <publicKey> retire a browser
……@@ -266,10 +266,25 @@ async function main () {
266266 case 'set-profile': {
267267 const name = str(argv, 'name')
268268 const avatar = str(argv, 'avatar')
269 if (name === undefined && avatar === undefined) {
270 throw new Error('set-profile needs --name and/or --avatar <file>')
269 // ⛔ THE BIO HAD NO WAY IN. `peer.setProfile` has taken `{name, avatar, bio}` since it was
270 // written and this caller only ever passed the first two, so the supported surface could not
271 // set a bio at all — the profile record's body stayed empty on every node, and every
272 // projection of it downstream (the AP actor's `summary`, the surface's byline) was empty for
273 // a reason that looked like the projection was broken. It was never reached.
274 const bio = str(argv, 'bio')
275 if (name === undefined && avatar === undefined && bio === undefined) {
276 throw new Error('set-profile needs --name, --bio and/or --avatar <file>')
277 }
278 // One call, so a name-and-bio change is ONE record write and not two — the record is
279 // overwritten in place, and two writes would briefly publish a profile with only half of it.
280 if (name !== undefined || bio !== undefined) {
281 const patch = {}
282 if (name !== undefined) patch.name = name
283 // ⚠ `''` is a REMOVAL, matching how setProfile already treats a blank name: absence asserts
284 // nothing, `""` would assert that the bio is empty.
285 if (bio !== undefined) patch.bio = bio
286 await call('set-profile', patch)
271287 }
272 if (name !== undefined) await call('set-profile', { name })
273288 if (avatar !== undefined) {
274289 if (!avatar) throw new Error('--avatar needs a file path')
275290 // ⛔ A PATH, never bytes. Both ends are on one machine — it is a unix socket — and
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "favela-peer",
3 "version": "0.0.46",
3 "version": "0.0.47",
44 "description": "The favela daemon — feeds and documents of markdown records over Hypercore. No atproto, no ActivityPub.",
55 "type": "module",
66 "scripts": {