From 853eab974a807bd6075c2e77819aea1406cc9cc7 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 17:00:42 +0000 Subject: [PATCH] v2.0: an update never leaves mining off (the founder's rule, 8 October 2026, 18:0x BST: the Devnet 3 off jobs left both PCs paused through api/pause, and the 2.0.0 update would have started paused with a click owed after the install). On the first start after an update (ota::updated_from, right after the "up after the update from" read-back line) a saved pause is cleared, saved and said: "mining was paused under ; the update to resumes it (an update never leaves mining off)"; an ordinary start keeps the pause the user or a job set. engine::resume_after_update is the rule; test known-failed first: engine::tests::the_first_start_after_an_update_never_leaves_mining_paused Co-Authored-By: Claude Fable 5.1 --- app/igneum-app/src/engine.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/app/igneum-app/src/engine.rs b/app/igneum-app/src/engine.rs index 1e9b1040a..711d15f22 100644 --- a/app/igneum-app/src/engine.rs +++ b/app/igneum-app/src/engine.rs @@ -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 { + 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.