diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-09 14:00:22 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-09 14:00:22 +0200 |
| commit | 53ea44cb03ef6f8d941f6c8c9446551b0c5cd1ac (patch) | |
| tree | 0d38403f86a0b96d5076c6404b471df7d1d41aad /packages/meshbay-hub/src/meshbay_hub/api/hub.py | |
| parent | dee57df42a525cead93fa30b4e7fa38a489d5b11 (diff) | |
| download | meshbay-53ea44cb03ef6f8d941f6c8c9446551b0c5cd1ac.tar.gz | |
feat: MNP 3.0 — a transfer needs a lease
Stage 4 of ~/next/improve-downloads.md, the flag day. Leases become compulsory
and a 2.x peer is refused at the handshake.
**The bound on leaseless reads (§3.4.1) did not exist, and it is what makes the
rest mean anything.** Browsing a group is never subject to a transfer slot —
that is an operator decision and a requirement: a member must be able to browse
a group at capacity exactly as they browse an idle one. But "not leased" cannot
mean "unbounded", or a client that simply omits `tr` transfers outside every cap
and the caps are decoration. A session may now read two distinct files at once
without a lease: one because a viewer looks at one file, two so that prefetching
the next photo stays possible. A count of files and not a byte budget, because a
RAW photo is 60-80 MB and is browsing while a 40 MB archive is a download, and
no size threshold separates them. Thumbnails, posters and cover art never reach
this check at all — they resolve out of the node's own cache.
It is a fairness control among cooperating clients, in the company of
`max_concurrent_streams`, and is not a defence against a member determined to
saturate a node's disk. That member is a member, and the answer to them is
`member revoke`.
**MNP_VERSION and MNP_MIN_SUPPORTED both move to 3.0**, on both sides. The
messages are additive; the requirement is not. An opt-in switch would leave a
leaseless branch reachable on every node, which is finding C6's lesson — a
transport that accepted a bare JWT — one feature later.
**The desktop client now checks before it connects.** The SPA is served by the
hub and picks up a new client on reload; the application ships its own
interface, so an un-updated one would sign in, list groups, and fail every
connection with `version_too_old` — a refusal in a protocol vocabulary with
nothing anyone can act on. It asks `/v1/hub/version` for `client.minimum` and
says so plainly instead. An unreachable hub is deliberately *not* "too old": a
captive portal or a closed laptop must not make starting the application
impossible.
**Every package is aligned on 0.13.0.** `meshbay-client/package.json` had
drifted to 1.0.0 while the Python packages were on 0.12.0 — invisible until
something compared those numbers, and then load-bearing: an installed client
announcing 1.0.0 sorts above a 0.13.0 minimum and walks through the gate meant
to stop it. That is stated in the code rather than left to be rediscovered; it
is acceptable exactly once, because the operator is updating every client, node
and hub by hand for this flag day. A new test fails if two packages ever
disagree again, and another fails if the hub would refuse the client the tree
builds.
Node suite 1209 passed, hub suite 861 passed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/api/hub.py')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/api/hub.py | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/api/hub.py b/packages/meshbay-hub/src/meshbay_hub/api/hub.py index 8223400..a48313d 100644 --- a/packages/meshbay-hub/src/meshbay_hub/api/hub.py +++ b/packages/meshbay-hub/src/meshbay_hub/api/hub.py @@ -54,8 +54,21 @@ async def hub_pubkey(): # user "update to keep using this" before it becomes "this stopped working". # Raise `minimum` only for a change a client genuinely cannot survive, and # remember store review latency makes that expensive on Android. -MIN_CLIENT_VERSION = "0.1.0" -RECOMMENDED_CLIENT_VERSION = "0.1.0" +# Raised on the MNP 3.0 flag day (2026-09-09). A client older than this speaks +# MNP 2.x, cannot ask for a transfer lease, and is refused at the node's +# handshake with `version_too_old` — a refusal in a protocol vocabulary that +# surfaces as "the node will not talk to me". The client checks this field +# before connecting and says something a person can act on instead. +# +# **This first raise does not reach the clients already installed**, and that is +# understood rather than overlooked. `package.json` had drifted to "1.0.0" while +# every other package was on 0.12.0, so an installed client announces a version +# that sorts *above* this minimum and sails through the gate — then meets the +# handshake refusal anyway. The operator is updating every client, node and hub +# by hand for this flag day, which is what makes that acceptable exactly once. +# The gate is in place for the next one, where it will work as intended. +MIN_CLIENT_VERSION = "0.13.0" +RECOMMENDED_CLIENT_VERSION = "0.13.0" @router.get("/version") |