<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packages/meshbay-hub/tests, branch 0.14</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.14</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.14'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-15T00:48:25Z</updated>
<entry>
<title>fix(ui): a group opened directly lands on the preferred app once preferences load</title>
<updated>2026-09-15T00:48:25Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-15T00:48:25Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=99f95dadee1a3c892bb0bc87e3564f71d07c88e0'/>
<id>urn:sha1:99f95dadee1a3c892bb0bc87e3564f71d07c88e0</id>
<content type='text'>
Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>fix(ui): sidebar stays above a phone's address bar and does not scroll the page</title>
<updated>2026-09-15T00:21:01Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-15T00:18:38Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=acb0d666540dacb092f596dada25822d1d0466f0'/>
<id>urn:sha1:acb0d666540dacb092f596dada25822d1d0466f0</id>
<content type='text'>
Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>feat(hub): session lifetime is an admin setting, and a browser signs out when idle</title>
<updated>2026-09-15T00:21:01Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-15T00:16:39Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=73ad8e4eb566fe682107fa7e50ef624591199e99'/>
<id>urn:sha1:73ad8e4eb566fe682107fa7e50ef624591199e99</id>
<content type='text'>
Browser idle sign-out (media playback counts as activity; not the desktop app),
refresh idle window and maximum session length, in hours. Sign-out now revokes
on the hub, and the profile has "sign out everywhere".

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>feat(hub): usernames are at least 8 characters at registration</title>
<updated>2026-09-15T00:21:01Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-15T00:16:39Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=bdefcd025604f2c3009fe5e0cc01213c2ba62a6a'/>
<id>urn:sha1:bdefcd025604f2c3009fe5e0cc01213c2ba62a6a</id>
<content type='text'>
Existing shorter accounts keep signing in. Test usernames padded to match.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>fix(ui): Search says nothing about groups it leaves out</title>
<updated>2026-09-15T00:21:01Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T22:30:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=027e7d55f3bb57ba5150fd77e8f0114a0baf8d5c'/>
<id>urn:sha1:027e7d55f3bb57ba5150fd77e8f0114a0baf8d5c</id>
<content type='text'>
Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>fix(win): a service-mode daemon can be replaced, and the Node page can link one</title>
<updated>2026-09-14T21:51:36Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T21:51:36Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=e12570f9d1aa2645e6bb223b1417fa0e81957b65'/>
<id>urn:sha1:e12570f9d1aa2645e6bb223b1417fa0e81957b65</id>
<content type='text'>
Two live-reproduced bugs in Windows node start/stop, found sideloading the
0.14.0 build:

- node:start's crash-recovery step killed a service-mode daemon with
  taskkill/CTRL_BREAK, both of which fail with "Access is denied" against a
  process running under the Scheduled Task's own S4U logon session (a
  different session from the Electron app's). The daemon it was meant to
  replace just kept running, unreplaced, and schtasks /run on a task Windows
  still considered Running was then a silent no-op too. Route through
  winServiceTaskEnd() (schtasks /end) first, the way nodeServiceStop/
  nodeServiceRestart already correctly do. service-mode.ps1 also now starts
  the task right after registering it -- Register-ScheduledTask's own
  AtStartup trigger does not run it immediately, so nothing was listening
  until the next reboot.

- The Node page's Start button called node.start() with no arguments, so an
  unlinked node (a fresh install, or one whose hub-side link was lost) could
  never link on Start alone -- only create-group-page.js's own call passed
  {hubUrl, username, token}. Reproduced on a fresh non-service install signed
  in to the real hub: Start hung for ~105s and failed with "could not link",
  pointing at a "Link Node" control that lives on Settings, not the Node
  page (that message is fixed too).

Co-Authored-By: Claude Sonnet 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: a group can be left out of Search, and Search tries every node</title>
<updated>2026-09-14T19:45:53Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T19:45:53Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=cd2745cecff12e894e0dfa702bff6a90f0e8734e'/>
<id>urn:sha1:cd2745cecff12e894e0dfa702bff6a90f0e8734e</id>
<content type='text'>
`search_listed` is a per-group setting on the node, changed by a signed
operator op and carried in the sealed handshake ack. Search reads it after
the handshake and stops there: no index is fetched, cached or merged, in any
of the four views, and the page says how many groups it left out. The switch
is a "Search" section in the group's settings, shown to the operator.

Absent means listed, at every layer: roster default, ack default, and the
client only drops a group on an explicit `false` — so an upgrade or an older
node removes nothing from anyone's Search.

It is a listing preference and protects nothing: the node serves the same
index to Search and to the group page and cannot tell them apart, every
member lists the group by opening it, and a client that ignores the flag
lists it in Search too. Design §9.11 says so, so it is never described as
private. The cost is one handshake per unlisted group, because only the node
knows the setting.

Search also took `nodes[0]` twice — for the index and for the pooled
connection — the defect 4cce50f fixed on the group page only. One
`connectToGroup` now walks the list the same way: a refusal about this
browser stops, `not_hosted` or a failed connection moves on.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01XuNrwLf5EFWCMHzfoEvnpm
</content>
</entry>
<entry>
<title>fix(ui): a signed-in person is never shown the sign-in form</title>
<updated>2026-09-14T14:16:45Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T14:16:45Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=df3b808792daa745b5b0d5b9896ddca8849fe8b1'/>
<id>urn:sha1:df3b808792daa745b5b0d5b9896ddca8849fe8b1</id>
<content type='text'>
The router rendered `#/login`, `#/register` and `#/reset` before it checked
for a user. A browser signed in as one account, opening on a `#/login` left
in the address bar, drew the login form (prefilled by the browser with
another account) under a navigation bar and a sidebar already showing the
first account and its Administration entry.

`#/login` and `#/register` now need no one signed in, and a signed-in person
landing on either is sent home with `location.replace`, so Back does not lead
to the form again. `#/reset` stays reachable: that flow signs in half-way and
still has its progress and result to show.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01T6jPTeocXA1BePekdsgPya
</content>
</entry>
<entry>
<title>feat(ui): an indexing dock above the music bar, on every page</title>
<updated>2026-09-14T09:17:42Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T09:17:42Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=2fb66c5baecdd8b49be904f6244f66ba04f68061'/>
<id>urn:sha1:2fb66c5baecdd8b49be904f6244f66ba04f68061</id>
<content type='text'>
Adding a large directory left the operator nothing to look at once they left
the Settings panel that started it, and nothing at all when it was added from
another machine. A band now sits above the music bar on every page: one row
per group with indexing under way, naming the root being walked, percent,
bytes and files, and the roots waiting their turn; "indexing finished" for a
few seconds at the end. A click opens the group's Settings, and × hides the
row until that group is idle.

Two sources feed it. On the node's own machine the desktop client polls the
loopback `GET /api/index-status` for every group, whatever the route. An
operator's group page forwards MNP `index_progress` pushes, resolving the
root from the roots table it opened; an ordinary member keeps the sidebar dot
only, and a page clears its row when it lets go of the group. Where both
describe a group, loopback wins.

Reconcile passes and watchdog bursts show only past 1 GB or 5 s, so a single
dropped file does not flash a bar. The logic lives in index-dock-model.js,
which has no imports and is tested under node. The dock publishes
`--index-dock-h` and the sidebar stops above it and the music bar.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01T6jPTeocXA1BePekdsgPya
</content>
</entry>
<entry>
<title>fix(hub): Argon2 runs off the event loop, on exactly one worker</title>
<updated>2026-09-14T00:29:13Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-14T00:29:13Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a1aaf31a27d1c1b65efc3c6a25fc6cc8771578ea'/>
<id>urn:sha1:a1aaf31a27d1c1b65efc3c6a25fc6cc8771578ea</id>
<content type='text'>
One derivation is 256 MB and a quarter to half a second of CPU (240 ms here,
485 ms on meshbay.org). All eleven call sites — sign-in, registration, the two
rehashes, passphrase change, reset and account deletion — ran it inline in an
async handler, so every one stopped the whole hub for that long: no request
served, no node socket read, no offer relayed. Measured on a local hub during
eight concurrent sign-ins, the worst `/v1/health` response went from 232 ms to
10 ms; the sign-ins themselves take the same time.

It could not simply go to a thread pool. Two concurrent `lanes=4` derivations
deadlock inside OpenSSL and never return, at no CPU — reproduced on
cryptography 50.0.x / OpenSSL 4.0.x both locally and on meshbay.org, while
`lanes=1` does not. `lanes` is part of every stored hash, so it is not ours to
change, and inline on the loop two derivations could never overlap, which is
the only reason production never hung.

So `auth.hash_password_off_loop` / `verify_password_off_loop` hand the work to
a dedicated executor with exactly one worker. Not a semaphore around
`to_thread`: a cancelled request would release its permit while its thread was
still deriving, and the next derivation would start beside it. One worker also
bounds Argon2's memory to one derivation whatever the number of callers.

`test_argon2_off_loop.py` reads every module for a direct call, pins the single
worker, runs four derivations and four sign-ins concurrently to completion, and
checks the loop keeps turning during a derivation; each fails with its guard
removed. CLAUDE.md and AV9 state the rule and the trap.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01LcF3QKWii7uQ2kSyXErzCt
</content>
</entry>
</feed>
