install_progress() mapped each phase to a start%, an end% and a hard-coded
"expected seconds", then interpolated on elapsed time. Those seconds were
calibrated on one machine, so the bar was only ever honest on that machine.
Measured against a real 69s install on an XPS 13, the table expected 145s: 95s
for a phase that took 58.6s, 10s for one that took 2.6s. On slow media it is
wrong the other way — the bar reaches each phase's ceiling in a fraction of the
real time and then sits there. Today's clamp turns that into a 386-second freeze
at 85% on a USB2 install.
Phases do not even scale together: package installation is bound by media read
and disk write, the UKI rebuild is CPU and compression bound. No single seconds
table can be right for both.
So stop predicting durations. Position is now max(floor, work), both
non-decreasing:
floor an asymptote over the phase's band, on time since this process first
saw the phase. tau is a shape constant, not a prediction — wrong by 3x
it changes the pace of a crawl, never the correctness.
work only for "Installing Arch + Omarchy", which is ~85% of the install.
libalpm creates one directory per package under
<target>/var/lib/pacman/local, so counting them counts finished work.
The denominator is resolved at ISO build time by pacman's own resolver
against the offline mirror, so there is no second package list to
drift. phases.py records expected and actual in the timing JSON on
every install, so drift shows up in acceptance runs.
There is deliberately no give-up predicate: two discontinuous curves selected by
a toggle, behind a monotonic clamp, is a freeze generator. If the signal never
appears — no denominator, wrong target, implausible count — the floor alone
still walks the band to its end.
Position moves to per-mille. That is load-bearing, not precision theatre: these
are asymptotes, and in whole percent an asymptote over a 2-point band has two
reachable values and stops moving within seconds.
Time now comes from /proc/uptime. The live ISO runs tzupdate and
systemd-timesyncd, and the old code read EPOCHSECONDS, so a clock step
mid-install jumped every band straight to its ceiling.
Also fixes drift the old table had accumulated: it still weighted five phases
that no longer exist and had no entry at all for "Preparing install target",
which fell through to a 1->99 sweep. Unknown names now derive an even band from
the index the orchestrator already publishes.
bin/omarchy-iso-installer fakes a pacman database so the preview exercises the
package path instead of the fallback; PREVIEW_PACKAGES tunes the count.
Verified by simulation against the real logic: a 69s NVMe install, a 6-minute
USB2 install with a 70s pre-extraction stall, an implausible denominator, an
unknown phase name, and a target that already holds packages. All monotonic, all
reach 100%. Not yet run on real hardware.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
QEMU's default COM1 is advertised to the guest via ACPI SPCR, the boot
stub appends console=uart,io,0x3f8 to the kernel cmdline, and Plymouth
deliberately forces its plain-text details mode whenever a serial console
is active. That made every omarchy-iso-boot test show an unthemed LUKS
prompt that real hardware (no serial port) never shows. Remove the serial
device so manual QEMU tests match real-hardware appearance.
omarchy-iso-test keeps its -serial file: logging on purpose — the harness
reads the console log and types blindly, so details mode is harmless there.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Offer the same gum chooser over release/*.iso when no ISO is passed,
and fail plainly when there is no existing ISO to test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Installs an ISO into a headless QEMU VM by driving the real interactive
install flow: each screen is read via QMP screendumps + OCR and answered
with virtual keystrokes, so the configurator wizard, install dashboard,
reboot prompt, and SDDM login are exercised exactly as a user would.
SSH access is bootstrapped by logging into a console TTY, the installed
disk is snapshotted for fast reruns, and a throwaway overlay then runs
the omarchy repo's in-guest acceptance suite over SSH.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remeasure the terminal at every screen redraw instead of once at boot:
the framebuffer can settle after the configurator starts (VM windows
especially), which left stale padding for the whole flow. Pad the
confirm-screen warnings with say so every line shares the same left
edge. Boot the test VM with SDL instead of GTK, whose GL display path
crops the guest framebuffer on HiDPI Wayland desktops.
Verified in a live VM by driving the whole flow over QMP and reading
each screen back from /dev/vcs1: all screens center on the real console
width.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The previous per-day cache (iso_YYYY-MM-DD) forced a fresh ~6GB download
on the first build of every day. Different channels (stable/edge/rc)
HAVE different package sets and shouldn't share a cache, but different
DAYS within a channel don't, so keying by channel gives us a stable
cache that persists indefinitely.
omarchy* packages always rebuild fresh inside the container regardless:
build-omarchy-packages.sh nukes /tmp/omarchy-pkg-build at the start
and the final mv overwrites the cached .pkg.tar.zst (pkgver is constant).
--no-cache still bypasses the mount entirely for a clean-slate run.
Also includes the build-iso.sh cleanup that I prepared earlier but
forgot to stage (replacing the inline ugly $(...) conditional pipe
with a normal if/then-fi block).
Dropped the sibling-dir convention ($BUILD_ROOT/../omarchy-installer
etc.). Callers now pass paths explicitly:
omarchy-iso-make --local-source <installer-checkout> <pkgs-checkout>
Errors clearly if either path is missing or doesn't exist.
The previous version made the local build the only path. Convention is
the opposite: omarchy-iso-make pulls released omarchy* packages from
the omacom-pkgs.org mirror by default, and only builds from local
checkouts when explicitly asked via --local-source.
- bin/omarchy-iso-make: only mount /omarchy-installer + /omarchy-pkgs
when --local-source is set. Default has neither mount.
- builder/build-iso.sh: skip build-omarchy-packages.sh when no local
source. Don't filter the omarchy* names out of the pacman -Syw list
in network mode (so they get downloaded from the mirror). With
--local-source, the four package names are stripped after assembly
so we don't re-fetch what we just built.
- For the package-list source: with /omarchy-installer mounted, read
omarchy-base.packages from the checkout. Without it, briefly pull
the published omarchy package, extract the .packages files from it
to /tmp, and use those.
The ISO no longer carries a cp -r'd copy of the omarchy git checkout
into /root/omarchy and the target /home/$user/.local/share/omarchy.
Instead it builds omarchy-installer + omarchy-settings + omarchy +
omarchy-limine from mounted source trees (${OMARCHY_INSTALLER_PATH:-
../omarchy-installer} and ${OMARCHY_PKGS_PATH:-../omarchy-pkgs}),
drops them in the offline mirror, and pacstraps omarchy-installer
during the target install — which deps-in the other three.
- builder/build-omarchy-packages.sh: new. Builds the four packages
inside the ISO build container using each PKGBUILD's OMARCHY_SRC
override (introduced in Chunk 2). Creates a 'builder' user because
makepkg refuses to run as root. Drops the resulting .pkg.tar.zst
files into the offline-mirror directory.
- builder/build-iso.sh: drop the git clone / -v omarchy mount path;
call build-omarchy-packages.sh first; filter out the locally-built
package names from the rest-of-mirror download so we don't try to
fetch them from the network mirror.
- configs/airootfs/root/.automated_script.sh: replace the install_omarchy
cp-and-source dance with 'arch-chroot pacman -S omarchy-installer'
followed by 'OMARCHY_INSTALL_MODE=offline omarchy-install'. Drop the
big chown/chmod block that was setting up the cloned tree.
use_omarchy_helpers extracts the installer's helpers/ tree directly
from the offline-mirror's omarchy-installer-*.pkg.tar.zst so the live
ISO has access to gum-styled logging before pacstrap.
- bin/omarchy-iso-make: always mount omarchy-installer and omarchy-pkgs
(paths configurable via OMARCHY_INSTALLER_PATH / OMARCHY_PKGS_PATH;
default to ../omarchy-installer and ../omarchy-pkgs). --local-source
is now a back-compat no-op.
* Configurator tester
* Make it a dry run
* Offer a no-encryption install mode
* Fix SDDM login
* Simplify the flow by using ctrl-c to toggle into unencrypted mode