1705 Commits

Author SHA1 Message Date
archipelago
f9f120f397 fix(ui): Invite a Peer sends trust_level=observer to federation.invite
The invite type chosen in QuickActions was only used for the modal
title — the RPC never carried it, so every invite was minted Trusted.
Pass it through so 'Invite a Peer' mints observer invites and 'Link
Your Nodes' keeps trusted ones.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:34:33 -04:00
archipelago
2434c55f32 fix(federation): dedupe accidentally double-inserted trust-threading tests
The tests landed twice (interrupted edit applied both paths), breaking
the test build with E0428. Federation suite: 33/33 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:33:39 -04:00
archipelago
950549304d fix(federation): thread invite trust level end-to-end — 'Invite a Peer' now federates as Observer
Invites carried no trust level, and both accept_invite and the
peer-joined handler hardcoded TrustLevel::Trusted — so 'Invite a Peer'
(Observer) federated both sides as fully Trusted.

- invite codes now carry a 'trust' field (legacy codes parse as Trusted)
- federation.invite accepts trust_level: trusted|observer
- accept_invite assigns the invite's level on the acceptor side
- peer-joined resolves the granted level authoritatively by matching the
  acceptor's echoed invite token against our stored outgoing invites;
  the peer's own unsigned claim is honored only as a downgrade, so no
  escalation is possible
- discovery/connection-request approvals mint Observer invites directly
  (the post-hoc demotion in handshake.rs stays as a legacy safety net)
- asymmetry self-heal re-asserts at the locally-held level

Tests: observer threading + legacy default-trusted parse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:24:38 -04:00
archipelago
919665fb16 fix(fleet): source Fleet view from trusted federation nodes
telemetry.fleet-status only read the telemetry-fleet/ collector inbox —
an opt-in anonymous-telemetry pipeline that federated peers never write
to — so Fleet showed 'No nodes reporting' even with a healthy federation.
Build the fleet list from nodes.json instead: every TRUSTED federated
node is mapped from its last_state sync snapshot (cpu/mem/disk, uptime,
apps, peer count) into the FleetNode shape the UI expects, keyed by DID.
Observer ('peer') and untrusted nodes are excluded by design. Collector
reports are still merged in for non-federated telemetry nodes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 05:39:55 -04:00
archipelago
03418e5d26 fix(iso): installer always installs the canonical archipelago.service (B17 regression)
The ISO's rootfs tar is a cached build artifact (currently 2026-04-20) and
its baked-in archipelago.service predates the B17 fix — no
RequiresMountsFor=/var/lib/archipelago — while auto-install.sh only copied
the configs/ unit when the rootfs had none. Every fresh install therefore
raced the LUKS data mount on cold boot and looped
'[FAILED] Failed to start archipelago.service' for minutes (seen on the
1.7.99-alpha ISO).

