package checkpoint import ( "context" "sync" ) // Memory is a zero-dependency in-process CheckpointStore. NOTE: an in-memory // checkpoint store does NOT survive the process restart it exists to recover // from — it is the test/light-host default and makes ListInterrupted meaningful // only within a single process lifetime. A host that wants real // crash-recovery wires a durable CheckpointStore (mort's durable-job table). type Memory struct { mu sync.RWMutex cps map[string]RunCheckpoint // by run id } // NewMemory returns an empty in-memory CheckpointStore. func NewMemory() *Memory { return &Memory{cps: map[string]RunCheckpoint{}} } var _ CheckpointStore = (*Memory)(nil) func (m *Memory) Save(_ context.Context, cp RunCheckpoint) error { m.mu.Lock() defer m.mu.Unlock() m.cps[cp.Meta.RunID] = cp return nil } func (m *Memory) Load(_ context.Context, runID string) (*RunCheckpoint, error) { m.mu.RLock() defer m.mu.RUnlock() cp, ok := m.cps[runID] if !ok { return nil, nil // no checkpoint (not an error — the run finished cleanly or never started) } return &cp, nil } func (m *Memory) Delete(_ context.Context, runID string) error { m.mu.Lock() defer m.mu.Unlock() delete(m.cps, runID) return nil } func (m *Memory) ListInterrupted(_ context.Context) ([]RunCheckpoint, error) { m.mu.RLock() defer m.mu.RUnlock() out := make([]RunCheckpoint, 0, len(m.cps)) for _, cp := range m.cps { out = append(out, cp) } return out, nil }