<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-node/src/meshbay_node/transport/webrtc, branch 0.16</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.16</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.16'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-26T12:28:13Z</updated>
<entry>
<title>fix(node,client): query TMDB only once a language is chosen, in that language</title>
<updated>2026-09-26T12:28:13Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-26T12:28:13Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=eccd465f8954bfd49c3f7d8f02446bc2aa5c4338'/>
<id>urn:sha1:eccd465f8954bfd49c3f7d8f02446bc2aa5c4338</id>
<content type='text'>
TMDB fiches are fetched lazily, on browse, and the fetch used to run whatever
the moment it was first triggered — routinely before the operator had opened
settings and picked a language, so it queried in TMDB's English default. Then
the fiche was cached by tmdb_id alone, with no note of language and a 30-day
TTL, so switching to the intended language afterwards changed nothing: the
English fiche was served until it expired. The operator's only recourse was to
find and wipe the cache by hand (found live 2026-09-26: a whole library indexed
in English although "Français" had been chosen).

Two rules now, both there to make the first fetch the right language rather
than English-then-corrected, and to stop the doubled requests that eventually
get a node rate-limited:

- No language configured, no query. media_meta_req/season_meta_req answer
  confidence 0 and make no TMDB call while tmdb_language is unset; the fetch
  waits for the operator's choice, so the first (and only) query is in it.
  English is now a first-class choice (en-US), not the default of skipping the
  setting.
- Changing the language wipes the metadata cache (ops.set_tmdb_config), so the
  new language takes effect on an already-browsed library. The file-&gt;tmdb
  matches are language-independent and kept. The client refetches on the
  tmdb_config_ack that carries the new language, so the grid updates without a
  page reload.

docs/MESHBAY_DESIGN.md §9.7 states both rules; tests cover the gate and the
cache wipe, and two existing handler harnesses now declare a language.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(protocol): bind the MNP token to the node it is for (E10)</title>
<updated>2026-09-26T00:03:50Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-26T00:03:50Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=2ccb6653e8841d4d6f3ab933f84746cce4e2fe2b'/>
<id>urn:sha1:2ccb6653e8841d4d6f3ab933f84746cce4e2fe2b</id>
<content type='text'>
The audience split stopped a member's node credential from opening the hub API.
It did not stop the credential being *replayed to another node*: the MNP token
carried the member's whole group set and named no node, so a token handed to
node A's operator could be presented to node B the member also belongs to. That
does not read content on B — the handshake still requires proving node B's group
key, which the operator lacks — but it reaches B's pre-proof window and fetches
the member's *encrypted* keypair bundle for B (offline-attackable, bounded,
audited): a disclosure §2.4 says should not follow from hosting a member on A.

The token now names the node it is minted for (a `node` claim = that node's
Ed25519 key), and authorize_token refuses one that names a different key. The
client already knows the target node's key (from /v1/groups/{id}/nodes) and asks
for a token bound to it: POST /v1/nodes/mnp-token takes node_pk, and
transport.connect threads it (group-page, the connection pool and rewrap pass
n.pk_node; reconnect preserves it). A token that names no node is still
accepted, because the hub only mints one for the authenticated requester, so an
unbound token grants nothing across accounts — which also keeps non-binding
callers working with no churn.

Done before deploy, so it folds into the MNP 4.0 flag day rather than needing
its own. Docs: §5.2, register E10, MESHBAY_NODE_PROTOCOL.md §6.3.
test_handshake.py and test_mnp_token.py hold the binding (a token for node A is
refused by node B, accepted by node A; an unbound token still works); red
before, green after. common/node/hub suites green.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): split ops.py into the ops package</title>
<updated>2026-09-24T23:30:47Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T23:30:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=762233772162a05be67432aa551a430b939250de'/>
<id>urn:sha1:762233772162a05be67432aa551a430b939250de</id>
<content type='text'>
Each section of ops.py becomes a module of meshbay_node/ops/ (core,
node_toml, members, chat, groups, roots, files, settings, apps), cut as
text; ops/__init__.py keeps the docstring and re-exports every name, so
`ops.&lt;name&gt;` is unchanged for every caller. Logger name unchanged.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): run signed operations through a table of executors</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T10:51:39Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=5a180dd05046499ae0867842bfb3913796b6bd39'/>
<id>urn:sha1:5a180dd05046499ae0867842bfb3913796b6bd39</id>
<content type='text'>
_do_admin_response looked each operation up in a 28-branch elif, every
branch the same call. The admin cases of the dispatch golden are
unchanged.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): dispatch MNP messages through a table</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T10:43:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=d60768b3812f30cf4109e2a5dab498d916262572'/>
<id>urn:sha1:d60768b3812f30cf4109e2a5dab498d916262572</id>
<content type='text'>
The pre-authentication guards stay explicit code, in the same order and
text. After the handshake, a table maps each type to its handler and to
whether it runs as a task, the choice each branch made; the three inline
blocks become StreamingMixin methods, unchanged. The dispatch golden is
identical, including types that are not strings.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): move _dispatch_message out of webrtc_server, unchanged</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T10:32:05Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=76c67f4ad43ddb30ac25868554638c1e0aac83bd'/>
<id>urn:sha1:76c67f4ad43ddb30ac25868554638c1e0aac83bd</id>
<content type='text'>
DispatchMixin in transport/webrtc/dispatch.py, with the pre-proof fetch
bound it enforces. The elif chain moves as it is; turning it into a table
is the next commit, on its own.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): move the session core out of webrtc_server</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T10:12:15Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=f453cd39ef0fec606b3d1a67b3fae5fa96e719f9'/>
<id>urn:sha1:f453cd39ef0fec606b3d1a67b3fae5fa96e719f9</id>
<content type='text'>
SessionCore in transport/webrtc/core.py, last among the bases: state,
the data channel, task ownership, the peer registry, sending and teardown.
The facade keeps _dispatch_message and WebRTCTransport.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): move operator authority and the admin response out of webrtc_server</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T09:40:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=fedb0f2afa552747a45b6b7c362a7977923e67ff'/>
<id>urn:sha1:fedb0f2afa552747a45b6b7c362a7977923e67ff</id>
<content type='text'>
AdminMixin in transport/webrtc/admin.py: who the operator is, the signed
challenge, signature checks, and _do_admin_response moved unchanged.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): move the operator's group controls out of webrtc_server</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T09:23:12Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=bd9f2e8a8d1d7abe05f61f749992cda30a81cd15'/>
<id>urn:sha1:bd9f2e8a8d1d7abe05f61f749992cda30a81cd15</id>
<content type='text'>
GroupOpsMixin in transport/webrtc/group_ops.py: member revocation and
unpinning, the group key rotation, apps and their directories with the
allow-list, and Search listing.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor(node): move the operator's node controls out of webrtc_server</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T09:15:20Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=56db13f8b3469c6063a5915155234b4a39aa328f'/>
<id>urn:sha1:56db13f8b3469c6063a5915155234b4a39aa328f</id>
<content type='text'>
NodeOpsMixin in transport/webrtc/node_ops.py: status and settings, roster
and denylist, roots, hosted groups, reload, scan pacing and transfer
limits, with their class-level bounds.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
