Checkpoint Re-evaluation¶
Re-scores saved checkpoints with the current evaluation code without training. It exists to repair evaluation bugs (the 2026-09-30 Pursuit horizon fix in final-satisfaction.md), to add fields to old reports (per-rollout bits, certification), and to draw a fresh confirmatory rollout batch for selection-free certification.
Switches¶
Shared config keys, all False by default and declared in the eight curated
notebooks so they can be passed on the command line:
reevaluate: skip training; re-score every completed run in the manifest.reevaluate_nashconv: also recompute ApxNashConv (retrains the finite-budget best responses, so it costs about as much as the original NashConv stage).confirmatory_satisfaction: also evaluate a second, disjoint batch ofsatisfaction_eval_episodesrollouts per seed.-
reevaluation_tag(string, default empty): write every output under<algorithm>/reevaluation/<tag>/and leave the main artifacts untouched, so several candidate re-evaluations of one profile can run concurrently. -
reevaluate_satisfaction(defaultTrue):Falsere-scores only NashConv (requiresreevaluate_nashconv=True, rejectsconfirmatory_satisfaction). Satisfaction artifacts andreevaluation.jsonare left untouched, a legacy automaton numbering is reused fromreevaluation.json'snumbering_identification.permutation(no probes), and the outcome goes toreevaluation_nashconv.json. objective_nashconv(defaultFalse, only affectshc_*profiles): score ApxNashConv in temporal satisfaction like the objective-trained profiles. Baseline and deviation rollouts use the objective-reward environment (episode success = automaton acceptance) and the deviating agent trains on that reward withCOUNTERFACTUAL_REPLAY=True. The previous handcrafted-return scores are kept once asnash_handcrafted_reward.npy/nash_handcrafted_reward_report.json, andnash_report.jsonmetadata recordsnashconv_score(objective_satisfactionorhandcrafted_return). Training-time NashConv, which drives auto-resume, is unchanged: handcrafted profiles still use their own reward there.
These keys are listed in EVALUATION_ONLY_CONFIG_KEYS and excluded from the
partial-resume fingerprint. The fingerprint hashes the whole resolved config,
so without the exclusion adding the keys would have invalidated every existing
export's manifest and the next resume would have wiped it.
Behaviour¶
_run_temporal_game_algorithm_experiment branches to
_reevaluate_algorithm_checkpoints before the partial-resume loader, so the
loader's artifact clearing never runs in this mode. The branch:
- Requires
partial_resume_manifest.jsonand a fingerprint equal to the one computed from the current config. Pass the same notebook arguments used for training (for the paper campaign:num_runs=5 calculate_satisfaction=True; the launcher addsresume_partial_runs=Trueandjust_vis=False). A mismatch raises before any rollout and leaves artifacts untouched. - Copies the first evaluation's
satisfaction.npy/satisfaction_report.json(and NashConv files withreevaluate_nashconv) intolegacy_evaluation/once; later re-evaluations never overwrite that record. - For every completed run, loads
checkpoints/<label>.pkl, rebuilds the run config as training did (algo_configwithSEED=run_seed) and re-runs satisfaction on the original seeds (run_seed * 10^6 + 503 + i). Where the rollout semantics did not change, the counts reproduce exactly. - Confirmatory rollouts use
run_seed * 10^6 + 500503 + i(CONFIRMATORY_SATISFACTION_SEED_OFFSET), disjoint from the primary satisfaction (+503), NashConv (+7) and AlphaRank (+701) blocks. - NashConv, when requested, reuses the original seeds (+7) and replaces the
entries at the manifest's
nash_indexpositions. - Writes
satisfaction.npy,satisfaction_report.json, optionalnash.npy/nash_report.json,confirmatory_satisfaction.npy,confirmatory_satisfaction_report.json, andreevaluation.json(legacy vs new success counts and NashConv per run, asatisfaction_changedflag, and the confirmatory joint verdict). The manifest,runs.npy, checkpoints and timings are not modified, so ordinary resumes keep reusing the runs.
Checkpoint train states are Flax state dicts; rollouts read params through
train_state_params, and best-response trainers restore them with
restore_train_state, so no TrainState reconstruction is needed.
Automaton numbering and identification¶
Legacy checkpoints were trained under a hash-seed-dependent automaton state
numbering (automaton-state-numbering.md),
and the same checkpoint behaves differently under another numbering. Bundles
that record monitor_state_numbering are evaluated under it. For legacy
bundles (no record) the branch recovers the training numbering automatically
(_identify_legacy_numbering):
- Read the objective formulas from one objective env and compute, for hash
seeds
0..REEVALUATION_PROBE_HASH_SEEDS-1(160), the flloat permutation of canonical state ids each seed would produce (flloat_numbering_permutations, one short subprocess per seed). Distinct permutations are the task's numbering classes (Pursuit Capture 1, Pursuit Classic and Stag Hunt 2, Coins and Territory 4, Harvest 16). - With more than one class, replay each class in-process
(
use_monitor_state_numbering(permutation)) on the training job's own NashConv baseline rollouts (same rollout function, env and seedsrun_seed * 10^6 + 7 + i,eval_episodesepisodes per run) and count per-seed, per-agent baseline success counts that equal the legacybaseline_p * eval_episodes. A class matching every count stops the scan; otherwise the class with the most matches wins (earliest on ties, which only occur when the policies ignore the differing ids). For Pursuit Classic only the guard's counts can match, because the horizon bug inflated the intruders' legacy baselines; the guard'sG !goal_reachedbit is unaffected by it. - Evaluate everything under the winning permutation and record
numbering_identification(number of classes, chosen hash seed, matches, every probe's counts),monitor_numberingfingerprints andpython_hash_seedinreevaluation.json.
The 64-episode baseline probe cannot separate classes that differ only in
rarely visited automaton states, and the default scan stops at the first class
matching every count. reevaluation_primary_tiebreak=True (evaluation-only,
default off) probes every class and, when several share the best score,
re-scores each tied class on the full primary satisfaction rollouts against the
original evaluation's per-seed, per-agent counts; the identification records
these under tiebreak. It costs one full primary evaluation per tied class, so
it is used only where the integrity audit shows a profile that does not
reproduce its original counts. In the campaign that happened for Coins
PR2-IPPO-CER (seed 4, player 1: 374 vs 381) and Pursuit Classic 3 hc-IQL (guard
off by one on two seeds), both of which had stopped at the first full baseline
match.
legacy_successes and the legacy NashConv baselines always come from the
first evaluation (legacy_evaluation/ when present).
Protocol caveat¶
Auto-resume decisions made during the original campaign used the NashConv estimates available at the time. For Pursuit those estimates were inflated by the horizon bug, so the saved final checkpoints may have received (or missed) the 25% extra budget for a different reason than the corrected diagnostic would give. Re-evaluation certifies these frozen profiles as they are; it does not replay the auto-resume rule.
Launching¶
Use the ordinary launchers with the training arguments plus the switches, e.g.
on cpucluster:
bash scripts/pltlf/env.sh classic_2 amd96 bundles=8 feasible=True \
walltime=24:00:00 num_runs=5 calculate_satisfaction=True \
reevaluate=True reevaluate_nashconv=True confirmatory_satisfaction=True
Then aggregate with uv run python scripts/certification_summary.py --exports
exports --json <out.json>; it prints per-profile joint-certification counts,
task- and campaign-wide family-wise counts, confirmatory counts, worst-agent
joint lower bounds, ApxNashConv and exclusivity violations.
2026-09-30 campaign re-evaluation¶
All 66 curated profiles (5 seeds each) were re-scored on cpucluster with
reevaluate=True confirmatory_satisfaction=True, plus reevaluate_nashconv=True
for Pursuit, after the horizon fix and canonical numbering (commits 3c9126f
to 52bac3c). The 200-job per-user submit cap was full with another project's
jobs, so a login-node script (~/logs/pltlf_reeval/trickle_v*.sh) submitted
one bundled job at a time as slots freed. A first round without numbering
identification was discarded.
- Numbering identification: Pursuit Capture tasks have a unique numbering;
every other profile's chosen class matched all legacy NashConv baseline
counts except where only the Pursuit Classic guard could match (intruder
baselines were inflated by the horizon bug). No best-scoring tie disagreed on
counts (
certification_summary.pycolumn "Numbering"). - Stag Hunt, Coins: primary satisfaction reproduced the original counts
(Coins
pr2_ippo_cerseed 4 differed by one rollout). Stag Hunt IPPO-CER, IQL-CER, PR2-IQL-CER, Nash-Q-CER and hc-PR2-IQL are jointly certified on 5/5 seeds on both batches and after task- and campaign-wide Bonferroni corrections; hc-Nash-Q 3/5, PR2-IPPO-CER 2/5, hc-PR2-IPPO 1/5. - Pursuit: no seed profile is jointly certified (guard and intruder objectives exclude each other); the largest worst-agent joint lower bound is 0.339 (Capture 2 IQL-CER). The legacy "certified" Pursuit seeds were horizon-bug artifacts. No rollout in any task violates a declared exclusivity group.
- Coins: all eight profiles identified with 10/10 matches over four classes; none is certified on either batch (largest worst-agent bound 0.474).
- Territory (jobs 9117-9120, finished 2026-10-01): every profile identified its numbering with 10/10 matches over four classes, reproduced the original counts exactly, and certifies no seed on either batch (largest worst-agent bound 0.325).
- Harvest (jobs 9079-9086, finished 2026-10-02): every job's early-stopped
identification matched 20/20 baseline counts; seven profiles reproduce their
original counts exactly. IQL-CER did not (1-6 rollouts per seed) and was
re-evaluated with
reevaluation_primary_tiebreak=True(job 9659, 47 h, finished 2026-10-04): the tie-break chose hash seed 11 (20/20 baseline matches over 16 classes), every seed reproduces its original counts exactly, and no seed is jointly certified on the confirmatory batch. The paper's tables were regenerated without overrides (commitb19e393). - Integrity audits (
check_reevaluation_integrity.py, jobs 9594, 9621 and 9660): the first flagged Coins PR2-IPPO-CER, and a guard-count cross-check flagged Pursuit Classic 3 hc-IQL. Both had stopped at the first full baseline match and were fixed by tie-break reruns (jobs 9603 and 9604): the chosen classes, from hash seeds 3 and 2, reproduce all original counts. The final audit (job 9660,exports/integrity_audit_final2.json) passes all 66 CER and handcrafted profiles. Its 33 FAILs are exactly the no-CER ablation profiles, for reasons that follow from training them after the campaign start (artifact times, no legacy numbering to identify, backups of their own fresh evaluation, NashConv computed in training, eight still training); the job therefore exits non-zero by design.
scripts/regenerate_paper_figures.py (job pltlf_figs) rebuilt the Pursuit
paper panels into exports/paper_figures/, because handcrafted-baseline
markers move with the corrected satisfaction reports. Job 10856 (2026-10-03)
then rebuilt all eight suites with the 3% display smoothing
(package.md); the paper (commit 13c175d) uses
those panels.
No-CER ablation campaign (2026-10-03)¶
The paper claims every learner family with and without CER, but the campaign
had trained only the -CER and hc- profiles. The 33 missing no-CER profiles
(ippo, pr2_ippo, iql, pr2_iql on all eight tasks, plus nashq on Stag
Hunt) were queued on cpucluster by ~/logs/pltlf_ablation/trickle.sh. For
each profile it submits a training job (env.sh <task> amd96
algorithms=<algo> bundles=1 ablations=True num_runs=5
calculate_satisfaction=True, walltime 7 days for Harvest, 2 for Stag Hunt, 4
otherwise) and a re-evaluation job with the same arguments plus
reevaluate=True confirmatory_satisfaction=True, made dependent on training
(--dependency=afterok) through the SUBMIT_CMD wrapper
~/logs/pltlf_ablation/submit_after.sh. Job pairs are logged in
~/logs/pltlf_ablation/submitted.txt. New checkpoints record canonical
automaton numbering, so the re-evaluation needs no identification; it only
adds the confirmatory batch the -CER profiles have. The integrity audit's
--reeval-start check flags these profiles' training artifacts as newer than
the re-evaluation campaign; audit them with a later start time or skip that
check for them.
All 33 profiles finished on 2026-10-05 (the four Harvest confirmatory
re-evaluations last, at about 20:00); every primary batch reproduces its
training-time counts. Under the curated thresholds the base variants are close
to their -CER counterparts overall, with notable differences in both
directions: base IPPO certifies 4/5 Territory seeds (CER 0/5), base PR2-IPPO
4/5 Stag Hunt seeds (CER 2/5), and base IQL reaches 0.919 in Territory (CER
0.696), while CER is clearly stronger for Harvest PR2-IPPO, Territory PR2-IQL
and Pursuit Capture 2 IPPO. The paper (commit 2cf8af3) now picks each task's
selected profile from base and -CER together (Classic 3 and Territory switch
to base IQL) and lays the certification table out as one row per reward set;
including the base variants raises the campaign family size from 330 to 495.
A notebook kernel can die after a job has saved its results and leave the Slurm
job RUNNING with nothing left to do: Harvest PR2-IQL training (job 11167) died
with signal 7 (SIGBUS) while plotting on 2026-10-04, after writing all five
runs, and blocked its afterok re-evaluation. Check the log for "kernel ...
died", confirm the manifest lists five completed runs with satisfaction and
NashConv evaluated, then scontrol update jobid=<reeval> dependency=afterany:<train>
and scancel <train>.
Handcrafted ApxNashConv in temporal satisfaction (2026-10-04)¶
All 33 hc_* profiles were re-scored with reevaluate=True
reevaluate_nashconv=True reevaluate_satisfaction=False objective_nashconv=True
(~/logs/pltlf_hc_nashconv/, jobs from 11829; all completed the same day,
Harvest in about 2 h each). Every directory has reevaluation_nashconv.json
with objective_nashconv: true, a nash_report.json labelled
objective_satisfaction, and its handcrafted-return scores in
nash_handcrafted_reward_report.json; every legacy profile reused the numbering
recorded in reevaluation.json. Mean ApxNashConv stays small (at most 0.059):
it rose for Pursuit Capture 2 hc-PR2-IQL (0.016 to 0.059), Capture 3 hc-PR2-IQL
(0.010 to 0.046) and Coins hc-IPPO (0.013 to 0.050), fell to 0 for Pursuit
Classic 2 hc-IPPO, Capture 3 hc-IQL and Territory hc-IPPO, and is 0 for every
Stag Hunt profile. The paper quotes no handcrafted ApxNashConv value; its method
text was updated in paper commit 51b2728. Integrity audit job 12011
(exports/integrity_audit_final3.json) passes all 33 CER and all 33 handcrafted
profiles, the latter including the re-scored NashConv checks; its 33 FAILs are
exactly the no-CER ablation profiles, for the same expected reasons as job 9660.
On 2026-10-10 the curated profiles (including legacy_evaluation/), the paper
panels and integrity_audit_final3.json were archived; the earlier audit
JSONs and every non-paper export were deleted. See
paper data archive.
Integrity audit¶
scripts/check_reevaluation_integrity.py --exports exports --json <out> audits
every curated algorithm directory against the campaign's failure modes. It
checks that training artifacts are untouched (manifest, runs.npy and
checkpoints older than --reeval-start; checkpoints load with their seeds) and
that numbering identification was recorded with no ambiguous tie. It checks
that primary and confirmatory reports are internally consistent (seed blocks,
bit counts, Hoeffding intervals, joint outcome counts, zero exclusivity
violations, recomputed certificates, .npy against JSON), and that
reevaluation.json agrees with the reports and the original evaluation in
legacy_evaluation/. It also checks that NashConv files are re-scored only
for Pursuit and that no tagged reevaluation/<tag>/ directories remain.
Unfinished re-evaluations are reported as pending; the exit code is non-zero on
any failure. It loads every checkpoint, so run it as a cluster job.