1750 Commits

Author SHA1 Message Date
Dorian
df90cdaac9 fix(cloud): satisfy noUncheckedIndexedAccess in categoryMeta fallback
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 10:02:35 +01:00
Dorian
0cf91136f9 feat(cloud): Apps-style tabs, categories and federated file search
Cloud gets the same header layout as Apps: All Files / My Files / Peer
Files tabs, Photos & Video / Music / Documents category filter, and a
search bar that queries your own FileBrowser sections (depth-limited
walk) plus every federation peer's shared catalog (content.browse-peer
fan-out, cached), with a loader while it runs. Peer Files lists the
actual files from all peers with attribution. Mobile uses the Apps
category-pill strips (which already opt out of the page-switch swipe)
with search below — no fixed top tabs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 10:01:36 +01:00
ai
6d7b39578e Merge pull request 'feat(wallet-ui): Ark send/receive/pay-with + mobile tx modal height' (#83) from ark-wallet-ui-demo into main
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m32s
2026-07-15 08:54:24 +00:00
Dorian
13909e28bf fix(ui): cap transactions modal at 60% of the live viewport on mobile
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:53:53 +01:00
Dorian
97488c83f7 feat(wallet-ui): Ark send/receive tabs + Ark pay-with option on peer files
Send modal gains an Ark tab (address/invoice/lightning-address via
wallet.ark-send), Receive gains an Ark address + QR tab, and the peer
file purchase confirm offers Ark alongside Cashu/Fedimint. Demo mock
exposes ark_sats in wallet.ecash-balance and deducts the chosen rail on
paid downloads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:53:53 +01:00
ai
eaf8b7b63e Merge pull request 'fix(demo): nginx cache regex was 404ing all /app/ shell assets' (#82) from demo-nginx-app-assets into main
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m35s
2026-07-15 08:45:44 +00:00
Dorian
46f7ac3fcf fix(demo): stop the static-cache regex from swallowing /app/ assets
nginx regex locations outrank prefix locations, so app-shell assets like
/app/bitcoin-core/tailwind.css and /app/lnd/qrcode.js hit the .css/.js
cache block and 404'd from the web root instead of proxying to the mock
backend — the actual cause of the unstyled Bitcoin UI (and the shabby
lnd-ui) on the demo. ^~ on the /app/ prefixes disables regex matching
for those paths. Config validated with nginx -t.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:44:56 +01:00
ai
76ad14ef64 Merge pull request 'fix(demo): Bitcoin UI styling + placeholder LND dashboard' (#81) from demo-ui-fixes into main
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m32s
2026-07-15 08:27:50 +00:00
Dorian
15b99a65e0 feat(demo): placeholder LND dashboard instead of the real lnd-ui shell
The official shell reads poorly inside the demo iframe; serve a
demoAppShell dashboard (balances, channels, node URI) consistent with
the /proxy/lnd/v1/* mocks.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:25:38 +01:00
Dorian
c49de3eb01 fix(demo): relative asset paths in bitcoin-ui/fedimint-ui shells
The shells are served at / in their containers but under /app/<id>/ in
the public demo, where absolute /tailwind.css and /assets/... 404 — the
Bitcoin UI rendered unstyled with a giant unconstrained SVG. Relative
paths resolve correctly in both contexts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:25:38 +01:00
archipelago
2f78fb6907 fix(ui): DNS apply no longer blanks the page + WiFi/DNS modals cover the whole app
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m39s
Applying DNS assigned the RPC response's fields into networkData without
guarding the shape; the demo mock answered {success:true} with no
servers array, dnsServers became undefined, and the dnsDisplayLabel
computed crashed the whole page render on .length. Guard the assignment,
teach the mock to round-trip DNS state per session, and Teleport the
WiFi + DNS modals to body so they overlay the full app instead of just
the right panel (position:fixed is containing-block-relative inside the
dashboard).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 04:21:39 -04:00
archipelago
2fce4fb842 fix(network): derive the host IP from the default route, not hostname -I order
On a fresh ISO node, NetBird's own WireGuard tunnel (10.44.0.1) sorted
ahead of the real NIC in hostname -I, so the NetBird launch URL (and the
{{HOST_IP}} baked into its cert/config) pointed at the tunnel instead of
the LAN address. The main routing table's default route names the
physical uplink even while a VPN is active (NetBird/Tailscale steer
traffic via policy-routing rules, not the main table), so read src/dev
from 'ip -4 route show default' first, then fall back to a connected UDP
socket's source address, then to the old hostname -I scan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 04:21:39 -04:00
ai
24be2e9e69 Merge pull request 'feat(wallet): Ark protocol support (barkd sidecar) + wallet UI' (#78) from ark-wallet-barkd into main
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m38s
2026-07-14 21:09:58 +00:00
Dorian
768c358546 feat(ui): Ark chip in transaction rail filter (shown when Ark txs exist)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:08:56 +01:00
Dorian
128c13e965 Merge remote-tracking branch 'origin/main' into ark-merge 2026-07-14 22:08:55 +01:00
Dorian
5642aae530 chore(ui): drop unused DISPLAY_MODE_KEY that broke vue-tsc build
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:57:12 +01:00
Dorian
6fa0aa46a9 feat(ui): Ark wallet tab, balances, history badge + demo mocks
Ark tab in Wallet Settings (status, balances, receive address,
board/offboard, server config via wallet.ark-*), teal Ark badge in the
transactions modal, Ark row on the home wallet card (hidden until barkd
reports a balance), official bark icon, and wallet.ark-* mocks so the
public demo renders the tab.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:57:12 +01:00
Dorian
bdb9826aba feat(wallet): Ark protocol support via barkd sidecar
barkd (Ark wallet daemon, pinned 0.3.0, checksum-verified release binary)
packaged as an installable app; thin HTTP bridge in wallet/ark_client.rs
mirrors the fedimint_client pattern — the bark SDK stays out of the node
binary. wallet.ark-* RPCs cover status/balance/address/send/invoice/
board/offboard/history/configure; Ark movements merge into the unified
ecash history (kind="ark") and spendable Ark sats into total_sats.
Signet defaults (Second's public Ark server) until Ark matures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 21:56:21 +01:00
archipelago
c3a4745d78 chore: sign v1.7.100-alpha OTA manifest (release-root)
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m43s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
v1.7.100-alpha
2026-07-14 16:39:40 -04:00
archipelago
93c3aad06a chore: release v1.7.100-alpha 2026-07-14 16:07:24 -04:00
archipelago
db4de0ac96 style: cargo fmt the workspace (release-gate cargo-fmt was red)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:38:32 -04:00
archipelago
412251ac9a docs(release): v1.7.100-alpha notes — fold in unshipped v1.8.00-alpha section + What's New sync
The v1.8.00-alpha changelog section never shipped as an OTA (no tag, live
manifest stayed 1.7.99-alpha); its content ships now as v1.7.100-alpha.
First 10 bullets are the OTA manifest changelog.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:37:20 -04:00
archipelago
69dc9ee27e fix(ci): demo-images workflow pushes to the plain-HTTP demo registry
All checks were successful
Demo images / Build & push demo images (push) Successful in 2m42s
docker login and buildkit both refused the HTTP registry. Host daemon on vps2
now lists it under insecure-registries (SIGHUP reload, no downtime); the
workflow configures buildkit with http=true for the registry host.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:48:23 -04:00
archipelago
bf3c38c7a1 fix(demo): stop proxying /app/mempool/ to mempool.guide — placeholder never showed
Some checks failed
Demo images / Build & push demo images (push) Failing after 29s
The mempool placeholder page (777d54ea) is served by the mock backend, but
the demo web nginx still had a location block reverse-proxying /app/mempool/
to mempool.guide, so it always won and the placeholder was unreachable.
Drop the block so mempool falls through to the generic /app/ backend proxy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:44:36 -04:00
archipelago
79564486d3 fix(demo): never leak the release-server IP in the public demo
Some checks failed
Demo images / Build & push demo images (push) Failing after 5m0s
- Companion QR overlay: demo builds encode the demo's own origin
  (/packages/archipelago-companion.apk ships in the web image) instead of
  the vps2 raw URL.
- Dockerfile.web/.backend: build-time scrub replaces every remaining
  occurrence of the release-server address with registry.demo.internal and
  fails the build if any survives.
- Mock backend update-mirror list, sideload help text, and changelog prose
  no longer name the server address.
- Copy demo-images workflow into .gitea/workflows/ — Gitea ignores
  .github/workflows when .gitea/workflows exists, so the CI never ran.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:38:51 -04:00
archipelago
ad3dae9983 chore(demo): document DEMO_REGISTRY_HOST var in demo-images workflow
Also serves as the first push that exercises the workflow now that the
vps2 runner and registry vars/secrets are configured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:09:51 -04:00
archipelago
777d54ea94 feat(demo): mempool placeholder page — branded 'Not available in the demo'
The public demo has no synced chain/electrs, so opening Mempool 502'd.
Serve a self-contained branded placeholder from the mock instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:23:08 -04:00
archipelago
dd31ba48a3 fix(bitcoin-ui): vendor Tailwind CSS — drop cdn.tailwindcss.com
The Bitcoin UI loaded the Tailwind Play CDN at runtime: unstyled on
offline nodes + a production console warning. Replaced with a
hand-extracted static stylesheet (~125 utilities actually used, same
approach as lnd-ui), served from the container. podman build + runtime
smoke test verified (GET /tailwind.css 200, zero cdn references).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:02:38 -04:00
archipelago
62adc64703 fix(install): failed installs no longer leave a phantom stopped app card
The optimistic package_data entry painted at install-spawn survived
failure as a 'Stopped' tile for an app with zero footprint (netbird on
the fresh ISO). On INSTALL FAIL with no container/user-stop marker for
the app, the entry and the pre-saved dynamic app config are removed and
an error notification is pushed; failures that left a real container
keep today's behavior (visible exited state for retry/diagnosis).
Install suite 39/39.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:02:16 -04:00
archipelago
9e2350a368 fix(bitcoin): size prune to the data volume — never full-archive a small disk
write_bitcoin_conf silently produced an unpruned (~810GB and growing)
config regardless of disk: the framework node got a full-archive chain
on a 205GB volume. Volumes under 1.2TB now get prune = 25% of the
volume, clamped to [550MB, 100GB]; bigger volumes keep full archive;
unknown df results stay unpruned (don't surprise big iron). Framework
node switched live to prune=50000.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:02:16 -04:00
archipelago
ec6172d7df fix(wallet): channel modals above settings modal, tx rail filters, LND seed-backup prompt
- Open/Close Channel modals sat at z-[60], BEHIND the wallet settings
  BaseModal (z-3000) — clicking 'Open Channel' looked like nothing
  happened while the form changed in the background. Raised to z-3100.
- TransactionsModal gains rail filter chips (All / On-chain / Lightning
  / Ecash with counts): instant ecash micro-payments were burying the
  standard transactions.
- Global LND seed-backup banner: once the wallet exists and the seed is
  un-acknowledged, a dismissible glass banner (24h snooze) prompts and
  routes to the LND backup card; polls only when authenticated, stops
  permanently once acked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:00:08 -04:00
archipelago
e113a2560e feat(ui): peer requests confirm via modal with optional message
Request-to-Peer (Federation Discover modal + Web5 Node Visibility list)
no longer fires instantly: a BaseModal confirm shows the target, an
optional 280-char message (handshake.connect already carried it), and
Send/Cancel with the standard orange CTA.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 09:28:21 -04:00
archipelago
9471d3727f fix(orchestrator): boot reconciler no longer installs apps on manifest presence alone
936b4cca made ANY loaded manifest with an absent container self-heal via
install_fresh — but the signed catalog and the ISO ship manifests for
EVERY app, installed or not, so 'manifest loaded' is not installation
evidence. On a fresh node this mass-installed the catalog: the framework
node grew portainer, vaultwarden, searxng, strfry, mempool, immich and
fedimint uninvited within an hour (fleet nodes showed the same loop as
reconcile-failed noise for unpullable images).

ExistingOnly (boot) reconcile now creates containers from nothing only
for required-baseline apps (filebrowser, fedimint-clientd); every other
absent app is Left('absent') and recreated ONLY via desired-state
recovery when it was running at the last snapshot — which still covers
the vanished-container regressions (indeedhub/immich) that motivated
936b4cca. Reconcile suite 16/16.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 09:26:09 -04:00
archipelago
23e214a85c fix(ui): login page refresh loop — guard 401 redirect + gate background polls on auth
The global mesh-detection poll (added for the device-detected modal)
fired on the login page, 401'd, and the session-expired handler
redirected to /login — reloading the page we were already on, forever.
Background polls now run only when authenticated, and a 401 never
redirects when the path is already /login.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 09:16:25 -04:00
archipelago
4e11f80771 chore(release): stage v1.7.100-alpha (ISO RC)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 08:58:31 -04:00
archipelago
b5265f4633 feat(demo): mock federation.invite carries the trust level
Parity with the backend's invite trust threading so the demo's Invite a
Peer / Link Your Nodes flows show the right level end-to-end.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 08:55:02 -04:00
archipelago
dc3892182d fix(ui): normalize dropdowns — one chevron, even right padding, label truncation
Native select arrows rendered with inconsistent right padding across
views and long labels could overflow into the icon. Global select rule:
appearance-none + a single SVG chevron at a fixed inset, uniform
padding-right (overrides ad-hoc pr-* utilities), ellipsis truncation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 08:53:31 -04:00
archipelago
7b36b5cc34 feat(mesh): device-detected setup modal with board images + full radio settings
Plugging in a LoRa radio now pops a global two-step setup modal on any
page: step 1 shows the ACTUAL detected board (25 board SVGs vendored
from the Meshtastic web-flasher, GPL-3.0; matched by USB product string
on native-USB boards, vid:pid heuristics for bridge chips, animated
fallback otherwise); step 2 configures with Archipelago presets — the
LoRa region pre-selected from the node's location (new lat/lon→region
mapping), channel 'archipelago', node name, and an advanced firmware
pin. Options adapt per protocol: region+channel program Meshtastic;
MeshCore shows its community frequency plan (firmware owns RF); RNode
defers to the Reticulum daemon config.

Backend: mesh.configure now accepts lora_region (validated against the
driver's region table) and device_kind (probe pin); mesh.status returns
the persisted values plus per-port USB identity (sysfs vid/pid/product)
for board identification. The Mesh Device tab gains a full settings
form (region with duty-cycle/legality hints, firmware pin, channel,
name, identity broadcast) replacing the read-only panel; the old
Mesh-page-only onboarding modal is superseded by the global flow.

Mock backend: stateful mesh config so the dev UI demos the full
detect→configure round-trip (disable mesh → modal fires with Heltec V3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 08:40:18 -04:00
archipelago
c014c4b3ee fix(install): ship app manifests where the backend loads them + self-heal existing nodes
Fresh ISO installs had ZERO disk manifests: auto-install.sh copied
apps/ to /etc/archipelago/apps but the backend/orchestrator loads
/opt/archipelago/apps — so any app not overlaid by the signed catalog
(netbird: 'manifests not available on this node') could never install.

- installer now also populates /mnt/target/opt/archipelago/apps
- bootstrap gains run_apps_dir_repair(): when /opt/archipelago/apps is
  empty and the installer copy exists, populate it at startup — heals
  already-deployed ISO nodes via OTA without reinstalling
- bootstrap's bitcoin.conf repair now also ensures rpcbind=0.0.0.0
  (same fix as install.rs; duplicate rpcbind with a manifest command
  line is harmless — bitcoind binds the first and logs the rest)

Verified live on the framework node: /opt populated (56 dirs), backend
restart loaded '50 app manifest(s) (disk + registry catalog)', all
containers kept running (they live in user.slice, not the service
cgroup).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 07:44:26 -04:00
archipelago
f2a94548ab fix(bitcoin/lnd): rpcbind=0.0.0.0 in generated bitcoin.conf + RPC readiness gate for dependent installs
Root cause of the fresh-install triple failure (LND needing ~5 install
attempts, Bitcoin UI bitcoin-rpc 502, backend getblockchaininfo errors):
the legacy conf writer set rpcallowip but never rpcbind, so bitcoind
bound RPC to the container's loopback only — every dial over the
container network (LND, bitcoin-ui) and the rootless port-forward was
refused. LND exited instantly, the 60s post-start poll read that as
INSTALL CRASH, and the wallet (and its seed backup) never got created.

- write_bitcoin_conf + ensure_bitcoin_rpc_config now emit/ensure
  rpcbind=0.0.0.0 (host exposure unchanged: publish stays 127.0.0.1)
- new install gate: bitcoin-dependent apps (lnd/electrs/electrumx/
  mempool-electrs/btcpay) wait up to 3 min for an authenticated
  getblockchaininfo to answer before their container starts, with
  INSTALL WAIT progress lines; on timeout the install fails with an
  actionable message instead of a crash-looping container

Verified live on the fresh-ISO framework node: after adding rpcbind and
restarting bitcoin-knots, LND connected, created its wallet, baked
macaroons, and settled into 'Waiting for chain backend to finish sync'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 07:31:12 -04:00
archipelago
b48ea85961 chore(apps): remove six fake bookmark apps
484.kitchen, Arch Presentation, Call the Operator, Next Web News
Network, Syntropy Institute, and T-0 were hardcoded web-only bookmark
apps (no manifests/containers). Removed across the frontend app grid /
curated / marketplace / session / launcher data, the backend
AppMetadata table, their icons, and the nginx /ext/ proxy blocks
(external-app-proxies.conf deleted — nothing installed it anymore).
botfights/nostrudel/gitea keep the shared external-app code paths.

Frontend: vue-tsc clean, 672 tests pass, production build verified
clean of the removed slugs. Backend: cargo check clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:56:03 -04:00
archipelago
85c29cd928 feat(ui): Node Visibility = one public-discoverability switch + inline node list
The old tri-state (hidden/discoverable/public) was confusing — its
'discoverable' level implied discovery by already-connected federated
peers, which is meaningless. The card is now a single Enable switch
(global ToggleSwitch style) that drives nostr presence publishing:
ON = public — anyone can find the node and request a connection
(requests join as Peer/observer on approval, never trusted).

The card also lists nostr-discoverable nodes inline with Request-to-Peer
buttons (same handshake.connect flow as the Federation Discover modal,
which stays available in Federation & Peers).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:45:15 -04:00
archipelago
5a21ac47eb fix(ui): standard tab + toggle styling — Federation view tabs, WLAN switch
- Federation List/Map tabs now use the Home mode-switcher tablist
  (full-width on mobile, shrink-wrapped on desktop, proper tablist a11y)
- Network Interfaces WLAN adapter toggle replaced with the shared
  ToggleSwitch used by AI data access in Settings; ToggleSwitch gains
  optional disabled/ariaLabel props (non-breaking)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:42:08 -04:00
archipelago
0f1d219357 feat(demo): mock WRT/TollGate gateway as thoroughly used + nostr discovery data
- openwrt.get-status/scan/scan-wifi/provision-tollgate/configure-wan
  mocked: 19-day-uptime GL-MT3000 TollGate gateway, two open TollGate
  SSIDs + private SSID, live upstream WAN, 21 sat/min pricing (edits
  via the reconfigure form persist in mock state)
- handshake.discover returns 4 discoverable nodes; nostr.set-discovery/
  discovery-status stateful; handshake.connect + pending-request
  approve/reject round-trip against mock state (incl. one inbound
  request for the demo)
- node-nostr-discover (Web5) list grown to 5 nodes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:40:26 -04:00
archipelago
a8b00e97b6 fix(ui): kill stray blue modal styling — standardize on glass orange CTA
The app-details credentials/version sidebar and the container-app Launch
button used solid bg-blue-600 CTAs and blue links/focus rings instead of
the global glass style; InstallVersionModal used an off-token solid
orange. All primary CTAs now use glass-button glass-button-warning (the
Create Identity orange) and links/focus accents use the orange tokens.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 06:36:51 -04:00
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