Files
buzz/desktop/src/shared/api/presenceRelaySubscription.test.mjs
Wes df9e773a13 Scope desktop presence subscriptions to active demand (#5830)
## Summary

- replace the desktop's global kind-20001 presence subscription with one
author-filtered subscription derived from active TanStack presence
queries
- reconcile changing demand without a delivery gap: promote only after
relay EOSE, keep the last confirmed subscription on failure, discard
stale opens, and close entirely when demand is empty
- preserve REST presence as the initial seed and TTL/crash-recovery
backstop
- add transport-seam and lifecycle tests for readiness, normalization,
churn, retries, close failures, reconnect ownership assumptions, and
disposal

## Why

The desktop currently receives presence heartbeats from every identity
on the relay. A live tap measured roughly 2,700 events/minute (45/sec),
about 1 MB/minute and 71.5% of readable traffic, from approximately
1,300 distinct fleet identities. Most are discarded only after
WebSocket, Tauri IPC, and JS parsing.

This change applies normal Nostr author filtering at relay fan-out,
before those costs. It deliberately does not introduce a relay digest
protocol or client-side event batching; relevant-author traffic should
be small after scoping, and the existing signed-delta/REST-TTL model
remains intact.

## Correctness model

- active query observers are the demand source; inactive cached queries
retain no authors
- replacement opens before old closes and is promoted only after EOSE
- timeout/CLOSED rejects and closes the candidate while preserving the
last good subscription
- rapid A→B→C and A→B→A churn cannot unseat current A with stale B
- empty demand never sends an unfiltered subscription
- RelayClient continues to own reconnect replay; the reconciler does not
duplicate subscriptions on reconnect

## Validation

Exact pushed head: `8845093aec0330be16efe52d3459ff67f1000ff4`

Pre-push hooks passed:
- desktop check and file-size ratchet
- desktop TypeScript
- desktop unit suite: 4,791/4,791
- branch-skew check

Focused lifecycle/transport suite: 34/34 passed before commit.
Independent Royal Court review found and blocked two prototype flaws
(timeout-as-success and starvation-prone trailing debounce); both were
fixed and the final worktree was cleared with no remaining correctness
or lifecycle blockers.

Signed-off-by: Wes <wesbillman@users.noreply.github.com>
Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz>
2026-08-13 20:32:34 -07:00

63 lines
1.8 KiB
JavaScript

import assert from "node:assert/strict";
import test from "node:test";
import { openPresenceSubscription } from "./presenceRelaySubscription.ts";
import { KIND_PRESENCE_UPDATE } from "../constants/kinds.ts";
const A = "a".repeat(64);
const B = "b".repeat(64);
function liveWithReadiness(readiness) {
const calls = [];
let closeCount = 0;
const openLive = async (filter, onEvent, onReady, readinessTimeoutMs) => {
calls.push({ filter, onEvent, readinessTimeoutMs });
onReady(readiness);
return async () => {
closeCount += 1;
};
};
return { calls, closeCount: () => closeCount, openLive };
}
test("presence waits for EOSE and sends only normalized authors", async () => {
const { calls, closeCount, openLive } = liveWithReadiness("eose");
const onEvent = () => {};
const close = await openPresenceSubscription(
[B, A.toUpperCase(), A],
onEvent,
openLive,
);
assert.deepEqual(calls, [
{
filter: { kinds: [KIND_PRESENCE_UPDATE], authors: [A, B], limit: 0 },
onEvent,
readinessTimeoutMs: 5_000,
},
]);
assert.equal(closeCount(), 0);
await close();
assert.equal(closeCount(), 1);
});
for (const readiness of ["timeout", "closed"]) {
test(`presence ${readiness} closes the candidate and rejects`, async () => {
const { closeCount, openLive } = liveWithReadiness(readiness);
await assert.rejects(
openPresenceSubscription([A], () => {}, openLive),
readiness === "closed" ? /rejected/ : /timed out/i,
);
assert.equal(closeCount(), 1);
});
}
test("empty demand never reaches the relay subscribe primitive", async () => {
const { calls, openLive } = liveWithReadiness("eose");
await assert.rejects(
openPresenceSubscription([], () => {}, openLive),
/at least one author/,
);
assert.deepEqual(calls, []);
});