aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-10 17:23:40 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-10 17:23:40 +0200
commit1dcedc77083b908b7b3b431bad679a4813884355 (patch)
treedb6ae06c05e5f337aeb42dde5c7bd2a7fe9444b5 /packages/meshbay-hub/tests
parent6964ff112fec47498ed778a491cf2a1490392c79 (diff)
downloadmeshbay-1dcedc77083b908b7b3b431bad679a4813884355.tar.gz
refactor(mnp)!: one answer to "may this member write", and it is the root
The group-wide `member_upload` switch is gone: the message, the signed operation, the field on the handshake ack, the `upload` alias on every root in the index payload, and the client's fallback path to it. Whether a member may write has been a property of each root for a while, and that is the model that survives: a single flag over the group cannot express "this library is published read-only and that folder is a drop box", which is the ordinary arrangement. What was left of the switch was a handler that logged a deprecation and acted on nothing, and a client that read `ack.member_upload` whenever the roots carried no `writable` — a second source for one question, with whichever the code consulted first deciding it. `roots.describe()` drops `upload` for the same reason: it was `writable` under an older name, and two names for one boolean is one too many. The paperclip now says "nowhere to write" rather than picking a root, in a group that has none writable. That is the honest answer; the fallback picked whatever came first and failed at send time. Node suite 1215 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AsoWC3GmhNdwVFomW3QjH3
Diffstat (limited to 'packages/meshbay-hub/tests')
-rw-r--r--packages/meshbay-hub/tests/harness/group_tab_probe.py2
-rwxr-xr-xpackages/meshbay-hub/tests/harness/sticky_header_probe.py2
-rw-r--r--packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py31
-rw-r--r--packages/meshbay-hub/tests/test_upload_controls_hidden.py22
4 files changed, 13 insertions, 44 deletions
diff --git a/packages/meshbay-hub/tests/harness/group_tab_probe.py b/packages/meshbay-hub/tests/harness/group_tab_probe.py
index b6d2bcc..da1e8d1 100644
--- a/packages/meshbay-hub/tests/harness/group_tab_probe.py
+++ b/packages/meshbay-hub/tests/harness/group_tab_probe.py
@@ -52,7 +52,7 @@ window.MeshBayTransport = class {
constructor() { this.connected = false; this.memberRole = 'member'; }
async connect() {
this.connected = true;
- return { is_node_admin: false, member_upload: true,
+ return { is_node_admin: false,
enabled_apps: %(enabled)s,
tmdb_enabled: false, musicbrainz_enabled: false,
video_root: '', audio_root: '', photo_roots: [] };
diff --git a/packages/meshbay-hub/tests/harness/sticky_header_probe.py b/packages/meshbay-hub/tests/harness/sticky_header_probe.py
index 9e9dc3c..320a2d4 100755
--- a/packages/meshbay-hub/tests/harness/sticky_header_probe.py
+++ b/packages/meshbay-hub/tests/harness/sticky_header_probe.py
@@ -199,7 +199,7 @@ for (let d = 0; d < 40; d++)
path: `photos/sortie ${String(d).padStart(2, '0')}`, type: 'image' });
const ACK = {
- is_node_admin: true, member_upload: true,
+ is_node_admin: true,
enabled_apps: ['chat', 'files', 'video', 'music', 'photo'],
tmdb_enabled: false, musicbrainz_enabled: false,
video_directories: ['films'], music_directories: ['musique'],
diff --git a/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py b/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
index 63390af..b15018b 100644
--- a/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
+++ b/packages/meshbay-hub/tests/test_mnp_1_0_node_compat.py
@@ -11,8 +11,6 @@ sends **nothing back**, so a control that speaks MNP 1.1 to it produces a
thirty-second wait ending in a timeout, with nothing on screen to say the node
simply cannot do this. Three of them were like that before these tests:
-* Files' Upload button read `root.writable`, which a 1.0 node does not send —
- it says `upload`. The button disappeared on every un-upgraded node.
* The shared-directories toggles, eject and plug have no older equivalent at
all.
* The per-app folder pickers spoke `app_directories`, where a 1.0 node
@@ -71,22 +69,6 @@ def test_the_capability_reads_the_version_rather_than_guessing():
# ── The three degraded paths ────────────────────────────────────────────────
-def test_the_upload_button_reads_the_older_flag_too():
- """
- A 1.0 node's roots carry `upload`; `writable` is the same answer renamed.
- Reading only the new name hides the Upload button on every node that has
- not been updated, which on the day the page ships is all of them.
- """
- page = _component(FILES_APP.read_text(encoding="utf-8"), "FilesPanel")
- decl = page[page.index("const currentRootWritable"):]
- decl = decl[:decl.index(";") + 1]
- assert "currentRoot.upload" in decl, (
- "the Upload button ignores the flag an older node actually sends")
- assert "writable !== undefined" in decl, (
- "a root that is explicitly writable=false must stay read-only — "
- "falling through to `upload` there would reopen it")
-
-
def test_app_directories_fall_back_to_the_three_older_messages():
"""
Videos, Music and Photos each had their own message before the generic op,
@@ -160,16 +142,3 @@ def test_the_ack_is_read_in_both_shapes(app=None):
assert legacy in block, f"{legacy} is not read as a fallback"
assert "ack.chat_link_preview !== false" in page, (
"an absent link-preview switch must read as on, not off")
-
-
-def test_the_attachment_root_falls_back_to_the_older_answer():
- """
- A 1.0 node's roots carry no `writable`, so nothing looks writable and the
- paperclip would vanish. The group-wide `member_upload` flag is the only
- answer such a node gives, and it is what gets used.
- """
- page = GROUP_PAGE.read_text(encoding="utf-8")
- block = page[page.index("const writableRoots"):]
- block = block[:block.index("const commonProps")]
- assert "legacyNode" in block and "memberUpload" in block
- assert "writable === undefined" in block
diff --git a/packages/meshbay-hub/tests/test_upload_controls_hidden.py b/packages/meshbay-hub/tests/test_upload_controls_hidden.py
index f6f476e..a2f9352 100644
--- a/packages/meshbay-hub/tests/test_upload_controls_hidden.py
+++ b/packages/meshbay-hub/tests/test_upload_controls_hidden.py
@@ -180,19 +180,19 @@ def test_the_answer_comes_from_the_node(app):
assert "hubFetch" not in app[idx - 400:idx]
-def test_an_older_node_is_treated_as_permissive(app):
+def test_there_is_no_group_wide_upload_flag_to_read(app):
"""
- A node speaking MNP 1.0 sends roots with no `writable` at all, plus the old
- group-wide flag. Reading a missing field as "read-only" would close every
- group on the older half of the network.
+ Whether a member may write is a property of each root, and the page must
+ have no second source for it.
+
+ A group-wide flag beside the per-root answer is a page that can show an
+ Upload button the node will refuse, or hide one it would have allowed —
+ and whichever of the two the code happens to consult first decides.
"""
- assert "ack.member_upload !== false" in app
- assert "!== false" in app[app.index("ack.member_upload"):
- app.index("ack.member_upload") + 60]
- block = app[app.index("const legacyNode"):]
- block = block[:block.index("const commonProps")]
- assert "writable === undefined" in block, (
- "nothing distinguishes a 1.0 node from one with no writable roots")
+ assert "member_upload" not in app, (
+ "the page reads a group-wide upload flag again")
+ assert "r.writable" in app or "writable" in app, (
+ "the page has to read the per-root answer from somewhere")
def test_a_change_reaches_people_already_connected(app):