In 0.8.1 on x86_64 UEFI (snponly.efi) the boot menu drew and the keyboard
worked, but every item except the first one bounced straight back to the
menu with the default Queued Deployment entry highlighted; the `x` Exit
item did the same. Root cause was the generated dispatch lines:
iseq ${target} linux && chain .../boot/_linux_menu.ipxe || goto menu
iPXE evaluates `&&`/`||` strictly left to right (src/core/exec.c
`system()`), so for `A && B || C` the `goto menu` runs whenever A fails --
for every item except the first. Only `local` ever reached its chain line,
which is exactly the reported symptom. The same shape made `x` useless,
and `goto menu` redraws with `--default queue`. The bug report's Ctrl-B
test (chaining an entry script by hand) booted fine, confirming the
scripts and HTTP/TFTP paths were healthy.
Fix, all in crates/http-api/src/ipxe_script.rs:
- Dispatch with `goto ${target} || goto menu` to `:label` blocks (the
canonical iPXE menu pattern) in the top menu, both installer submenus,
the tools menu and the utilities menu, so a non-matching item can never
fall through into a stray `goto menu`.
- Menu-to-menu transitions use `chain --replace`, so the previous menu
image is replaced: `exit` from any submenu reaches the firmware and
repeated Back/forward navigation no longer nests script images.
- Boot-entry scripts now recover to the menu themselves (kernel/initrd
fetches `|| goto failed`, `:failed` chain --replace boot.ipxe), since
with --replace the calling menu can no longer catch their errors.
- Arch-label mapping: three `|| echo` probes instead of one chain ending
in `|| true` (`true` is not an iPXE command; non-allowlisted pairs such
as i386+efi aborted the script before the menu was drawn).
- Utilities menu Back really returns to Tools (it used to redraw
Utilities); `prompt --timeout` expiry no longer aborts NIC info;
password prompt tests emptiness with `isset` instead of a literal `""`
token (iPXE has no quoting, so an empty Enter skipped the main-menu
path); queue entry view falls back to the main menu if the queue
endpoint is unreachable.
Tests: new `menu_dispatch_tests` interpreter that mirrors iPXE's
`system()`/`process_script()` (whitespace tokenisation, left-associative
`&&`/`||`, goto labels, abort on nonzero line) and asserts each top-menu
and submenu item reaches its expected chain URL (the old lines would
fail these), plus exit/reboot/firmware, unknown-architecture, password
prompt, shell and queue flows. Text assertions, the insta snapshot and the
tools-menu wiring assertion in tests/full_flow.rs updated to match.
`cargo fmt --check` clean, no new clippy warnings, `cargo test
--workspace` green (all crates).