Skip to content

TASK-045: headless periodic checkpointing (pyflow record) - #77

Merged
AdamClemens merged 3 commits into
mainfrom
feat/task-045-checkpoint-recording
Sep 7, 2026
Merged

TASK-045: headless periodic checkpointing (pyflow record)#77
AdamClemens merged 3 commits into
mainfrom
feat/task-045-checkpoint-recording

Conversation

@AdamClemens

Copy link
Copy Markdown
Owner

Summary

Opens Stage 8 (Recording & Playback) with its first task: a new pyflow record subcommand that steps a simulation forward with no rendering window at all, writing self-contained, resumable checkpoint files at a bounded, config-driven interval.

  • simulation_run.py extracts bootstrap.py's simulation-state construction/advancement logic so a genuinely headless path can reuse it without ever constructing a RenderWindow (verified behaviour-preserving by the full pre-existing suite passing unmodified).
  • checkpoint.py holds the torch.save-based, weights_only=True-loadable checkpoint format (config embedded as dataclasses.asdict, no per-field type tag needed since PressureField is never checkpointed) and restore_simulation_state, which reconstructs a resumable SimulationState correctly for "passive" mode (whose prescribed velocity field is never itself checkpointed).
  • recording.py never imports rendering/pygfx/rendercanvas at all -- headless is structural, not a default.
  • Resume-from-checkpoint determinism is checked bit-identical (rtol=0, atol=0) and confirmed to have real teeth by deliberately corrupting restore_simulation_state and watching the test fail before trusting it green.

Replay and playback (TASK-046/047) are deliberately out of scope, named explicitly throughout Stage 8's own Completion Criteria and Discharge map, along with the two backlog/doc obligations they leave open (docs/planning/backlog.md, docs/architecture/sequences.md's Section 3).

Test plan

  • make ci green in full (lint, mypy --strict, full suite, all doc-consistency checks)
  • Mutation-tested the determinism test by hand (corrupted restore_simulation_state, confirmed the test failed, reverted, confirmed green)
  • Manual smoke test: pyflow record --config examples/golden-demos/heat_diffusion.yaml --max-frames 200 --output-dir ... produced the expected 3 checkpoint files; inspected one directly with torch.load to confirm shape/content
  • tests/integration/test_record_cli.py runs pyflow record as a real subprocess against a real golden demo

🤖 Generated with Claude Code

AdamClemens and others added 3 commits September 7, 2026 11:15
Opens Stage 8 (Recording & Playback) with its first task: a new
pyflow record subcommand that steps a simulation forward with no
rendering window at all, writing self-contained, resumable checkpoint
files at a bounded, config-driven interval. bootstrap.py's simulation-
state construction/advancement logic is extracted into simulation_run.py
so the headless path can reuse it without paying for a RenderWindow;
checkpoint.py holds the torch.save-based file format and the
restore_simulation_state logic needed to resume a "passive"-mode run
correctly. Deterministic resume-from-checkpoint is verified bit-
identical and confirmed to have real teeth by deliberate mutation.

Replay and playback (TASK-046/047) are deliberately out of scope, named
as such throughout the stage's own Completion Criteria and Discharge
map, along with the two backlog/doc obligations they leave open
(docs/planning/backlog.md, docs/architecture/sequences.md).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
README's Current Phase still said Stage 8 was "not yet started" after
TASK-045 landed -- the fourth time this exact section has gone stale
this way, and its own prose already documents the first three. Fixed,
and added the user-facing walkthrough that was missing from the
original PR: a verified `pyflow record` example against Heat Diffusion
plus a real checkpoint inspection snippet, both run for real and their
output pasted in rather than guessed.

Also found while checking: Stage 8's own "Status as of" heading used
free text that satisfied check_stages.py's loose prefix match but not
generate_status_report.py's stricter template, so the status line was
silently invisible to the checker meant to catch exactly this kind of
staleness (complete_claimed parsed as None, not False). Rewritten to
the template; verified directly against parse_roadmap rather than only
against make check-status passing.

Added checkpoints/ to .gitignore -- RecordingConfig's own default
output_dir, now that README documents running it from the repo root.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A user asked whether resuming from a checkpoint is really deterministic
given the prescribed velocity field isn't checkpointed. It is -- the
field is a pure function of the checkpoint's own embedded config, not
evolved state -- but tests/unit/test_recording_determinism.py's only
fixture had zero prescribed velocity, so a reconstruction bug that
silently defaulted to zero would have passed unnoticed. Added a nonzero-
velocity fixture and two tests pinning this: one at the trajectory
level, one a direct ground-truth check of the reconstructed field.

Both were run under two deliberate mutations to confirm they actually
catch what they claim to: a corrupted restore_simulation_state (caught
by the trajectory test, missed by the old zero-velocity one -- proving
the gap was real) and a config parser silently dropping the velocity
field (missed by an earlier differential draft of the direct test,
which compared two calls sharing the same buggy code path, until it was
rewritten to check against a hand-computed expected value instead).

Also adds `pyflow resume --checkpoint <file> --max-frames N`: continues
a headless recording from an existing checkpoint, no --config at all
(the checkpoint carries its own), sharing its checkpoint-writing policy
with `record` through a new _advance_and_checkpoint helper -- confirmed
to genuinely share behaviour, not just source, by an off-by-one mutation
that broke both functions' own tests together. Still recording's own
scope, not the deterministic windowed replay or playback TASK-046/047
still own -- no rendering, no dense per-frame materialization.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@AdamClemens
AdamClemens merged commit 5fe543e into main Sep 7, 2026
2 checks passed
@AdamClemens
AdamClemens deleted the feat/task-045-checkpoint-recording branch September 7, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant