This commit is contained in:
spaced4ndy committed 2026-07-23 13:59:05 +04:00
1 parent c98987d014
commit d152243d84
1 file changed
+1 -1
+1 -1
View File
@@ -59,7 +59,7 @@ Link data and keys already *have* a sequencer — the server — so they need on
**Source — max across relays, with a timestamp.** Each relay batches its own *current absolute* subscriber count and broker timestamp with the join/leave/removal event it already sends owners — no extra SMP block, restated only when the count changes. An owner keeps the latest `(count, ts)` **per relay** (a field on the relay's member row); its estimate is the **max** count, carrying that relay's `ts`. The max is what ignores a newly-added relay that subscribers are still slowly connecting to (its low count stays below the max until it catches up) while still decreasing on a real departure (the max-holding relay's own count drops — a lagging second relay reporting a slightly lower number never lowers the max, so cross-relay skew causes no spurious decrease). Deltas cannot do this: a leave is *deduplicated* across relays, so an owner cannot attribute a decrease; the per-relay count event, being distinct per relay, is not deduplicated.
**Published on channel open, not on events.** Link data carries `(subscriberCount, subscriberCountTs)`. When an owner opens the channel it already reconciles link data (§2); if its estimate differs materially from the published count *and* its `ts` is newer than `subscriberCountTs`, it publishes `(estimate, ts)`. The timestamp is a **freshness gate** — only an owner whose data is newer than what is published writes, so a *behind* owner (stale data, older `ts`) stays quiet and cannot push a wrong value in either direction, which is exactly what lets the update go **both ways** safely. Concurrent opens CAS: one wins, the other re-reads and sees it already fresh. This needs no leading owner, no handover, no staleness detection, no debounce, and no extra query — the count tracks owner activity (fine for a cosmetic number) and writes the link at most once per owner-open, not per join. (Use the relay's *broker* timestamp so owner clock skew is irrelevant; relay-to-relay skew is absorbed by the max.)
**Published on channel open, not on events.** Link data carries `(subscriberCount, subscriberCountTs)`. When an owner opens the channel it already reconciles link data (§2); if its estimate differs from the published count (by any amount) *and* its `ts` is newer than `subscriberCountTs`, it publishes `(estimate, ts)`. No delta threshold — a small/new channel must move on every joiner (1 → 2 → 3). There is no write-amplification to guard against: publishing is gated by *channel open*, not by joins, and the `ts` gate means an owner writes only when it is genuinely fresher — if the published count is already current it writes nothing. The timestamp is thus a **freshness gate** — a *behind* owner (stale data, older `ts`) stays quiet and cannot push a wrong value in either direction, which is what lets the update go **both ways** safely. Concurrent opens CAS: one wins, the other re-reads and sees it already fresh. This needs no leading owner, no handover, no staleness detection, no debounce, and no extra query — the count tracks owner activity (fine for a cosmetic number) and writes the link at most once per owner-open, not per join. (Use the relay's *broker* timestamp so owner clock skew is irrelevant; relay-to-relay skew is absorbed by the max.)
## 6. Owner promotion (adding an owner)