<feed xmlns='http://www.w3.org/2005/Atom'>
<title>meshbay.git/packaging, branch 0.17</title>
<subtitle>MeshBay — read-only public mirror</subtitle>
<id>https://git.meshbay.org/meshbay.git/atom?h=0.17</id>
<link rel='self' href='https://git.meshbay.org/meshbay.git/atom?h=0.17'/>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/'/>
<updated>2026-09-30T10:37:31Z</updated>
<entry>
<title>fix(hub): the admin allow-list grants an account, not a username</title>
<updated>2026-09-30T10:37:31Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-30T10:37:31Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=8a4651e9d223de856ff085b329801998f95db138'/>
<id>urn:sha1:8a4651e9d223de856ff085b329801998f95db138</id>
<content type='text'>
Each name in admin_usernames is pinned to the first active account seen
holding it (admin_pins), so a name freed by a deletion grants nothing.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>refactor: remove the unused GroupIndex.serialize chain</title>
<updated>2026-09-28T14:24:12Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-28T14:24:12Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=a4b36e5fe31cb671a4cbbdaad75746cd68b601fe'/>
<id>urn:sha1:a4b36e5fe31cb671a4cbbdaad75746cd68b601fe</id>
<content type='text'>
serialize/deserialize had no production caller, and took with them the
per-chunk signature, the ChaCha20 cipher variant and the zstandard
dependency. Key derivations are unchanged. Docs corrected, including
design §4.3's claim that chunks are compressed.

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: Windows installer and desktop app start and stop the node one way</title>
<updated>2026-09-27T20:20:53Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-27T20:20:53Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=8c7e39b6dca758badec6867ab6610fd5e8d93d1e'/>
<id>urn:sha1:8c7e39b6dca758badec6867ab6610fd5e8d93d1e</id>
<content type='text'>
A 0.16 upgrade in service mode left the previous node running: setup's
unelevated taskkill cannot reach session 0, and it ran in customInstall, which
electron-builder inserts after the files are copied. The locked exe was not
replaced, and the new app talked to the old node ("started but could not link",
"No operator paired").

Installer (build/installer.nsh, build/stop-node.ps1):
- customCheckAppRunning, which runs before uninstallOldVersion and extraction,
  stops the node with an embedded stop-node.ps1: control API, then schtasks
  /end, then Stop-Process, and refuses to half-upgrade if one survives.
- An upgrade keeps the mode it finds (task, launcher, previous install),
  restores the sign-in launcher the old uninstaller deletes, and restarts the
  node the way that mode runs it. A silent upgrade of an "at sign-in" install
  used to end with no autostart and no node.
- The uninstaller removes the task and firewall rules only on a real
  uninstall, not on an update.

Desktop app (src/main.js):
- Start, Stop, Restart and node:start go through the CLI's lifecycle verbs
  instead of a second implementation; a child spawned by Electron also held
  Electron's sockets after the app quit.
- "Only while MeshBay is open" is a real mode: the app starts a provisioned
  node at launch and stops the one it started when it quits.
- Switching modes stops the node first -- deleting a task does not end its
  instance, and a new service found the port taken -- keeps the firewall
  rules every mode needs, and starts the node again. A declined or unanswered
  UAC prompt restores the node instead of leaving it stopped, and says that
  nothing changed.
- waiting_for_hub counts as a node that is up; linking waits for a node that
  answers, with a longer deadline, and reports a version mismatch.

Packaging (packaging/win):
- The service task gets no 72-hour limit, runs on battery and ignores a second
  start; service.ps1 status reports a stale registration so setup re-registers
  it; remove ends the running instance before deleting the task.
- build-node-runtime.ps1 starts the frozen daemon in a throwaway profile
  (smoke-node-runtime.ps1) instead of only asking for --help.

The mode that was "Off (start manually)" is labelled "Only while MeshBay is
open" in all ten catalogues.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>fix(node): read the packaged TMDB token in place</title>
<updated>2026-09-26T10:23:16Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-26T10:23:16Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=fc761e7df40eac828d4e9858fab56958078c928b'/>
<id>urn:sha1:fc761e7df40eac828d4e9858fab56958078c928b</id>
<content type='text'>
A node onboarded by the desktop client never ran `init`, so default.env was
never copied to node.env; and default.env was 0600 root, unreadable to a
per-user node anyway. The daemon now loads it beneath node.env, 0644.

