<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-node/src/meshbay_node/transport, branch main</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=main</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=main'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-26T00:03:50Z</updated>
<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>
<entry>
<title>refactor(node): section headers follow the code they introduce</title>
<updated>2026-09-24T14:45:38Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T09:01:19Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=5dd59b000f6ca2205adb3ba359e60eb823c97f10'/>
<id>urn:sha1:5dd59b000f6ca2205adb3ba359e60eb823c97f10</id>
<content type='text'>
Three headers stayed in webrtc_server when their sections moved; they now
sit above the same methods in blobs.py and admission.py. Two that were only
a title over what is now a whole module are dropped.

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