fix(textarena): honor reset(seed) so episodes are reproducible - #1078
fix(textarena): honor reset(seed) so episodes are reproducible#1078adithya-s-k wants to merge 1 commit into
Conversation
TextArenaEnvironment.reset() accepted a `seed` argument but ignored it: it called `self._ta_env.reset(num_players=...)` without seeding, so the Wordle secret word (chosen via the global `random` module) was non-deterministic on every reset. This made the environment non-reproducible and, in particular, broke GRPO-style training where all rollouts in a group must share the same episode (same word) for the group-relative advantage baseline to be valid. TextArena's own reset(seed=...) does not apply the seed to word selection, so we seed the process-global `random` (and `numpy`, if present) immediately before the underlying reset. A lock keeps seed+selection atomic across concurrent sessions, and the prior RNG state is restored afterwards so unseeded sessions sharing the process are undisturbed. The seed is also forwarded to the underlying reset for games/versions that consume it. Adds tests: same seed -> same word (across resets and instances), seed drives selection, unseeded reset still works, and a seeded reset restores global RNG.
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want higher recall? High effort reviews run extra passes and find more bugs. A team admin can switch effort levels in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 58723a9. Configure here.
| """ | ||
| if seed is None: | ||
| self._ta_reset(seed) | ||
| return |
There was a problem hiding this comment.
Unseeded reset skips seed lock
Medium Severity
_seeded_reset only acquires _SEED_LOCK when seed is set, so an unseeded reset (and __init__'s direct _ta_env.reset) can run while another session has temporarily reseeded the process-global RNGs. With SUPPORTS_CONCURRENT_SESSIONS and a thread-pool server, that interleaving can steal draws from a seeded episode or break same-seed reproducibility.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 58723a9. Configure here.


What
TextArenaEnvironment.reset()accepts aseedargument but never uses it. It callsself._ta_env.reset(num_players=...)without seeding, so the episode (for Wordle, the secret word, chosen via the globalrandommodule) is non-deterministic on every reset. The client -> HTTP -> server plumbing already forwardsseedintoenvironment.reset(seed=...); only the wrapper was dropping it.This makes the environment non-reproducible, and it specifically breaks GRPO-style training: all rollouts in a group must share the same episode (same word) for the group-relative advantage baseline to be meaningful. Today each rollout in a group draws a different word.
Repro (before)
Fix
TextArena's own
reset(seed=...)does not apply the seed to word selection (Wordle usesrandom.choice(word_list)), so the wrapper seeds the process-globalrandom(andnumpyif present) immediately before the underlying reset:seed=Nonekeeps the existing random behaviour.Tests
tests/envs/test_textarena_seed.py(skipped iftextarenaisn't installed):Validated locally with textarena 0.7.4: 5 passed.
ruff format/ruff checkclean.Note
Medium Risk
Touches reset/concurrency behavior for a shared server env used in training; logic is localized but global RNG save/restore must stay correct under concurrent
resetcalls.Overview
TextArenaEnvironment.reset(seed=...)now drives episode selection (e.g. Wordle’s secret word) instead of ignoring the seed. TextArena picks episodes via the process-globalrandom(and sometimesnumpy) RNGs without applyingreset(seed=...), so the wrapper seeds those RNGs immediately before the underlying reset, forwardsseedwhen the game supports it, and leavesseed=Nonebehavior unchanged.Seeding runs under a process-wide lock so concurrent sessions can’t interleave seed + selection, and the prior RNG state is restored afterward so unseeded resets in the same process aren’t perturbed. This enables reproducible rollouts (e.g. GRPO groups sharing the same word).
Adds
tests/envs/test_textarena_seed.py(skipped withouttextarena) for same-seed determinism across resets/instances, seed-driven variety, unseeded resets, and global RNG preservation.Reviewed by Cursor Bugbot for commit 58723a9. Bugbot is set up for automated code reviews on this repo. Configure here.