From 9a4f6c6cdd96500be8b35fe2e2490fe4e2562968 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 4 Aug 2026 15:26:54 +0000 Subject: [PATCH] feat(quartz): optional kinds on the read-test filter (production finding) Verified the new probe surface end-to-end against production relays (probeFlow streaming, readWriteCheck, signed 30166 templates). One compatibility finding: purpose relays like purplepag.es reject any REQ that names no kind ('blocked: filters must specify at least one kind'), leaving their read side unobserved. readTestFilter/readWriteCheck now take an optional kinds list for those; the default stays kind-less because naming kinds also narrows the query on every other relay. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01A9sSyh1QLJD3PZ18tVPPVK --- .../nip66RelayMonitor/reachability/RelayProber.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip66RelayMonitor/reachability/RelayProber.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip66RelayMonitor/reachability/RelayProber.kt index 5dcf878aad..d03fb01208 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip66RelayMonitor/reachability/RelayProber.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip66RelayMonitor/reachability/RelayProber.kt @@ -194,12 +194,13 @@ class RelayProber( timeoutMs: Long = 15_000, waveSize: Int = 1000, readLimit: Int = 1, + readKinds: List? = null, ): Map { val out = HashMap() val distinct = relays.toSet() for ((waveIndex, wave) in distinct.chunked(waveSize.coerceAtLeast(1)).withIndex()) { val reads = HashMap() - probeWave(wave, timeoutMs, readTestFilter(readLimit)) { reads[it.relay] = it.rttEoseMs } + probeWave(wave, timeoutMs, readTestFilter(readLimit, readKinds)) { reads[it.relay] = it.rttEoseMs } // A distinct event id per wave (createdAt has second granularity, so the // content must vary) keeps a straggler OK from an earlier wave's relays @@ -346,8 +347,17 @@ class RelayProber( * [filters] to turn [Verdict.rttEoseMs] into a genuine read test rather * than a liveness ping — the time still counts from the wave start (dial * included), so compare it against [Verdict.rttOpenMs], not across waves. + * + * [kinds] widens compatibility with purpose relays: some (purplepag.es) + * reject any REQ that names no kind with `blocked: filters must specify at + * least one kind`, which leaves their read side unobserved. Passing e.g. + * `listOf(0, 1)` satisfies them; the default stays kind-less because a + * kind list also narrows the query on every OTHER relay. */ - fun readTestFilter(limit: Int = 1) = listOf(Filter(limit = limit)) + fun readTestFilter( + limit: Int = 1, + kinds: List? = null, + ) = listOf(Filter(kinds = kinds, limit = limit)) /** * The relay universe the local store knows: every read/write relay advertised