Commits
When /var/download drops below 100 GiB free the guard now stops all
transmission torrents (it has no native low-disk pause like sabnzbd's
download_free) and posts a Matrix message to !MRjkvAaFPsjdYCpeiZ:lassul.us
via the archiver bot's access token. Torrents are restarted and a
recovery message sent once space climbs back above the threshold. State
is tracked in StateDirectory so alerts fire only on transitions, not
every run.
Assisted-by: Claude Code (claude-opus-4-8)
The previous guard only throttled sabnzbd below 100 GiB and paused at a
15 GiB floor, which still let the disk fill close to full. Use sabnzbd's
native download_free/complete_free (continuous pause + auto-resume) set
to 100 GiB so it pauses the moment free space drops below that, and have
the guard keep those configured. Transmission has no equivalent low-disk
guard, so the guard still throttles its downloads to a trickle below the
threshold while leaving seeding alone.
Assisted-by: Claude Code (claude-opus-4-8)
Assisted-by: Claude Code (claude-opus-4-8)
Recent wireguard-tools resolve the peer Endpoint in the namespace where
`wg syncconf` runs. The transmission netns has no route until the tunnel
is up, so resolving europe.vpn.airdns.org from inside it always fails;
wg burns ~70s of DNS-retry backoff per attempt before erroring. During a
nixos switch that restarts transmission-netns this stalled the whole
deploy for >2min and left the service (and the download stack) failed.
Resolve the endpoint in the main netns (which has connectivity, and is
already gated on the `host` check above) and hand wg a numeric Endpoint,
so the tunnel comes up instantly. Also fix the bare `sleep` in the DNS
wait loop, which errored under `set -e` instead of retrying.
Assisted-by: Claude Code (claude-opus-4-8)
Adds download-space-guard: a 5-min oneshot that caps sabnzbd and
transmission speeds once free space on /var/download drops below 100 GiB,
and pauses sabnzbd below a 15 GiB floor. This prevents a full disk from
hard-wedging sabnzbd with an unrecoverable "Disk full! Forcing Pause";
the guard auto-resumes once space frees up.
Assisted-by: Claude Code (claude-opus-4-8)
/boot is only 1 GiB (disk.nix). Without configurationLimit, GRUB retains
every generation's kernel+initrd until the ESP fills, at which point the
bootloader install fails ("No space left on device") and deploys can't
finish. Keep the 10 most recent; older kernels get pruned automatically.
Assisted-by: Claude Code (claude-fable-5)
The whole system lives on one btrfs-on-LUKS-on-NVMe device, so downloads
and builds were starving latency-sensitive reads — launching a terminal
would freeze for seconds (PSI full IO pressure spikes, near-zero CPU/mem
pressure). Three independent fixes:
- mq-deadline scheduler on nvme0n1: the default "none" gives no read/write
fairness, so reads queued behind up to 1023 writes.
- vm.dirty_bytes/dirty_background_bytes as small fixed values instead of
the ratio defaults (~6/12 GB on 62 GB RAM) that caused multi-GB flush
bursts.
- bypassWorkqueues on the LUKS device to drop the kcryptd serialization
point (safe: AES-NI is present).
Assisted-by: Claude Code (claude-fable-5)
The clan bump removes the `clan.core.vars.generators.<name>.migrateFact`
option, which made every host fail to evaluate. Fact migration is a
one-time step that's long complete, so drop the now-removed option from
all generators (retiolum, syncthing, shadowsocks, hedgedoc, mycelium,
hotdog/orange containers, nextcloud, wiregrill, nix-serve, matrix).
Assisted-by: Claude Code (claude-fable-5)
Level 3 maps to per-packet Trace logging in tincr, which flooded
journald (tens of thousands of suppressed messages per minute) and
rotated all other units' logs out of the journal within hours,
leaving nothing to debug the whatsapp bridge with.
Assisted-by: Claude Code (claude-fable-5[1m])
Outgoing messages went unbridged silently from 2026-05-28 to 2026-06-08
(WhatsApp rejecting sends from the outdated client; fixed by the bridge
update) and no error ever reached the client. Positive per-message
confirmation makes a broken send path visible.
Assisted-by: Claude Code (claude-fable-5[1m])
simple-nixos-mailserver now stores per-user Sieve scripts in each user's
Dovecot home (~/sieve, active link ~/.dovecot.sieve) instead of the old
global /var/sieve, and asserts stateVersion >= 5 when enableManageSieve is
set. Existing scripts were migrated with migration #5 on neoprism.
Assisted-by: Claude Code (claude-opus-4-8[1m])
Run an n2n v3 supernode and point n2n.lassul.us at neoprism.
- Listens on UDP 7654 (main n2n protocol) and TCP 7654 (aux listener used
by edges started with -S2 when their network blocks UDP); both opened in
the firewall.
- Starts as root: the supernode unconditionally drops privileges to nobody
(uid/gid 65534) and aborts if the setuid() fails, so DynamicUser does not
work. It ends up running as uid 65534 with the remaining hardening.
- Sets the federation name with -F krebs (n2n prepends '*', yielding the
federation community '*krebs') to avoid the default '*Federation', which
n2n warns is for testing only. This only scopes supernode-to-supernode
federation, not the community (-c) edges use.
Assisted-by: Claude Code (claude-opus-4-8[1m])
Firefox started from the systemd user manager (firefox.service) only got
DISPLAY but not XDG_SESSION_TYPE. With DISPLAY set and XDG_SESSION_TYPE
unset, its WebRTC capturer takes the X11/XWayland screencast path, which
captures a black screen under sway. Exporting XDG_SESSION_TYPE=wayland
makes it use the PipeWire portal instead, fixing screen sharing.
Assisted-by: Claude Code (claude-opus-4-8[1m])
The hardcoded `export SWAYSOCK=/run/user/$(id -u)/sway-ipc.sock` in
extraSessionCommands is ignored by sway >=1.11, which creates its own per-pid
socket (sway-ipc.$uid.$pid.sock). The dead path got baked into the firefox and
workspace-manager user services, so every swaymsg call failed and the extension
silently skipped tab restore on each workspace switch. Drop the export and let
the existing import-environment propagate the real socket sway advertises.
Also:
- workspace-menu: "Restore tabs" used pkgs.firefox (upstream stable) instead of
the wrapped Dev Edition daemon, launching a separate browser/profile
- workspace-tabs: never overwrite a saved workspace with an empty tab list, so
the transient blank window after a Firefox restart can't wipe real tabs
Assisted-by: Claude Code (claude-opus-4-8[1m])
It's too close to shift+insert (paste) and the default reset binding
scrambles running programs on accidental presses.
Assisted-by: Claude Code (claude-opus-4-8[1m])
mumble-reminder: add 26.05 Release Animal Yarara
- firefox.service: restartIfChanged/stopIfChanged = false so nixos-rebuild
switch no longer kills all open browser windows
- xdg-desktop-portal-wlr: retry until system-wide pipewire is reachable
(RestartSec=2, startLimitIntervalSec=0) instead of tripping the start-limit
at boot and staying dead, which silently broke screensharing
- workspace-tabs: register the anchor-window scratchpad rule statically in the
sway config, only persist/restore http(s) URLs, and skip anchor-titled
windows in the sway mapping, so the anchor no longer leaks into workspace
files and reappears as a phantom window after a restart
Assisted-by: Claude Code (claude-opus-4-8[1m])
The btmtk WMT-funcc fix (e3ac0d9f1a20) is now upstream; the override
fails to apply against 7.0.10. Use linuxPackages_latest directly.
Assisted-by: Claude Code (claude-opus-4-7)
Adjusts /var/download/games to ipfs:users mode 2775 so the upload
service (running as ipfs) can write into it while lass keeps write via
the users group. systemd-tmpfiles refuses to bootstrap this transition
when child and parent have different owners, so the first chown was
done out-of-band; this `z` rule keeps the perms from drifting.
Also drops the non-existent `download` group from the staging dir
tmpfiles entries (download group only exists on the yellow container,
not on the host).
Assisted-by: Claude Code (claude-opus-4-7)
Adds an ipfs-upload service (Python http.server on 127.0.0.1:8090) and
routes POSTs on ipfs.lassul.us to it (GET/HEAD still go to the kubo
gateway, via nginx upstream + map on $request_method).
Each chunk is written to a deterministic staging file under
/var/download/incoming/uploader/<sha256(rel)>.upload (same fs as the
destination, outside the pin-watcher's watch dirs). When the staging
size reaches the Content-Range total, it is atomically renamed to
/var/lib/ipfs/download/<rel> and pinned with ipfs add --nocopy --pin.
Protocol:
POST /<path> one-shot upload
POST /<path> with Content-Range bytes a-b/T resumable chunk
POST /<path> with Content-Length: 0 returns current offset
Assisted-by: Claude Code (claude-opus-4-7)
Pairing an Xbox Wireless Controller over Bluetooth (LE HoG) on stock
bluez 5.86 failed with "Connection terminated due to authentication
failure" on every connection attempt after pair. Enable xpadneo so the
hid_xpadneo driver handles the controller, and add two bluez tweaks
that resolve the LE auth loop:
* JustWorksRepairing = always: accept fresh pairings without requiring
a manual remove of the prior bond.
* Privacy = device: pin the host BT address so the controller's stored
bond key isn't invalidated when bluez rotates resolvable addresses.
Assisted-by: Claude Code (claude-opus-4-7[1m])
Upstream 634a4408c061 ("Bluetooth: btmtk: validate WMT event SKB
length before struct access"), backported into 7.0.7, rejects the
shorter WMT FUNC_CTRL events MT7925 firmware actually sends, leaving
hci0 stuck DOWN with "Failed to send wmt func ctrl (-22)".
Apply upstream e3ac0d9f1a20 ("Bluetooth: btmtk: accept too short
WMT FUNC_CTRL events") on top of linux_latest until the fix is
backported into linux-7.0.y stable. Remove this override once nixpkgs
ships a kernel that already contains the fix.
Assisted-by: Claude Code (claude-opus-4-7[1m])
Was killing remote tmux sessions the moment all ssh clients detached —
the actual cause of "tmux dies when everyone disconnects from neoprism".
Linger/KillUserProcesses were red herrings; tmux itself was tearing
the sessions down from inside.
Assisted-by: Claude Code (claude-opus-4-7)
Without lingering, systemd-logind tears down user@1337.service when the
last session disconnects, killing tmux along with the user slice. The
KillUserProcesses=no setting only prevents logind from explicitly killing
scope leftovers — it does not keep the user manager alive.
Assisted-by: Claude Code (claude-opus-4-7)
nixpkgs nginx is compiled with /tmp/nginx_* as temp paths. Combined
with systemd PrivateTmp, host-side cleanup of /tmp can leave nginx
with missing temp dirs after restart, breaking large POSTs (e.g.
matrix /keys/upload) and federation PUTs. Move to /var/cache/nginx,
which is auto-created via the systemd unit's CacheDirectory=nginx.
Assisted-by: Claude Code (claude-opus-4-7)
Confused agents that did plain `ipfs add` of files already on disk
caused ~9G of blockstore/filestore duplication and ~10G of
blockstore-only content. Shadow the CLI with a wrapper that rejects
`add` calls missing --nocopy; the kubo daemon and pin-watcher use
absolute store paths so they keep working.
Assisted-by: Claude Code (claude-opus-4-7)
Pin-watcher was creating MFS entries for aria2 control files that get
deleted once the download finishes, leaving orphans in the index. Also
ensure the cid-map file is world-readable after creation and after
reconcile rewrites it.
Assisted-by: Claude Code (claude-opus-4-7)
Upstream NixOS tinc module's preStart chowns hosts/ and invitations/
but not the network dir itself, so tincr can't persist the per-peer
address bootstrap cache it tries to write under /etc/tinc/retiolum/
addrcache/. The save fails with "Permission denied" (debug-only), the
cache stays empty, and retries to peers without a live meta-conn fall
back to DNS instead of the last-known address. Drop this tmpfiles rule
once nixpkgs#520533 lands.
Assisted-by: Claude Code (claude-opus-4-7)
New extension queries /api/tags at startup and registers every model
under a single "ollama" provider via the OpenAI-compat layer. Endpoint
points at neoprism.r:11434 — reachable from retiolum via the c-base-ai
autossh tunnel.
settings-env.patch also patches SettingsManager.reload() so the
PI_SETTINGS_FILE merge survives resourceLoader.reload() — without this
the bundled extensions list was being wiped after initial load.
Persistent autossh tunnel via tunnel.c-base.org exposing
ai.cbrp3.c-base.org:11434 on neoprism, reachable from retiolum at
neoprism.r:11434. ssh key generated by clan vars; pubkey must be
installed on tunnel.c-base.org under lassulus before the tunnel comes up.
PR Mic92/tincr#5 (merged 2026-05-11) removes the auto-purge in
on_del_edge that drove reachability oscillation in mixed
tincr/tinc-1.1pre18 meshes.
On top, pin Lassulus/tincr@a25eec05 which adds udp_addr clearing on
ENETUNREACH/EHOSTUNREACH/EAFNOSUPPORT/EADDRNOTAVAIL — without it,
IPv4-only hosts retry the same broken cached IPv6 udp_addr forever
when a peer's wire-advertised contact is v6 only. Submitted upstream
as Mic92/tincr#6.
Under load, the swaymsg get_tree subprocess could time out, the host
returned an empty windows list, and the extension treated that as "no
Firefox windows anywhere" — restoring a window for a workspace that
already had one. Distinguish query failure from a genuinely empty
result and skip restoration when state is unknown.
Adds `s say "..."` which speaks via flite TTS and posts a desktop
notification. The notify skill documents when to use it; the wrapper
registers the skill and allows `s` in Bash so calls don't prompt.
Upstream creates /var/lib/mautrix-discord at mode 0770 owned by
mautrix-discord:mautrix-discord, but only adds matrix-synapse to the
mautrix-discord-registration supplementary group. That left synapse
unable to traverse the directory to read discord-registration.yaml,
crashing matrix-synapse on startup.
dhtclient only announces to the DHT. lassie (and IPNI/cid.contact)
never learned about neoprism's pins, so all fetchIpfs calls fell back
to archive.org. autoclient keeps DHT client mode but also pushes
provider records to IPNI via HTTP, making content discoverable by
lassie without a fallbackUrl.
ns1.first-ns.de, robotns2.second-ns.de, robotns3.second-ns.com
When /var/download drops below 100 GiB free the guard now stops all
transmission torrents (it has no native low-disk pause like sabnzbd's
download_free) and posts a Matrix message to !MRjkvAaFPsjdYCpeiZ:lassul.us
via the archiver bot's access token. Torrents are restarted and a
recovery message sent once space climbs back above the threshold. State
is tracked in StateDirectory so alerts fire only on transitions, not
every run.
Assisted-by: Claude Code (claude-opus-4-8)
The previous guard only throttled sabnzbd below 100 GiB and paused at a
15 GiB floor, which still let the disk fill close to full. Use sabnzbd's
native download_free/complete_free (continuous pause + auto-resume) set
to 100 GiB so it pauses the moment free space drops below that, and have
the guard keep those configured. Transmission has no equivalent low-disk
guard, so the guard still throttles its downloads to a trickle below the
threshold while leaving seeding alone.
Assisted-by: Claude Code (claude-opus-4-8)
Recent wireguard-tools resolve the peer Endpoint in the namespace where
`wg syncconf` runs. The transmission netns has no route until the tunnel
is up, so resolving europe.vpn.airdns.org from inside it always fails;
wg burns ~70s of DNS-retry backoff per attempt before erroring. During a
nixos switch that restarts transmission-netns this stalled the whole
deploy for >2min and left the service (and the download stack) failed.
Resolve the endpoint in the main netns (which has connectivity, and is
already gated on the `host` check above) and hand wg a numeric Endpoint,
so the tunnel comes up instantly. Also fix the bare `sleep` in the DNS
wait loop, which errored under `set -e` instead of retrying.
Assisted-by: Claude Code (claude-opus-4-8)
Adds download-space-guard: a 5-min oneshot that caps sabnzbd and
transmission speeds once free space on /var/download drops below 100 GiB,
and pauses sabnzbd below a 15 GiB floor. This prevents a full disk from
hard-wedging sabnzbd with an unrecoverable "Disk full! Forcing Pause";
the guard auto-resumes once space frees up.
Assisted-by: Claude Code (claude-opus-4-8)
/boot is only 1 GiB (disk.nix). Without configurationLimit, GRUB retains
every generation's kernel+initrd until the ESP fills, at which point the
bootloader install fails ("No space left on device") and deploys can't
finish. Keep the 10 most recent; older kernels get pruned automatically.
Assisted-by: Claude Code (claude-fable-5)
The whole system lives on one btrfs-on-LUKS-on-NVMe device, so downloads
and builds were starving latency-sensitive reads — launching a terminal
would freeze for seconds (PSI full IO pressure spikes, near-zero CPU/mem
pressure). Three independent fixes:
- mq-deadline scheduler on nvme0n1: the default "none" gives no read/write
fairness, so reads queued behind up to 1023 writes.
- vm.dirty_bytes/dirty_background_bytes as small fixed values instead of
the ratio defaults (~6/12 GB on 62 GB RAM) that caused multi-GB flush
bursts.
- bypassWorkqueues on the LUKS device to drop the kcryptd serialization
point (safe: AES-NI is present).
Assisted-by: Claude Code (claude-fable-5)
The clan bump removes the `clan.core.vars.generators.<name>.migrateFact`
option, which made every host fail to evaluate. Fact migration is a
one-time step that's long complete, so drop the now-removed option from
all generators (retiolum, syncthing, shadowsocks, hedgedoc, mycelium,
hotdog/orange containers, nextcloud, wiregrill, nix-serve, matrix).
Assisted-by: Claude Code (claude-fable-5)
simple-nixos-mailserver now stores per-user Sieve scripts in each user's
Dovecot home (~/sieve, active link ~/.dovecot.sieve) instead of the old
global /var/sieve, and asserts stateVersion >= 5 when enableManageSieve is
set. Existing scripts were migrated with migration #5 on neoprism.
Assisted-by: Claude Code (claude-opus-4-8[1m])
Run an n2n v3 supernode and point n2n.lassul.us at neoprism.
- Listens on UDP 7654 (main n2n protocol) and TCP 7654 (aux listener used
by edges started with -S2 when their network blocks UDP); both opened in
the firewall.
- Starts as root: the supernode unconditionally drops privileges to nobody
(uid/gid 65534) and aborts if the setuid() fails, so DynamicUser does not
work. It ends up running as uid 65534 with the remaining hardening.
- Sets the federation name with -F krebs (n2n prepends '*', yielding the
federation community '*krebs') to avoid the default '*Federation', which
n2n warns is for testing only. This only scopes supernode-to-supernode
federation, not the community (-c) edges use.
Assisted-by: Claude Code (claude-opus-4-8[1m])
Firefox started from the systemd user manager (firefox.service) only got
DISPLAY but not XDG_SESSION_TYPE. With DISPLAY set and XDG_SESSION_TYPE
unset, its WebRTC capturer takes the X11/XWayland screencast path, which
captures a black screen under sway. Exporting XDG_SESSION_TYPE=wayland
makes it use the PipeWire portal instead, fixing screen sharing.
Assisted-by: Claude Code (claude-opus-4-8[1m])
The hardcoded `export SWAYSOCK=/run/user/$(id -u)/sway-ipc.sock` in
extraSessionCommands is ignored by sway >=1.11, which creates its own per-pid
socket (sway-ipc.$uid.$pid.sock). The dead path got baked into the firefox and
workspace-manager user services, so every swaymsg call failed and the extension
silently skipped tab restore on each workspace switch. Drop the export and let
the existing import-environment propagate the real socket sway advertises.
Also:
- workspace-menu: "Restore tabs" used pkgs.firefox (upstream stable) instead of
the wrapped Dev Edition daemon, launching a separate browser/profile
- workspace-tabs: never overwrite a saved workspace with an empty tab list, so
the transient blank window after a Firefox restart can't wipe real tabs
Assisted-by: Claude Code (claude-opus-4-8[1m])
- firefox.service: restartIfChanged/stopIfChanged = false so nixos-rebuild
switch no longer kills all open browser windows
- xdg-desktop-portal-wlr: retry until system-wide pipewire is reachable
(RestartSec=2, startLimitIntervalSec=0) instead of tripping the start-limit
at boot and staying dead, which silently broke screensharing
- workspace-tabs: register the anchor-window scratchpad rule statically in the
sway config, only persist/restore http(s) URLs, and skip anchor-titled
windows in the sway mapping, so the anchor no longer leaks into workspace
files and reappears as a phantom window after a restart
Assisted-by: Claude Code (claude-opus-4-8[1m])
Adjusts /var/download/games to ipfs:users mode 2775 so the upload
service (running as ipfs) can write into it while lass keeps write via
the users group. systemd-tmpfiles refuses to bootstrap this transition
when child and parent have different owners, so the first chown was
done out-of-band; this `z` rule keeps the perms from drifting.
Also drops the non-existent `download` group from the staging dir
tmpfiles entries (download group only exists on the yellow container,
not on the host).
Assisted-by: Claude Code (claude-opus-4-7)
Adds an ipfs-upload service (Python http.server on 127.0.0.1:8090) and
routes POSTs on ipfs.lassul.us to it (GET/HEAD still go to the kubo
gateway, via nginx upstream + map on $request_method).
Each chunk is written to a deterministic staging file under
/var/download/incoming/uploader/<sha256(rel)>.upload (same fs as the
destination, outside the pin-watcher's watch dirs). When the staging
size reaches the Content-Range total, it is atomically renamed to
/var/lib/ipfs/download/<rel> and pinned with ipfs add --nocopy --pin.
Protocol:
POST /<path> one-shot upload
POST /<path> with Content-Range bytes a-b/T resumable chunk
POST /<path> with Content-Length: 0 returns current offset
Assisted-by: Claude Code (claude-opus-4-7)
Pairing an Xbox Wireless Controller over Bluetooth (LE HoG) on stock
bluez 5.86 failed with "Connection terminated due to authentication
failure" on every connection attempt after pair. Enable xpadneo so the
hid_xpadneo driver handles the controller, and add two bluez tweaks
that resolve the LE auth loop:
* JustWorksRepairing = always: accept fresh pairings without requiring
a manual remove of the prior bond.
* Privacy = device: pin the host BT address so the controller's stored
bond key isn't invalidated when bluez rotates resolvable addresses.
Assisted-by: Claude Code (claude-opus-4-7[1m])
Upstream 634a4408c061 ("Bluetooth: btmtk: validate WMT event SKB
length before struct access"), backported into 7.0.7, rejects the
shorter WMT FUNC_CTRL events MT7925 firmware actually sends, leaving
hci0 stuck DOWN with "Failed to send wmt func ctrl (-22)".
Apply upstream e3ac0d9f1a20 ("Bluetooth: btmtk: accept too short
WMT FUNC_CTRL events") on top of linux_latest until the fix is
backported into linux-7.0.y stable. Remove this override once nixpkgs
ships a kernel that already contains the fix.
Assisted-by: Claude Code (claude-opus-4-7[1m])
Without lingering, systemd-logind tears down user@1337.service when the
last session disconnects, killing tmux along with the user slice. The
KillUserProcesses=no setting only prevents logind from explicitly killing
scope leftovers — it does not keep the user manager alive.
Assisted-by: Claude Code (claude-opus-4-7)
nixpkgs nginx is compiled with /tmp/nginx_* as temp paths. Combined
with systemd PrivateTmp, host-side cleanup of /tmp can leave nginx
with missing temp dirs after restart, breaking large POSTs (e.g.
matrix /keys/upload) and federation PUTs. Move to /var/cache/nginx,
which is auto-created via the systemd unit's CacheDirectory=nginx.
Assisted-by: Claude Code (claude-opus-4-7)
Confused agents that did plain `ipfs add` of files already on disk
caused ~9G of blockstore/filestore duplication and ~10G of
blockstore-only content. Shadow the CLI with a wrapper that rejects
`add` calls missing --nocopy; the kubo daemon and pin-watcher use
absolute store paths so they keep working.
Assisted-by: Claude Code (claude-opus-4-7)
Upstream NixOS tinc module's preStart chowns hosts/ and invitations/
but not the network dir itself, so tincr can't persist the per-peer
address bootstrap cache it tries to write under /etc/tinc/retiolum/
addrcache/. The save fails with "Permission denied" (debug-only), the
cache stays empty, and retries to peers without a live meta-conn fall
back to DNS instead of the last-known address. Drop this tmpfiles rule
once nixpkgs#520533 lands.
Assisted-by: Claude Code (claude-opus-4-7)
New extension queries /api/tags at startup and registers every model
under a single "ollama" provider via the OpenAI-compat layer. Endpoint
points at neoprism.r:11434 — reachable from retiolum via the c-base-ai
autossh tunnel.
settings-env.patch also patches SettingsManager.reload() so the
PI_SETTINGS_FILE merge survives resourceLoader.reload() — without this
the bundled extensions list was being wiped after initial load.
PR Mic92/tincr#5 (merged 2026-05-11) removes the auto-purge in
on_del_edge that drove reachability oscillation in mixed
tincr/tinc-1.1pre18 meshes.
On top, pin Lassulus/tincr@a25eec05 which adds udp_addr clearing on
ENETUNREACH/EHOSTUNREACH/EAFNOSUPPORT/EADDRNOTAVAIL — without it,
IPv4-only hosts retry the same broken cached IPv6 udp_addr forever
when a peer's wire-advertised contact is v6 only. Submitted upstream
as Mic92/tincr#6.
Under load, the swaymsg get_tree subprocess could time out, the host
returned an empty windows list, and the extension treated that as "no
Firefox windows anywhere" — restoring a window for a workspace that
already had one. Distinguish query failure from a genuinely empty
result and skip restoration when state is unknown.
Upstream creates /var/lib/mautrix-discord at mode 0770 owned by
mautrix-discord:mautrix-discord, but only adds matrix-synapse to the
mautrix-discord-registration supplementary group. That left synapse
unable to traverse the directory to read discord-registration.yaml,
crashing matrix-synapse on startup.