Commit Graph
13 Commits
Author SHA1 Message Date
archipelago 0f85f588fb Fix Cashu file redemption and Bitcoin-dependent wallet readiness 2026-09-29 14:42:44 -04:00
archipelago 9c6580f5c0 fix: prevent stale catalog updates and redundant container recreation
Demo images / Build & push demo images (push) Failing after 40s
2026-09-15 03:40:21 -04:00
ssmithxandarchipelago 86052d9552 refactor(cuprate): one CUPRATE_MIN_DISK_GB, manifest matches it (review)
450 existed as two independent Rust constants (RPC gates vs boot
reconciler) linked only by a "keep in lockstep" comment — updating one
would reopen the disk-fill hole. Move it to crate::constants as the
single source of truth both paths import.

Also raise apps/cuprate/manifest.yml storage dependency and disk_limit
from 300Gi to 450Gi so manifest-driven surfaces (store size, pre-checks)
show the number the gate actually enforces — a user provisioning to the
displayed 300 was refused at an unexplained 450. Catalog regenerated
(cuprate entry re-embedded; still unsigned pending sign-catalog.sh).
2026-09-12 16:14:55 -04:00
ssmithxandarchipelago c681472e15 fix(cuprate): gate package.restart and package.update too (review)
Restart and update are stop + recreate — a fresh start by another name —
but only start carried the disk gate, so on a disk that shrank below the
floor after install, either action silently resumed the unprunable
Monero sync: the exact failure the gate exists to close.

Both now call check_cuprate_disk_compatibility after validate_app_id and
BEFORE any state mutation (user-stopped clear / Restarting / Updating
flip), matching handle_package_start's fail-clean contract.
2026-09-12 16:14:55 -04:00
ssmithxandarchipelago 34b68001d1 fix(cuprate): refuse to run on disks too small for the Monero chain
Cuprate has no pruning — verified against upstream main
(binaries/cuprated/src/config.rs): the 'pruning' crate is Monero's p2p
protocol pruning, not on-disk. Unlike the bitcoin apps, which branch on
DISK_GB in their entrypoint and self-prune, a disk-constrained cuprate
can only sync until the filesystem fills and take Archipelago down.

Translate the bitcoin disk-awareness into the only form cuprate can
honor — refuse rather than prune:
- install (sync + async RPC paths) and package.start fail with an
  actionable message below CUPRATE_MIN_DISK_GB (450 GB total: chain
  ~250 GiB + headroom; allows 500 GB-class, refuses the 250 GB VPS)
- boot reconcile skips an already-installed cuprate on a shrunken disk,
  recorded as Left("cuprate-insufficient-disk") before ensure_running
  so desired-state recovery can never undo it (same shape as
  requires-archival-bitcoin)
- df failure fail-opens at install (never block on an unreadable disk),
  fail-closes at boot (never start a doomed sync)

prod_orchestrator also registers cuprate-ui in UI_APP_IDS (its
companion commit follows).
2026-09-12 16:14:02 -04:00
archipelago e625b29d9e fix: route GitWorkshop installs through orchestrator 2026-09-12 04:41:14 -04:00
archipelago 564ffe1c47 fix(indeedhub): generate per-node encryption root 2026-09-11 11:25:44 -04:00
archipelago f5c0ba85cd feat(release): stage GitWorkshop and next node updates 2026-09-09 18:15:21 -04:00
archipelago f133d5555a feat(apps): surface Portainer's first-run setup token in the credentials interstitial
Portainer >=2.21 no longer lets whoever loads the page first claim the
admin account: on a fresh install it mints a one-time setup token and
prints it ONLY to the server logs. On an appliance that is a dead end —
'check the Portainer server logs' is exactly what a user cannot follow,
and after the 2.45.0 update it made a freshly restarted Portainer look
broken ('disappeared', then demands a token nobody can find).

package.credentials — the same RPC that powers the login-credentials
card on the app page — now extracts the setup_token line from
portainer's recent container logs and hands it over with the existing
copy-button treatment, titled and explained for a first-time user. The
token stops being printed once setup completes, and any container
recreate drops the log line, so the card disappears on its own and no
dead token lingers. Parsing is a pure, unit-tested scan against the
live-captured 2.45.0 log shape (64 hex chars after setup_token=).
2026-09-01 10:28:57 -04:00
archipelago c188d9de78 fix(lifecycle): abort unsafe declarative uninstall 2026-08-23 07:59:40 -04:00
archipelagoandClaude Fable 5 9ccc325a4d fix(container): reap ghost containers so an app can't be locked out of itself
Demo images / Build & push demo images (push) Successful in 3m24s
A ghost is a container whose process tree is still running while podman
has no record of it: the exit-command's `cleanup --rm` deletes the record,
conmon and the payload survive. It keeps owning exactly what the app needs
— the published host port and the file locks in its data dir — so the
replacement container either fails to bind ("address already in use") or
starts and dies on the lock, and Restart=always loops it there forever.
Nothing in the stack could see it: every podman-level stop/rm/recreate
misses a container podman lost.

Seen twice now: 752 restarts on a fleet node (2026-08-10) and again on the
dev box today, where Gitea flapped until it fell out of My Apps. Both were
cleared by hand; container-doctor.sh has the same logic but is an
out-of-band script the daemon never calls.

- New container::ghost_reaper: finds conmon processes whose 64-hex
  container id is absent from `podman ps -a --no-trunc -q`, then kills the
  payload's children and conmon (TERM, 5s grace, then KILL — the Gitea
  ghost ignored TERM). Id-based, never name-based: killing by name would
  hit the live managed container. A failed `podman ps` reaps nothing
  rather than treating every container as a ghost.
- Hooked at repair_before_package_start (covers package.start,
  package.restart and the orchestrator start path) and in the boot
  reconciler's 30s tick, so ghosts are cleared before an app is asked to
  start and swept for every app continuously.

Restart feedback: the lifecycle RPCs return {"status":"restarting"} in
milliseconds and work in the background, so "Restarting..." flashed for a
few frames and the buttons went idle while the app was still down — the
click read as a no-op. The hero buttons now show a spinner and hold it off
the node's own state (starting/stopping/restarting/updating, plus running
+ health=starting), and the just-clicked action is held until the backend
confirms it picked the work up, with a 12s cap so an unresponsive node
still releases the controls.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-16 13:45:45 -04:00
archipelagoandClaude Fable 5 6833920778 feat(bitcoin): autoprune default raised 550 → 50000 MB
Small-disk nodes (<1000 GB data volume) keep the same dynamic
prune-vs-archival logic but now retain ~50 GB of recent blocks instead
of the bare 550 MB minimum. Takes effect for catalog-covered installs
at the next catalog regeneration + signing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 09:23:57 -04:00
Archipelago b67e1527a2 Archipelago — open-source initial import 2026-08-12 10:55:50 +00:00