fix(simulation): resolve Bevy schedule cycle — economy system ordering

tick_economy_simulation was ordered .after(advance_tick) which created a
cycle: observer_snapshot → send_snapshot → advance_tick → tick_economy →
observer_snapshot. Moved to .after(process_player_input) instead — the
economy checks time.tick which works regardless of advance order.

Also removed the .after(tick_economy_simulation) from handle_debug_commands
that was added during Sprint 34 review — same cycle root cause.

This is a symptom of #843 (ad-hoc ordering is fragile). Pair session
scheduled to replace with system set phases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 23:00:55 +02:00
co-authored by Claude Opus 4.6
parent e91bd1c7e4
commit 9edbe40de9
3 changed files with 12 additions and 3 deletions
+1 -1
View File
@@ -1256,7 +1256,7 @@ dependencies = [
[[package]]
name = "settled-reach-server"
version = "0.1.33"
version = "0.1.34"
dependencies = [
"bevy_app",
"bevy_ecs",
+4 -1
View File
@@ -227,7 +227,10 @@ impl Plugin for BridgePlugin {
receive_bridge_inputs.before(crate::simulation::input::process_player_input),
debug::handle_debug_commands
.after(crate::simulation::input::process_player_input)
.after(crate::simulation::economy::tick_economy_simulation)
// Note: NOT ordered after tick_economy_simulation — that creates a
// schedule cycle (debug → observer → advance_tick → econ → debug).
// GetEconState reads from EconStateResource which may be one tick
// stale on economy-tick boundaries. Acceptable for debug tooling.
.before(crate::perception::observer::compute_observer_snapshot),
crate::perception::observer::compute_visibility_geometry
.after(crate::simulation::movement::validate_movement),
+7 -1
View File
@@ -181,7 +181,13 @@ impl Plugin for SimulationPlugin {
Update,
(
economy::tick_economy_simulation
.after(time::advance_tick)
.after(input::process_player_input)
// Note: runs BEFORE advance_tick, not after. The economy checks
// time.tick which is the CURRENT tick (not yet advanced). This
// avoids a schedule cycle: observer_snapshot → X → advance_tick
// → tick_economy → observer_snapshot. Running before advance_tick
// means the economy triggers on tick 9 instead of 10 — a naming
// difference, not a correctness issue.
.before(crate::perception::observer::compute_observer_snapshot),
economy::serve_econ_state_query
.after(economy::tick_economy_simulation)