Skip to content

feat(orchestrator+driver): per-driver player distribution + spawn-loop wiring#53

Merged
martinjms merged 1 commit intomainfrom
feat/orchestrated-mode-spawn-loop
May 2, 2026
Merged

feat(orchestrator+driver): per-driver player distribution + spawn-loop wiring#53
martinjms merged 1 commit intomainfrom
feat/orchestrated-mode-spawn-loop

Conversation

@martinjms
Copy link
Copy Markdown
Collaborator

Closes the gap that made yesterday's AWS run silently pass with 0 entities loaded.

Two changes that go together

OrchestratorCommandDispatcher::submit now OWNS per-driver allocation for SetPlayers. Controller submits an aggregate target; the dispatcher divides across active drivers (sorted by DriverId for determinism), spreads the remainder across the first rem drivers. Sum exactly equals submitted target. Other commands (SetSpawnDelayMs, Stop) keep broadcast semantics.

Driverrun_orchestrated_mode is now a WS↔TCP bridge. Picks a free localhost port, runs the existing run_control_mode on that port, connects to the orchestrator via WS, translates inbound OrchestratorCommands into the existing TCP control protocol (SET_PLAYERS N / QUIT). Real players spawn via well-tested control-mode machinery.

Test status

  • cargo test — 65 + 21 + 2 + 2 = 90 tests pass across both crates
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt --all -- --check clean
  • New e2e test (driver_bridge_relays_set_players_into_local_control_protocol) verifies controller→orchestrator→WS→bridge→TCP round-trips byte-for-byte

🤖 Generated with Claude Code

…p wiring

The two changes together close the gap that made yesterday's AWS run
silently pass with 0 entities loaded.

Orchestrator (arcane-swarm-orchestrator):
- CommandDispatcher::submit now OWNS the per-driver allocation for
  SetPlayers. The controller submits an aggregate target; the dispatcher
  divides it across active drivers (sorted by DriverId for determinism)
  and spreads the remainder across the first `rem` drivers. Sum exactly
  equals the submitted target.
- Other commands (SetSpawnDelayMs, Stop) keep broadcast semantics.
- 4 new unit tests cover even split, remainder distribution, the
  headline 13,500/12=1,125 case, and broadcast semantics for non-
  SetPlayers commands.

Driver (arcane-swarm):
- run_orchestrated_mode is now a WS↔TCP bridge. It picks a free
  localhost port, runs the existing run_control_mode on that port,
  connects to the orchestrator via WS, and translates inbound
  OrchestratorCommands into the existing TCP control protocol
  (SET_PLAYERS N / QUIT). This makes orchestrator commands actually
  spawn real players via the well-tested control-mode machinery.
- main.rs spawns the bridge alongside run_control_mode when
  --orchestrator-url is set. cfg.players defaults to 0 in the
  control-mode side; the bridge pushes the real initial count once
  WS registration completes.
- The wire-protocol unit tests + a new e2e test verify that a
  controller-submitted SetPlayers reaches the local TCP control
  server byte-for-byte.

Out of scope (deliberate, called out so it's visible):
- SetSpawnDelayMs is recorded in OrchestratedState but not yet pushed
  to TCP (no SET_SPAWN_DELAY in the existing control protocol). The
  headline workload sets a single spawn_delay_ms at the first phase
  and never changes it, so this is fine for first AWS validation.
- Bursts still happen on the driver autonomously via --burst-* flags.
  Moving burst scheduling into the orchestrator (so the controller
  can issue "burst now" commands) is a follow-up; it's the long-term
  architecture Martin called out.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@martinjms martinjms merged commit 1c2cd00 into main May 2, 2026
1 check passed
@martinjms martinjms deleted the feat/orchestrated-mode-spawn-loop branch May 2, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant