Games and Learned Game Engines › Long-Horizon Consistency and Rules

Michael BrenndoerferJuly 25, 202612 min read
World Models HandbookAll chapters
Part 10 of 12Application Domains
Chapter 55Games and Learned Game Engines › Long-Horizon Consistency and Rules
Reading section 5 of 10 · Long-Horizon Consistency and Rules · 12 minSection 5 of 10 · 12 min

Book contents

Section 5 of 10 · 12 min read

Games and Learned Game Engines › Long-Horizon Consistency and RulesOne section · Sections in this chapter5 / 10 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

One-step accuracy is not enough when a model is fed its own predictions. A small error may change the next input, which can create further error; whether the deviation grows, shrinks, or changes decisions depends on the learned transition and the states visited. The bound below shows one possible relationship between one-step and recursive errors under an explicit smoothness assumption. It is not a universal forecast that every video model fails after a fixed number of frames.

Compounding Error: The Math

Suppose the true dynamics are st+1=f(st,at)s_{t+1}=f(s_t,a_t) and a model rollout is s^t+1=f^(s^t,at)\hat{s}_{t+1}=\hat f(\hat s_t,a_t) under the same action sequence. Let et=∥s^t−st∥2e_t=\|\hat s_t-s_t\|_2 and let ϵt=∥f^(st,at)−f(st,at)∥2\epsilon_t=\|\hat f(s_t,a_t)-f(s_t,a_t)\|_2 be the one-step model error evaluated at the true state. If f^\hat f is LL-Lipschitz in its state input along both compared trajectories, the triangle inequality gives

et+1≤L⋅et+ϵt,e_{t+1} \le L \cdot e_t + \epsilon_t,

where:

  • ete_t: the error ∥s^t−st∥\|\hat{s}_t - s_t\| between the predicted and true state at rollout step tt
  • LL: the Lipschitz constant of f^\hat{f} with respect to its state input, i.e., the worst-case factor by which a small state perturbation is amplified in one model step
  • ϵt\epsilon_t: the one-step model error at step tt, i.e., the error introduced when the model predicts the next state from the true current state

Unrolling the recursion gives the error at horizon TT:

eT≤LTe0+∑t=0T−1LT−1−tϵt.e_T \le L^T e_0 + \sum_{t=0}^{T-1} L^{T-1-t} \epsilon_t.

Here e0e_0 is the initial error. If every ϵt≤ϵ\epsilon_t\le\epsilon, then for L<1L<1 the bound approaches ϵ/(1−L)\epsilon/(1-L) as TT grows while the initial-error term decays; for L=1L=1 it is e0+Tϵe_0+T\epsilon; and for L>1L>1 it may grow exponentially. This is an upper bound, not an equality or a measured growth law. Its premises require the same actions and a Lipschitz bound covering the compared states, including the model-generated ones; a bound measured only on training states would not suffice for an out-of-distribution rollout.

The three regimes can be compared directly by iterating the recursion with a constant per-step error.

In[15]:
Code
# Theoretical rollout-error envelopes from e_{t+1} = L * e_t + eps_t,
# with a constant per-step error eps = 0.05 and initial error e_0 = eps.
# L < 1 damps prior error toward a finite bound, L = 1 accumulates
# linearly, and L > 1 permits exponential growth of the bound. These
# curves iterate the bound above; they are not measurements, so no seed is needed.
lipschitz_values = [0.8, 1.0, 1.2]
per_step_error = 0.05
theoretical_horizon = np.arange(0, 21)
theoretical_error_curves = {}
for L_val in lipschitz_values:
    errs = np.empty(theoretical_horizon.size)
    errs[0] = per_step_error
    for t in range(1, theoretical_horizon.size):
        errs[t] = L_val * errs[t - 1] + per_step_error
    theoretical_error_curves[L_val] = errs
Out[16]:
Visualization
Line plot of rollout error growth for Lipschitz constants 0.8, 1.0, and 1.2.
Illustrative equality recursion e_{t+1} = L e_t + 0.05, initialized at e_0 = 0.05. The L = 0.8 curve approaches a finite bound, L = 1 grows linearly, and L = 1.2 grows faster over the plotted horizon. These are theoretical envelopes, not a fit to the learned grid-world model or evidence that its Lipschitz constant is near one.

The analytical curves illustrate possible amplification. They do not estimate this fitted grid-world model's Lipschitz constant. Shortening a rollout limits the number of recursive predictions, and re-anchoring replaces a predicted state with an observation; whether either improves decisions still requires evaluation.

Two Failure Modes: Drift and Collapse

Two useful descriptions of long-horizon failure are gradual drift and abrupt rule failure. They are not exhaustive or tied to a universal time scale.

  • Drift. A predicted trajectory can gradually diverge in position, appearance, or timing while each frame still looks plausible. Measure it against a reference trajectory under a specified action sequence; do not infer a fixed failure frame count from a single demonstration.
  • Rule failure. A model may generate a transition that violates a specified mechanic, such as a character jumping again in mid-air when the game permits only one jump. The error may appear abruptly or after a long rollout; it need not be caused only by an out-of-distribution input.

Different measurements reveal different problems. A frame-distance curve may reveal accumulating prediction error, while a targeted rule test can expose a failure that looks visually minor. Noise augmentation, broader training coverage, longer context, and explicit constraints are possible interventions, but their effects depend on the model and rule being tested.

Diffusion does not make temporal errors disappear: an autoregressive diffusion world model still conditions future frames on generated history. DIAMOND's project report shows a concrete rule violation—repeated jumps not allowed by the reference game. GameNGen used conditioning augmentations for stable autoregressive generation, and its authors evaluated clips after five minutes of generation. Neither example supports a blanket claim that visual generators fail after 30–60 frames or that one model family is intrinsically immune to collapse.

Rule Consistency: The Underappreciated Signal

Games have mechanics that can be stated and tested. A learned model that lets an agent pass through an impassable wall may support a policy that fails in the reference game. But scores can legitimately decrease in some games, and a visible inconsistency does not guarantee that a trained agent will exploit it. To assess rule consistency, specify the rule, action distribution, and observation conditions, then count violations over evaluated transitions.

This idea is worth stating as a criterion.

Rule Consistency

A learned game engine is rule-consistent on a distribution of trajectories if the fraction of transitions that violate a specified rule of the underlying game is small. Rule consistency is a separate requirement from perceptual similarity: a model can look right while breaking a rule that the eye does not check.

Downstream agent return in the reference game is a separate, indirect test of decision usefulness: poor transfer could stem from rule errors, reward errors, policy optimization, or another mismatch. It cannot by itself identify which mechanic failed. Direct tests can replay a chosen action sequence and score specified mechanics. Part XI's planned chapter on state, physics, causality, and memory evaluation develops that distinction further.

Techniques for Long-Horizon Consistency

Several techniques can be tested for longer rollouts; none is universal.

  • Exposure to predicted states. Training on some model-generated histories can reduce the mismatch between training and rollout inputs, if those histories are representative. Do not assume every cited system uses the same procedure.
  • Conditioning augmentation. Corrupting conditioning frames during training may improve robustness to prediction noise; GameNGen reports this intervention. It can also change one-step accuracy, so both should be measured.
  • Temporal context or external memory. Access to earlier observations can help recover hidden or revisited details, at a model-dependent compute cost. A demonstrated one-minute video is not evidence of a one-minute input context window. See Temporal State and Memory.
  • Latent prediction. A compact latent can omit pixel detail irrelevant to a decision objective; it does not make state or reward prediction error vanish.
  • Re-anchoring. Replacing a predicted state with a new observation truncates the executed model rollout. It cannot retroactively remove errors in the candidate futures that selected the preceding action.

In the mathematical bound, a shorter horizon reduces the number of propagated terms. The other techniques may change the local errors or dynamics but do not guarantee a smaller ϵt\epsilon_t or LL. They need before-and-after evaluation under the same protocol.

Measuring Drift in Our Grid-World Engine

We now collect fifty new random-policy episodes with a separate seed and compare model-generated observations with the reference environment under the same recorded actions, for at most twenty steps. Episodes terminate at different times, so the number contributing to each horizon can change. This is a fresh-episode test, unlike the transition-level validation split above.

In[17]:
Code
def recursive_rollout(model, obs0_flat, actions):
    """Roll the model forward autoregressively. Returns predictions for t=0..T."""
    preds = [obs0_flat.detach().clone()]
    cur = obs0_flat.unsqueeze(0)
    with torch.no_grad():
        for a in actions:
            a_t = torch.tensor([int(a)])
            next_obs, _ = model(cur, a_t)
            preds.append(next_obs.squeeze(0))
            cur = next_obs
    return torch.stack(preds)


def collect_held_out_episodes(n_episodes=50, seed=999):
    env = GridWorld(seed=seed)
    episodes = []
    for _ in range(n_episodes):
        obs = env.reset()
        ep_obs, ep_act = [obs], []
        done = False
        while not done:
            a = int(env.rng.integers(0, 4))
            next_obs, _, done = env.step(a)
            ep_act.append(a)
            ep_obs.append(next_obs)
            obs = next_obs
        episodes.append(
            (
                np.array(ep_obs, dtype=np.float32),
                np.array(ep_act, dtype=np.int64),
            )
        )
    return episodes


