<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/docs/MESHBAY_DESIGN.md, 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-25T11:05:19Z</updated>
<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>
<entry>
<title>feat(client): fetch the media apps, the player, settings and search on first use</title>
<updated>2026-09-25T08:47:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-25T08:47:37Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=0bdce359c0bf19fa98f1b7f9975be32704abe1f0'/>
<id>urn:sha1:0bdce359c0bf19fa98f1b7f9975be32704abe1f0</id>
<content type='text'>
apps.js registers Videos, Music, Photos and every settings pane through
lazy.js; the group page does the same for the video player and the
settings panel, and the shell for the search page. The first download
goes from 49 modules / 386 KB gzip to 37 / 289 KB; opening Music now
fetches music-app.js and media-tiles.js and nothing of Videos.
test_first_load_is_lean holds the eager graph; test_spa_imports checks
that every on-demand load names an export that exists.

Co-Authored-By: Claude Opus 5.5 &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>docs: the transcoded-seek test passes without transcoding</title>
<updated>2026-09-24T14:45:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-24T00:33:06Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=eaac12bf945cab10f02429aa8d85239f22280554'/>
<id>urn:sha1:eaac12bf945cab10f02429aa8d85239f22280554</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: listing a group's folders walks every root on the event loop</title>
<updated>2026-09-24T14:45:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T20:26:11Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=45f1564ae22b14509d6e9ee1d864ed445a896d13'/>
<id>urn:sha1:45f1564ae22b14509d6e9ee1d864ed445a896d13</id>
<content type='text'>
Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(hub): Search reaches each group with one offer, and a busy hub is not a dead node</title>
<updated>2026-09-23T22:10:41Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T22:10:41Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=059eb0318daf27d98bd1c9532705ff406c0a10f8'/>
<id>urn:sha1:059eb0318daf27d98bd1c9532705ff406c0a10f8</id>
<content type='text'>
The other half of the 4G failure. The page negotiated every group twice: the
sweep opened a connection, read the index and closed it, then the warm-up
opened the same group again. The sweep, the warm-up and the tiles each had a
concurrency ceiling of their own, and together they went past what the hub
admits per account. Whatever the hub refused was then reported as "node
unreachable" and remembered as down, which put that group last next time.

- Every connection goes through ConnectionPool, which holds the page's one
  ceiling (six at once, sized for twenty groups on a phone) and keeps what
  the sweep opened for the tiles. A visit costs one offer per group. A
  refresh costs none for a connection that answers a four-second ping, and
  a connection that died while the phone slept is replaced, not waited on.
- A connection whose index is being read is held against eviction. With
  more groups than the pool keeps, it was otherwise the least recently used
  one.
- Negotiations still under way when the page closes close what they get,
  and a sweep cut short that way remembers nobody as down.
- transport.js sends an offer again on 429, 502 or 503, honouring
  Retry-After, with jittered waits of about twenty seconds at worst. Search
  counts each retry as progress. A 404, 403 or 504 still fails at once, so
  a dead node costs no time.

The fan-out tests assumed a ceiling of three and were re-measured: four dead
groups of twelve now hold nothing back, even on a first visit. The pool and
the retry run as shipped code, lifted as text, against a fake clock. Each
guard was checked by removing it and seeing its test fail.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(hub): a redeemed invitation link leaves the owner's list</title>
<updated>2026-09-23T17:30:47Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T17:30:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=95cec0e0bbc28e930f297f44bbd3dbf4d63f0bc2'/>
<id>urn:sha1:95cec0e0bbc28e930f297f44bbd3dbf4d63f0bc2</id>
<content type='text'>
The list under "Invite by link" answered every ticket the group had ever
minted, so a link that somebody had already used sat there saying "used by
&lt;name&gt;" for the thirty days of KEEP_REDEEMED — beside the member row it had
just produced, and above the links that still wait for somebody, which are
the only ones there is anything to do about. The node's own `member list`
had never shown them: it selects `used_at IS NULL`.

The listing now selects `redeemed_by IS NULL`, and drops the `redeemed`
status and the `redeemed_by` field with it. The row itself still lives for
KEEP_REDEEMED, which is what lets a reload or a second tab of the invitation
page be answered rather than refused; its comment says that now instead of
naming a list it is no longer in.

The SPA filters too, because the desktop client's copy of this interface can
be newer than the hub it is signed into.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(hub): an invitation no longer holds back its invitee's sign-up code</title>
<updated>2026-09-23T17:01:37Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T17:01:37Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=3a27a5cd3ae1e752b17d27844cee3d18a35d4498'/>
<id>urn:sha1:3a27a5cd3ae1e752b17d27844cee3d18a35d4498</id>
<content type='text'>
The per-recipient cooldown was shared by every purpose, so the code a
person asked for by registering within two minutes of an invitation
link was refused, silently. The cooldown is now per family (invitations
vs the account's own steps); the daily cap still counts everything.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: qualify what an invitation link changes about the code</title>
<updated>2026-09-23T16:16:44Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T16:16:44Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1f6b67c7bfc8078991a4607bb0419aea15bfd54c'/>
<id>urn:sha1:1f6b67c7bfc8078991a4607bb0419aea15bfd54c</id>
<content type='text'>
The security claims table, §3.4's property 2, the protocol's stated
limits, the quickstart and the user guide's defaults now say where a
link's code differs: bound to its account only when redeemed, and held
by the hub when the inviter asks it to mail.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat(node): member invite --link and member cancel in the CLI</title>
<updated>2026-09-23T16:16:02Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T16:16:02Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=1d169141f3a5542efda2f7fdb0bb88308c06191b'/>
<id>urn:sha1:1d169141f3a5542efda2f7fdb0bb88308c06191b</id>
<content type='text'>
The CLI makes both halves itself — the node's code, then the hub's
ticket bound to the address — and prints the link; a refused ticket
takes the code back, and cancel takes back both. The CLI never asks the
hub to mail.

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