Co-Authored-By: Claude Opus 5.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>feat(hub): invitation-link tickets bound to a verified address</title>
<updated>2026-09-23T15:46:48Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-23T15:46:48Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=998f9c69308ee88fac36cfb77dfb6d07c6fa926a'/>
<id>urn:sha1:998f9c69308ee88fac36cfb77dfb6d07c6fa926a</id>
<content type='text'>
group_invite_links holds sha256(ticket) and the invitee's address blind
index; redeeming grants membership to that account only. Owner-only
create/list/cancel (a node token may create, never mail), 20 outstanding
per group, optional mail written by the hub itself and capped at 10 per
sender per day (mail.invite_link_daily_cap). MESHBAY_DESIGN.md §3.4 now
carries the whole link design.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: cite MESHBAY_DESIGN.md and a section instead of the merged notes</title>
<updated>2026-09-19T00:12:47Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-19T00:12:47Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=20a824118c09af15d6c338db4c9480ffe5cbcdb6'/>
<id>urn:sha1:20a824118c09af15d6c338db4c9480ffe5cbcdb6</id>
<content type='text'>
The per-feature design notes were merged into docs/MESHBAY_DESIGN.md and
deleted from the tree on 2026-09-11, but ~230 comments across the three
packages still named them — usually written `docs/musicbay.md §3.2`, as
though the file were still in docs/. A reader had to know §16 existed to
resolve any of them. They now name the section directly.

Every mapping comes from §16, the concordance, which already records where
each old section landed: musicbay -&gt; §9.8, mediacenter -&gt; §9.7 for the
Videos app and §6.5 where the subject is derived data, photos -&gt; §9.9,
auth-confirm -&gt; §3.6, refactoring-search -&gt; §9.11, invite-pairing-v1 -&gt;
§3.4, per-node-identity-v1 -&gt; §3.2, captcha -&gt; §7.7, chat-sender-keys -&gt;
§4.5, apps/refactor-groups -&gt; §9.1–§9.4, desktop-client-v1 per section.
Bare citations of the same documents (`draft-v6 §2.11`, `§4.8`, `§3.4`)
are retargeted too: those collide with real section numbers in the design
document, so leaving them would have been worse than the named form.

Four cases the concordance does not cover, each decided rather than guessed:

  Sub-item references into documents that no longer exist — mediacenter's
  `§3.3 row 4`, `§3.4b/c`, `apps.md §3b` — name rows and sub-items §9.7 and
  §9.2 do not reproduce. The module-level citation stays; the sub-item
  pointer is dropped.

  The V-findings keep their labels but lose the dead `§10.1/` prefix.
  §13.8 lists V1–V13 as per-application open items, which is not what the
  labels mean in these comments, so pointing them at §13.8 would have been
  a false citation.

  `apps.md §5`'s virtualization requirement has no counterpart anywhere in
  the design document. The requirement is stated in the comment itself, so
  the citation is dropped rather than aimed at a section that does not say
  it.

  Comments that attributed a *sentence* to an old note — musicbay's "several
  thousand files" example, its "what got measured" note, its measured
  ~11%/~26% cover-art figures, the "original no root, whole shared tree"
  call — state the fact without attribution now. §9.8 does not contain those
  sentences and citing it for them would have been wrong.

CLAUDE.md's "a reference to a document that no longer exists" row now says
the concordance is for git history and out-of-tree material; the code cites
sections directly.

Verified: 2851 passed, 4 skipped. The 12 errors in the run are the Firefox
leg of test_sticky_header.py's browser harness, which is broken at the
browser level on this machine — headless Firefox (snap) dies with
`[GFX1-]: RenderCompositorSWGL failed mapping default framebuffer`, renders
nothing, and the probe exits `{"error": "no measurement"}` after its full
90s wait. Chrome runs the same 12 assertions in 3.2s and passes. Nothing
here can affect it: every changed line in style.css is inside a comment.
Also checked: ast.parse on every changed .py, `node --check` on every
changed .js, the /* */ balance in style.css, and that no changed line
exceeds the width its file already used.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>docs: drop the references to design notes that live outside the repo</title>
<updated>2026-09-18T23:15:53Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-18T23:15:53Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=cc0820de8d8c33560c44bd6a0864de30e33a0109'/>
<id>urn:sha1:cc0820de8d8c33560c44bd6a0864de30e33a0109</id>
<content type='text'>
Seventeen comments across the Windows packaging targets pointed at
C:\Users\admin\devel\light-client.md and msix-installer.md -- absolute
paths on one developer's machine, unreadable to anyone else who clones
this repository and unverifiable by any test here.

