Reproduction
Scenario.__init__ retains the caller's is_focal sequence directly, although player roles and the background population are configured at construction.
Construct a scenario with mask = [True, False, True, False], then assign mask[:] = [False, True, False, True]. The existing scenario's action/observation/reward specs and timestep partitions switch to different players. Its background population still has the original roles. Clearing or extending the same list can also change the accepted focal action count after initialization.
This reproduces through the actual Scenario and Population implementations. It affects direct construction and callers of build_scenario that retain a mutable mask; ScenarioFactory already snapshots its own constructor input.
Expected behavior
Snapshot the player mask as a tuple during Scenario construction, just as the factory does. Later changes to caller-owned lists or NumPy arrays should not reassign player slots. Preserve action ordering, observation filtering, timestep routing and existing constructor/action-count validation for unchanged inputs.
This is distinct from the prior focal-action-count validation and the open empty-background-population changes.
Reproduction
Scenario.__init__retains the caller'sis_focalsequence directly, although player roles and the background population are configured at construction.Construct a scenario with
mask = [True, False, True, False], then assignmask[:] = [False, True, False, True]. The existing scenario's action/observation/reward specs and timestep partitions switch to different players. Its background population still has the original roles. Clearing or extending the same list can also change the accepted focal action count after initialization.This reproduces through the actual Scenario and Population implementations. It affects direct construction and callers of
build_scenariothat retain a mutable mask; ScenarioFactory already snapshots its own constructor input.Expected behavior
Snapshot the player mask as a tuple during Scenario construction, just as the factory does. Later changes to caller-owned lists or NumPy arrays should not reassign player slots. Preserve action ordering, observation filtering, timestep routing and existing constructor/action-count validation for unchanged inputs.
This is distinct from the prior focal-action-count validation and the open empty-background-population changes.