World-model variant study (Stage 1)¶
A model-level comparison of transition-kernel estimators, run before any downstream campaign. A failure here is a useful result: it says the more structurally appropriate model did not materially improve kernel estimation, without paying for the full RL campaign.
The arms and the adoption gate are predeclared in goal.md before the sweep
runs. This note describes the machinery; it must not be used to redefine the
criteria afterwards.
Why a standalone harness¶
The WM notebooks hard-code dir = f"exports/.../{N_AGENTS}/wm" and pass no seed
to collect_rollouts_ppo, so they cannot be fanned out per variant without
colliding. scripts/wm_variant_study.py is also the better experiment: every arm
sees the same rollout buffer and the same fitting protocol, so a difference
between arms is representational rather than procedural, and results pair cleanly
by (environment, seed).
The notebooks stay untouched until the gate passes.
The five arms¶
| Arm | Definition |
|---|---|
bit_mlp |
existing WorldModelMLP, product-Bernoulli scoring — the baseline |
successor |
masked categorical SuccessorEdgeModel |
counts |
MLE \(N(s,a,s')/N(s,a)\), uniform fallback on unvisited rows |
counts_dirichlet |
\(q\) uniform over \(\mathrm{Succ}(s,a)\), \(\alpha = 1\) |
counts_neural_prior |
\(q = \Gamma_\theta\), \(\alpha = 1\) |
\(q\) and \(\alpha\) are fixed per arm so no estimator is defined after seeing results.
Protocol¶
PPO buffer
├── train subset -> all learned and count arms fit here
└── validation subset -> epoch selection / early stopping only
held-out random buffer -> evaluation only
oracle graph -> final metrics only, never tuning
A representation comparison is only valid if the training procedure is held
constant. The published train_world_model_mlp has no validation split, so
giving only the successor model best-epoch selection would confound
representation with procedure. It therefore gained opt-in val_indices and
early_stopping_patience, off by default so the published path is unchanged,
and both neural arms use the same rule on the same split.
Scoring¶
Each arm is scored from its annotated graph, not from the model object. That is exactly the kernel the shield will consume, and it is the only way to put the product-Bernoulli baseline on the same footing as the categorical arms, since its row distribution exists only after candidate renormalisation.
- Exhaustive transition TV reuses
export_world_model_transition_tvunchanged, so numbers stay comparable withreports/08/2026-08-16 reward-safety and guarantee audit.md§12.1. - Row NLL, oracle cross-entropy, KL, categorical Brier, successor-conditioned
reward MAE and
oracle_row_masscome fromsrc/world_model/successor/eval.py. See../world-model/successor-kernel.md. - Bit and cell accuracy remain available as debugging columns only.
Environments and seeds¶
Six environments have a tractable exact oracle. Bertrand, Chicken and Congestion-2 are deterministic — every row is a singleton, so TV is structurally zero for every arm — and act as regression guards. The signal is Gathering-2, MSH-2 and Pursuit-2.
Ten seeds per environment. The gate rests on bootstrap CIs over paired differences, and five paired observations per environment gives unstable intervals. If the stochastic environments prove expensive, the fallback is a five-seed pilot expanded to ten on those three before any adoption decision — never deciding on the pilot.
Caching¶
The legal graph and the oracle graph are seed-independent and are cached once per
environment under a FileLock, not per cell. Ten concurrent seeds would
otherwise rebuild them ten times, and those builds dominate cost on the larger
environments.
Running it¶
# local smoke check on the smallest graph
uv run python scripts/wm_variant_study.py --env bertrand --seeds 1 \
--train_steps 4000 --holdout_steps 2000 --epochs 8 --hidden 64
# inspect the fan-out before submitting
DRY_RUN=1 bash notebooks/experiments/scripts/wm_variants.sh
# ten seeds across six environments on cpucluster: 60 jobs
bash notebooks/experiments/scripts/wm_variants.sh
# stochastic environments only, larger budget
STOCHASTIC_ONLY=1 bash notebooks/experiments/scripts/wm_variants.sh train_steps=250000
# apply the predeclared gate
uv run python scripts/summarize_wm_variants.py --tag wm_variant_stage1
The cluster Python runner requires strict key=value arguments and translates
each into --key value. The launcher therefore rejects CLI-flag syntax in its
pass-through arguments, and the study script accepts underscore spellings
(--seed_offset, --train_steps, …) with --allow_unresolved taking an
explicit boolean value rather than being a bare store_true.
Results land under <output_root>/<env>/<agents>/seed<N>/summary.json, with
wm_variant_gate.json, wm_variant_summary.md and wm_variant_comparison.tex
written by the aggregator alongside them. The .tex is the paper's Stage 1
table; it is generated rather than maintained by hand so it cannot drift from the
summaries.
Note that --output_root must already include the tag. The study writes
<output_root>/<env>/<agents>/seed<N> and does not append --tag to the path —
the tag labels the run, not the directory — so passing a bare reports root
scatters cells beside the other tags' directories, where the next aggregation
over that root will mix two sweeps.
The gate¶
Applied by scripts/summarize_wm_variants.py. Paired by (env, seed) on
identical buffers, over the three stochastic environments, with 95% bootstrap CIs
on the paired differences.
- Primary criteria: mean TV, p95 TV, oracle cross-entropy.
- Adopt an arm over
bit_mlpif: paired mean-TV relative reduction \(\ge 20\%\) in at least 2 of 3 environments, with no environment worse than \(+5\%\) relative; paired p95-TV no worse than \(+5\%\) relative anywhere; paired oracle cross-entropy improved in all 3, with the CI excluding zero in at least 2. - Max TV is a safety-oriented non-regression diagnostic: flagged if worse by more than \(10\%\) relative, but a single worst-row outlier does not by itself fail an arm.
- Deterministic environments: TV \(\le 10^{-6}\) for every arm.
- All four non-baseline arms are judged on the same footing. If a count model wins, that is the result — adopt and report it rather than forcing adoption of the neural arm. A null result is reported as-is.
Two protocol amendments, and how to reproduce either¶
The harness defaults reproduce the original 2026-09-20 gate, not the shipped protocol. That is deliberate — the gate verdict is immutable and must stay reproducible — but it means a probe of the current model has to ask for it:
| gate run (default) | shipped protocol | |
|---|---|---|
selection_metric |
row_nll |
objective |
min_optimizer_steps |
0 |
2000 |
Selection moved to the full validation objective because the row NLL is
identically zero from the first pass on a singleton-support row, so selecting on
it restores a checkpoint whose reward head is untrained. The optimiser-step floor
followed because exact count aggregation makes an epoch a single update on a
low-group-count environment, so the epoch cap ended training before patience ever
fired. Neither is sufficient alone, which was measured rather than assumed:
running the floor while leaving selection at row_nll recovers the original
reward errors to within seed noise — 3.227, 1.438 and 1.331 over three seeds
against 3.229, 1.427 and 1.321 over ten — because selection still pins at update
1 however long training runs. The 2,000 updates are taken and then discarded.
The whole 60-cell matrix was rerun with objective selection
(wm_variant_stage1_objective, the paper's table) and reached the same verdict
with the same passing arms; both verdicts stand, the later one alongside rather
than replacing the earlier. That rerun predates the step floor: its archived
summary.json configs have selection_metric: objective and no
min_optimizer_steps key (checked 6 Nov 2026), so it ran with floor 0. The CX3
re-run repeats exactly that (cx3_arxiv_independent.sh).
min_optimizer_steps and max_optimizer_steps are pinned config keys in the
aggregator alongside selection_metric, so a tree mixing budgets is reported as
two protocols rather than one experiment.
What follows¶
Stage 2A (the downstream RL campaign) runs only if the gate passes; a null result
leaves bit_mlp as the published nominal model. Stage 2B, the certified
ambiguity-set evaluation, runs regardless — see
../shielding/anytime-ambiguity-sets.md.