Merge resume-on-update-20 853eab97 into release-2.0.1 (the first start after an update clears a pause the previous version saved; the founder's rule of 8 October 2026: an update never leaves mining off)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
igneum-labs 2026-10-08 17:04:49 +00:00
commit 0dd5a8d7ee

View file

@ -1011,6 +1011,16 @@ impl Engine {
// version up before anything else happens; the shipper's rollout table reads it per machine
if let Some(from) = self.ota.updated_from() {
self.shared.log(&format!("update-return: app {VERSION} up after the update from {from} (node {v}, machine {})", self.shared.runtime.id8()));
// the founder's rule (8 October 2026, 18:0x BST): an update never leaves mining off, no click after an install.
// A pause the previous version saved (a job's api/pause, the user's own) does not outlive the update
let paused = self.shared.settings.lock().unwrap().paused;
if let Some(line) = resume_after_update(Some(&from), paused) {
self.shared.settings.lock().unwrap().paused = false;
self.shared.save_settings();
self.st().mining.paused = false;
self.shared.log(&format!("update-return: {line}"));
self.shared.event("ok", &line);
}
}
// a PC that lost power or hard-reset is a fault row at its next start, not a silence (PC 2, 7 October 2026)
if let Some(line) = crate::bootcheck::unexpected_restart() {
@ -5739,6 +5749,15 @@ impl Engine {
/// the installer (PC 2, 7 October 2026, 20:54 BST: a job's silent 0.3.22 install quit the engine through api/quit, the
/// 0.3.21 host's restart ladder started the old engine 10 s later, Inno could not replace the locked host, and every
/// file stayed 0.3.21). A plain "EXIT" for every other quit (the tray, a crash of the node the engine gave up on).
/// The founder's rule (8 October 2026): an update never leaves mining off. On the first start after an update, a saved
/// pause is cleared and said; on any other start a pause stays what the user or a job made it. The words, or None.
pub fn resume_after_update(updated_from: Option<&str>, paused: bool) -> Option<String> {
match updated_from {
Some(from) if paused => Some(format!("mining was paused under {from}; the update to {VERSION} resumes it (an update never leaves mining off)")),
_ => None,
}
}
/// How a remote `restart --what app` brings the app back (v2.0.0). Under the window host: the engine's plain EXIT and the
/// host's restart ladder (10 s), nothing else started. With no host: the detached relaunch helper (src/jobrun.rs).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -6189,6 +6208,21 @@ mod tests {
assert_eq!(crate::ember::amd_gmax_arg(2992, 3292, true), -300);
}
/// Known-failed first (the founder's rule, 8 October 2026, 18:0x BST: the Devnet 3 off jobs left both PCs paused, and the
/// 2.0.0 update would have started paused, a click owed after an install): the first start after an update clears a
/// saved pause and says so; an ordinary start keeps the pause the user or a job set.
#[test]
fn the_first_start_after_an_update_never_leaves_mining_paused() {
let line = super::resume_after_update(Some("0.3.26"), true).unwrap();
assert!(line.starts_with("mining was paused under 0.3.26; the update to ") && line.ends_with(" resumes it (an update never leaves mining off)"), "{line}");
assert_eq!(super::resume_after_update(Some("0.3.26"), false), None, "nothing to resume");
assert_eq!(super::resume_after_update(None, true), None, "an ordinary start keeps the user's pause");
let e = include_str!("engine.rs");
let rb = e.find("update-return: app {VERSION} up after the update from {from}").unwrap();
let body = &e[rb..rb + 900];
assert!(body.contains("resume_after_update(Some(&from), paused)") && body.contains("settings.lock().unwrap().paused = false") && body.contains("self.shared.save_settings()") && body.contains("st().mining.paused = false"), "the start path clears and saves the pause right after the read-back line");
}
/// Known-failed first (PC 1, 6 and 8 October 2026: a remote app restart left the app down for hours, "the relaunch
/// helper did not bring it back"): under the window host the restart is the host's ladder after a plain EXIT, never a
/// helper racing it; the helper only with no host; the quit source reads as a plain EXIT, not an update exit.