held_out = collect_held_out_episodes()

T = 20
horizon_err_sum = np.zeros(T + 1)
horizon_counts = np.zeros(T + 1)

with torch.no_grad():
    for ep_obs, ep_act in held_out:
        obs0 = torch.from_numpy(ep_obs[0].reshape(-1))
        preds = recursive_rollout(W_model, obs0, ep_act[:T])
        L = len(preds)
        true_obs = torch.from_numpy(ep_obs[:L].reshape(L, -1))
        errs = ((preds - true_obs) ** 2).sum(dim=-1).sqrt().numpy()
        horizon_err_sum[:L] += errs
        horizon_counts[:L] += 1

horizon_errors = horizon_err_sum / np.maximum(horizon_counts, 1)
Out[18]:
Console
Rollout L2 error by horizon: [0.    1.001 1.113 1.182 1.226 1.296 1.334 1.401 1.444 1.469 1.527 1.58
 1.607 1.669 1.746 1.815 1.929 2.065 2.201 2.41  2.585]
Out[19]:
Visualization
Line plot of measured recursive rollout L2 error rising from about one to about 2.6 over twenty steps.
Mean recursive rollout L2 error against held-out true observations over up to twenty steps. Starting from an exact first frame, error rises from about one after a single predicted step to about 2.6 at step twenty in this seeded run. This is measured drift, not evidence of a twentyfold increase or a fitted Lipschitz constant.

The mean L2 distance rises from around one after the first predicted transition to about 2.6 at step twenty in this seeded run. At each horizon the mean uses episodes still available there, so the changing set is another reason not to read the curve as a fitted growth law. It neither identifies the model's Lipschitz constant nor proves that a trajectory left the training-state distribution.

The aggregate curve hides the appearance of an individual trajectory. For one selected held-out episode, we decode the highest-scoring agent cell in each predicted frame and compare it with the true path. This illustration does not estimate how frequently such divergences occur.

In[20]:
Code
# Decode the agent cell from channel 0 of each predicted observation and
# compare it with the true agent cell from the held-out episode.
# Selection rule: keep episodes with at least 15 actions; choose the episode
# whose true path visits the most distinct cells (first index breaks ties).
# Episodes come from collect_held_out_episodes(seed=999) collected above.
trajectory_rollout_horizon = 15
candidate_episodes = [
    idx for idx, (ep_obs, ep_act) in enumerate(held_out) if len(ep_act) >= 15
]
# Selection uses only the true path, not model error; the figure is illustrative.
candidate_episodes = sorted(
    candidate_episodes,
    key=lambda i: len(
        np.unique(
            [
                tuple(np.unravel_index(int(c.argmax()), (5, 5)))
                for c in held_out[i][0].reshape(-1, 2, 5, 5)[:, 0]
            ],
            axis=0,
        )
    ),
    reverse=True,
)
selected_episodes = candidate_episodes[:1]

trajectory_episodes = []
with torch.no_grad():
    for idx in selected_episodes:
        ep_obs, ep_act = held_out[idx]
        obs0 = torch.from_numpy(ep_obs[0].reshape(-1))
        preds = recursive_rollout(
            W_model, obs0, ep_act[:trajectory_rollout_horizon]
        )
        n_steps = len(preds)
        true_agent = ep_obs[:n_steps].reshape(n_steps, 2, 5, 5)[:, 0]
        pred_agent = preds.reshape(n_steps, 2, 5, 5)[:, 0]
        true_cells = np.array(
            [np.unravel_index(int(p.argmax()), (5, 5)) for p in true_agent]
        )
        pred_cells = np.array(
            [np.unravel_index(int(p.argmax()), (5, 5)) for p in pred_agent]
        )
        goal_cell = np.unravel_index(int(ep_obs[0, 1].argmax()), (5, 5))
        trajectory_episodes.append(
            {
                "episode": idx,
                "goal": goal_cell,
                "true": true_cells,
                "pred": pred_cells,
            }
        )
Out[21]:
Visualization
Five-by-five grid showing one true agent path, one predicted path, and the true goal over at most fifteen actions.
True and model-rolled-out agent paths for one held-out episode over at most fifteen actions. The episode is selected by the number of distinct cells in its true path, not by model error. Both paths start from the real first observation; the star marks its true goal.

The natural questions are: can an agent still use this model to make decisions, and how careful must it be about the drift? The next section addresses that.