fix: fresh-ISO feedback bug-bash — onboarding, status truthfulness, recovery, kiosk, logs

Fixes from real fresh-install feedback (Framework node .81) + its log bundle:

Backend:
- websocket: subscribe before initial snapshot — broadcasts in the gap were
  silently lost, stranding clients on stale state until a hard refresh
  (the "everything needs ctrl-r" bug: My Apps stuck Loading, App Store
  stuck Checking, containers-scanned never arriving)
- crash recovery: check the crash marker BEFORE writing our own PID —
  recovery had never run on any node (always saw its own PID and skipped);
  PID-reuse guard via /proc cmdline
- boot status: pending-boot-starts registry (recovery, stack recovery,
  reconciler, adoption) — scanner overlays queued-but-down apps as
  Restarting instead of Stopped after a reboot; scanner-authored
  Restarting resolves immediately on a settled scan (no transitional wedge)
- install deps: bounded wait (36x5s) when a dependency is installed but
  still starting ("Waiting for Bitcoin to start…") instead of instant
  rejection; dependency-gate rejections remove the optimistic entry (no
  phantom Stopped tile) and surface as a notification
- seed backup: auth.setup persists the onboarding mnemonic as the
  encrypted seed backup (reveal previously failed on EVERY node — nothing
  ever wrote master_seed.enc); seed.restore stashes too; error sanitizer
  lets seed/2FA errors through instead of "Check server logs"
- lnd: bitcoind.rpchost resolved from the running Bitcoin variant
  (hardcoded bitcoin-knots broke Core nodes); manifest uses derived_env
- bitcoin status: clean human message for connection-reset/startup; raw
  URLs + os-error chains no longer reach the app card
- fedimint-clientd: chown /var/lib/archipelago/fmcd to 1000:1000 (root-
  created dir crash-looped the rootless container, EACCES) — first-boot
  script + pre-start self-heal
- log volume (>1GB/day on a day-old node): journald caps drop-in (ISO +
  bootstrap self-heal), bitcoind -printtoconsole=0 everywhere (90% of the
  journal was IBD UpdateTip spam), tracing default debug→info

Frontend:
- Login: Enter advances to confirm field then submits; submit always
  clickable with inline errors (was silently disabled on mismatch);
  Restart Onboarding needs a confirming second click (the mismatch →
  "onboarding restarted" trap)
- sync store: 30s state reconciliation + refetch on re-entrant connect;
  20s containers-scanned escape hatch so Checking can never show forever;
  fresh empty node reaches the real "no apps yet" state
- intro video: CRF20 re-encode (SSIM 0.988) + faststart — moov was at EOF
  so playback needed the full 15MB first (the intro lag)
- backgrounds: 10 heaviest JPEGs → WebP q90 (9.4MB→6.6MB); 7 stayed JPEG
  (WebP larger on noisy sources)
- Web5ConnectedNodes: drop unused template ref that failed vue-tsc -b

ISO/kiosk:
- nginx: /assets/ 404s no longer cached immutable for a year; HTTPS block
  gained the missing /assets/ location (served index.html as images)
- kiosk: launcher/service spliced from configs/ at ISO build (stale
  heredoc force-disabled GPU); MemoryHigh/Max 1200/1500→2200/2800M (kiosk
  rode the reclaim throttle = the lag); firmware-intel-graphics +
  firmware-amd-graphics (trixie split DMC blobs out of misc-nonfree)

Verified: cargo test 898/898 green, npm run build green with dist
contents confirmed (webp refs, lnd.png, faststart video, new strings).
Handover for ISO build + deploy: docs/HANDOVER-2026-07-02-iso-feedback.md

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-07-02 08:00:39 -04:00
co-authored by Claude Fable 5
parent 8256fde1a6
commit c375ecc441
65 changed files with 1514 additions and 210 deletions
+13 -13
View File
@@ -109,16 +109,16 @@ const useVideoBackground = computed(() => {
// Note: bg-intro.jpg is used for splash and /onboarding/intro for seamless transition
const routeBackgrounds: Record<string, string> = {
'/onboarding/intro': 'bg-intro.jpg', // Video will be used instead
'/onboarding/options': 'bg-intro-4.jpg',
'/onboarding/options': 'bg-intro-4.webp',
'/onboarding/path': 'bg-intro-3.jpg',
'/onboarding/seed': 'bg-intro-1.jpg',
'/onboarding/seed-verify': 'bg-intro-1.jpg',
'/onboarding/seed-restore': 'bg-intro-1.jpg',
'/onboarding/did': 'bg-intro-4.jpg',
'/onboarding/identity': 'bg-intro-1.jpg',
'/onboarding/backup': 'bg-intro-6.jpg',
'/onboarding/seed': 'bg-intro-1.webp',
'/onboarding/seed-verify': 'bg-intro-1.webp',
'/onboarding/seed-restore': 'bg-intro-1.webp',
'/onboarding/did': 'bg-intro-4.webp',
'/onboarding/identity': 'bg-intro-1.webp',
'/onboarding/backup': 'bg-intro-6.webp',
'/onboarding/verify': 'bg-intro-2.jpg',
'/onboarding/done': 'bg-intro-1.jpg',
'/onboarding/done': 'bg-intro-1.webp',
'/login': 'bg-intro.jpg' // Video loops from splash (same as intro)
}
@@ -126,12 +126,12 @@ const routeBackgrounds: Record<string, string> = {
// identical on every logout. Cycles through bg-intro-1..6 using a
// counter persisted to localStorage so subsequent visits advance.
const LOGIN_BACKGROUNDS = [
'bg-intro-1.jpg',
'bg-intro-1.webp',
'bg-intro-2.jpg',
'bg-intro-3.jpg',
'bg-intro-4.jpg',
'bg-intro-5.jpg',
'bg-intro-6.jpg',
'bg-intro-4.webp',
'bg-intro-5.webp',
'bg-intro-6.webp',
]
function pickNextLoginBackground(): string {
try {
@@ -307,7 +307,7 @@ watch(() => route.path, (newPath, oldPath) => {
// Login route: set background immediately, no zoom, no transition (glitch is always-on)
if (newPath === '/login') {
currentBackground.value = 'bg-intro-1.jpg'
currentBackground.value = 'bg-intro-1.webp'
isTransitioning.value = false
isGlitching.value = false
return