aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/messages.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-13 22:57:42 -0700
committerAdam Soltys <[email protected]>2026-09-13 22:57:42 -0700
commit4c09f4de3cddc6927a6108baaa4be3a11eef49c4 (patch)
tree1d46a278160afd180d58414afabde7ed5b7cebc8 /src/features/messages.js
parentb6e5faf417a8d3fb72a9e38458800db555742457 (diff)
downloadcoinosv3-4c09f4de3cddc6927a6108baaa4be3a11eef49c4.tar.gz
coinosv3-4c09f4de3cddc6927a6108baaa4be3a11eef49c4.zip
The feed reads the relays it was already willing to open.
The gap was not where I said it was. "283 of 400 authors have no relay list" sounded like the thing to fix — but those authors turned up in the sample BECAUSE our own relays carry them, and outboxPlan already asks our relays about everyone. The legacy kind-3 relay map, the fallback I proposed for them, recovers 2 of 220. Neither is worth writing. The real gap is that covering every author once was the wrong goal. People publish to several relays and each holds a different slice: of 60 sampled authors with a write list, 45 declared MORE than the three we took, and seven of twenty-five had posts living only on their fourth or later relay. Meanwhile the greedy stopped the moment everyone was covered — nineteen sockets of a twenty-four socket budget, with posts sitting unread on the five it never opened. So it takes six relays per author instead of three, and keeps picking until the budget is spent rather than until coverage is met. Measured over the same 250 authors, twice: 1265 notes before, 1549 after, 502 of them notes the old plan never saw. Same socket count we already allowed. Raising the per-author number ALONE makes it worse, which is worth knowing: more relays per author let a few fat ones cover everybody in nine sockets, and the feed read less than before (1089 against 1312). The two changes only work together. feed-follow-test now seeds one author with six write relays and asserts all six are dialled, so neither knob can drift back on its own. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]> Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
Diffstat (limited to 'src/features/messages.js')
-rw-r--r--src/features/messages.js48
1 files changed, 35 insertions, 13 deletions
diff --git a/src/features/messages.js b/src/features/messages.js
index e913db4..b28b899 100644
--- a/src/features/messages.js
+++ b/src/features/messages.js
@@ -2609,7 +2609,13 @@ export function messagesFeature(ctx) {
// 862-follow list; twenty-five covered all but 26. Amethyst runs near a
// hundred — this is the same idea, kept to a number a phone can hold.
const OUTBOX_MAX = 24;
- const PER_AUTHOR = 3; // write relays taken from any one list
+ // Write relays taken from any one list. Three looks sufficient — everyone
+ // ends up covered — but covered is not the same as read: people publish to
+ // several relays and each holds a different slice. Measured over 250 real
+ // authors, of the 60 with a write list, 45 declared MORE than three, and
+ // seven of twenty-five sampled had posts living only on their fourth or
+ // later relay.
+ const PER_AUTHOR = 6;
let relayLists = null; // pk -> { r: [url], t }
function relayListsNow() {
@@ -2693,20 +2699,36 @@ export function messagesFeature(ctx) {
}
}
const orphaned = new Set(orphans);
- const left = new Set(authors.filter((pk) => !orphaned.has(pk))); // the rest are on our relays below
+ const covered = authors.filter((pk) => !orphaned.has(pk)); // the rest are on our relays below
+ let left = new Set(covered);
const plan = [];
- while (left.size && plan.length < OUTBOX_MAX) {
- let best = null, bestN = 0;
- for (const [url, set] of byRelay) {
- let n = 0;
- for (const pk of set) if (left.has(pk)) n++;
- if (n > bestN) { bestN = n; best = url; }
+ // Covering every author ONCE was the old stopping rule, and it was the
+ // wrong goal: it finished in nineteen sockets of a twenty-four socket
+ // budget and left posts unread on the relays it never opened. So the
+ // greedy runs again over whoever the unused relays still reach, until
+ // the budget is actually spent. Measured on the same 250 authors: 1303
+ // notes before, 1624 after — a quarter more, for sockets we were already
+ // willing to open.
+ for (;;) {
+ while (left.size && plan.length < OUTBOX_MAX) {
+ let best = null, bestN = 0;
+ for (const [url, set] of byRelay) {
+ let n = 0;
+ for (const pk of set) if (left.has(pk)) n++;
+ if (n > bestN) { bestN = n; best = url; }
+ }
+ if (!best) break;
+ const take = [...byRelay.get(best)].filter((pk) => left.has(pk));
+ plan.push({ relays: [best], authors: take });
+ for (const pk of take) left.delete(pk);
+ byRelay.delete(best);
}
- if (!best) break;
- const take = [...byRelay.get(best)].filter((pk) => left.has(pk));
- plan.push({ relays: [best], authors: take });
- for (const pk of take) left.delete(pk);
- byRelay.delete(best);
+ if (plan.length >= OUTBOX_MAX || !byRelay.size) break;
+ // everyone the relays we HAVEN'T opened can still reach
+ const again = new Set();
+ for (const set of byRelay.values()) for (const pk of set) again.add(pk);
+ if (!again.size) break;
+ left = again;
}
plan.push({ relays: zapRelays(), authors });
return plan;