The surrounding prose already carried the substance in every case, so
these are removals, not rewrites, with two exceptions where the pointer
was doing real work:

  electron-builder.msix.yml's header told the reader to go read §4 and §8
  first. It now states the fact directly (an AppX/MSIX install never
  elevates, by design, so the package carries none of installer.nsh's
  elevation logic) and says the open items are called out at each
  declaration below -- which they already were, at `capabilities` and
  `customExtensionsPath`.

  The two "msix-installer.md §8" citations become "an open item" / "the
  other open item", beside the description of the item that was already
  there.

Paragraphs the removals left ragged are re-wrapped.

Verified: node suite 1403 pass / 4 skip (71 of them test_packaging_win.py),
both electron-builder configs still parse as YAML, node --check on main.js.
The .ps1 edits are inside &lt;# #&gt; comment headers plus one deleted Write-Host
in a block that keeps two others; no pwsh on this machine to parse them.

Not touched, and much larger: ~230 comments elsewhere in the codebase cite
per-feature design notes (musicbay.md, mediacenter.md, auth-confirm.md and
twenty more) that were merged into docs/MESHBAY_DESIGN.md.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
</content>
</entry>
<entry>
<title>feat: decode and re-encode video on the GPU where there is one</title>
<updated>2026-09-18T12:37:08Z</updated>
<author>
<name>Christophe Besson</name>
<email>cbesson@gmail.com</email>
</author>
<published>2026-09-18T12:37:08Z</published>
<link rel='alternate' type='text/html' href='https://git.meshbay.org/meshbay.git/commit/?id=d22ce0ba5aebfff5ffaea97982472f876af5da22'/>
<id>urn:sha1:d22ce0ba5aebfff5ffaea97982472f876af5da22</id>
<content type='text'>
A 1080p film is decoded by whoever watches it and re-encoded by the node
when no browser can decode the source. Both were on the CPU, and on an
Atom or Celeron mini-PC neither reaches real time — which is what
`transcode_incompatible_video` exists to refuse. This adds the mechanism
that makes refusing it unnecessary.

Node — `hwaccel.py`: VA-API on Linux, Quick Sync or NVENC on Windows,
established by encoding 1080p and reading the file back with ffprobe.
Nothing is accepted that does not produce the exact profile and level
`stream_init` announces, since the client checks that string before it
trusts a byte: an encoder that wrote another level would make the node's
own codec string a lie, and ffmpeg takes `-level 4.1` and `-level 41`
from h264_qsv without saying which it understood. Three modes per
stream — hardware decode and encode, hardware encode alone, libx264 —
demoted per source codec, because a GPU that decodes HEVC may have no
decoder for MPEG-4 Part 2 and only asking it finds out. A mode that
fails is detected on an empty stdout before `stream_init` goes out, so
the viewer sees one working stream and never an error.

Client — Chromium ships VA-API off on Linux. It is enabled where a
render node and a driver are present, then verified through
`navigator.mediaCapabilities`: a no moves to the next GL backend on the
next launch and an exhausted list drops the switches, so a renamed
feature cannot pass for a feature that is on and `--ignore-gpu-blocklist`
cannot survive on a machine it did not help. Feature lists now merge
rather than overwrite — `appendSwitch` replaces the value, and a second
caller would have silently cancelled the mDNS switch aiortc depends on.

Packaging — the drivers are weak dependencies on all four formats, so a
machine without a GPU installs exactly as before. `dpkg -i` and
`rpm -ivh` ignore weak deps; `packaging/README.md` now says so. Windows
needs no driver: the bundled ffmpeg already carries h264_qsv and
h264_nvenc, and a re-pin that dropped them would cost every low-power
Windows node its hardware encoding silently.

AMD on Windows (AMF) and macOS (VideoToolbox) are named gaps, not
oversights: neither could be tried anywhere in this project, and both
re-encode in software as before.

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