Phase 06 / Data & checkpoint recovery
Asynchronous checkpoints and failure boundaries
Revision v0.7.0 · Updated since your last visit. Review the changes; your progress is saved.
Lesson · about 90 minutes · CPU practice
Distinguish requested, completed, verified and published checkpoint state. Continue a functional update while an asynchronous writer is alive.
Phase study guide: preparation, milestones and project evidence
Before you start
Before this: Recover data position and resume
Hardware: CPU
Setup help: Python, notebook, or Cloud TPU VM
Use the tested CPU packages (the recorded environment uses Python 3.14.3). Other Python versions and accelerator environments require separate checks. The optional Cloud TPU specialization explains the target-specific execution boundaries. Logical CPU devices practice partitioning; they do not simulate TPU performance.
Download the repository ZIP or use your existing checkout. Extract it and open a terminal in the folder containing requirements-cpu.txt. The beginner ZIP is separate; these lessons use the full repository folder.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements-cpu.txtpy -3 -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements-cpu.txtAfter activation, run the complete worked example from that same folder:
python phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.py.\.venv\Scripts\python.exe phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.pyFor an incremental build, create main.py in your own practice folder, append each build block in order, and run python main.py with this environment active. Keep that file separate from the downloaded reference solution.
Download this lesson’s notebook. Open it with a Python kernel using the course environment. Run cells from the top after restarting the kernel; experiments depend on earlier definitions.
For local Jupyter, first install the course requirements using the Local Python steps, then use your environment’s Python to start Jupyter:
python -m pip install jupyterlab
python -m jupyter lab.\.venv\Scripts\python.exe -m pip install jupyterlab
.\.venv\Scripts\python.exe -m jupyter labSelect the downloaded recovery-05.ipynb file in JupyterLab. The notebook contains reference solutions; make your prediction and attempt each practice task before opening them. Restart the kernel before changing logical device setup.
The worked reference for this lesson is CPU-validated. Some references explicitly configure logical CPU devices; setting JAX_PLATFORMS does not adapt them to a TPU. Follow the execution matrix and reviewed multi-host example before attempting a target run.
For accelerator preparation, study TPU setup, observed runtime receipts, checkpointed jobs and precision and retained traces. These target paths remain unqualified on physical TPU hardware until an actual receipt is recorded. Cloud provisioning is optional for CPU learning.
Check: The accepted step remains while the live state reaches . A real local checkpoint restores the saved vector. Both timing intervals are observed and vary by machine.
Revisit the guided CPU setup · Open 19: TPU Setup. Package instructions are CPU instructions; Windows and accelerator environments need their own validation.
What you will be able to do
- Distinguish requested, completed, verified and published checkpoint state.
- Continue a functional update while an asynchronous writer is alive.
- Recover from the last accepted checkpoint after an interrupted publication.
- Surface an asynchronous failure before announcing a checkpoint.
The problem
Your training loop says “saved,” then the process disappears. Which step can you safely resume? We will separate an asynchronous save request, completed storage work and the application’s announcement of a recoverable checkpoint. You will interrupt publication deliberately and show which state recovery selects.
The idea
Asynchronous saving overlaps writing with training. A snapshot moves through requested, writing, completed and accepted states. Recovery must select a checkpoint whose completion and validity satisfy the actual storage contract.
Distinguish a save request from a recovery point
Imagine live training reaches step 42 while a snapshot of step 40 is still being written. The live progress log does not make step 42 recoverable. Failure before the pending snapshot is accepted may leave an earlier checkpoint as the valid choice.
Keep completion signals separate from the record used to select accepted snapshots. Validate required files and metadata before making a new snapshot eligible. Also ensure live training cannot mutate the snapshot's intended contents during writing.
The saved/live/accepted bars represent different boundaries. Their gaps describe work at risk of replay or loss, not necessarily a defect. Interpret them against the failure location and the checkpoint API's stated guarantees.
Define a completed training boundary
Let the completed training step be . Our state contains a weight vector and that step counter. A snapshot at must restore the vector belonging to that step, even if the live computation advances to . The example adds the same known increment to every weight, so an independent array comparison can identify the snapshot without relying on a decreasing training loss.
A real training snapshot also includes optimizer memory, random state and input position from the preceding lessons. Asynchronous writing changes when storage finishes; it does not reduce the state that must be captured.
Separate save latency from acceptance
The timer before and after save measures the blocking part of the call. A second interval includes our continuing update and the remaining completion wait. These intervals are adjacent in one run, so their sum describes this application’s request-to-completion boundary. Neither isolates disk throughput.
Keep the checkpointer alive until its work finishes. A quickly returned call can already be finished for a small snapshot; do not require a race to reproduce. The invariant we control is that the application does not update its accepted-checkpoint manifest before completion and restoration checks.
Publish a checkpoint you can actually restore
After waiting, restore against an explicit target and compare the step and every saved value with the snapshot. Write a new manifest to a temporary sibling and replace the old manifest only after the checks pass. On the local filesystem used here this avoids a reader seeing a half-written JSON file.
A rename alone is not a universal durability or distributed-consistency protocol. Object stores, power failures, concurrent writers and multiple hosts need storage-specific guarantees. Our local manifest is an instructional boundary around a single writer, not a replacement for a production checkpoint manager.
Practice interruption without relying on lucky timing
The second checkpoint is fully written, but an injected exception prevents application publication. Recovery still selects step one through the unchanged manifest. Step two exists on disk yet is not selected by this application. This distinction explains why “directory exists” is a weak recovery test.
The extra failure experiment injects an exception in a finalization callback. The exception is observed when waiting; no manifest is published for that attempt. It exercises error propagation after finalization, not a claim to reproduce every disk failure. Preserve the old accepted checkpoint until the new one is accepted.
Translate the boundary into an operational rule
Log the requested step, completed step and accepted step separately. If a job exits with an outstanding save, wait during orderly shutdown; if it dies abruptly, resume from the last accepted artifact and expect to repeat work after that step. Record the replay policy rather than silently claiming no work was lost.
When a restore differs, compare sample IDs and state before tuning tolerances. A different next batch, reset optimizer or mismatched package/data contract is a different trajectory, even if the restored weights look reasonable.
A live step can be ahead of the accepted checkpoint
Predict before looking: After the publication interruption, which step will application recovery select?
Read the figure
The horizontal labels name three different state positions; the vertical axis is a completed-step count, not elapsed time. The saved snapshot and accepted checkpoint both have height , while the live computation reaches . Equal bars here mean equal step counters.
The gap of one step is intentional. It shows work that the live process has completed but the application has not accepted as its recovery point. The failed publication does not move the accepted bar to two merely because a newer directory is present.
Connect it to the computation
The code verifies the saved vector and then injects an interruption before publishing the next checkpoint. Recovery consults the earlier manifest and restores the earlier vector. The full state comparison, rather than bar height alone, establishes which values were restored.
This plot is a local controlled failure experiment. It does not measure checkpoint bandwidth, simulate power loss or establish multi-host atomicity. Inspect the separately recorded timing intervals and exception output for those different questions.
Open full-size figureDownload data and provenance
The notebook contains the data experiment, plotting code, and recorded figure output. Rerun it to test your changes.
Where to put & run this code: Work in phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.py (or downloaded exercises/recovery-05.py / exercises/recovery-05.ipynb) and execute from the repository root with python3 phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.py.
1 Define functional state and publication
Create a Python file in the course environment. Add this block after the preceding block, then run the assembled file.
# Step 1 — Define functional state and publication: The manifest has its own acceptance boundary.
import json
import tempfile
import time
from pathlib import Path
import jax
import jax.numpy as jnp
import numpy as np
import orbax.checkpoint as ocp
root=Path(tempfile.mkdtemp(prefix='jax-async-lesson-'))
def transition(state):
return {'weight':state['weight']+.25,'step':state['step']+1}
def publish(path, step):
pending=root/'LATEST.pending'
# Write the serialized artifact payload to disk.
pending.write_text(json.dumps({'path':str(path),'step':step}))
pending.replace(root/'LATEST.json')
def accepted():
return json.loads((root/'LATEST.json').read_text())Code building blocks in this step
Path(...)— CallPathwith your updated parameters or inputs from this lesson's workspace.tempfile.mkdtemp(...)— Calltempfile.mkdtempwith your updated parameters or inputs from this lesson's workspace.
The manifest has its own acceptance boundary. State updates return new arrays so later work cannot redefine the snapshot.
2 Save, continue and verify
Create a Python file in the course environment. Add this block after the preceding block, then run the assembled file.
# Step 2 — Save, continue and verify: Wait on the real background writer, restore against the snapshot...
state={'weight':jnp.arange(1024,dtype=jnp.float32),'step':jnp.array(0,jnp.int32)}
snapshot=transition(state)
path=root/'step_1'
t0=time.perf_counter()
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(path,args=ocp.args.StandardSave(snapshot))
returned=time.perf_counter()
assert not (root/'LATEST.json').exists()
live=transition(snapshot)
cp.wait_until_finished()
committed=time.perf_counter()
restored=cp.restore(path,args=ocp.args.StandardRestore(snapshot))
# Execute `np.testing.assert_array_equal(restored['weight'],snapshot['w`
np.testing.assert_array_equal(restored['weight'],snapshot['weight'])
assert int(restored['step'])==1 and int(live['step'])==2
publish(path,1)
report={'save_call_seconds':returned-t0,'remaining_work_and_wait_seconds':committed-returned,
'accepted_step':accepted()['step'],'live_step':int(live['step'])}
assert report['accepted_step']==1Code building blocks in this step
jnp.arange(n, dtype=...)— Creates a 1-D JAX array of evenly spaced values[0, 1, ..., n-1]on the target device.jnp.array(values, dtype=...)— Constructs an immutable device-backed JAX array from Python/NumPy values.
Wait on the real background writer, restore against the snapshot contract and publish only after the comparison passes.
3 Interrupt publication deliberately
Create a Python file in the course environment. Add this block after the preceding block, then run the assembled file.
# A deliberately interrupted application publication leaves the previous commit selected.
unpublished=root/'step_2'
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(unpublished,args=ocp.args.StandardSave(live))
cp.wait_until_finished()
# Run the boundary check and catch the expected exception:
try:
raise RuntimeError('injected interruption before updating LATEST')
except RuntimeError:
pass
assert accepted()['step']==1
# Enter `ocp.StandardCheckpointer()` context block:
with ocp.StandardCheckpointer() as cp:
previous=cp.restore(accepted()['path'],target=snapshot)
# Execute `np.testing.assert_array_equal(previous['weight'],snapshot['w`
np.testing.assert_array_equal(previous['weight'],snapshot['weight'])
assert int(previous['step'])==1
print('Checkpoint workspace:',root)
print(json.dumps(report,indent=2))
print('Unpublished step 2 exists; application recovery still selects verified step 1.')Code building blocks in this step
ocp.AsyncCheckpointer(...)— Callocp.AsyncCheckpointerwith your updated parameters or inputs from this lesson's workspace.ocp.StandardCheckpointHandler(...)— Callocp.StandardCheckpointHandlerwith your updated parameters or inputs from this lesson's workspace.assert condition— Verify that the observed output shape, status, or numerical value satisfies the contract.
The injected application interruption leaves the old accepted checkpoint intact even though a newer directory exists.
View the cumulative build in main.py
These blocks append in order to the same file.
# Step 1 — Define functional state and publication: The manifest has its own acceptance boundary.
import json
import tempfile
import time
from pathlib import Path
import jax
import jax.numpy as jnp
import numpy as np
import orbax.checkpoint as ocp
root=Path(tempfile.mkdtemp(prefix='jax-async-lesson-'))
def transition(state):
return {'weight':state['weight']+.25,'step':state['step']+1}
def publish(path, step):
pending=root/'LATEST.pending'
# Write the serialized artifact payload to disk.
pending.write_text(json.dumps({'path':str(path),'step':step}))
pending.replace(root/'LATEST.json')
def accepted():
return json.loads((root/'LATEST.json').read_text())
# Step 2 — Save, continue and verify: Wait on the real background writer, restore against the snapshot...
state={'weight':jnp.arange(1024,dtype=jnp.float32),'step':jnp.array(0,jnp.int32)}
snapshot=transition(state)
path=root/'step_1'
t0=time.perf_counter()
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(path,args=ocp.args.StandardSave(snapshot))
returned=time.perf_counter()
assert not (root/'LATEST.json').exists()
live=transition(snapshot)
cp.wait_until_finished()
committed=time.perf_counter()
restored=cp.restore(path,args=ocp.args.StandardRestore(snapshot))
# Execute `np.testing.assert_array_equal(restored['weight'],snapshot['w`
np.testing.assert_array_equal(restored['weight'],snapshot['weight'])
assert int(restored['step'])==1 and int(live['step'])==2
publish(path,1)
report={'save_call_seconds':returned-t0,'remaining_work_and_wait_seconds':committed-returned,
'accepted_step':accepted()['step'],'live_step':int(live['step'])}
assert report['accepted_step']==1
# A deliberately interrupted application publication leaves the previous commit selected.
unpublished=root/'step_2'
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(unpublished,args=ocp.args.StandardSave(live))
cp.wait_until_finished()
# Run the boundary check and catch the expected exception:
try:
raise RuntimeError('injected interruption before updating LATEST')
except RuntimeError:
pass
assert accepted()['step']==1
# Enter `ocp.StandardCheckpointer()` context block:
with ocp.StandardCheckpointer() as cp:
previous=cp.restore(accepted()['path'],target=snapshot)
# Execute `np.testing.assert_array_equal(previous['weight'],snapshot['w`
np.testing.assert_array_equal(previous['weight'],snapshot['weight'])
assert int(previous['step'])==1
print('Checkpoint workspace:',root)
print(json.dumps(report,indent=2))
print('Unpublished step 2 exists; application recovery still selects verified step 1.')Run the example
python3 phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.pyAbout this command
This shortcut uses an activated macOS/Linux course environment in the repository folder. For Windows, use the explicit interpreter command in “Setup help” above. The script includes worked examples and reference solutions.
Inspect the complete assembled example
# Step 1 — Define functional state and publication: The manifest has its own acceptance boundary.
import json
import tempfile
import time
from pathlib import Path
import jax
import jax.numpy as jnp
import numpy as np
import orbax.checkpoint as ocp
root=Path(tempfile.mkdtemp(prefix='jax-async-lesson-'))
def transition(state):
return {'weight':state['weight']+.25,'step':state['step']+1}
def publish(path, step):
pending=root/'LATEST.pending'
# Write the serialized artifact payload to disk.
pending.write_text(json.dumps({'path':str(path),'step':step}))
pending.replace(root/'LATEST.json')
def accepted():
return json.loads((root/'LATEST.json').read_text())
# Step 2 — Save, continue and verify: Wait on the real background writer, restore against the snapshot...
state={'weight':jnp.arange(1024,dtype=jnp.float32),'step':jnp.array(0,jnp.int32)}
snapshot=transition(state)
path=root/'step_1'
t0=time.perf_counter()
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(path,args=ocp.args.StandardSave(snapshot))
returned=time.perf_counter()
assert not (root/'LATEST.json').exists()
live=transition(snapshot)
cp.wait_until_finished()
committed=time.perf_counter()
restored=cp.restore(path,args=ocp.args.StandardRestore(snapshot))
# Execute `np.testing.assert_array_equal(restored['weight'],snapshot['w`
np.testing.assert_array_equal(restored['weight'],snapshot['weight'])
assert int(restored['step'])==1 and int(live['step'])==2
publish(path,1)
report={'save_call_seconds':returned-t0,'remaining_work_and_wait_seconds':committed-returned,
'accepted_step':accepted()['step'],'live_step':int(live['step'])}
assert report['accepted_step']==1
# A deliberately interrupted application publication leaves the previous commit selected.
unpublished=root/'step_2'
# Enter `ocp.AsyncCheckpointer(ocp.StandardCheckpointH` context block:
with ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler()) as cp:
cp.save(unpublished,args=ocp.args.StandardSave(live))
cp.wait_until_finished()
# Run the boundary check and catch the expected exception:
try:
raise RuntimeError('injected interruption before updating LATEST')
except RuntimeError:
pass
assert accepted()['step']==1
# Enter `ocp.StandardCheckpointer()` context block:
with ocp.StandardCheckpointer() as cp:
previous=cp.restore(accepted()['path'],target=snapshot)
# Execute `np.testing.assert_array_equal(previous['weight'],snapshot['w`
np.testing.assert_array_equal(previous['weight'],snapshot['weight'])
assert int(previous['step'])==1
print('Checkpoint workspace:',root)
print(json.dumps(report,indent=2))
print('Unpublished step 2 exists; application recovery still selects verified step 1.')Expected result: The accepted step remains while the live state reaches . A real local checkpoint restores the saved vector. Both timing intervals are observed and vary by machine.
Recorded reference execution
Reference output captured from executing the complete lesson script (code/main.py) and its assertions in the course CPU environment.
Checkpoint workspace: /var/folders/mp/_mq7srqx2y10p5nhjz9m7hj40000gn/T/jax-async-lesson-9ibeu4bo
{
"save_call_seconds": 0.0035320832394063473,
"remaining_work_and_wait_seconds": 0.017399583011865616,
"accepted_step": 1,
"live_step": 2
}
Unpublished step 2 exists; application recovery still selects verified step 1.
Checkpoint workspace: /var/folders/mp/_mq7srqx2y10p5nhjz9m7hj40000gn/T/jax-async-lesson-xq01n_nx
{
"save_call_seconds": 0.0024104579351842403,
"remaining_work_and_wait_seconds": 0.009226541966199875,
"accepted_step": 1,
"live_step": 2
}
Unpublished step 2 exists; application recovery still selects verified step 1.
Expected background failure surfaced: injected finalization callback failure
Step two verified and accepted; next transition agrees.
Missing target rejected; accepted checkpoint unchanged.
PASS: recovery-05
Download execution record · The notebook includes executed cells and figure outputs. Compare your run with these values; timings depend on the machine.
Trigger an asynchronous error
# Experiment — Trigger an asynchronous error: The controlled failure happens in the finalization callback.
def injected_failure():
raise RuntimeError('injected finalization callback failure')
failed_path=root/'callback_failure'
cp=ocp.AsyncCheckpointer(ocp.StandardCheckpointHandler(),async_options=ocp.options.AsyncOptions(post_finalization_callback=injected_failure))
# Run the boundary check and catch the expected exception:
try:
cp.save(failed_path,args=ocp.args.StandardSave(live))
# Run the boundary check and catch the expected exception:
try:
cp.wait_until_finished()
except RuntimeError as error:
assert 'injected' in str(error)
print('Expected background failure surfaced:',error)
else:
raise AssertionError('background error was hidden')
finally:
cp.close()
assert accepted()['step']==1Expected: An intentional error log and caught RuntimeError; the accepted step is unchanged.
The controlled failure happens in the finalization callback. Some storage may already exist; the application still requires successful completion and verification before accepting it.
Make it yours
Where to put your code: Append your solution at the bottom of phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.py (or inside the Make it yours cell of exercises/recovery-05.ipynb) and run python3 phases/06-recovery/05-asynchronous-checkpoints-and-failure-boundaries/code/main.py to verify your prediction before opening the reference solution.
Verify and publish the already written second checkpoint. Restore it and compare the next functional transition against the live state. Keep the original snapshot unchanged.
Show a writing guide and starter scaffold
How to write this exercise code: step-by-step recipe & starter scaffold
1. Key functions & syntax to use:
ocp.StandardCheckpointer(...)— Callocp.StandardCheckpointerwith your updated parameters or inputs from this lesson's workspace.cp.restore(...)— Callcp.restorewith your updated parameters or inputs from this lesson's workspace.assert condition— Verify that the observed output shape, status, or numerical value satisfies the contract.
2. Step-by-step implementation plan:
- Enter
ocp.StandardCheckpointer()context block: - Execute
np.testing.assert_array_equal(verified['weight'],live['weigh - Execute
np.testing.assert_array_equal(transition(verified)['weight']
# Exercise solution: Verify and publish the already written second checkpoint.
# Enter `ocp.StandardCheckpointer()` context block:
with ocp.StandardCheckpointer() as cp:
verified = cp.restore(...) # TODO: compute verified
# Execute `np.testing.assert_array_equal(verified['weight'],live['weigh`
np.testing.assert_array_equal(verified['weight'],live['weight'])
assert int(verified['step']) # TODO: complete assertion check
publish(unpublished,2)
# Execute `np.testing.assert_array_equal(transition(verified)['weight']`
np.testing.assert_array_equal(transition(verified)['weight'],transition(live)['weight'])
assert accepted()['step'] # TODO: complete assertion check
print('Step two verified and accepted; next transition agrees.')
Reveal the reference solution
# Exercise solution: Verify and publish the already written second checkpoint.
# Enter `ocp.StandardCheckpointer()` context block:
with ocp.StandardCheckpointer() as cp:
verified=cp.restore(unpublished,target=live)
# Execute `np.testing.assert_array_equal(verified['weight'],live['weigh`
np.testing.assert_array_equal(verified['weight'],live['weight'])
assert int(verified['step'])==2
publish(unpublished,2)
# Execute `np.testing.assert_array_equal(transition(verified)['weight']`
np.testing.assert_array_equal(transition(verified)['weight'],transition(live)['weight'])
assert accepted()['step']==2 and int(snapshot['step'])==1
print('Step two verified and accepted; next transition agrees.')Keep only a genuinely accepted target
Transfer
Create a manifest pointing to a nonexistent checkpoint in a disposable variable. Write a preflight that rejects it without replacing the real accepted manifest. Explain why a preflight alone cannot prove numerical correctness.
Show a writing guide and starter scaffold
How to write this practice solution: step-by-step recipe & starter scaffold
1. Key functions & syntax to use:
target(...)— Calltargetwith your updated parameters or inputs from this lesson's workspace.preflight(...)— Callpreflightwith your updated parameters or inputs from this lesson's workspace.assert condition— Verify that the observed output shape, status, or numerical value satisfies the contract.
2. Step-by-step implementation plan:
- Guard input contract (
not Path(record['path']).is_dir() or int(record['step']) < 0) and fail fast if violated. - Run the boundary check and catch the expected exception:
# Keep only a genuinely accepted target (Transfer): File presence is a necessary local preflight, not proof that...
def preflight(record):
# Guard input contract (`not Path(record['path']).is_dir() or int(record['step']) < 0`) and fail fast if violated.
if not Path(record['path']).is_dir() or int(record['step'])<0:
raise ValueError('checkpoint target unavailable')
return ... # TODO: return computed result
before = accepted(...) # TODO: compute before
# Run the boundary check and catch the expected exception:
try:preflight({'path':str(root/'never_saved'),'step':99})
except ValueError:pass
else:raise AssertionError('missing target accepted')
assert accepted() # TODO: complete assertion check
preflight(before)
print('Missing target rejected; accepted checkpoint unchanged.')
Show a hint
Check path existence and the declared step before restoration; still compare restored contents afterward.
Reveal reference solution and reasoning
# Keep only a genuinely accepted target (Transfer): File presence is a necessary local preflight, not proof that...
def preflight(record):
# Guard input contract (`not Path(record['path']).is_dir() or int(record['step']) < 0`) and fail fast if violated.
if not Path(record['path']).is_dir() or int(record['step'])<0:
raise ValueError('checkpoint target unavailable')
return record
before=accepted()
# Run the boundary check and catch the expected exception:
try:preflight({'path':str(root/'never_saved'),'step':99})
except ValueError:pass
else:raise AssertionError('missing target accepted')
assert accepted()==before
preflight(before)
print('Missing target rejected; accepted checkpoint unchanged.')File presence is a necessary local preflight, not proof that metadata, data or training state is correct. The restore comparison supplies the stronger check.
Diagnose the result
If the accepted step is ahead of the restored state, inspect publication order and the saved step counter. If wait raises, keep that error and the last accepted manifest; do not suppress the error and publish anyway.
Carry forward
- Record save request, completion and acceptance separately.
- Keep the asynchronous writer alive until completion or reported failure.
- Verify a restored next transition before replacing the accepted recovery point.
Keep your evidence
Keep the requested/completed/accepted step log, the restored snapshot comparison, interrupted-publication result and surfaced finalization error. Explain why directory presence alone is separate from acceptance.
Save your modified code, its output, and an explanation of your prediction. Checkpoint answers and exercise evidence are tracked separately.
Saved in this browser. Export or back up your portfolio anytime in My learning.
Verified on local CPU. Stage to a Cloud TPU VM via Cloud TPU setup to record accelerator execution receipts (TODO: add automated Cloud TPU CI execution receipts).