From 85196e5436cc6f227ba4e6426607802e85dc103b Mon Sep 17 00:00:00 2001 From: Andrew Gazelka Date: Mon, 27 Jul 2026 09:22:04 -0700 Subject: [PATCH 1/2] fix: move off the nightlies that ICE compiling tokio nightly-2026-07-24 through -07-26 carry rust-lang/rust#159815, an ICE in rustc_codegen_ssa when a function returns an all-uninit MaybeUninit. tokio 1.53.1 hits it in the multi-thread runtime, so `nix build .#packages.x86_64-linux.bedwars` could not produce a release binary at all, and nothing could be deployed. Differentials, on the minimal repro from the upstream issue: opt-level 0, 1 OK opt-level 2, 3 ICE aarch64-apple-darwin ICE, identically so it is not x86 codegen and not something a build flag avoids without deoptimising tokio. Bumping tokio is not available either: 1.53.1 is the newest published version. Walking the nightlies gives a three-day window: nightly-2026-07-23 rustc 6f72b5dd5 OK nightly-2026-07-24 rustc 89c61a754 ICE nightly-2026-07-25 rustc da86f4d07 ICE nightly-2026-07-26 rustc 008fa22ce ICE <- the old pin nightly-2026-07-27 rustc dc3f85158 OK <- the fix landed rust-lang/rust#159825 merged 2026-07-26T06:29:12Z, so -07-27 is the first nightly carrying it. That makes this a one-day move forward rather than a three-day rollback, and it leaves no knob behind: when the fix reaches beta the pin is just a normal pin again. Upstream issue: https://github.com/rust-lang/rust/issues/159815 Upstream fix: https://github.com/rust-lang/rust/pull/159825 --- rust-toolchain.toml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 7b7583e98..3d065b62a 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,8 @@ [toolchain] -channel = "nightly-2026-07-26" +# nightly-2026-07-24 through -07-26 ICE in rustc_codegen_ssa building tokio at +# opt-level >= 2, so the release build could not be produced on any target: +# rust-lang/rust#159815, fixed by rust-lang/rust#159825. -07-27 is the first +# nightly carrying that fix. Do not move below it. +channel = "nightly-2026-07-27" components = ["rustfmt", "clippy"] profile = "minimal" From 9990b05f25620895e2d4eda2d839121ec7c10012 Mon Sep 17 00:00:00 2001 From: Andrew Gazelka Date: Mon, 27 Jul 2026 09:43:24 -0700 Subject: [PATCH 2/2] test(smash): give each world its own passive counter The coverage job failed on a test that passes under nextest: a_passive_owned_by_the_kit_module_sees_the_damage_pipeline assertion left == right failed: the passive should only arm against non-melee The counter the Porcupine passive incremented was a process-global static. Nine tests in that file build a Porcupine world, cargo test runs them as threads in one process, and any two dealing non-melee damage at the same moment shared one number. nextest gives every test its own process, so nix run .#test never saw it and never will. It is a flecs singleton now, so it belongs to the world that observed the damage. Registered explicitly because this workspace builds flecs with manual registration, where first use of an unregistered component aborts. Five consecutive cargo test --all-features --workspace runs pass. --- events/smash/tests/modularity.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/events/smash/tests/modularity.rs b/events/smash/tests/modularity.rs index cd4a090fc..cd4f6ba5d 100644 --- a/events/smash/tests/modularity.rs +++ b/events/smash/tests/modularity.rs @@ -12,8 +12,6 @@ mod harness; -use std::sync::atomic::{AtomicU32, Ordering}; - use flecs_ecs::prelude::*; use glam::Vec3; use harness::Game; @@ -30,7 +28,15 @@ use smash::{ /// How many times the passive fired, so the test can prove an out-of-crate /// module can hook the damage pipeline. -static SHIELD_TRIGGERS: AtomicU32 = AtomicU32::new(0); +/// How many times this world's Porcupine passive has armed. +/// +/// A world rather than a `static`: nine tests in this file build a Porcupine +/// world, `cargo test` runs them as threads in one process, and any two that +/// deal non-melee damage at the same moment would share one counter. That is +/// invisible under nextest, which gives each test its own process, and it +/// failed exactly once in CI under `cargo test --all-features`. +#[derive(Component, Debug, Default, Clone, Copy)] +struct ShieldTriggers(u32); /// A kit that exists only in this test file. #[derive(Component)] @@ -93,6 +99,15 @@ impl Module for Porcupine { }) .register(); + // Registered explicitly: this workspace builds flecs with + // `flecs_manual_registration`, so first use of an unregistered + // component aborts rather than registering it lazily. + world.component::(); + + // Set before the observer that reads it, or the first non-melee hit + // asks for a component the world does not have. + world.set(ShieldTriggers::default()); + // A passive, as an observer this module owns. Nothing in the crate // knows it exists. world @@ -100,7 +115,8 @@ impl Module for Porcupine { .with(Player::id()) .each_iter(|it, _index, _health| { if it.param().kind != DamageKind::Melee { - SHIELD_TRIGGERS.fetch_add(1, Ordering::SeqCst); + it.world() + .get::<&mut ShieldTriggers>(|triggers| triggers.0 += 1); } }); } @@ -287,14 +303,13 @@ fn a_passive_owned_by_the_kit_module_sees_the_damage_pipeline() { let mut game = game_with_porcupine(); let victim = game.player("victim", Vec3::new(3.0, 0.0, 0.0)); - SHIELD_TRIGGERS.store(0, Ordering::SeqCst); hurt(game.world.entity_from_id(victim), Damaged { attacker: None, amount: 2.0, knockback: smash::module::knockback::Knockback::from(Vec3::ZERO), kind: DamageKind::Projectile, }); - assert_eq!(SHIELD_TRIGGERS.load(Ordering::SeqCst), 1); + assert_eq!(game.world.cloned::<&ShieldTriggers>().0, 1); hurt(game.world.entity_from_id(victim), Damaged { attacker: None, @@ -303,7 +318,7 @@ fn a_passive_owned_by_the_kit_module_sees_the_damage_pipeline() { kind: DamageKind::Melee, }); assert_eq!( - SHIELD_TRIGGERS.load(Ordering::SeqCst), + game.world.cloned::<&ShieldTriggers>().0, 1, "the passive should only arm against non-melee" );