record-run
Log an experiment run (training and/or eval) using this repo's manifest + notes + generated-index convention so results from different mechanisms and collaborators stay apples-to-apples. Use whenever
SKILL.md.claude/skills/record-run/SKILL.md
GitHubRecording runs
Every real run gets logged — pilot, sweep, failed or not. Skip only throwaway smoke tests (n < 10, just checking code runs); delete their output. A run on real data at a meaningful n that produces a number anyone might compare against is a real run.
Steps
Save the record with
RunRecord:from latentreasoning.runlog.manifest import RunRecord, ModelInfo, DatasetInfo, new_run_id from latentreasoning.utils import set_seed seed = set_seed(42) # before any training/generation ... record = RunRecord( run_id=new_run_id("filler_tokens", "budget-sweep-32"), mechanism="filler_tokens", # latentreasoning.runlog.manifest.MECHANISMS, or "baseline_*" stage="pilot", # "smoke_test" | "pilot" | "full_run" model=ModelInfo(backbone="gpt2-edited", checkpoint="results/<run_id>/ckpt", n_params=124_439_808), dataset=DatasetInfo(name="gsm8k-aug", split="test", n_examples=200, seed=0), metrics={"final_answer_accuracy": 0.31, "unparseable_rate": 0.02, "compute_steps": 32, "extra": {"cot_tokens": 41}}, # mechanism-specific stuff goes under "extra" hyperparams={"lr": 5e-5, "epochs": 3, "batch_size": 16, "filler_token": "."}, seed=seed, hardware="RunPod A40 x1", notes="one line on what this run asks", ) record.save(predictions=eval_result.records) # -> results/<run_id>/{manifest.json, predictions.jsonl, notes.md}Always pass
predictions— per-example outputs are the error-analysis and decoder-training data later. Also droptrainer.state.log_historyintoresults/<run_id>/train_log.jsonif you trained.Fill in
results/<run_id>/notes.md—save()created a template with the numbers pre-filled. Goal, command, interpretation, gotchas, caveats, next. A number without the story is hard to trust later.Regenerate the index:
uv run python scripts/rebuild_index.pyrewritesresults/README.mdandEXPERIMENTS.md. Never hand-edit those two.Commit
results/<run_id>/+ the two generated files. Checkpoints and other large artifacts stay on the pod volume (.gitignoredrops everything inresults/<run_id>/except manifest / notes / predictions / train_log); reference them by path inmodel.checkpoint.
Never rewrite a past run's numbers or notes. If it turns out flawed, append a correction
to its notes.md (or log a follow-up run) and rebuild.
Merge conflicts
Run directories never conflict. results/README.md and EXPERIMENTS.md will — take
either side, rerun rebuild_index.py, commit. tests/test_index.py fails if they're stale.
Comparing runs — the compute-budget rule
metrics["compute_steps"] is the budget knob: filler tokens emitted / loop iterations r /
continuous-thought tokens. explicit_cot is unbudgeted; it reports
metrics["extra"]["cot_tokens"] instead.
Only compare final_answer_accuracy when compute_steps, dataset.split,
dataset.n_examples, dataset.seed, and seed match. 32 filler tokens vs r=32 loops
is not automatically matched — say in notes.md what you matched on (extra forward
passes, FLOPs, ...) before quoting one against the other.
from latentreasoning.runlog.manifest import load_all_runs
runs = [r for r in load_all_runs() if r["dataset"]["split"] == "test"
and r["dataset"]["n_examples"] == 200 and r["metrics"].get("compute_steps") == 32]
Shell: jq '[.mechanism, .metrics.final_answer_accuracy, .metrics.compute_steps]' results/*/manifest.json
Runs on unmerged branches aren't in main's index — check open branches before
concluding something wasn't tried.
Canonical metric keys
final_answer_accuracy, unparseable_rate (don't let a high one hide inside a mediocre
accuracy), compute_steps, train_loss, eval_loss, sec_per_example. Anything else
under metrics["extra"].
Reserved for the October milestones (PROPOSAL.md metrics) -- use these spellings when
you get there, and define exactly how you computed it in notes.md:
decoding_accuracy, early_termination_necessity, intervention_accuracy,
transplant_success. Note early_termination_necessity (truncate the scratchpad at
inference on a full-budget model) is a different measurement from a compute_steps
sweep (train + eval at each budget) -- don't quote one as the other.