Experiments¶
Experiment notebooks compare reward, safety cost, and shield behavior across unconstrained, constrained-training, and runtime-shielded algorithms.
Select Stages Explicitly¶
Every environment notebook defines these switches:
| Key | Stage | Reported as | Learned WM/OM required? |
|---|---|---|---|
run_ippo |
IPPO | IPPO | No |
run_ippo_lag |
IPPO-Lagrangian | IPPO-Lagrangian | No |
run_cpo |
Constrained policy optimization | CPO | No |
run_ippo_shielded |
Learned transition shield + IPPO | OmSh-Monotone (default) | Yes |
run_ippo_true_shielded |
Exact true-policy shield + IPPO (oracle reference) | IPPO-TrueShielded | No |
run_exact_anytime_diagnostic |
Exact arbitrary-opponent certificate audit; no RL training | — | No |
just_vis |
Skip training and rebuild figures from saved histories | — | Existing histories |
All stages default to disabled. Select only the run_* keys needed for a
given invocation. IPPO, IPPO-Lagrangian, CPO, and OmSh-Monotone are the four
primary methods. TrueShielded is an oracle reference with information no
deployed agent has, and it is worth running for every environment and agent
count you report.
Shared Training Configuration¶
Common experiment keys include timesteps, num_runs, rollouts,
learning_epochs, mini_batches, learning_rate, max_risk, and
use_wandb. Use experiment_tag to isolate a campaign and seed_offset to
reserve a disjoint seed block. Shield controls include shield_action_mode,
shield_opponent_mode, shield_reward_mode, shield_patience,
shield_padding_radius, shielded_agent_ids, the credible-floor parameters,
debug/trace limits, and true_policy_refresh_interval_updates. The
Configuration reference lists every key with
its default.
CLI flags use kebab case:
uv run python notebooks/matrix/chicken/experiments_mo.py \
--run-ippo-shielded=true \
--max-risk=0.2 \
--shield-debug-mode=minimal \
--shield-patience=64
This call needs the learned graph and opponent stack. If the initial robust
risk demand exceeds max_risk, setup fails before training rather than running
an uncertified shield.
Reproduce the Campaign Protocol¶
Notebook defaults are convenient for local work, but they are not the published protocol. The campaign passes these settings explicitly:
| Setting | Matrix games, Pursuit, Gathering | Markov Stag Hunt | Congestion |
|---|---|---|---|
timesteps |
250,000 | 1,000,000 | 250,000 |
max_risk |
0.20 (Pursuit 0.16) | 0.20 | 0.10 |
seed_offset |
2200 | 2200 | 5300 |
num_runs |
5 | 5 | 5 |
final_policy_eval_episodes |
1,000 | 1,000 | 2,000 |
final_policy_eval_horizons |
(1,10,50,100,200) |
(1,10,50,100,200) |
(1,2,10,64) |
final_policy_eval_seed_offset |
2,200,000 | 2,200,000 | 4,200,000 |
shielded_agent_ids |
player_0 |
player_0 |
player_0,player_1 |
Always set an experiment_tag; the campaign aggregators only discover tagged
runs. Before trusting a new launch, diff its manifest config against the
reference campaign's, not only the flags you remember passing.
On the cluster, corrected_final_campaign.sh encodes this protocol for the
five non-Congestion environments only. Pass the tag explicitly (its default is
the August campaign's paper_final_corrected_2026_08_v2), and pass
PURSUIT_MAX_RISK=0.16 for a successor-world-model campaign, because it
defaults Pursuit to 0.11. Congestion is a separate predeclared confirmation
run through pipeline_env.sh or env.sh with its own seeds. The CX3
submitters encode all six. See Cluster Execution.
Final-Policy Evaluation¶
With final_policy_eval_episodes > 0, every algorithm run is frozen after
training and evaluated on fresh seeds, without adding episodes to its training
history. Shielded policies are evaluated within the same action masks they
were trained under. See Final-Policy Evaluation
for the keys, the exact post-processing of baselines, and campaign summaries.
Coordinated Multi-Role Shielding¶
In Congestion and Markov Stag Hunt, shielded_agent_ids names every role the
shield protects:
uv run python notebooks/gridworlds/congestion/train_om_mo.py --focal-idx=1
uv run python notebooks/gridworlds/congestion/experiments_mo.py \
--run-ippo-shielded=true --shielded-agent-ids=player_0,player_1
Each extra role needs its own opponent model, trained first with focal_idx.
Coordinated shielding requires shield_action_mode=pure. The campaign shields
both roles in Congestion but only player_0 in Markov Stag Hunt. When no explicit
shield_version is given, the notebook versions the run by its agent set
(for example agents_0_1), so it cannot overwrite the single-role condition.
Reports label it OmSh-Monotone (both roles). See
Probabilistic Shielding.
Parameterized OmSh Conditions¶
Every standard environment notebook exposes all four cells of the pure/mixed ×
egalitarian/learned-budget design through shield_action_mode:
| Value | Primitive action | Successor-budget allocation | Reported as |
|---|---|---|---|
pure |
One discrete action | Robust egalitarian fill | OmSh-Monotone |
egalitarian_mixed |
Pairwise mixture | Robust egalitarian fill | OmSh-Egalitarian-Mixed |
learned_budget_pure |
One discrete action | Learned proposal, robustly projected | OmSh-LearnedBudget-Pure |
learned_budget_mixed |
Pairwise mixture | Learned proposal, robustly projected | OmSh-LearnedBudget-Mixed |
Selecting a non-pure mode automatically uses ParameterizedIPPO and a
ParameterizedTransitionShield; no custom driver is required. All conditions
start PPO from fresh initialization and share the same compatible WM/OM
artifacts. Condition-specific names prevent their histories, diagnostics,
checkpoints, timings, and plots from overwriting the default pure condition.
For example:
uv run python notebooks/matrix/chicken/experiments_mo.py \
--run-ippo-shielded=true \
--shield-action-mode=learned_budget_pure \
--experiment-tag=chicken_budget_holdout \
--seed-offset=400 --num-runs=5
The lower-level PARAMETERIZED_OMSH_VARIANTS and
make_parameterized_shielded_env_factory(...) helpers remain available for
custom experiment drivers. Ablations covers this and the
other shield variants, including padding and patience.
Robustness Diagnostics in Training¶
Two keys add guarantee-facing diagnostics to a normal training run:
shield_padding_radius=rtrains with the padded certificate (default0, the deployed shield). Padded runs get their own artifact stem and label, for exampleOmSh-Monotone-Padded-r0.15.log_opponent_level_gap=truerecords the closest-retained-level opponent gap on sampled rollout states. Unlikeverbose_data, it does not also turn on heavy per-step shield traces.
See Guarantees and Robustness for what they measure.
Exact Anytime Diagnostic¶
The optional anytime audit is disabled in every environment notebook. Enable it independently of all training stages:
uv run python notebooks/matrix/chicken/experiments_mo.py \
--run-exact-anytime-diagnostic=true \
--max-risk=0.2
It builds or reuses the serialized exact transition graph, binds it to the
recorded environment contract, solves the arbitrary-opponent reachability
game, independently validates the certificate, and writes
true_shield/exact_anytime/certificate.pkl plus report.json. The report
always records training_environment_steps=0; enabling this switch does not
run PPO or repeat experiment seeds. On the matrix games it is a small offline
cost. For gridworlds, a cache miss can make exact graph enumeration the
dominant cost, but it is still separate from the multi-run training budget.
Recommended reporting order for the retained suite:
| Environment | Use in an anytime table? | Reason |
|---|---|---|
| Bertrand, Chicken | Yes, first | Tiny exact graphs built by stepping the live simulator, so the rows are simulator-bound. |
| Congestion | Yes | Surely-safe from reset; start with two vehicles, because larger fleets grow the exact graph rapidly. |
| Pursuit (2 agents) | Yes, as a negative control | Arbitrary opponents may make the requested reset budget infeasible. |
| Gathering, Markov Stag Hunt | Only with a reset-support caveat | Default exact builds use sampled reset states; do not generalize the certificate to unlisted resets. |
Only a report with certificate_status="certified" (complete reset support) or
"certified_on_declared_reset_support" (an explicitly conditional claim),
solver_converged=true, certificate_inductive=true, and
reset_feasible=true supports the guarantee. infeasible is a valid audit
outcome, not a certified runtime condition. The scope is one focal agent and
one episode beginning at reset. delta_cov=0 is relative to the serialized
exact graph, matching environment contract, and declared reset support. The
gridworld exact builders use separate successor functions, so their
certificates are relative to the serialized graph rather than the simulator
itself.
For evaluation-only deployment, reconstruct existing policy adapters and call
evaluate_exact_anytime_policies(...). It writes streaming episode aggregates
to true_shield/exact_anytime/evaluation_report.json, performs no learning,
and stores no per-step trace. scripts/summarize_exact_anytime_diagnostics.py
collects the reports into paper tables.
Tagged Evaluations¶
A non-empty experiment_tag writes each condition's histories, diagnostics,
checkpoints, final-policy reports, manifest, and timing sidecar below
experiments/runs/<normalized-tag>/ and leaves the corresponding canonical
stage artifacts untouched. Tags are normalized to lowercase
underscore-separated tokens. seed_offset changes trainer seeds without
changing the local run indices used for paired comparisons.
Tagged runs also render their aggregate figures in the tagged directory, so OmSh-Monotone, OmSh-Credible, and other conditions in one tag share a campaign plot.
Summarize all matching environment runs with:
The command writes JSON, Markdown, and compact LaTeX diagnostics under
exports/reports/<normalized-tag>/. It aggregates within each seed before
averaging seeds, reports whole-run and final-window reward and observed safety,
and only emits paired baseline deltas when matching baseline seeds exist.
Incomplete or tuning-only tags remain visible but are marked incomplete. For
frozen-policy results use scripts/summarize_final_policy_campaign.py
instead.
Repeated Runs and Histories¶
num_runs selects independent seeds. Each stage writes a list of episode
histories under experiments/histories/. EpisodeLog rows contain episode
boundaries, focal reward/safety totals, level raises, and shield telemetry
aggregates where applicable.
Figure exports include cumulative, episodic, post-WM-timeline, no-legend, and shield telemetry variants. Structured single-metric episode graphs are derived from completed episode rows rather than per-update approximations.
Compact episode tables, update metrics, aggregate diagnostics, checkpoints,
and completion manifests are always exported. verbose_data=true additionally
enables bounded raw shield traces and sampled live-policy/IOP comparisons; it
does not add environment rollouts.
Weights & Biases¶
When use_wandb=true, each algorithm run creates a run using the shared config
and logs its history. Congestion and Markov Stag Hunt default it on; the other
notebooks default it off. Pass --use-wandb=false for unattended smoke tests
unless credentials and project behavior are deliberately configured.