<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/docs, 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-28T10:29:20Z</updated>
<entry>
<title>fix(hub): say so when a lazily loaded view cannot be fetched</title>
<updated>2026-09-28T10:29:20Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-28T10:29:20Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=34576a1ccda1ee192e8efbc653cb436111a9c5e8'/>
<id>urn:sha1:34576a1ccda1ee192e8efbc653cb436111a9c5e8</id>
<content type='text'>
A tab opened before a hub deploy got 404 for every module it had not
loaded yet, and lazy.js kept its spinner for good. It now shows a notice
with a Reload button and logs the failure.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(hub): keep a show's detail modal open under the player</title>
<updated>2026-09-28T09:09:12Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-28T09:09:12Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=694a3832f4b57d007b79b3b21dd47b55e6ef3c42'/>
<id>urn:sha1:694a3832f4b57d007b79b3b21dd47b55e6ef3c42</id>
<content type='text'>
Closing the player lands back on the season being watched, with the
episode just started marked. A film's modal still closes on Play.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: the Windows node's three modes and one lifecycle, and what it cost</title>
<updated>2026-09-27T20:21:42Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-27T20:21:42Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=6c7b61a8e946b777ea1985058dbed9019bddd53a'/>
<id>urn:sha1:6c7b61a8e946b777ea1985058dbed9019bddd53a</id>
<content type='text'>
- MESHBAY_DESIGN.md §11.2: the node runs only while the app is open, at
  sign-in, or as a boot-time service; starting and stopping have one
  implementation, the CLI's; a second instance refuses before it writes
  anything the running one depends on.
- packaging/win/README.md: the three modes, switching between them, upgrading
  a running node, where the log is, the service task's settings.
- docs/windows-build.md: the build's smoke start of the frozen daemon, the log
  location, and what an upgrade does to a running node.
- CLAUDE.md: four engineering lessons -- an upgrade that cannot stop the node
  installs around it; on Windows the CLI is the process it is stopping; a
  second instance must fail before it touches anything shared; a test that
  redirects HOME isolates nothing on Windows.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<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>fix(hub): the NAT-punch signal needs a shared active group, like the offer relay</title>
<updated>2026-09-26T00:44:52Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-26T00:44:52Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=4500fe3854fd3a499d1139bc89ccc488d104cc29'/>
<id>urn:sha1:4500fe3854fd3a499d1139bc89ccc488d104cc29</id>
<content type='text'>
POST /v1/nodes/{id}/incoming checked only the caller's own address, then revealed
whether the node was connected (404 vs 504) and, with QUIC on, made it punch —
so any authenticated account could poll it for a node's liveness or make a
stranger's node emit a UDP probe. The membership gate webrtc_offer did inline is
now require_shared_active_group() in api/signaling.py, called by both routes; in
notify_incoming it runs before anything depends on the node's connection state,
so a non-member gets one uniform 403 whether the node is up or not.

test_incoming_membership.py holds it (a non-member is refused with a membership
403 whether the node is connected or not; a member passes the gate); red before,
green after. The offer relay is unchanged in behaviour (it now calls the shared
helper); signaling/availability suites pass. Design §7.2 updated.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs(design): state the node-bound MNP token as a rule, not an incident</title>
<updated>2026-09-26T00:32:02Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-26T00:32:02Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=bfd12aee8e3452f078ec20e3ee4d45c4fe9b4521'/>
<id>urn:sha1:bfd12aee8e3452f078ec20e3ee4d45c4fe9b4521</id>
<content type='text'>
§5.2, register E10 and decision 23 described the node-audience token and its
node binding partly as "before this, an operator could…". Restate them as the
design they are — the credential a member presents to a node opens nothing at
the hub and names the one node it is for — keeping the adversary named per the
document's convention but not retelling the gap.

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>feat(protocol): MNP 4.0 flag day for the node-audience token (B2)</title>
<updated>2026-09-25T15:43:28Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-25T15:43:28Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3f3c67a4aff7b800c271e88e2bc5e5294b010fb9'/>
<id>urn:sha1:3f3c67a4aff7b800c271e88e2bc5e5294b010fb9</id>
<content type='text'>
The node-audience token (previous commit) is a change to what a peer must
present, so it is a MAJOR per the versioning rule (§5.6): a pre-4.0 client
presents its hub session token and a 4.0 node refuses it, and there is no
compatibility branch, because leaving one would keep a hub credential reachable
by every node (C6's lesson). So the floor moves with the version.

- MNP_VERSION 3.4 -&gt; 4.0 and MNP_MIN_SUPPORTED 3.0 -&gt; 4.0 (meshbay_common);
  transport.js MNP_V/MNP_V_MIN -&gt; 4.0 to match.
- MIN_CLIENT_VERSION 0.13.0 -&gt; 0.16.0 so a stale desktop client is told to
  update before connecting rather than meeting a handshake refusal it cannot
  read; the browser reloads this build from the hub.
- Regenerate tests/golden/dispatch.json: the only change is the `v` the node
  stamps on outbound messages, 3.4 -&gt; 4.0 (56 cases, v field only).
- Document the split and the flag day: MESHBAY_DESIGN.md §5.2 (the handshake
  token is the MNP-audience token), §5.6 (the 4.0 flag day), register E10 and
  decision 23; MESHBAY_NODE_PROTOCOL.md §6.3 (authorize_token binds MNP_AUD)
  and the wire-version banner.

Deploy is coordinated and atomic (common+hub+node+SPA together); a live
browser-to-node validation and the deploy itself remain. common (173), node
(1489, the pre-existing test_cli_golden argparse/prog artifact aside) and hub
(1471) suites all green.

Co-Authored-By: Claude Opus 4.8 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: invitation links no longer bound to an e-mail address</title>
<updated>2026-09-25T15:10:15Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-25T15:10:15Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=90c69477d5f701158112b3c294eff26312f89da6'/>
<id>urn:sha1:90c69477d5f701158112b3c294eff26312f89da6</id>
<content type='text'>
A link is redeemable by whoever opens it first, so it can be sent by any
messaging app. The address is optional (mail + label only); a link lives
7 days, fixed. Adds a Share button; see MESHBAY_DESIGN.md §3.4.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>chore: bump version to 0.16.0</title>
<updated>2026-09-25T11:05:19Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-25T11:04:33Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=10c58792c7591accdb84c92201f77843ec39ee7b'/>
<id>urn:sha1:10c58792c7591accdb84c92201f77843ec39ee7b</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
</feed>
