Module: 8 · Duration: 40 min · Environment: Codespace, Node 18+.
import { writeFileSync, renameSync, readFileSync, existsSync } from "fs";
function atomicCheckpoint(path: string, state: any) {
const tmp = path + ".tmp";
writeFileSync(tmp, JSON.stringify(state));
renameSync(tmp, path); // ATOMIC on POSIX
}
function loadCheckpoint(path: string): any | null {
return existsSync(path) ? JSON.parse(readFileSync(path, "utf-8")) : null;
}
Verify: write a checkpoint; read it back; confirm round-trip. Then simulate a crash mid-temp-write (delete the .tmp before rename); confirm the OLD checkpoint is intact.
Run a 10-step task that checkpoints after each step. Kill the process at step 6 (Ctrl+C or process.exit()). Re-run: the harness reads the checkpoint, resumes at step 6, completes 6–10. Verify no step ran twice (add a side-effect counter).
Build a task that: Session 1 does steps 1–4, checkpoints, exits. Session 2 reads checkpoint, does 5–8, checkpoints, exits. Session 3 reads checkpoint, does 9–10, completes. All three sessions are separate process invocations.
git reset --hard <last-commit> to recover. Compare to the file-based checkpoint.# Lab Specification — Module 8: State, Checkpointing & Multi-Session
**Module**: 8 · **Duration**: 40 min · **Environment**: Codespace, Node 18+.
## Learning objectives
1. Implement **atomic checkpoint writes** (temp + rename).
2. **Kill the process mid-task**; verify resume from last checkpoint with no duplicated side effects.
3. Build a **3-session task** that pauses between sessions via checkpoints.
## Phase 1 — Atomic checkpoint (15 min)
```typescript
import { writeFileSync, renameSync, readFileSync, existsSync } from "fs";
function atomicCheckpoint(path: string, state: any) {
const tmp = path + ".tmp";
writeFileSync(tmp, JSON.stringify(state));
renameSync(tmp, path); // ATOMIC on POSIX
}
function loadCheckpoint(path: string): any | null {
return existsSync(path) ? JSON.parse(readFileSync(path, "utf-8")) : null;
}
```
**Verify**: write a checkpoint; read it back; confirm round-trip. Then simulate a crash mid-temp-write (delete the .tmp before rename); confirm the OLD checkpoint is intact.
## Phase 2 — Crash recovery (10 min)
Run a 10-step task that checkpoints after each step. Kill the process at step 6 (Ctrl+C or `process.exit()`). Re-run: the harness reads the checkpoint, resumes at step 6, completes 6–10. **Verify no step ran twice** (add a side-effect counter).
## Phase 3 — 3-session task (15 min)
Build a task that: Session 1 does steps 1–4, checkpoints, exits. Session 2 reads checkpoint, does 5–8, checkpoints, exits. Session 3 reads checkpoint, does 9–10, completes. All three sessions are separate process invocations.
## Deliverables
- [ ] Phase 1: atomic write code + crash-safety test (old checkpoint intact after interrupted temp-write)
- [ ] Phase 2: side-effect counter showing no step ran twice after crash+resume
- [ ] Phase 3: 3 sessions completing a 10-step task across process boundaries
## Stretch goals
1. **Git-backed checkpoints**: commit after each step; on crash, `git reset --hard <last-commit>` to recover. Compare to the file-based checkpoint.
2. **Session diffing**: run the same task with two different prompts; diff the checkpoints to find where behavior diverged.