Repository navigation
Every ssh the metal loop runs ends: a dropped connection within 40 s, a command at its bound - #1255
Conversation
Review of #1255 at 2a2d432 (on f79df95)Architecture. One owner and one wait: every Bounds. The settle bound comes from udevd's own 180 s. The floor rests on a measurement: in the orchestrator's local log
Blockers
Suggestions
Metal (LAND-pending-metal once the blockers are fixed)For each of the four flashes (
A normal-path SEND BACK |
… a command at its bound An AMD-bench boot's `sudo -n /usr/sbin/reboot` did not return: the machine rebooted, booted ToyOS and was back in Ubuntu within minutes, but the session's close never reached this host, and `ssh` sat on the connection for 75 minutes until it was killed. The loop set only `ConnectTimeout` and waited on every remote command for as long as it ran; nothing but TCP's own keepalive, which starts after 7200 s idle on the development host, would have ended that connection. Every `ssh` now carries `ServerAliveInterval=10` and `ServerAliveCountMax=3`, so a machine that stops answering ends the connection with ssh's own 255 within about 40 s. Every command runs through one `bounded` wait: a command that has not ended by its failure bound is killed and refused as `Expired`, naming what it was doing. A command that moves no image's bytes gets 120 s; a settle gets udevd's own 180 s more; a write or the log volume's read gets its bytes at 32 KiB/s more, under a fifth of the slowest a flash over the bench links has gone (153 MB in 832.7 s of `dd` on the AMD bench, 184 kB/s). Each write prints its `dd` seconds against its bound. The feed's copy, stdout and stderr run on threads of their own, so the wait is on the command and not on a pipe. `reboot` is the one command whose connection is expected to go: shutdown can stop the network before `sshd` closes the session. ssh(1) exits 255 the same way when it fails before the command ran, though, as on a refused connect, and that reboot was never sent. So the machine's shell says `rebooting` before it runs `reboot`, and only an `ssh` that failed itself after that line is ridden; one that failed before it is the loop's own failure, as before, and exits 2. What establishes that the reboot happened is the firmware's list read as the machine comes back: the boot manager deletes `BootNext` before it boots the entry it names (UEFI 2.10 §3.1.2), so a list still holding one is refused as `Untaken` before any log is read, whatever `reboot` answered, and the `BootNext` is deleted so that no later reboot boots the entry. That check replaces `--fall-through`'s own `BootNext` check, which said the same thing as a firmware finding, and the list it reads is the one the order check after the readback compares. `--boot-internal`, which rides nothing, still refuses a failed reboot. The `down` phase is counted from the reboot's ask, so a ridden connection's 40 s stays inside the window a boot is known to have run in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2a2d432 to
01e092d
Compare
Follow-up review of #1255 at 01e092d (over 2a2d432, on f79df95)Scope. This round checks the round-1 blockers and the code changed for them. Interdiff: +75/−38 in
Round-1 blockers
Suggestions taken
Suggestion
EvidenceThe checks ran at 01e092d on a clean tree:
That is sufficient for this round. Nothing else needs to run. Metal (LAND-pending-metal)These are the queued
The two AMD flashes at 2a2d432 are local logs only, so they are not evidence here. LAND (pending metal) |
…ounds are owed on metal A `--delete-bootnext` that failed after an `Untaken` was dropped silently after its `run:` line, so the log read as if the bench had been left clean; it now prints the refusal it got beside the one it answers with. Both benches are down. The AMD bench's two flashes ran through this loop before they went, and showed its normal path; the T14's did not, and no judge read the AMD readbacks. The record of the loop's `ssh` names what is owed on metal and what main must show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Orchestrator verification, landing under the benches-down rule (metal unavailable): review LAND pending metal. Since the reviewed 01e092d: the review's optional suggestion (a failed BootNext deletion is now printed, not discarded: |
Problem
toyos-metalwaited on everysshfor as long as it ran. Itssshline set onlyConnectTimeout: noServerAliveInterval/ServerAliveCountMax, and nothing bounded the remote command. On 2026-11-11 an AMD-bench boot'ssudo -n /usr/sbin/rebootdid not return. The machine had rebooted, booted ToyOS and was back in Ubuntu within minutes (its uptime said so when probed), but the session's close never reached the development host.sshsat on the connection for 75 minutes until the orchestrator killed it. Only TCP's own keepalive would otherwise have ended it, and that starts after 7200 s idle on the development host (inferred fromnet.inet.tcp.keepidle, not observed). Every wait needs a failure timeout; these had none.Resulting behavior
sshcarriesServerAliveInterval=10andServerAliveCountMax=3. A machine that stops answering ends the connection withssh's own 255 within about 40 s (four unanswered intervals). That is earlier than any command's bound and distinguishable from it; a compile-time assertion holds it under the shortest bound.sshruns through oneboundedwait. A command still running at its failure bound is killed and refused asExpired("… had not ended after N s, its failure bound, so it was ended"), with exit 2 like every refusal of the loop. The bounds (Job::secs):dd, 184 kB/s).ddseconds against its bound.sshfails. ssh(1) exits 255 both when the connection fails before the command ran (a refused connect, a failed key exchange:rebootwas never sent) and when it drops after. So the reboot's line isecho rebooting && sudo -n '/usr/sbin/reboot':rebootingline is ridden as before, and the loop saysssh failed itself once the machine had started the reboot (…);Remote, exit 2), as on main.BootNext. UEFI 2.10 §3.1.2: "The boot manager removes the BootNext variable before transferring control to the BootNext boot option."Untaken(exit 2) while it still holdsBootNext, before any log is read.BootNextis then deleted (efibootmgr --delete-bootnext), so no later reboot of the bench boots the entry once.--fall-through's ownBootNextcheck. The same list is what the order check after the readback compares, so there is oneefibootmgrread fewer.downphase is counted from the reboot's ask, so a ridden connection's seconds stay insideReadback::ran_within's window;entryends at the ask.--delete-bootnextthat fails after anUntakenprints its own refusal beside the one the loop answers with.--boot-internal, which rides nothing, still refuses a failedreboot.Nothing a readback holds (
boot.txt,verdict.txt) or the command line changes.Consequential decisions
rebootingline is the one fact that tells the two apart, andUntakenchecks the rest after the ride.Checks
Evidence: ToyOSOrg/evidence@b0f828aef618 (paths masked). The logs answering review round 1 live under
r2/and was taken at the commit itself (01e092da8, clean tree). The first round's logs at2a2d4325estay at the branch's root.The change is one file of
toyos-metal, so the checks are that crate's:cargo test -p toyos-metal: 77 passed, exit 0 (log). New tests:a_command_that_outlasts_its_bound_is_ended_and_refused: asleep 30under a 1 s bound is refused asExpiredwithin 20 s;a_bounded_command_is_fed_its_slice_and_answers_whole: the feed's slice, both streams and the status come back;only_a_reboot_the_machine_started_is_ridden_when_ssh_fails: 255 afterrebootingis ridden; 255 without it, and 1 after it, are refusals that are not the boot's; the reboot's line is pinned;a_machine_still_holding_bootnext_never_booted_its_entry.--delete-bootnextline.636b71537; the headdb7f1e57fdiffers from it only in an issue record): the failed-delete print.cargo test -p toyos-metalpassed 77 and clippy exited 0 (dir).cargo clippy -p toyos-metal --all-targetswith the workspace's adopted lints and-D warnings: exit 0 (log).rebooting;BootNextstill set.ssh -G, which connects to nothing) (log). The UEFI text the check rests on: excerpt. The flash and log-read rates the transfer bounds rest on: excerpt.Metal. Both benches went down on 2026-11-11, so metal is no longer this PR's landing condition.
boot:testcases(testcasesandtestcases-watchdog) ran through this branch at01e092da8before the benches went down (the loop's lines, masked). Both exited 0, with noExpiredand noUntaken. Each reboot wasecho rebooting && sudo -n '/usr/sbin/reboot'and was answered cleanly. Every piece printed itsddseconds against its bound; the largest share any piece took was 17.4 s of 1208 s. Those two readbacks were deleted before a judge read them, sowall_clock_is_firmwareswas not judged on either.issues/a-boots-readback-is-lost-to-one-ssh-that-times-out.md:boot:testcases. Eachtoyos-metallog of main must show:Expiredand noUntaken;ssh failed itself once the machine had started the reboot (…); it is ridden, then a readback;dd took X s of its Y s boundfor every piece, with the smallest margin recorded;wall_clock_is_firmwares, which must not be red on its window:downis counted from the reboot's ask.The dropped-connection race itself cannot be provoked on demand; the host tests and the specification cover it.
Not run: the full
--ci host(one crate changed; the merge queue runs it), any guest row (nothing a guest runs changed).Risks
Untakenis new on a normal boot's path. If a bench firmware keptBootNextafter booting the entry, every run there would be refused by name (exit 2), loudly and before judging. Both benches'--fall-throughruns passed the check this replaces, and the UEFI text says the boot manager removes it.Expired. The floor is under a fifth of the slowest observed flash rate, and every write now prints its margin.rebootingline was lost with the connection is refused (exit 2) although the reboot may have run. That costs a boot and is said as the loop's failure, not the machine's.🤖 Generated with Claude Code