Skip to content

Silent fixed-seed default prevents independent runs for most games. Consider adding a warning? #84

Description

@abahgat

When using Jericho to evaluate LLM agents, most callers would expect FrotzEnv without a seed to be stochastic, so that multiple experimental runs would be independent from each other. The paper explicitly defines a fixed random seed as a "handicap" that authors should consciously choose and disclose:

Handicaps: In summary, to ease the difficulty of IF games, Jericho optionally provides the following handicaps: 1) Fixed random seed to enforce determinism... For reproducibility, we report the handicaps used by all algorithms in this paper and encourage future work to do the same.

However, the jericho-python API silently enables this handicap by default. Right now, the unseeded default does the exact opposite of what most callers assume: it locks the environment to a single, hardcoded seed.

Problem

FrotzEnv.seed() resolves an unspecified seed like this:

jericho/jericho/jericho.py

Lines 432 to 446 in b6b48b5

def seed(self, seed=None):
'''
Changes seed used for the emulator's random number generator.
:param seed: Seed the random number generator used by the emulator.
Default: use walkthrough's seed if it exists,
otherwise use value of -1 which changes with time.
:returns: The value of the seed.
.. note:: :meth:`jericho.FrotzEnv.reset()` must be called before the seed takes effect.
'''
seed = seed or self.bindings.get('seed', -1)
self._seed = seed
return seed

For any game with walkthrough bindings (every game in the bundled benchmark suite) self.bindings.get('seed', -1) returns a fixed, positive integer (12 for Zork I), not -1.
-1 (the time-randomized fallback) only applies to a ROM without bindings, which I assume is the least common scenario.

This is the reverse of common conventions (omit a seed → get randomness), so, for most games, it's easy to construct FrotzEnv(rom) with no seed argument and reasonably assume you have independent, stochastic episodes when you don't.

Why this matters

This introduces multiple risks for researchers who inadvertently make incorrect assumptions.

  • Findings artificially weakened: Researchers testing agents typically assume "no seed passed" means "stochastic" (the standard convention in most environment APIs). When evaluating games with inherent randomness (like Zork), a fixed seed collapses the possibility space. The agent is not being tested on its ability to handle dynamic situations, varying combat outcomes, or bad luck; it is just replaying a single deterministic state path. This significantly weakens the validity of the evaluation.
  • Undisclosed handicaps: The Jericho paper asks authors to disclose fixed-seed handicaps, but researchers cannot disclose a handicap they do not know was implicitly applied for them.
  • Invisible provenance: The implicit seed's origin is invisible from a caller's code. You cannot tell whether a given run is on the walkthrough-bound seed or a real one without reading Jericho's source.

Additional Context

FrotzEnv.reset()'s own docstring already documents a use_walkthrough_seed parameter:

jericho/jericho/jericho.py

Lines 448 to 457 in b6b48b5

def reset(self):
'''
Resets the game.
:param use_walkthrough_seed: Seed the emulator to reproduce the walkthrough.
:returns: A tuple containing the initial observation,\
and a dictionary of info.
:rtype: string, dictionary
'''

But reset(self) takes no arguments, so this parameter doesn't exist anywhere in the implementation presently.

Suggest actually implementing the toggle this docstring already implies was intended, as a way to make the choice explicit rather than implicit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions