summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_transport_contracts.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-14 21:45:53 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-14 21:45:53 +0200
commitcd2745cecff12e894e0dfa702bff6a90f0e8734e (patch)
tree8e864603cfd4c49cde535c8c4f96c5151ed4276c /packages/meshbay-hub/tests/test_transport_contracts.py
parentdf3b808792daa745b5b0d5b9896ddca8849fe8b1 (diff)
downloadmeshbay-cd2745cecff12e894e0dfa702bff6a90f0e8734e.tar.gz
feat: a group can be left out of Search, and Search tries every node
`search_listed` is a per-group setting on the node, changed by a signed operator op and carried in the sealed handshake ack. Search reads it after the handshake and stops there: no index is fetched, cached or merged, in any of the four views, and the page says how many groups it left out. The switch is a "Search" section in the group's settings, shown to the operator. Absent means listed, at every layer: roster default, ack default, and the client only drops a group on an explicit `false` — so an upgrade or an older node removes nothing from anyone's Search. It is a listing preference and protects nothing: the node serves the same index to Search and to the group page and cannot tell them apart, every member lists the group by opening it, and a client that ignores the flag lists it in Search too. Design §9.11 says so, so it is never described as private. The cost is one handshake per unlisted group, because only the node knows the setting. Search also took `nodes[0]` twice — for the index and for the pooled connection — the defect 4cce50f fixed on the group page only. One `connectToGroup` now walks the list the same way: a refusal about this browser stops, `not_hosted` or a failed connection moves on. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
Diffstat (limited to 'packages/meshbay-hub/tests/test_transport_contracts.py')
-rw-r--r--packages/meshbay-hub/tests/test_transport_contracts.py28
1 files changed, 28 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_transport_contracts.py b/packages/meshbay-hub/tests/test_transport_contracts.py
index c506ff1..ab942e4 100644
--- a/packages/meshbay-hub/tests/test_transport_contracts.py
+++ b/packages/meshbay-hub/tests/test_transport_contracts.py
@@ -506,3 +506,31 @@ def test_the_refusal_the_loop_keys_on_has_a_message(transport):
refusals = transport[transport.index("const HANDSHAKE_REFUSALS"):]
refusals = refusals[:refusals.index("};")]
assert "not_hosted:" in refusals
+
+
+# Search had the same `nodes[0]` twice — once to read a group's index, once for
+# the pooled connection its thumbnails and playback use — and was not part of
+# the fix above, so a group with a second, working node counted as unreachable
+# there while it opened fine from the sidebar.
+
+SEARCH_PAGE = STATIC / "search-page.js"
+
+
+def test_search_tries_every_node_the_hub_offers():
+ code = _code_only(SEARCH_PAGE.read_text(encoding="utf-8"))
+ assert "nodes[0]" not in code, "Search takes the head of the node list again"
+ walk = code[code.index("for (const n of nodesData.nodes)"):]
+ walk = walk[:walk.index("throw (lastErr")]
+ assert "not_hosted" in walk and "throw e" in walk, (
+ "the walk must stop for a refusal about this browser and move on "
+ "for one about this node")
+
+
+def test_search_connects_in_one_place():
+ """Two call sites with their own connect is how one of them kept `nodes[0]`."""
+ code = _code_only(SEARCH_PAGE.read_text(encoding="utf-8"))
+ assert code.count("transport.connect(") == 1
+ pool = code[code.index("async _doConnect("):code.index("_evict() {")]
+ index = code[code.index("async function fetchGroupIndex("):
+ code.index("async function fetchAllIndexes(")]
+ assert "connectToGroup(" in pool and "connectToGroup(" in index