Ship configs/archipelago.service on the ISO at archipelago/configs/ and
make the installer overwrite the rootfs copy unconditionally. Also add
RequiresMountsFor to the legacy install-to-disk.sh inline unit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 05:29:20 -04:00
archipelago
13ee019b85 revert(ui): restore previous web5 dashboard background image
The Jul 10 asset swap (75ed3041) replaced the progressive JPEG with a
baseline re-encode that trips the known Chromium compositor black-layer
bug in the 3D perspective background stack — the image paints for a
second, then the layer drops and the #000 container fill shows through.
Restore the pre-swap progressive encoding.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 05:29:20 -04:00
621636492b Merge pull request 'fix(ui): size mobile layout from live visible viewport (browser tab bar cutoff)' (#77) from mobile-viewport-fix into main 2026-07-14 08:33:43 +00:00
Dorian
cb4d17d1a9 fix(ui): size mobile layout from the live visible viewport, not dvh
Brave Android (custom bottom toolbar) and some other mobile browsers report
dvh taller than the actually visible area while position:fixed elements track
the visible viewport — so 100dvh containers extended under the browser tab
bar and the bottom of every page could never be scrolled into view.

main.ts now keeps --visual-viewport-height synced to window.innerHeight
(resize / orientationchange / visualViewport events — the same reference
frame as the fixed tab bar), and the dashboard shell, chat, and app-session
mobile heights consume it with 100dvh as fallback. The app now scales with
the browser chrome as it shows/hides. Scroll clearance margin 16px → 28px.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 09:31:52 +01:00
85f9fc2296 Merge pull request 'Demo fixes: real media, LND QR/balances, mempool.guide, overlay sessions, mobile scroll' (#76) from demo-fixes-20260714 into main 2026-07-14 02:50:01 +00:00
Dorian
0a734cb6b2 chore(dev): vite /app catch-all + filebrowser proxy to mock; demo docs to main
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:56 +01:00
Dorian
5c2622f39a feat(lnd-ui): on-chain + Lightning balance cards in the summary strip
Fetched from /proxy/lnd/v1/balance/{blockchain,channels}; the cards stay
hidden when the endpoints are unavailable so older deployments are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:56 +01:00
Dorian
890364331e fix(ui): pin dashboard to dynamic viewport across the whole mobile breakpoint
The 100dvh pin only applied below 768px; between 768–920px mobile browsers
still sized the dashboard to 100vh, hiding the bottom of every page behind
the browser tab bar with no way to scroll it into view. Apply the same pin
at ≤920px so pages always scroll fully clear with the scroll-pad margin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:56 +01:00
Dorian
4135ee5f4a fix(demo-ui): demoable apps launch in-frame; 'Not available in demo' label
- Register the 8 new placeholder apps in DEMO_MOCK_UI so they're launchable
  and installable in the demo.
- Demo bypasses the new-tab/tab-launch lists for demoable apps — they're
  served same-origin by the mock backend with no framing headers, so they
  render in the in-app session instead of opening broken localhost tabs.
- Non-demoable apps now say 'Not available in demo' instead of 'No demo'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:56 +01:00
Dorian
7d7a7d08af feat(ui): app sessions overlay the current page in every display mode
Launching an app (or opening a tx in mempool from Home/wallet/channels) used
to router.push the app-session page in overlay/fullscreen modes, swapping the
page underneath — confusing and lossy. All display modes are now store-driven:
panel renders beside the page, overlay/fullscreen render above it (teleported
to body), and the route never changes. Deep-link paths (/tx/<hash>) ride along
via the launcher's panelPath instead of a route query; closing always returns
exactly where the user was. The app-session route stays for direct links.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:32 +01:00
Dorian
fa37155ff3 fix(demo): mock backend overhaul — real media, correct shapes, mempool.guide
- Serve committed demo/content (music/photos/documents) alongside demo/files
  drop-ins, normalizing top-level folder names; Dockerfile now COPYs it. This
  is why Cloud music failed: the real library sat in demo/content while the
  loader only read the empty demo/files.
- Drop unbacked seeded Videos; runtime WAV/SVG fallback for any seeded media
  without a real file so playback never hits 'no supported source'.
- monitoring.current/history/alerts/alert-rules/export rewritten to the exact
  MetricSnapshot shapes Monitoring.vue expects (epoch-second timestamps,
  containers with limits/block IO, rpc_latency_ms, ws_connections).
- streaming.list-services + configure-service (Networking Profits page was
  erroring with Method not found).
- server.get-state snapshot so the 30s resync / reconnect path stops erroring.
- lnd-connect-info now returns cert/macaroon base64url + grpc/rest ports (the
  lnd-ui shell only renders the wallet QR + details when they're present);
  LND REST balance endpoints for the shell's new balance cards.
- Fix broken icon paths (lnd.svg → lnd.png and 15 others) against real assets.
- containers-scanned: true so app cards never sit on 'Checking…'.
- 8 new installed demo apps with placeholder dashboard UIs (btcpay-server,
  grafana, nextcloud, jellyfin, vaultwarden, nostr-rs-relay, searxng,
  uptime-kuma) via the previously unused demoAppShell.
- WS heartbeat 45s → 20s (+ping 25s) so idle-timeout proxies in front of the
  public demo stop killing the socket (the 'always reconnecting' report).
- nginx demo proxy: mempool.space → mempool.guide (mempool.space blocks the
  proxied embed) + WebSocket upgrade passthrough; txid hydration follows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 03:39:01 +01:00
Dorian
8b0b672674 revert(iso): drop i915 kernel params — kiosk oversize was the window-size bug
The X250 symptom was the UI rendered at a hardcoded 1920x1080 and clipped
on the 1366x768 panel (fixed in 7e996d6), not eDP corruption. Keep RC2
minimal: no speculative kernel params.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 22:18:17 +01:00
Dorian
7e996d6244 fix(kiosk): laptop eDP corruption — i915 stability params + panel-sized Chromium window
ThinkPad X250 (Broadwell HD 5500) internal panels show horizontal corruption
bands at the kiosk; known i915 eDP power-feature issue. Boot installed and
live systems with i915.enable_ips=0 enable_psr=0 enable_fbc=0 (no-ops off
Intel, nothing lost on a kiosk). Debug boot entries stay stock for A/B.
Also size the Chromium kiosk window from the detected mode instead of a
hardcoded 1920x1080 that clips on 1366x768 panels.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:59:41 +01:00
Dorian
7a08ed6687 fix(iso): non-root registries.conf.d write killed the build under set -e
The insecure-registry config was written to /etc unconditionally; as the
archipelago build user the redirection fails and set -e aborts check_tools
before Step 1. Write to the rootless podman per-user config dir when not
root, tolerate failure (nodes may already carry the config), and drop the
duplicated 146.59.87.168:3000 entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:24:11 +01:00
Dorian
1f2cf1e13c fix(iso): wrapper missed repo-root ../../ rewrites, breaking version + source paths
b8002885 moved the archived builder's repo-root refs to ../../ (correct for
direct _archived/ execution) but the wrapper pins SCRIPT_DIR to image-recipe/
and only rewrote the ../../scripts form. core, neode-ui, docker, apps, demo,
web and the $(cd "$SCRIPT_DIR/../..") expressions all resolved one level
above the repo, so wrapper builds ran with an empty BUILD_VERSION and would
have failed at the backend/web-UI steps. Rewrite the ../../ prefix generically.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 21:11:59 +01:00
Dorian
f5ffd5657c fix(network): accept-request/reject-request param mismatch broke connection requests
Web5ConnectedNodes sent { request_id } but the backend only read
params.id, so accepting/rejecting a connection request always failed
with 'Missing required parameter: id'. Frontend now sends id; backend
accepts both spellings for older deployed UIs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 20:51:03 +01:00
Dorian
b09142e0df feat(lnd): capture aezeed at wallet init + encrypted backup + reveal UI
- aezeed words are now captured at BOTH wallet-init paths and stored
  encrypted (Argon2 + ChaCha20-Poly1305, per-node wallet secret) at
  identity/lnd_aezeed.enc; ack marker cleared when a wallet is recreated
- lnd.init-wallet-from-seed was posting seed_entropy to /v1/initwallet,
  which is a GenSeed field — the wallet was never actually derived from
  the master seed; now GenSeed(entropy) → InitWallet(words)
- new RPCs: lnd.seed-backup-status / lnd.seed-reveal (password + 2FA
  gated, same as seed.reveal via shared verify_reveal_auth) /
  lnd.seed-backup-ack
- LND app detail page: Lightning-seed card with first-launch backup
  prompt, tap-to-reveal modal, 'I've backed it up' acknowledgment

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 20:51:02 +01:00
Dorian
59cc10f4aa fix: LND icon svg→png in neode-ui public catalog too
00a70c6 fixed app-catalog/catalog.json but the served copy in
neode-ui/public/catalog.json still pointed at the nonexistent lnd.svg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 20:09:34 +01:00
Dorian
00a70c6193 fix: RC feedback round 2 — kiosk staleness, LND icon+retry, mesh detection surfacing
Kiosk (backgrounds + FIPS mismatch, one root cause each):
- kiosk service now also waits for the web-ui asset swap (probes a large
  bg asset, bounded 60s) — it launched mid-rsync and CSS background 404s
  are never refetched, hence blank backgrounds on first boot
- FipsNetworkCard polls every 15s instead of fetching once on mount
- PWA updates auto-apply on the kiosk (localStorage kiosk flag) — an
  unattended kiosk could never click 'Update Now' and ran stale bundles

LND App Store:
- catalog icon pointed at lnd.svg which doesn't exist (lnd.png does);
  store card also retries the sibling extension before the placeholder
- image pulls retry once after fast transient failures (<30s) — fresh
  first-boot networks reset connections; slow failures aren't retried
  so the UI never waits longer than before

Mesh detection:
- mesh.status now always reports device_present + detected_devices
  (previously only when the service wasn't running, so the UI couldn't
  tell 'no radio' from 'radio present, session connecting')
- Mesh page shows 'Mesh device detected' badge + 'Device detected —
  connecting' status for present-but-not-connected radios
- the 99-mesh-radio.rules udev rule was never staged into the ISO tree
  (installer searched for it and found nothing) — ship it at the media
  root and install it from install-to-disk.sh too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 18:41:00 +01:00
Dorian
ca89cb4196 fix: RC hardware-test feedback — mesh serial access, federation.list, masked install errors
- image: create archipelago user with dialout so the backend can open
  /dev/ttyUSB*/ttyACM* LoRa radios; doctor Fix 14 heals existing nodes
  (verified live on the .65 RC install — device detected after the fix)
- Web5Federation.vue called nonexistent federation.list (Unknown method);
  now uses federation.list-nodes + federation.list-pending-requests with
  a last-seen-based online count
- sanitizer: let app-install dependency errors through — 'LND requires a
  running Bitcoin node' was masked as 'Check server logs', so install
  failures on fresh nodes looked random

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 18:08:25 +01:00
Dorian
b800288550 fix(iso): repo-root paths broke when builder moved into _archived/
BUILD_VERSION/EXPECTED_VERSION/LOCAL_RELEASE, the backend container build
context, and the neode-ui/web-dist/apps/demo/docker copies all resolved
one level short (image-recipe/ instead of the repo root), so the builder
never found the prebuilt binary and its container fallback died on
'COPY core ./core'. configs/ references were already correct.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 15:23:34 +01:00
Dorian
f600eaf145 feat(wallet): show Lightning, Cashu and Fedimint activity in the transactions modal
- new lnd.lightning-history RPC: settled invoices (incoming) + succeeded
  payments (outgoing) normalized to the wallet-transaction shape; on-chain
  history stays in lnd.gettransactions
- Home merges on-chain + lightning + ecash history into one sorted list;
  every entry now carries kind (onchain/lightning/cashu/fedimint)
- modal renders a rail badge for non-onchain rows instead of a bogus
  confirmation count, and only on-chain rows link into mempool

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 14:10:45 +01:00
Dorian
533c0713c7 docs(tracker): tick §F per-device secrets + ISO checksums (caf9e6d3)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 13:42:23 +01:00
Dorian
caf9e6d3a3 feat(iso): per-device secrets on first boot + checksum emission and signing
- archipelago-first-boot-secrets.service regenerates the self-signed TLS
  keypair (device hostname in SAN) and all SSH host keys on the installed
  system's first boot, before ssh/nginx start — the squashfs bakes one
  key set at build time, so every flashed device shared them (§F 🔴)
- staging-first swaps: a failed regeneration keeps the baked keys rather
  than leaving the device keyless
- the builder now emits <iso>.sha256 next to the ISO, and
  scripts/sign-iso-checksums.sh signs {artifact,sha256,size} as a JSON
  doc with the release-root ceremony (verify: ceremony verify) (§F 🟠)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-13 13:41:16 +01:00
13c593b3c2 Merge pull request 'Release merge: btcpay plugins/LND + doctor netns fix + tx1138 purge + kiosk audio + cashu v4 + tollgate' (#73) from release/merge-all-20260710 into main 2026-07-10 20:13:16 +00:00
Dorian
78b8a25099 Merge fix/tollgate-nodogsplash-enforcement: NoDogSplash client gating + router wallet sweep
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:22:47 +01:00
Dorian
2ca7e9cad2 Merge cashu-v4-token-support: Cashu v4 (CBOR) token support in the wallet
Same kiosk.service conflict resolution as the previous merge (branch carried
rebased duplicates of the kiosk commits): CPUQuota=200% + main's memory tuning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:20:47 +01:00
Dorian
3878644fe8 Merge kiosk-hdmi-audio-fix: PipeWire env, in-process-gpu, asound.conf tracking
Conflict resolution: keep the branch's CPUQuota=200% (75% was the proven
cause of choppy HDMI audio — the file's own comment says so; the 75% on main
was an accidental regression bundled into an unrelated UI commit) and keep
main's newer MemoryMax=2800M/MemoryHigh=2200M tuning.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:19:47 +01:00
Dorian
f318009308 Merge fix/btcpay-lnd-plugins-doctor: btcpay plugins/LND wiring, doctor netns rebuild+latch, tx1138 purge
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 20:12:21 +01:00
Dorian
4b0e44fc6c chore: purge retired git.tx1138.com registry host from the codebase
The tx1138 Gitea was retired as a release server 2026-06-13 and its registry
frontend is fully dead (500 on every /v2 manifest read, observed 2026-07-10).
Nothing may reference it anymore:

- registry.rs: no longer a default registry, no longer force-enabled on
  load; saved configs are stripped of it on load (same one-time migration
  treatment as the decommissioned Hetzner mirror), with a regression test.
- image_policy.rs: removed from TRUSTED_REGISTRIES — refs through the dead
  host are now refused at the pull site (rejection test added).
- api/handler: dropped the legacy catalog-proxy fallback URL.
- .gitmodules: indeedhub submodule repointed to the OVH Gitea.
- scripts, image-recipe, app-catalog data, neode-ui strings, docs, and all
  test fixtures repointed to 146.59.87.168:3000 (or neutral example hosts).
- image-versions.sh: ARCHY_REGISTRY_FALLBACK emptied (guarded consumers
  skip it); reconcile-containers.sh candidate guard hardened.

The only remaining occurrences of the host string are the strip/reject
enforcement paths and their regression tests — the code that guarantees it
is never used again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:55:32 +01:00
Dorian
99529fcce5 fix(doctor): install catatonit when missing — Portainer init deploys fail without it
Debian's podman only Recommends catatonit; nodes installed before
install-podman.sh gained the dependency fail any init-enabled container
deploy (observed on shorty-s deploying sites via Portainer). Doctor
Fix 13 installs it via apt when absent.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:22:20 +01:00
Dorian
2d8606872e fix(doctor): enforce BTCPay Lightning route hints so private-channel invoices stay payable
A store on a node whose LND has only unannounced channels mints BOLT11
invoices with no route hints when lightningPrivateRouteHints is off, and
external wallets fail with "no way to pay this invoice" (hit on shorty-s
2026-07-10 with a Blink payer). Hints cost nothing on public channels, so
the doctor now flips the flag on for every store on each run.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 18:16:21 +01:00
Dorian
51aa400431 fix(doctor): actually rebuild the rootless netns, and latch after repeated failures
The netns-egress repair only stopped/started containers, which reuses the
existing netns — its holders (aardvark-dns, podman pause) survive, so a
missing pasta tap was never rebuilt. On shorty-s (2026-07-10) this cycled all
35 containers every timer run for ~an hour, bouncing bitcoind/LND/BTCPay the
whole time, with 'egress still broken after cycle' after every pass.

Now the cycle kills the netns holders, runs podman system migrate, and clears
/run/user/<uid>/containers/networks so the first container start recreates
pasta + aardvark-dns from scratch (the sequence that actually fixed the node).
A failure counter (/var/lib/archipelago/doctor-netns-cycle-failures) stops the
fleet-wide cycling after 3 consecutive failed rebuilds until egress is
observed healthy again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:48:27 +01:00
Dorian
6f1d0695d0 fix(apps): persist btcpay plugins and wire the internal LND node
Two btcpay-server manifest gaps found on shorty-s (2026-07-10):

- BTCPAY_PLUGINDIR=/datadir/Plugins: the image default is container-local,
  so every container recreate silently wiped installed plugins (the
  reinstall-the-nostr-plugin-after-every-restart symptom, plus a soft-restart
  loop while an install was pending).
- BTCPAY_BTCLIGHTNING via optional secret_env btcpay-lnd-connection: the
  manifest never wired the internal LND node. The secret is generated by the
  daemon (see previous commit); nodes without LND skip it.

releases/app-catalog.json regenerated (embeds the manifest; origin-wins
overlay means nodes only pick this up from the published catalog). Signature
stripped by regeneration — run scripts/sign-catalog.sh before publishing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:48:27 +01:00
Dorian
ce6ec13e28 feat(lnd): auto-generate btcpay internal-LND connection secret
Materialise /var/lib/archipelago/secrets/btcpay-lnd-connection
(type=lnd-rest;server=https://lnd:8080/;macaroon=<hex>;certthumbprint=<sha256>)
in ensure_app_secrets before btcpay-server env resolution.

The macaroon travels inline as hex because LND's datadir is owned by its
container subuid (100999) — bind-mounting it into btcpay's userns EACCESes.
Reads the macaroon via the existing read_file_as_root sudo fallback; pins the
TLS cert by DER SHA256 thumbprint and rewrites on cert rotation. No-op while
LND is absent (btcpay's secret_env entry is optional), and generation errors
log-and-continue so btcpay never fails to start over this.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:46:25 +01:00
Dorian
bb0875f7f2 feat(manifest): optional secret_env entries
A secret_env entry with optional: true is skipped when its secret file is
missing, unreadable, or empty, instead of failing the whole resolution and
taking the app down. Needed for per-node integrations like btcpay's
internal-LND connection string: nodes without LND must still run btcpay.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 17:46:25 +01:00
archipelago
140b703838 feat(orchestrator): surface apps running with failed dependencies
btcpay-server started and reported healthy while its declared
dependencies (archy-btcpay-db, archy-nbxplorer) failed every boot
reconcile (live-testing report 2026-07-10, Fix 3). After each
reconcile pass, flag every app the pass left up whose manifest
dependency landed in the failure list — a loud DEGRADED journal error
instead of silence. True start-gating on dependency health is a
larger design change (boot-ordering/deadlock risk) and stays open.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:39:24 -04:00
archipelago
ebd904262e fix(apps): resolve latent host-port collisions + detect at load time
The strfry/vaultwarden 8082 collision shipped in a signed catalog
because nothing checks cross-app host ports. Fix the remaining latent
pairs from the cfb8d953 audit — did-wallet 8083→8088 (filebrowser
keeps 8083), morphos-server 8086→8089 (netbird-server keeps 8086),
lightning-stack 8087→8091/9737→9738 (netbird and fedimint-gateway
keep theirs) — and fix their healthchecks, which probed the HOST port
inside the container (same class as strfry 6fe62355; now 127.0.0.1 +
container port). load_manifests now flags collisions across the
merged disk+catalog set (bitcoin variants and the mempool umbrella
pair are exempt as mutually exclusive), and a repo-level test parses
apps/*/manifest.yml so a future latent pair fails CI instead of
shipping.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 12:25:42 -04:00
archipelago
9b1c090e21 Merge feat/mesh-archy-command: lightning channel controls + open-race fix
Channel open fee control, channels tab in wallet settings, mempool tx
link, and the channel-open async peer-connect race fix. Conflict in
LightningChannels.vue resolved to the branch's extracted
LightningChannelsPanel component, with main's Teleport-to-body modal
fixes and glass-button-warning class (8256fde1) ported into the panel
so they aren't lost. lnd tests 16/16, LightningChannels vitest green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:42:54 -04:00
archipelago
755cd4f235 fix(orchestrator): reconcile recreates of bitcoin cascade-restart lnd
24fd97ed cascades on package.start/restart, but a reconcile pass that
recreates or starts a bitcoin backend (desired-state recovery, repair
recreate, boot InstallMissing) also moves the RPC address behind a
running lnd's back — §C 'restart lnd after ANY bitcoin recreate'.
After the pass, dependents from the shared address_caching_dependents
table (moved to app_ops as the single source of truth) that sat
untouched (NoOp) and aren't user-stopped are restarted under their op
lock; a dependent the pass itself (re)created already resolved the
fresh address and is left alone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:27:36 -04:00
Dorian
8b5f357c1d feat(lightning): channel open fee control, channels tab in wallet settings, mempool tx link
- Fee selector on channel open: Standard (~6 blocks) / Medium (~3) /
  Fast (next block) presets, or custom target confirmations / sat/vB;
  backend validates and passes target_conf / sat_per_vbyte to LND
- Extract channel management into LightningChannelsPanel, reused by the
  LND channels page and a new Channels tab in the Wallet Settings modal
- Funding tx link on each channel card opens the node's mempool app at
  /tx/<txid>

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:21:34 +01:00
archipelago
854925c598 fix(orchestrator): user stop aborts host-port readiness/repair waits
wait_for_manifest_host_ports polls up to 420s while the caller holds
the per-app lock, so a user's stop request queued behind it and the
scanner painted the app Restarting for the whole wait (the dd3afbba
transitional-state stick; gate take-2 iter 5 vaultwarden). The wait
now selects against a user-stop-marker watcher (2s poll on
user-stopped.json, by app id or container name) and aborts with a
recognizable error, and the host-port repair path skips its restart
when a stop was requested while it settled — restarting there would
fight the queued stop worker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 10:13:33 -04:00
Dorian
75ed3041dc chore(ui): update bg-web5 background asset
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:12:01 +01:00
Dorian
c141a733b4 fix(lightning): channel open raced async peer connect, errors were swallowed
- Connect to peer synchronously (perm=false, 30s timeout) and check the
  result before opening the channel; previously the connect was fired
  with perm=true (queued in background, returns immediately) and its
  result ignored, so the open failed with 'peer is not online'
- Let LND channel/peer errors through the error sanitizer so the UI
  shows the real cause instead of 'Check server logs'
- Add private (unannounced) channel option to backend and UI — some
  peers (e.g. Olympus/ZEUS LSP) reject public channel opens

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 15:04:13 +01:00
archipelago
c07f38a903 fix(apps): repoint image refs from retired git.tx1138.com to vps2
Six manifests still pulled through git.tx1138.com/lfg2025, which is
dead — every boot reconcile of archy-btcpay-db/archy-nbxplorer failed
at the pull step (live-testing report 2026-07-10; the orchestrator
now also falls back to local storage, 3a5c5db1). All six tags
verified present on 146.59.87.168:3000/lfg2025 via the registry API.
Ships fleet-wide at the next catalog ceremony (catalog manifests
override disk ones).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:51:38 -04:00
archipelago
b7be296953 fix(quadlet): HealthCmd falls back to bash /dev/tcp before exit 0
The generated HealthCmd reported healthy (exit 0) whenever the image
shipped neither wget nor curl — btcpay-server sat 'healthy' in podman
ps while completely non-functional (live-testing report 2026-07-10).
Try a bash /dev/tcp connect to the health URL's host:port before
giving up; only images with none of wget/curl/bash still skip Podman
health (dropping exit 0 entirely would restart-loop those). Podman's
health timeout bounds the connect attempt.

Note: the rendered unit text changes, so every http-healthcheck app
gets a one-time unit rewrite + restart on first reconcile after this
binary lands.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 09:45:06 -04:00