checkpoint: name Write requests by scope (Session / Checkpoint*) · Entire

Home

Log in

checkpoint: name Write requests by scope (Session / Checkpoint*)

72eee65·

Soph·3w ago·60 files·+296 added/-294 removed

Rename the Write request union to noun-based, scope-explicit names — the verb is already Write, and the tier (session vs checkpoint) should be visible in the type: WriteSession -> Session (session-level: write/replace a session) BackfillTranscript -> SessionTranscript (session-level) BackfillSummary -> SessionSummary (session-level) BackfillAttribution -> CheckpointAttribution (checkpoint-level: root combined attribution)

The old BackfillAttribution name hid that it targets the checkpoint root's combined attribution across all sessions, not a single session — CheckpointAttribution makes the one checkpoint-level write explicit alongside the three session-level ones.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

Sessions

1dc8e6fe2d64View transcript

?\ Review Checkpoint Commit f16b7101Codex·GPT-5.5·1 step

Changes

60

79 unmodified lines

80
81
82
83
84
83
84
85
86
87

79 unmodified lines

// ReadSession reads session data from agent's storage.
    ReadSession(input *HookInput) (*AgentSession, error)

// WriteSession writes session data for resumption.
    WriteSession(ctx context.Context, session *AgentSession) error
    // Session writes session data for resumption.
    Session(ctx context.Context, session *AgentSession) error

// FormatResumeCommand returns command to resume a session.
    FormatResumeCommand(sessionID string) string

Mcmd/entire/cli/agent/agent.go+2/-2

41 unmodified lines

42
43
44
45
46
47
45
46
47
48
49
50

41 unmodified lines

}

//nolint:nilnil // Mock implementation
func (m *mockAgent) ReadSession(_ *HookInput) (*AgentSession, error)       { return nil, nil }
func (m *mockAgent) WriteSession(_ context.Context, _ *AgentSession) error { return nil }
func (m *mockAgent) FormatResumeCommand(_ string) string                   { return "" }
func (m *mockAgent) ReadSession(_ *HookInput) (*AgentSession, error)  { return nil, nil }
func (m *mockAgent) Session(_ context.Context, _ *AgentSession) error { return nil }
func (m *mockAgent) FormatResumeCommand(_ string) string              { return "" }

// mockHookSupport implements both Agent and HookSupport interfaces.
type mockHookSupport struct {

Mcmd/entire/cli/agent/agent_test.go+3/-3

22 unmodified lines

23
24
25
26
27
28
29
30
31
32
26
27
28
29
30
31
32
33
34
35

22 unmodified lines

func (m *mockBaseAgent) ChunkTranscript(context.Context, []byte, int) ([][]byte, error) {
    return nil, nil
}
func (m *mockBaseAgent) ReassembleTranscript([][]byte) ([]byte, error)     { return nil, nil }
func (m *mockBaseAgent) GetSessionID(*HookInput) string                    { return "" }
func (m *mockBaseAgent) GetSessionDir(string) (string, error)              { return "", nil }
func (m *mockBaseAgent) ResolveSessionFile(string, string) string          { return "" }
func (m *mockBaseAgent) ReadSession(*HookInput) (*AgentSession, error)     { return nil, nil } //nolint:nilnil // test mock
func (m *mockBaseAgent) WriteSession(context.Context, *AgentSession) error { return nil }
func (m *mockBaseAgent) FormatResumeCommand(string) string                 { return "" }
func (m *mockBaseAgent) ReassembleTranscript([][]byte) ([]byte, error) { return nil, nil }
func (m *mockBaseAgent) GetSessionID(*HookInput) string                { return "" }
func (m *mockBaseAgent) GetSessionDir(string) (string, error)          { return "", nil }
func (m *mockBaseAgent) ResolveSessionFile(string, string) string      { return "" }
func (m *mockBaseAgent) ReadSession(*HookInput) (*AgentSession, error) { return nil, nil } //nolint:nilnil // test mock
func (m *mockBaseAgent) Session(context.Context, *AgentSession) error  { return nil }
func (m *mockBaseAgent) FormatResumeCommand(string) string             { return "" }

// mockBuiltinHookAgent is a built-in agent that implements HookSupport but NOT CapabilityDeclarer.
type mockBuiltinHookAgent struct {

Mcmd/entire/cli/agent/capabilities_test.go+7/-7

147 unmodified lines

148
149
150
151
151
152
153
154
154
155
156
157

147 unmodified lines

}, nil
}

// WriteSession writes a session to Claude's storage (JSONL transcript file).
// Session writes a session to Claude's storage (JSONL transcript file).
// Uses the NativeData field which contains raw JSONL bytes.
// The session must have been created by Claude Code (AgentName check).
func (c *ClaudeCodeAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (c *ClaudeCodeAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/claudecode/claude.go+2/-2

156 unmodified lines

157
158
159
160
161
160
161
162
163
164

156 unmodified lines

}, nil
}

// WriteSession writes a session to Codex's storage (JSONL rollout file).
func (c *CodexAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
// Session writes a session to Codex's storage (JSONL rollout file).
func (c *CodexAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/codex/codex.go+2/-2

114 unmodified lines

115
116
117
118
119
118
119
120
121
122

114 unmodified lines

}, nil
}

// WriteSession writes a session to Copilot CLI's storage (JSONL transcript file).
func (c *CopilotCLIAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
// Session writes a session to Copilot CLI's storage (JSONL transcript file).
func (c *CopilotCLIAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/copilotcli/copilotcli.go+2/-2

228 unmodified lines

229
230
231
232
232
233
234
235
10 unmodified lines

246
247
248
249
250
249
250
251
252
253
25 unmodified lines

279
280
281
282
283
282
283
284
285
286
13 unmodified lines

300
301
302
303
304
303
304
305
306
307
5 unmodified lines

313
314
315
316
317
316
317
318
319
320
8 unmodified lines

329
330
331
332
333
332
333
334
335
336
4 unmodified lines

341
342
343
344
345
344
345
346
347
348
4 unmodified lines

353
354
355
356
357
356
357
358
359
360

228 unmodified lines

}
}

// --- WriteSession ---
// --- Session ---

func TestWriteSession_Success(t *testing.T) {
    t.Parallel()
10 unmodified lines

NativeData: []byte(content),
    }

if err := ag.WriteSession(context.Background(), session); err != nil {
        t.Fatalf("WriteSession() error = %v", err)
    if err := ag.Session(context.Background(), session); err != nil {
        t.Fatalf("Session() error = %v", err)
    }

data, err := os.ReadFile(transcriptPath)
25 unmodified lines

// Write to new path
    newPath := filepath.Join(tmpDir, "roundtrip.jsonl")
    session.SessionRef = newPath
    if err := ag.WriteSession(context.Background(), session); err != nil {
        t.Fatalf("WriteSession() error = %v", err)
    if err := ag.Session(context.Background(), session); err != nil {
        t.Fatalf("Session() error = %v", err)
    }

// Read back and compare
13 unmodified lines

func TestWriteSession_Nil(t *testing.T) {
    t.Parallel()
    ag := &CopilotCLIAgent{}
    if err := ag.WriteSession(context.Background(), nil); err == nil {
        t.Error("WriteSession(nil) should error")
    if err := ag.Session(context.Background(), nil); err == nil {
        t.Error("Session(nil) should error")
    }
}

5 unmodified lines

SessionRef: "/path/to/file",
        NativeData: []byte("data"),
    }
    if err := ag.WriteSession(context.Background(), session); err == nil {
        t.Error("WriteSession() should error for wrong agent")
    if err := ag.Session(context.Background(), session); err == nil {
        t.Error("Session() should error for wrong agent")
    }
}

8 unmodified lines

SessionRef: transcriptPath,
        NativeData: []byte("data"),
    }
    if err := ag.WriteSession(context.Background(), session); err != nil {
        t.Errorf("WriteSession() with empty AgentName should succeed, got: %v", err)
    if err := ag.Session(context.Background(), session); err != nil {
        t.Errorf("Session() with empty AgentName should succeed, got: %v", err)
    }
}

4 unmodified lines

AgentName:  agent.AgentNameCopilotCLI,
        NativeData: []byte("data"),
    }
    if err := ag.WriteSession(context.Background(), session); err == nil {
        t.Error("WriteSession() should error when SessionRef is empty")
    if err := ag.Session(context.Background(), session); err == nil {
        t.Error("Session() should error when SessionRef is empty")
    }
}

4 unmodified lines

AgentName:  agent.AgentNameCopilotCLI,
        SessionRef: "/path/to/file",
    }
    if err := ag.WriteSession(context.Background(), session); err == nil {
        t.Error("WriteSession() should error when NativeData is empty")
    if err := ag.Session(context.Background(), session); err == nil {
        t.Error("Session() should error when NativeData is empty")
    }
}

Mcmd/entire/cli/agent/copilotcli/copilotcli_test.go+15/-15

201 unmodified lines

202
203
204
205
206
205
206
207
208
209

201 unmodified lines

return nil
}

// WriteSession writes a session to Cursor's storage (JSONL transcript file).
func (c *CursorAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
// Session writes a session to Cursor's storage (JSONL transcript file).
func (c *CursorAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/cursor/cursor.go+2/-2

334 unmodified lines

335
336
337
338
338
339
340
341
10 unmodified lines

352
353
354
355
356
355
356
357
358
359
25 unmodified lines

385
386
387
388
389
388
389
390
391
392
13 unmodified lines

406
407
408
409
410
409
410
411
412
413
5 unmodified lines

419
420
421
422
423
422
423
424
425
426
8 unmodified lines

435
436
437
438
439
438
439
440
441
442
4 unmodified lines

447
448
449
450
451
450
451
452
453
454
4 unmodified lines

459
460
461
462
463
462
463
464
465
466

334 unmodified lines

}
}

// --- WriteSession ---
// --- Session ---

func TestWriteSession_Success(t *testing.T) {
    t.Parallel()
10 unmodified lines

NativeData: []byte(content),
    }

data, err := os.ReadFile(transcriptPath)
25 unmodified lines

// Read back and compare
13 unmodified lines

func TestWriteSession_Nil(t *testing.T) {
    t.Parallel()
    ag := &CursorAgent{}
    if err := ag.WriteSession(context.Background(), nil); err == nil {
        t.Error("WriteSession(nil) should error")
    if err := ag.Session(context.Background(), nil); err == nil {
        t.Error("Session(nil) should error")
    }
}

5 unmodified lines

8 unmodified lines

4 unmodified lines

AgentName:  agent.AgentNameCursor,
        NativeData: []byte("data"),
    }
    if err := ag.WriteSession(context.Background(), session); err == nil {
        t.Error("WriteSession() should error when SessionRef is empty")
    if err := ag.Session(context.Background(), session); err == nil {
        t.Error("Session() should error when SessionRef is empty")
    }
}

4 unmodified lines

AgentName:  agent.AgentNameCursor,
        SessionRef: "/path/to/file",
    }
    if err := ag.WriteSession(context.Background(), session); err == nil {
        t.Error("WriteSession() should error when NativeData is empty")
    if err := ag.Session(context.Background(), session); err == nil {
        t.Error("Session() should error when NativeData is empty")
    }
}

Mcmd/entire/cli/agent/cursor/cursor_test.go+15/-15

71 unmodified lines

72
73
74
75
76
75
76
77
78
79

71 unmodified lines

func (w *wrappedAgent) ReadSession(input *agent.HookInput) (*agent.AgentSession, error) {
    return w.ea.ReadSession(input)
}
func (w *wrappedAgent) WriteSession(ctx context.Context, s *agent.AgentSession) error {
    return w.ea.WriteSession(ctx, s)
func (w *wrappedAgent) Session(ctx context.Context, s *agent.AgentSession) error {
    return w.ea.Session(ctx, s)
}
func (w *wrappedAgent) FormatResumeCommand(id string) string { return w.ea.FormatResumeCommand(id) }

Mcmd/entire/cli/agent/external/capabilities.go+2/-2

350 unmodified lines

351
352
353
354
355
354
355
356
357
358

350 unmodified lines

func (f *fakeBuiltInAgent) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // test fake — no session is a valid state
}
func (f *fakeBuiltInAgent) WriteSession(context.Context, *agent.AgentSession) error { return nil }
func (f *fakeBuiltInAgent) FormatResumeCommand(string) string                       { return "" }
func (f *fakeBuiltInAgent) Session(context.Context, *agent.AgentSession) error { return nil }
func (f *fakeBuiltInAgent) FormatResumeCommand(string) string                  { return "" }

func TestDiscoverAndRegister_SkipsInfoFailure(t *testing.T) {
    if _, err := exec.LookPath("sh"); err != nil {

Mcmd/entire/cli/agent/external/discovery_test.go+2/-2

199 unmodified lines

200
201
202
203
203
204
205
206

199 unmodified lines

return unmarshalAgentSession(&resp)
}

func (e *Agent) WriteSession(ctx context.Context, session *agent.AgentSession) error {
func (e *Agent) Session(ctx context.Context, session *agent.AgentSession) error {
    data, err := marshalAgentSession(session)
    if err != nil {
        return fmt.Errorf("write-session: marshal: %w", err)

Mcmd/entire/cli/agent/external/external.go+1/-1

150 unmodified lines

151
152
153
154
154
155
156
156
157
158
159

150 unmodified lines

}, nil
}

// WriteSession writes a session to Factory AI Droid's storage (JSONL transcript file).
// Session writes a session to Factory AI Droid's storage (JSONL transcript file).
// Uses the NativeData field which contains raw JSONL bytes.
func (f *FactoryAIDroidAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (f *FactoryAIDroidAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/factoryaidroid/factoryaidroid.go+2/-2

153 unmodified lines

154
155
156
157
157
158
159
160
64 unmodified lines

225
226
227
228
228
229
230
231
232
233
234
235
235
236
237
238
9 unmodified lines

248
249
250
251
252
251
252
253
254
255
256
257
258
259
259
260
261
262
263
264
265
265
266
267
268
269
270
271
272
272
273
274
275
276
277
277
278
279
280
281
282
283
284
284
285
286
287
288
289
289
290
291
292
23 unmodified lines

316
317
318
319
320
319
320
321
322
323

153 unmodified lines

}
}

// --- ReadSession / WriteSession tests ---
// --- ReadSession / Session tests ---

func TestReadSession(t *testing.T) {
    t.Parallel()
64 unmodified lines

nativeData := []byte(`{"type":"message","id":"msg1","message":{"role":"user","content":"hello"}}`)

ag := &FactoryAIDroidAgent{}
    err := ag.WriteSession(context.Background(), &agent.AgentSession{
    err := ag.Session(context.Background(), &agent.AgentSession{
        SessionID:  "test-session-456",
        AgentName:  agent.AgentNameFactoryAIDroid,
        SessionRef: transcriptPath,
        NativeData: nativeData,
    })
    if err != nil {
        t.Fatalf("WriteSession() error = %v", err)
        t.Fatalf("Session() error = %v", err)
    }

// Verify file was written correctly
9 unmodified lines

func TestWriteSession_NilSession(t *testing.T) {
    t.Parallel()
    ag := &FactoryAIDroidAgent{}
    if err := ag.WriteSession(context.Background(), nil); err == nil {
        t.Error("WriteSession(nil) should error")
    if err := ag.Session(context.Background(), nil); err == nil {
        t.Error("Session(nil) should error")
    }
}

func TestWriteSession_WrongAgent(t *testing.T) {
    t.Parallel()
    ag := &FactoryAIDroidAgent{}
    err := ag.WriteSession(context.Background(), &agent.AgentSession{
    err := ag.Session(context.Background(), &agent.AgentSession{
        AgentName:  "claude-code",
        SessionRef: "/tmp/test.jsonl",
        NativeData: []byte("data"),
    })
    if err == nil {
        t.Error("WriteSession() should error for wrong agent name")
        t.Error("Session() should error for wrong agent name")
    }
}

func TestWriteSession_EmptyRef(t *testing.T) {
    t.Parallel()
    ag := &FactoryAIDroidAgent{}
    err := ag.WriteSession(context.Background(), &agent.AgentSession{
    err := ag.Session(context.Background(), &agent.AgentSession{
        AgentName:  agent.AgentNameFactoryAIDroid,
        NativeData: []byte("data"),
    })
    if err == nil {
        t.Error("WriteSession() should error on empty SessionRef")
        t.Error("Session() should error on empty SessionRef")
    }
}

func TestWriteSession_EmptyNativeData(t *testing.T) {
    t.Parallel()
    ag := &FactoryAIDroidAgent{}
    err := ag.WriteSession(context.Background(), &agent.AgentSession{
    err := ag.Session(context.Background(), &agent.AgentSession{
        AgentName:  agent.AgentNameFactoryAIDroid,
        SessionRef: "/tmp/test.jsonl",
    })
    if err == nil {
        t.Error("WriteSession() should error on empty NativeData")
        t.Error("Session() should error on empty NativeData")
    }
}

23 unmodified lines

// Write to new location
    session.SessionRef = restoredPath
    if err := ag.WriteSession(context.Background(), session); err != nil {
        t.Fatalf("WriteSession() error = %v", err)
    if err := ag.Session(context.Background(), session); err != nil {
        t.Fatalf("Session() error = %v", err)
    }

// Verify content matches

Mcmd/entire/cli/agent/factoryaidroid/factoryaidroid_test.go+13/-13

166 unmodified lines

167
168
169
170
170
171
172
172
173
174
175

166 unmodified lines

}, nil
}

// WriteSession writes a session to Gemini's storage (JSON transcript file).
// Session writes a session to Gemini's storage (JSON transcript file).
// Uses the NativeData field which contains raw JSON bytes.
func (g *GeminiCLIAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (g *GeminiCLIAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/geminicli/gemini.go+2/-2

264 unmodified lines

265
266
267
268
268
269
270
270
271
272
273
12 unmodified lines

286
287
288
289
289
290
291
291
292
293
294
7 unmodified lines

302
303
304
305
305
306
307
307
308
309
310
6 unmodified lines

317
318
319
320
320
321
322
322
323
324
325
6 unmodified lines

332
333
334
335
335
336
337
337
338
339
340

264 unmodified lines

NativeData: []byte(`{"messages": []}`),
    }

err := ag.WriteSession(context.Background(), session)
    err := ag.Session(context.Background(), session)
    if err != nil {
        t.Fatalf("WriteSession() error = %v", err)
        t.Fatalf("Session() error = %v", err)
    }

// Verify file was written
12 unmodified lines

ag := &GeminiCLIAgent{}

err := ag.WriteSession(context.Background(), nil)
    err := ag.Session(context.Background(), nil)
    if err == nil {
        t.Error("WriteSession(nil) should error")
        t.Error("Session(nil) should error")
    }
}

7 unmodified lines

NativeData: []byte("{}"),
    }

err := ag.WriteSession(context.Background(), session)
    err := ag.Session(context.Background(), session)
    if err == nil {
        t.Error("WriteSession() should error for wrong agent")
        t.Error("Session() should error for wrong agent")
    }
}

6 unmodified lines

NativeData: []byte("{}"),
    }

err := ag.WriteSession(context.Background(), session)
    err := ag.Session(context.Background(), session)
    if err == nil {
        t.Error("WriteSession() should error when SessionRef is empty")
        t.Error("Session() should error when SessionRef is empty")
    }
}

6 unmodified lines

SessionRef: "/path/to/file",
    }

err := ag.WriteSession(context.Background(), session)
    err := ag.Session(context.Background(), session)
    if err == nil {
        t.Error("WriteSession() should error when NativeData is empty")
        t.Error("Session() should error when NativeData is empty")
    }
}

Mcmd/entire/cli/agent/geminicli/gemini_test.go+10/-10

212 unmodified lines

213
214
215
216
216
217
218
219

212 unmodified lines

}, nil
}

func (a *OpenCodeAgent) WriteSession(ctx context.Context, session *agent.AgentSession) error {
func (a *OpenCodeAgent) Session(ctx context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("nil session")
    }

Mcmd/entire/cli/agent/opencode/opencode.go+1/-1

248 unmodified lines

249
250
251
252
252
253
254
255
255
256
257
258

248 unmodified lines

}, nil
}

// WriteSession writes a captured Pi transcript back to disk so Pi can resume
// Session writes a captured Pi transcript back to disk so Pi can resume
// from it. Pi loads sessions from arbitrary paths via `pi --session <path>`,
// so a plain write is sufficient.
func (a *PiAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (a *PiAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("nil session")
    }

Mcmd/entire/cli/agent/pi/pi.go+2/-2

312 unmodified lines

313
314
315
316
316
317
318
319
21 unmodified lines

341
342
343
344
344
345
346
347

312 unmodified lines

}
}

// --- ReadSession / WriteSession ---
// --- ReadSession / Session ---

func TestReadSession(t *testing.T) {
    t.Parallel()
21 unmodified lines

dir := t.TempDir()
    path := filepath.Join(dir, "subdir", "session.json")
    body := []byte(`{"type":"session","version":3}` + "\n")
    err := (&PiAgent{}).WriteSession(context.Background(), &agent.AgentSession{
    err := (&PiAgent{}).Session(context.Background(), &agent.AgentSession{
        SessionID:  "abc",
        SessionRef: path,
        NativeData: body,

Mcmd/entire/cli/agent/pi/transcript_test.go+2/-2

111 unmodified lines

112
113
114
115
115
116
117
118

111 unmodified lines

}, nil
}

func (v *Agent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (v *Agent) Session(_ context.Context, session *agent.AgentSession) error {
    if session == nil {
        return errors.New("session is nil")
    }

Mcmd/entire/cli/agent/vogon/vogon.go+1/-1

336 unmodified lines

337
338
339
340
340
341
342
343

336 unmodified lines

writeOpts.HasReview = true
    }

if err := store.Write(ctx, cpkg.WriteSession(writeOpts)); err != nil {
    if err := store.Write(ctx, cpkg.Session(writeOpts)); err != nil {
        return fmt.Errorf("failed to write checkpoint: %w", err)
    }

Mcmd/entire/cli/attach.go+1/-1

424 unmodified lines

425
426
427
428
428
429
430
431
827 unmodified lines

1259
1260
1261
1262
1262
1263
1264
1265

424 unmodified lines

// Seed the local branch with a checkpoint representing Alice's session.
    alicesCheckpoint := id.MustCheckpointID("abcdef012345")
    store := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs())
    if writeErr := store.Write(context.Background(), cpkg.WriteSession{
    if writeErr := store.Write(context.Background(), cpkg.Session{
        CheckpointID: alicesCheckpoint,
        SessionID:    "alice-original",
        Strategy:     "manual-commit",
827 unmodified lines

sessionID := "test-attach-review-metadata-only"
    checkpointID := id.MustCheckpointID("aabbccddeeff")
    store := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs())
    if err := store.Write(context.Background(), cpkg.WriteSession{
    if err := store.Write(context.Background(), cpkg.Session{
        CheckpointID: checkpointID,
        SessionID:    sessionID,
        Strategy:     strategy.StrategyNameManualCommit,

Mcmd/entire/cli/attach_test.go+2/-2

544 unmodified lines

545
546
547
548
548
549
550
551

544 unmodified lines

if opts.SessionID == "" {
        opts.SessionID = checkpointID
    }
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteSession(opts)))
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.Session(opts)))

// WriteCommitted uses git plumbing only, but keep the worktree file system
    // anchored for git CLI blame in these tests.

Mcmd/entire/cli/attribution_test.go+1/-1

323 unmodified lines

324
325
326
327
327
328
329
330

323 unmodified lines

b.Fatalf("generate ID: %v", err)
            }
            redactedTranscript := redact.AlreadyRedacted(transcript)
            err = repo.Store.Write(ctx, checkpoint.WriteSession{
            err = repo.Store.Write(ctx, checkpoint.Session{
                CheckpointID:     cpID,
                SessionID:        fmt.Sprintf("bench-session-%d", i),
                Strategy:         "manual-commit",

Mcmd/entire/cli/benchutil/bench_test.go+1/-1

401 unmodified lines

402
403
404
405
405
406
407
408

401 unmodified lines

files = append(files, fmt.Sprintf("src/file_%03d.go", (i*5+j)%100))
        }

err = br.Store.Write(context.Background(), checkpoint.WriteSession{
        err = br.Store.Write(context.Background(), checkpoint.Session{
            CheckpointID:     cpID,
            SessionID:        sessionID,
            Strategy:         br.Strategy,

Mcmd/entire/cli/benchutil/benchutil.go+1/-1

53 unmodified lines

54
55
56
57
57
58
59
60

53 unmodified lines

checkpointID := id.MustCheckpointID("def456abc123")

// Write checkpoint WITHOUT token usage (simulates old checkpoints)
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    "test-session-old",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/backwards_compat_test.go+1/-1

133 unmodified lines

134
135
136
137
137
138
139
140

133 unmodified lines

repo, store, cpID := setupRepoForUpdate(t)

// Write a second session to the same checkpoint
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-002",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/blob_resolver_test.go+1/-1

271 unmodified lines

272
273
274
275
275
276
277
278

271 unmodified lines

// CombinedAttribution is holistic attribution across all sessions.
    // Used during migration to preserve v1 root summary attribution.
    // During normal condensation this is nil (computed post-commit via a BackfillAttribution write).
    // During normal condensation this is nil (computed post-commit via a CheckpointAttribution write).
    CombinedAttribution *Attribution

// Summary is an optional AI-generated summary for this checkpoint.

Mcmd/entire/cli/checkpoint/checkpoint.go+1/-1

141 unmodified lines

142
143
144
145
145
146
147
148
409 unmodified lines

558
559
560
561
561
562
563
564
126 unmodified lines

691
692
693
694
694
695
696
697
33 unmodified lines

731
732
733
734
734
735
736
737
18 unmodified lines

756
757
758
759
759
760
761
762
25 unmodified lines

788
789
790
791
791
792
793
794
41 unmodified lines

836
837
838
839
839
840
841
842
34 unmodified lines

877
878
879
880
880
881
882
883
62 unmodified lines

946
947
948
949
949
950
951
952
78 unmodified lines

1031
1032
1033
1034
1034
1035
1036
1037
9 unmodified lines

1047
1048
1049
1050
1050
1051
1052
1053
58 unmodified lines

1112
1113
1114
1115
1115
1116
1117
1118
13 unmodified lines

1132
1133
1134
1135
1135
1136
1137
1138
65 unmodified lines

1204
1205
1206
1207
1207
1208
1209
1210
62 unmodified lines

1273
1274
1275
1276
1276
1277
1278
1279
44 unmodified lines

1324
1325
1326
1327
1327
1328
1329
1330
18 unmodified lines

1349
1350
1351
1352
1352
1353
1354
1355
43 unmodified lines

1399
1400
1401
1402
1402
1403
1404
1405
32 unmodified lines

1438
1439
1440
1441
1441
1442
1443
1444
45 unmodified lines

1490
1491
1492
1493
1493
1494
1495
1496
55 unmodified lines

1552
1553
1554
1555
1555
1556
1557
1558
42 unmodified lines

1601
1602
1603
1604
1604
1605
1606
1607
32 unmodified lines

1640
1641
1642
1643
1643
1644
1645
1646
1434 unmodified lines

3081
3082
3083
3084
3084
3085
3086
3087
13 unmodified lines

3101
3102
3103
3104
3104
3105
3106
3107
13 unmodified lines

3121
3122
3123
3124
3124
3125
3126
3127
88 unmodified lines

3216
3217
3218
3219
3219
3220
3221
3222
8 unmodified lines

3231
3232
3233
3234
3234
3235
3236
3237
54 unmodified lines

3292
3293
3294
3295
3295
3296
3297
3298
7 unmodified lines

3306
3307
3308
3309
3309
3310
3311
3312
7 unmodified lines

3320
3321
3322
3323
3323
3324
3325
3326
49 unmodified lines

3376
3377
3378
3379
3379
3380
3381
3382
8 unmodified lines

3391
3392
3393
3394
3394
3395
3396
3397
8 unmodified lines

3406
3407
3408
3409
3409
3410
3411
3412
47 unmodified lines

3460
3461
3462
3463
3463
3464
3465
3466
24 unmodified lines

3491
3492
3493
3494
3494
3495
3496
3497
123 unmodified lines

3621
3622
3623
3624
3624
3625
3626
3627
105 unmodified lines

3733
3734
3735
3736
3736
3737
3738
3739
211 unmodified lines

3951
3952
3953
3954
3954
3955
3956
3957
36 unmodified lines

3994
3995
3996
3997
3997
3998
3999
4000
7 unmodified lines

4008
4009
4010
4011
4011
4012
4013
4014
31 unmodified lines

4046
4047
4048
4049
4049
4050
4051
4052
826 unmodified lines

4879
4880
4881
4882
4882
4883
4884
4885
16 unmodified lines

4902
4903
4904
4905
4905
4906
4907
4908
22 unmodified lines

4931
4932
4933
4934
4934
4935
4936
4937

141 unmodified lines

sessionID := "test-session-123"
    agentType := agent.AgentTypeClaudeCode

err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    sessionID,
        Strategy:     "manual-commit",
409 unmodified lines

}

cpID := id.MustCheckpointID("abcdef123456")
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "test-session-id",
        Strategy:     "manual-commit",
126 unmodified lines

// Write a committed checkpoint with branch information
        checkpointID := id.MustCheckpointID("a1b2c3d4e5f6")
        store := NewGitStore(repo, DefaultV1Refs())
        err = store.Write(context.Background(), WriteSession{
        err = store.Write(context.Background(), Session{
            CheckpointID: checkpointID,
            SessionID:    "test-session-123",
            Strategy:     "manual-commit",
33 unmodified lines

// Write a committed checkpoint (branch should be empty in detached HEAD)
        checkpointID := id.MustCheckpointID("b2c3d4e5f6a7")
        store := NewGitStore(repo, DefaultV1Refs())
        err = store.Write(context.Background(), WriteSession{
        err = store.Write(context.Background(), Session{
            CheckpointID: checkpointID,
            SessionID:    "test-session-456",
            Strategy:     "manual-commit",
18 unmodified lines

checkpointID := id.MustCheckpointID("f1e2d3c4b5a6")

// First, create a checkpoint without a summary
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    "test-session-summary",
        Strategy:     "manual-commit",
25 unmodified lines

OpenItems: []string{"Open item 1"},
    }

err = store.Write(context.Background(), BackfillSummary{CheckpointID: checkpointID, Summary: summary})
    err = store.Write(context.Background(), SessionSummary{CheckpointID: checkpointID, Summary: summary})
    if err != nil {
        t.Fatalf("UpdateSummary() error = %v", err)
    }
41 unmodified lines

checkpointID := id.MustCheckpointID("000000000000")
    summary := &Summary{Intent: "Test", Outcome: "Test"}

err = store.Write(context.Background(), BackfillSummary{CheckpointID: checkpointID, Summary: summary})
    err = store.Write(context.Background(), SessionSummary{CheckpointID: checkpointID, Summary: summary})
    if err == nil {
        t.Error("UpdateSummary() should return error for non-existent checkpoint")
    }
34 unmodified lines

// Create entire/checkpoints/v1 branch on the remote with a checkpoint
    remoteStore := NewGitStore(remoteRepo, DefaultV1Refs())
    cpID := id.MustCheckpointID("abcdef123456")
    err = remoteStore.Write(context.Background(), WriteSession{
    err = remoteStore.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "test-session-id",
        Strategy:     "manual-commit",
62 unmodified lines

authorName := "Alice Developer"
    authorEmail := "alice@example.com"

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    "test-session-author",
        Strategy:     "manual-commit",
78 unmodified lines

checkpointID := id.MustCheckpointID("a1a2a3a4a5a6")

// Write first session
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-one",
        Strategy:         "manual-commit",
9 unmodified lines

}

// Write second session to the same checkpoint ID
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-two",
        Strategy:         "manual-commit",
58 unmodified lines

checkpointID := id.MustCheckpointID("b1b2b3b4b5b6")

// Write first session with specific stats
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-one",
        Strategy:         "manual-commit",
13 unmodified lines

}

// Write second session with overlapping and new files
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-two",
        Strategy:         "manual-commit",
65 unmodified lines

// Write two sessions
    for i, sessionID := range []string{"session-alpha", "session-beta"} {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        sessionID,
            Strategy:         "manual-commit",
62 unmodified lines

}

for _, s := range sessions {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        s.id,
            Strategy:         "manual-commit",
44 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    checkpointID := id.MustCheckpointID(cpIDStr)

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        sessionID,
        Strategy:         "manual-commit",
18 unmodified lines

{"timestamp":"2026-03-25T11:31:11.756Z","type":"compacted","payload":{"message":"","replacement_history":[{"type":"message","role":"user","content":[{"type":"input_text","text":"hello"}]},{"type":"reasoning","summary":[{"text":"nested"}],"encrypted_content":"REDACTED"},{"type":"compaction","encrypted_content":"REDACTED"},{"type":"compaction_summary","encrypted_content":"REDACTED"}]}}
`

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "codex-session",
        Strategy:         "manual-commit",
43 unmodified lines

// Write three sessions
    for i := range 3 {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        fmt.Sprintf("session-%d", i),
            Strategy:         "manual-commit",
32 unmodified lines

// Write two sessions with distinct IDs
    sessionIDs := []string{"unique-id-alpha", "unique-id-beta"}
    for i, sid := range sessionIDs {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        sid,
            Strategy:         "manual-commit",
45 unmodified lines

// Write two sessions to the same checkpoint
    for i, sid := range []string{"list-session-1", "list-session-2"} {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        sid,
            Strategy:         "manual-commit",
55 unmodified lines

checkpointID := id.MustCheckpointID("313233343536")

// Write session without prompts
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "no-prompts-session",
        Strategy:         "manual-commit",
42 unmodified lines

Outcome: "Bug was fixed",
    }

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "summary-session",
        Strategy:         "manual-commit",
32 unmodified lines

// Write three sessions
    for i := range 3 {
        err := store.Write(context.Background(), WriteSession{
        err := store.Write(context.Background(), Session{
            CheckpointID:     checkpointID,
            SessionID:        fmt.Sprintf("three-session-%d", i),
            Strategy:         "manual-commit",
1434 unmodified lines

checkpointID := id.MustCheckpointID("deda01234567")

// Write session "X" with initial data
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-X",
        Strategy:         "manual-commit",
13 unmodified lines

}

// Write session "Y"
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-Y",
        Strategy:         "manual-commit",
13 unmodified lines

}

// Write session "X" again with updated data (should replace, not append)
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-X",
        Strategy:         "manual-commit",
88 unmodified lines

checkpointID := id.MustCheckpointID("dedb07654321")

// Write session "X" with initial data
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-X",
        Strategy:         "manual-commit",
8 unmodified lines

}

// Write session "X" again with updated data
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-X",
        Strategy:         "manual-commit",
54 unmodified lines

checkpointID := id.MustCheckpointID("dedc0abcdef1")

// Write session A at index 0
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-A",
        Strategy:         "manual-commit",
7 unmodified lines

}

// Write session B at index 1
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-B",
        Strategy:         "manual-commit",
7 unmodified lines

}

// Write session A again — should reuse index 0, not create index 2
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-A",
        Strategy:         "manual-commit",
49 unmodified lines

checkpointID := id.MustCheckpointID("dedd0abcdef2")

// Write session A with prompts and context
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-A",
        Strategy:         "manual-commit",
8 unmodified lines

}

// Write session B with prompts
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-B",
        Strategy:         "manual-commit",
8 unmodified lines

}

// Overwrite session A WITHOUT prompts
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "session-A",
        Strategy:         "manual-commit",
47 unmodified lines

t.Fatalf("redact.JSONLBytes() error = %v", err)
    }

err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "redact-transcript-session",
        Strategy:         "manual-commit",
24 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    checkpointID := id.MustCheckpointID("aabbccddeef2")

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "redact-prompt-session",
        Strategy:         "manual-commit",
123 unmodified lines

checkpointID := id.MustCheckpointID("b1c2d3e4f5a6")
    sessionID := "test-session-version"

err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    sessionID,
        Strategy:     "manual-commit",
105 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())

checkpointID := id.MustCheckpointID("c1d2e3f4a5b6")
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: checkpointID,
        SessionID:    "test-session-model",
        Strategy:     "manual-commit",
211 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    checkpointID := id.MustCheckpointID("aabbccddeef7")

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "redact-summary-session",
        Strategy:         "manual-commit",
36 unmodified lines

checkpointID := id.MustCheckpointID("aabbccddeef8")

// First write a checkpoint without a summary
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "update-summary-session",
        Strategy:         "manual-commit",
7 unmodified lines

}

// Now update the summary with a secret
    err = store.Write(context.Background(), BackfillSummary{CheckpointID: checkpointID, Summary: &Summary{
    err = store.Write(context.Background(), SessionSummary{CheckpointID: checkpointID, Summary: &Summary{
        Intent:  "Rotated key " + highEntropySecret,
        Outcome: "Done",
    }})
31 unmodified lines

t.Fatalf("failed to write transcript: %v", err)
    }

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:           checkpointID,
        SessionID:              "jsonl-fallback-session",
        Strategy:               "manual-commit",
826 unmodified lines

checkpointID := id.MustCheckpointID("aabbccddeeff")

// First session: investigate session, sets HasInvestigation=true.
    if err := store.Write(context.Background(), WriteSession{
    if err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "investigate-session-1",
        Strategy:         "manual-commit",
16 unmodified lines

// Second session: ordinary session, HasInvestigation=false. The OR-merge
    // against the existing summary must keep HasInvestigation=true.
    if err := store.Write(context.Background(), WriteSession{
    if err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "ordinary-session-2",
        Strategy:         "manual-commit",
22 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    checkpointID := id.MustCheckpointID("11223344aabb")

if err := store.Write(context.Background(), WriteSession{
    if err := store.Write(context.Background(), Session{
        CheckpointID:     checkpointID,
        SessionID:        "investigate-roundtrip",
        Strategy:         "manual-commit",

Mcmd/entire/cli/checkpoint/checkpoint_test.go+45/-45

47 unmodified lines

48
49
50
51
51
52
53
54
47 unmodified lines

102
103
104
105
105
106
107
108
25 unmodified lines

134
135
136
137
137
138
139
140
50 unmodified lines

191
192
193
194
194
195
196
197
20 unmodified lines

218
219
220
221
221
222
223
224
21 unmodified lines

246
247
248
249
249
250
251
252
9 unmodified lines

262
263
264
265
265
266
267
268

47 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    cpID := id.MustCheckpointID("a1b2c3d4e5f6")

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
47 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    cpID := id.MustCheckpointID("b2c3d4e5f6a1")

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:              cpID,
        SessionID:                 "session-001",
        Strategy:                  "manual-commit",
25 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    cpID := id.MustCheckpointID("c3d4e5f6a1b2")

err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
50 unmodified lines

// Initial write sanitizes before compaction. With start=2 the dropped
    // compaction line shifts the window so only "gamma" survives.
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID:              cpID,
        SessionID:                 "session-001",
        Strategy:                  "manual-commit",
20 unmodified lines

// Finalize with the same raw transcript. replaceTranscript must sanitize
    // before compaction; otherwise the raw slice at line 2 would reintroduce
    // "beta".
    err = store.Write(context.Background(), BackfillTranscript{
    err = store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted(raw),
21 unmodified lines

cpID := id.MustCheckpointID("d4e5f6a1b2c3")

initial := claudeStyleTranscript()
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
9 unmodified lines

extended := append([]byte{}, initial...)
    extended = append(extended,
        []byte(`{"type":"user","uuid":"u3","timestamp":"2026-01-01T00:00:04Z","message":{"role":"user","content":"hello three"}}`+"\n")...)
    err = store.Write(context.Background(), BackfillTranscript{
    err = store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted(extended),

Mcmd/entire/cli/checkpoint/persistent_compact_transcript_test.go+7/-7

45 unmodified lines

46
47
48
49
49
50
51
52

45 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    cpID := id.MustCheckpointID("a1b2c3d4e5f6")

err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "regression-no-opf-trailer",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/persistent_opf_trailer_test.go+1/-1

39 unmodified lines

40
41
42
43
43
44
45
46
39 unmodified lines

86
87
88
89
89
90
91
92

39 unmodified lines

cpID := id.MustCheckpointID("d4e5f6a1b2c3")

// Write a checkpoint with NO transcript
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-no-transcript",
        Strategy:     "manual-commit",
39 unmodified lines

cpID := id.MustCheckpointID("e5f6a1b2c3d4")

// Write a checkpoint WITH a transcript
    err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-with-transcript",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/persistent_phantom_paths_test.go+2/-2

84 unmodified lines

85
86
87
88
88
89
90
91

84 unmodified lines

store := NewGitStore(repo, refs)

cpID := id.MustCheckpointID("a1b2c3d4e5f6")
    require.NoError(t, store.Write(context.Background(), WriteSession{
    require.NoError(t, store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/persistent_read_store_test.go+1/-1

55 unmodified lines

56
57
58
59
59
60
61
62
1 unmodified line

64
65
66
67
67
68
69
70

55 unmodified lines

ctx := context.Background()
    cpID := id.MustCheckpointID("222222222222")

require.NoError(t, store.Write(ctx, WriteSession{
    require.NoError(t, store.Write(ctx, Session{
        CheckpointID: cpID,
        SessionID:    "session-a",
        Strategy:     "manual-commit",
1 unmodified line

AuthorName:   "Test",
        AuthorEmail:  "test@example.com",
    }))
    require.NoError(t, store.Write(ctx, WriteSession{
    require.NoError(t, store.Write(ctx, Session{
        CheckpointID: cpID,
        SessionID:    "session-b",
        Strategy:     "manual-commit",

Mcmd/entire/cli/checkpoint/persistent_reader_test.go+2/-2

51 unmodified lines

52
53
54
55
55
56
57
58
61 unmodified lines

120
121
122
123
123
124
125
126
17 unmodified lines

144
145
146
147
147
148
149
150
18 unmodified lines

169
170
171
172
172
173
174
175
20 unmodified lines

196
197
198
199
199
200
201
202
14 unmodified lines

217
218
219
220
220
221
222
223
22 unmodified lines

246
247
248
249
249
250
251
252
10 unmodified lines

263
264
265
266
266
267
268
269
21 unmodified lines

291
292
293
294
294
295
296
297
36 unmodified lines

334
335
336
337
337
338
339
340
8 unmodified lines

349
350
351
352
352
353
354
355
22 unmodified lines

378
379
380
381
381
382
383
384
48 unmodified lines

433
434
435
436
436
437
438
439
15 unmodified lines

455
456
457
458
458
459
460
461
15 unmodified lines

477
478
479
480
480
481
482
483
151 unmodified lines

635
636
637
638
638
639
640
641
6 unmodified lines

648
649
650
651
651
652
653
654
100 unmodified lines

755
756
757
758
758
759
760
761
21 unmodified lines

783
784
785
786
786
787
788
789
5 unmodified lines

795
796
797
798
798
799
800
801
30 unmodified lines

832
833
834
835
835
836
837
838
2 unmodified lines

841
842
843
844
844
845
846
847

51 unmodified lines

store := NewGitStore(repo, DefaultV1Refs())
    cpID := id.MustCheckpointID("a1b2c3d4e5f6")

err = store.Write(context.Background(), WriteSession{
    err = store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
61 unmodified lines

// Update with full transcript (replace semantics)
    fullTranscript := []byte("full transcript line 1\nfull transcript line 2\nfull transcript line 3\n")
    err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted(fullTranscript),
17 unmodified lines

t.Parallel()
    _, store, cpID := setupRepoForUpdate(t)

err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Prompts:      []string{"prompt 1", "prompt 2", "prompt 3"},
18 unmodified lines

_, store, cpID := setupRepoForUpdate(t)

fullTranscript := []byte("complete transcript\n")
    err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted(fullTranscript),
20 unmodified lines

t.Parallel()
    _, store, _ := setupRepoForUpdate(t)

err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: id.MustCheckpointID("deadbeef1234"),
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted([]byte("should fail")),
14 unmodified lines

}

// Update only transcript
    err = store.Write(context.Background(), BackfillTranscript{
    err = store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted([]byte("updated transcript\n")),
22 unmodified lines

// Write a second checkpoint
    cpID2 := id.MustCheckpointID("b2c3d4e5f6a1")
    err := store.Write(context.Background(), WriteSession{
    err := store.Write(context.Background(), Session{
        CheckpointID: cpID2,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
10 unmodified lines

// Update both checkpoints with the same full transcript
    for _, cpID := range []id.CheckpointID{cpID1, cpID2} {
        err = store.Write(context.Background(), BackfillTranscript{
        err = store.Write(context.Background(), SessionTranscript{
            CheckpointID: cpID,
            SessionID:    "session-001",
            Transcript:   redact.AlreadyRedacted(fullTranscript),
21 unmodified lines

repo, store, cpID := setupRepoForUpdate(t)

// Update transcript
    err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted([]byte("new full transcript content\n")),
36 unmodified lines

t.Parallel()
    _, store, _ := setupRepoForUpdate(t)

err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        SessionID:  "session-001",
        Transcript: redact.AlreadyRedacted([]byte("should fail")),
    })
8 unmodified lines

// Update with wrong session ID — should fall back to latest (index 0)
    fullTranscript := []byte("updated via fallback\n")
    err := store.Write(context.Background(), BackfillTranscript{
    err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "nonexistent-session",
        Transcript:   redact.AlreadyRedacted(fullTranscript),
22 unmodified lines

t.Fatalf("Read() before error = %v", err)
    }

err = store.Write(context.Background(), BackfillTranscript{
    err = store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted([]byte("updated\n")),
48 unmodified lines

summary.CheckpointVersion = ""
    })

if err := store.Write(context.Background(), BackfillAttribution{CheckpointID: cpID, Attribution: &Attribution{AgentLines: 7}}); err != nil {
    if err := store.Write(context.Background(), CheckpointAttribution{CheckpointID: cpID, Attribution: &Attribution{AgentLines: 7}}); err != nil {
        t.Fatalf("UpdateCheckpointSummary() error = %v", err)
    }

15 unmodified lines

summary.CheckpointVersion = futureVersion
    })

if err := store.Write(context.Background(), BackfillAttribution{CheckpointID: cpID, Attribution: &Attribution{AgentLines: 11}}); err != nil {
    if err := store.Write(context.Background(), CheckpointAttribution{CheckpointID: cpID, Attribution: &Attribution{AgentLines: 11}}); err != nil {
        t.Fatalf("UpdateCheckpointSummary() error = %v", err)
    }

15 unmodified lines

summary.CheckpointVersion = futureVersion
    })

if err := store.Write(context.Background(), WriteSession{
    if err := store.Write(context.Background(), Session{
        CheckpointID: cpID,
        SessionID:    "session-002",
        Strategy:     "manual-commit",
151 unmodified lines

// Write initial checkpoint
            store := NewGitStore(repo, DefaultV1Refs())
            cpID := id.MustCheckpointID("a1b2c3d4e5f6")
            err = store.Write(context.Background(), WriteSession{
            err = store.Write(context.Background(), Session{
                CheckpointID: cpID,
                SessionID:    "session-001",
                Strategy:     "manual-commit",
6 unmodified lines

}

// Call UpdateCommitted — this is the operation under test
            err = store.Write(context.Background(), BackfillTranscript{
            err = store.Write(context.Background(), SessionTranscript{
                CheckpointID: cpID,
                SessionID:    "session-001",
                Transcript:   redact.AlreadyRedacted([]byte("full transcript\n")),
100 unmodified lines

t.Fatal("precompute returned zero content-hash blob")
    }

if err := store.Write(context.Background(), BackfillTranscript{
    if err := store.Write(context.Background(), SessionTranscript{
        CheckpointID:     cpID,
        SessionID:        "session-001",
        Transcript:       transcript,
21 unmodified lines

transcript := redact.AlreadyRedacted([]byte("stable transcript content\n"))

if err := store.Write(context.Background(), BackfillTranscript{
    if err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   transcript,
5 unmodified lines

// should never touch the chunking function.
    calls := installChunkCounter(t)

if err := store.Write(context.Background(), BackfillTranscript{
    if err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   transcript,
30 unmodified lines

first := redact.AlreadyRedacted([]byte("first version\n"))
    second := redact.AlreadyRedacted([]byte("second version with more content\n"))

if err := store.Write(context.Background(), BackfillTranscript{
    if err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   first,
2 unmodified lines

}
    hashBefore := readTranscriptBlobHash(t, repo, cpID)

if err := store.Write(context.Background(), BackfillTranscript{
    if err := store.Write(context.Background(), SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   second,

Mcmd/entire/cli/checkpoint/persistent_update_test.go+22/-22

20 unmodified lines

21
22
23
24
24
25
26
27
27
28
29
29
30
31
32
32
33
34
34
35
36
36
37
38
39
40
41
41
42
43
43
44
45
46
47
48
49
48
49
50
51
50
51
52
53
54
55
56
5 unmodified lines

62
63
64
63
65
66
65
67
68
67
69
70
69
71
72
73
74

20 unmodified lines

isWriteRequest()
}

// WriteSession creates or replaces a session document within a checkpoint,
// Session creates or replaces a session document within a checkpoint,
// materializing the checkpoint on its first session. This is condensation's
// write. (Maps to the former writeSession.)
type WriteSession WriteOptions
type Session WriteOptions

// BackfillTranscript replaces a session's transcript, prompts, and skill
// SessionTranscript replaces a session's transcript, prompts, and skill
// events at stop time without clobbering sibling fields. (Maps to the former
// backfillTranscript.)
type BackfillTranscript UpdateOptions
type SessionTranscript UpdateOptions

// BackfillSummary rewrites only the summary of the checkpoint's latest
// SessionSummary rewrites only the summary of the checkpoint's latest
// session. (Maps to the former backfillSummary.)
type BackfillSummary struct {
type SessionSummary struct {
    CheckpointID id.CheckpointID
    Summary      *Summary
}

// BackfillAttribution rewrites the checkpoint root's combined attribution.
// CheckpointAttribution rewrites the checkpoint root's combined attribution.
// (Maps to the former backfillAttribution.)
type BackfillAttribution struct {
//
//nolint:revive // CheckpointAttribution stutter is accepted — the name makes the checkpoint (vs session) tier explicit alongside the Session* requests.
type CheckpointAttribution struct {
    CheckpointID id.CheckpointID
    Attribution  *Attribution
}

func (WriteSession) isWriteRequest()        {}
func (BackfillTranscript) isWriteRequest()  {}
func (BackfillSummary) isWriteRequest()     {}
func (BackfillAttribution) isWriteRequest() {}
func (Session) isWriteRequest()               {}
func (SessionTranscript) isWriteRequest()     {}
func (SessionSummary) isWriteRequest()        {}
func (CheckpointAttribution) isWriteRequest() {}

// Writer is the committed-store write surface: a single Write that accepts any
// WriteRequest. It is the natural type for mirror fan-out.
5 unmodified lines

// Unknown request types are a programmer error, surfaced rather than ignored.
func (s *GitStore) Write(ctx context.Context, req WriteRequest) error {
    switch r := req.(type) {
    case WriteSession:
    case Session:
        return s.writeSession(ctx, WriteOptions(r))
    case BackfillTranscript:
    case SessionTranscript:
        return s.backfillTranscript(ctx, UpdateOptions(r))
    case BackfillSummary:
    case SessionSummary:
        return s.backfillSummary(ctx, r.CheckpointID, r.Summary)
    case BackfillAttribution:
    case CheckpointAttribution:
        return s.backfillAttribution(ctx, r.CheckpointID, r.Attribution)
    default:
        return fmt.Errorf("checkpoint: unsupported write request %T", req)

Mcmd/entire/cli/checkpoint/persistent_write.go+18/-16

25 unmodified lines

26
27
28
29
30
29
30
31
32
33
2 unmodified lines

36
37
38
39
39
40
41
42
43
43
44
45
46
46
47
48
48
49
50
51
52
53
53
54
55
56
57
58
59
60
60
61
62
63
64
63
64
65
66
67
68
68
69
70
71
71
72
73
74
75
74
75
76
77
78
79
79
80
81
82
83
84
85
86
86
87
88
89
4 unmodified lines

94
95
96
97
97
98
99
100
47 unmodified lines

148
149
150
151
151
152
153
154
155
156
156
157
158

25 unmodified lines

ctx := context.Background()
    cpID := id.MustCheckpointID("a1b2c3d4e5f6")

// WriteSession materializes the checkpoint on first session.
    if err := store.Write(ctx, WriteSession{
    // Session materializes the checkpoint on first session.
    if err := store.Write(ctx, Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
2 unmodified lines

AuthorName:   "Test",
        AuthorEmail:  "test@test.com",
    }); err != nil {
        t.Fatalf("Write(WriteSession) error = %v", err)
        t.Fatalf("Write(Session) error = %v", err)
    }
    summary, err := store.Read(ctx, cpID)
    if err != nil || summary == nil {
        t.Fatalf("checkpoint not created by WriteSession: summary=%v err=%v", summary, err)
        t.Fatalf("checkpoint not created by Session: summary=%v err=%v", summary, err)
    }

// BackfillTranscript replaces the session transcript.
    // SessionTranscript replaces the session transcript.
    full := []byte("full line 1\nfull line 2\n")
    if err := store.Write(ctx, BackfillTranscript{
    if err := store.Write(ctx, SessionTranscript{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Transcript:   redact.AlreadyRedacted(full),
    }); err != nil {
        t.Fatalf("Write(BackfillTranscript) error = %v", err)
        t.Fatalf("Write(SessionTranscript) error = %v", err)
    }
    content, err := store.ReadSessionContent(ctx, cpID, 0)
    if err != nil {
        t.Fatalf("ReadSessionContent() error = %v", err)
    }
    if string(content.Transcript) != string(full) {
        t.Errorf("BackfillTranscript not applied: got %q want %q", content.Transcript, full)
        t.Errorf("SessionTranscript not applied: got %q want %q", content.Transcript, full)
    }

// BackfillSummary rewrites the latest session's summary.
    if err := store.Write(ctx, BackfillSummary{
    // SessionSummary rewrites the latest session's summary.
    if err := store.Write(ctx, SessionSummary{
        CheckpointID: cpID,
        Summary:      &Summary{Intent: "why", Outcome: "what"},
    }); err != nil {
        t.Fatalf("Write(BackfillSummary) error = %v", err)
        t.Fatalf("Write(SessionSummary) error = %v", err)
    }
    if meta := readLatestSessionMetadata(t, repo, cpID); meta.Summary == nil || meta.Summary.Intent != "why" {
        t.Errorf("BackfillSummary not applied: %+v", meta.Summary)
        t.Errorf("SessionSummary not applied: %+v", meta.Summary)
    }

// BackfillAttribution rewrites the checkpoint root combined attribution.
    if err := store.Write(ctx, BackfillAttribution{
    // CheckpointAttribution rewrites the checkpoint root combined attribution.
    if err := store.Write(ctx, CheckpointAttribution{
        CheckpointID: cpID,
        Attribution:  &Attribution{AgentLines: 42},
    }); err != nil {
        t.Fatalf("Write(BackfillAttribution) error = %v", err)
        t.Fatalf("Write(CheckpointAttribution) error = %v", err)
    }
    rootSummary, err := store.Read(ctx, cpID)
    if err != nil {
        t.Fatalf("Read() error = %v", err)
    }
    if rootSummary.CombinedAttribution == nil || rootSummary.CombinedAttribution.AgentLines != 42 {
        t.Errorf("BackfillAttribution not applied: %+v", rootSummary.CombinedAttribution)
        t.Errorf("CheckpointAttribution not applied: %+v", rootSummary.CombinedAttribution)
    }
}

4 unmodified lines

ctx := context.Background()
    cpID := id.MustCheckpointID("b1b2c3d4e5f6")

if err := store.Write(ctx, WriteSession{
    if err := store.Write(ctx, Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
47 unmodified lines

t.Fatalf("ensureSessionsBranch() error = %v", err)
    }

err := store.Write(context.Background(), BackfillSummary{
    err := store.Write(context.Background(), SessionSummary{
        CheckpointID: id.MustCheckpointID("000000000000"),
        Summary:      &Summary{Intent: "x"},
    })
    if !errors.Is(err, ErrCheckpointNotFound) {
        t.Errorf("Write(BackfillSummary) error = %v, want ErrCheckpointNotFound", err)
        t.Errorf("Write(SessionSummary) error = %v, want ErrCheckpointNotFound", err)
    }
}

Mcmd/entire/cli/checkpoint/persistent_write_test.go+19/-19

324 unmodified lines

325
326
327
328
328
329
330
331
60 unmodified lines

392
393
394
395
395
396
397
398
435 unmodified lines

834
835
836
837
837
838
839
840

324 unmodified lines

if err != nil {
        t.Fatal(err)
    }
    err = store.Write(context.Background(), checkpoint.WriteSession{
    err = store.Write(context.Background(), checkpoint.Session{
        CheckpointID:     parsedID,
        SessionID:        "session-1",
        Strategy:         "manual-commit",
60 unmodified lines

if err != nil {
        t.Fatal(err)
    }
    err = store.Write(context.Background(), checkpoint.WriteSession{
    err = store.Write(context.Background(), checkpoint.Session{
        CheckpointID:     parsedID,
        SessionID:        "session-1",
        Strategy:         "manual-commit",
435 unmodified lines

t.Fatal(err)
    }

err = store.Write(context.Background(), checkpoint.WriteSession{
    err = store.Write(context.Background(), checkpoint.Session{
        CheckpointID:     cpID,
        SessionID:        "session-1",
        Strategy:         "manual-commit",

Mcmd/entire/cli/dispatch/mode_local_test.go+3/-3

941 unmodified lines

942
943
944
945
945
946
947
948

941 unmodified lines

}
    elapsed := time.Since(start)

if err := store.Write(ctx, checkpoint.BackfillSummary{CheckpointID: checkpointID, Summary: summary}); err != nil {
    if err := store.Write(ctx, checkpoint.SessionSummary{CheckpointID: checkpointID, Summary: summary}); err != nil {
        return fmt.Errorf("failed to save summary: %w", err)
    }

Mcmd/entire/cli/explain.go+1/-1

74 unmodified lines

75
76
77
78
78
79
80
81
84 unmodified lines

166
167
168
169
169
170
171
172

74 unmodified lines

opts.AuthorEmail = exportTestAuthorEmail
    }
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    require.NoError(t, store.Write(context.Background(), checkpoint.WriteSession(opts)))
    require.NoError(t, store.Write(context.Background(), checkpoint.Session(opts)))
}

func TestRunExplainExport_JSONSingleCheckpoint(t *testing.T) {
84 unmodified lines

cpID := id.MustCheckpointID("777711112222")
    v1 := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    require.NoError(t, v1.Write(context.Background(), checkpoint.WriteSession{
    require.NoError(t, v1.Write(context.Background(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1-only",
        Strategy:     "manual-commit",

Mcmd/entire/cli/explain_export_test.go+2/-2

74 unmodified lines

75
76
77
78
79
78
79
80
81
82

74 unmodified lines

func (s *stubTextAgent) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // test stub
}
func (s *stubTextAgent) WriteSession(context.Context, *agent.AgentSession) error { return nil }
func (s *stubTextAgent) FormatResumeCommand(string) string                       { return "" }
func (s *stubTextAgent) Session(context.Context, *agent.AgentSession) error { return nil }
func (s *stubTextAgent) FormatResumeCommand(string) string                  { return "" }
func (s *stubTextAgent) GenerateText(context.Context, string, string) (string, error) {
    return `{"intent":"Intent","outcome":"Outcome","learnings":{"repo":[],"code":[],"workflow":[]},"friction":[],"open_items":[]}`, nil
}

Mcmd/entire/cli/explain_summary_provider_test.go+2/-2

413 unmodified lines

414
415
416
417
417
418
419
420
254 unmodified lines

675
676
677
678
678
679
680
681
86 unmodified lines

768
769
770
771
771
772
773
774
236 unmodified lines

1011
1012
1013
1014
1014
1015
1016
1017
975 unmodified lines

1993
1994
1995
1996
1996
1997
1998
1999
57 unmodified lines

2057
2058
2059
2060
2060
2061
2062
2063
61 unmodified lines

2125
2126
2127
2128
2128
2129
2130
2131
74 unmodified lines

2206
2207
2208
2209
2209
2210
2211
2212
70 unmodified lines

2283
2284
2285
2286
2286
2287
2288
2289
51 unmodified lines

2341
2342
2343
2344
2344
2345
2346
2347
42 unmodified lines

2390
2391
2392
2393
2393
2394
2395
2396
163 unmodified lines

2560
2561
2562
2563
2563
2564
2565
2566
35 unmodified lines

2602
2603
2604
2605
2605
2606
2607
2608
122 unmodified lines

2731
2732
2733
2734
2734
2735
2736
2737
37 unmodified lines

2775
2776
2777
2778
2778
2779
2780
2781
3199 unmodified lines

5981
5982
5983
5984
5984
5985
5986
5987
61 unmodified lines

6049
6050
6051
6052
6052
6053
6054
6055
66 unmodified lines

6122
6123
6124
6125
6125
6126
6127
6128

413 unmodified lines

ctx := context.Background()

cpID := id.MustCheckpointID("deadbeefcafe")
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.WriteSession{
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-auto",
        Strategy:     "manual-commit",
254 unmodified lines

id.MustCheckpointID("e7aaaaaaaaaa"),
        id.MustCheckpointID("e7bbbbbbbbbb"),
    } {
        require.NoError(t, store.Write(ctx, checkpoint.WriteSession{
        require.NoError(t, store.Write(ctx, checkpoint.Session{
            CheckpointID: cpID,
            SessionID:    "session-" + cpID.String(),
            Strategy:     "manual-commit",
86 unmodified lines

commitPrefix := head.Hash().String()[:7]
    collisionID := id.MustCheckpointID(commitPrefix + "aaaaa")

require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.WriteSession{
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.Session{
        CheckpointID: collisionID,
        SessionID:    "session-collision",
        Strategy:     "manual-commit",
236 unmodified lines

require.NoError(t, err)
    store := stores.Persistent
    cpID := id.MustCheckpointID("a1b2c3d4e5f6")
    require.NoError(t, store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-001",
        Strategy:     "manual-commit",
975 unmodified lines

`{"type":"user","message":{"content":[{"type":"text","text":"old prompt before checkpoint"}]}}` + "\n" +
            `{"type":"user","message":{"content":[{"type":"text","text":"scoped prompt for checkpoint"}]}}` + "\n",
    )
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteSession{
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.Session{
        CheckpointID:              cpID,
        SessionID:                 "session-v1",
        Strategy:                  "manual-commit",
57 unmodified lines

cpID := id.MustCheckpointID("ab12ab12ab12")
    ctx := context.Background()
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.WriteSession{
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1-only-generate",
        Strategy:     "manual-commit",
61 unmodified lines

}

cpID := id.MustCheckpointID("cd12cd12cd12")
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.WriteSession{
    require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1-mode-generate",
        Strategy:     "manual-commit",
74 unmodified lines

transcript := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"generate test"}]}}` + "\n" +
        `{"type":"assistant","message":{"content":"done"}}` + "\n")

require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1",
        Strategy:     "manual-commit",
70 unmodified lines

transcript := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"generate v1 test"}]}}` + "\n" +
        `{"type":"assistant","message":{"content":"done"}}` + "\n")

require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1",
        Strategy:     "manual-commit",
51 unmodified lines

`{"type":"assistant","message":{"content":"raw reply"}}` + "\n",
    )

require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1-transcript",
        Strategy:     "manual-commit",
42 unmodified lines

rawTranscript := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"v1 raw fallback prompt"}]}}` + "\n" +
        `{"type":"assistant","message":{"content":"v1 raw reply"}}` + "\n")

require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-v1-fallback",
        Strategy:     "manual-commit",
163 unmodified lines

v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())

nativeTranscript := []byte("EXTERNAL_NATIVE_TRANSCRIPT\nuser=external native prompt\nassistant=external native reply\n")
    require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-external-display",
        Strategy:     "manual-commit",
35 unmodified lines

v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())

nativeTranscript := []byte("EXTERNAL_NATIVE_BEFORE\nEXTERNAL_NATIVE_SCOPE\nuser=scoped external prompt\nassistant=scoped external reply\n")
    require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID:              cpID,
        SessionID:                 "session-external-verbose",
        Strategy:                  "manual-commit",
122 unmodified lines

v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())

nativeTranscript := []byte("EXTERNAL_NATIVE_TRANSCRIPT\nuser=unparseable native prompt\nassistant=unparseable native reply\n")
    require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-external-fallback",
        Strategy:     "manual-commit",
37 unmodified lines

transcript := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"hello"}]}}` + "\n")

v1ID := id.MustCheckpointID("ccc777888999")
    require.NoError(t, v1Store.Write(ctx, checkpoint.WriteSession{
    require.NoError(t, v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: v1ID,
        SessionID:    "session-v1",
        Strategy:     "manual-commit",
3199 unmodified lines

// Write committed checkpoint metadata so getBranchCheckpoints can find it
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := store.Write(context.Background(), checkpoint.WriteSession{
    if err := store.Write(context.Background(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "test-session",
        Strategy:     "manual-commit",
61 unmodified lines

expectedPrompt := "Refactor the authentication module to use JWT tokens"
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := store.Write(context.Background(), checkpoint.WriteSession{
    if err := store.Write(context.Background(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "2026-02-27-test-session",
        Strategy:     "manual-commit",
66 unmodified lines

cpID := id.MustCheckpointID("bbcc33445566")
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    for _, sessionID := range []string{"older-session-aaaa", "latest-session-bbbb"} {
        require.NoError(t, store.Write(context.Background(), checkpoint.WriteSession{
        require.NoError(t, store.Write(context.Background(), checkpoint.Session{
            CheckpointID: cpID,
            SessionID:    sessionID,
            Strategy:     "manual-commit",

Mcmd/entire/cli/explain_test.go+18/-18

45 unmodified lines

46
47
48
49
49
50
51
52

45 unmodified lines

t.Helper()
    cpID := id.MustCheckpointID("aabbccdd1122")
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    require.NoError(t, store.Write(context.Background(), checkpoint.WriteSession{
    require.NoError(t, store.Write(context.Background(), checkpoint.Session{
        CheckpointID:     cpID,
        SessionID:        "head-flags-session",
        Strategy:         "manual-commit",

Mcmd/entire/cli/head_checkpoint_flags_test.go+1/-1

211 unmodified lines

212
213
214
215
215
216
217
218
41 unmodified lines

260
261
262
263
263
264
265
266
17 unmodified lines

284
285
286
287
288
287
288
289
290
291
6 unmodified lines

298
299
300
301
301
302
303
304
5 unmodified lines

310
311
312
313
313
314
315
315
316
317
318
352 unmodified lines

671
672
673
674
674
675
676
677
44 unmodified lines

722
723
724
725
725
726
727
728
16 unmodified lines

745
746
747
748
749
748
749
750
751
752
6 unmodified lines

759
760
761
762
762
763
764
765
5 unmodified lines

771
772
773
774
774
775
776
776
777
778
779
289 unmodified lines

1069
1070
1071
1072
1072
1073
1074
1075
37 unmodified lines

1113
1114
1115
1116
1116
1117
1118
1119
16 unmodified lines

1136
1137
1138
1139
1140
1139
1140
1141
1142
1143
186 unmodified lines

1330
1331
1332
1333
1333
1334
1335
1336
45 unmodified lines

1382
1383
1384
1385
1385
1386
1387
1388
1389
1390
1391
1390
1391
1392
1393
1394
1393
1394
1395
1396
1397

211 unmodified lines

})
}

// TestAgentSessionOperations verifies ReadSession/WriteSession via agent interface.
// TestAgentSessionOperations verifies ReadSession/Session via agent interface.
func TestAgentSessionOperations(t *testing.T) {
    t.Parallel()

41 unmodified lines

}
    })

t.Run("WriteSession writes NativeData to file", func(t *testing.T) {
    t.Run("Session writes NativeData to file", func(t *testing.T) {
        t.Parallel()
        env := NewTestEnv(t)
        env.InitRepo()
17 unmodified lines

dstPath := filepath.Join(env.RepoDir, "dst.jsonl")
        session.SessionRef = dstPath

// Verify file was written
6 unmodified lines

}
    })

t.Run("WriteSession rejects wrong agent", func(t *testing.T) {
    t.Run("Session rejects wrong agent", func(t *testing.T) {
        t.Parallel()

ag, _ := agent.Get("claude-code")
5 unmodified lines

NativeData: []byte("data"),
        }

err := ag.WriteSession(context.Background(), session)
        err := ag.Session(context.Background(), session)
        if err == nil {
            t.Error("WriteSession() should reject session from different agent")
            t.Error("Session() should reject session from different agent")
        }
    })
}
352 unmodified lines

})
}

// TestGeminiCLISessionOperations verifies ReadSession/WriteSession via Gemini agent interface.
// TestGeminiCLISessionOperations verifies ReadSession/Session via Gemini agent interface.
func TestGeminiCLISessionOperations(t *testing.T) {
    t.Parallel()

44 unmodified lines

}
    })

t.Run("WriteSession writes NativeData to file", func(t *testing.T) {
    t.Run("Session writes NativeData to file", func(t *testing.T) {
        t.Parallel()
        env := NewTestEnv(t)
        env.InitRepo()
16 unmodified lines

dstPath := filepath.Join(env.RepoDir, "dst.json")
        session.SessionRef = dstPath

// Verify file was written
6 unmodified lines

}
    })

t.Run("WriteSession rejects wrong agent", func(t *testing.T) {
    t.Run("Session rejects wrong agent", func(t *testing.T) {
        t.Parallel()

ag, _ := agent.Get("gemini")
5 unmodified lines

NativeData: []byte("data"),
        }

err := ag.WriteSession(context.Background(), session)
        err := ag.Session(context.Background(), session)
        if err == nil {
            t.Error("WriteSession() should reject session from different agent")
            t.Error("Session() should reject session from different agent")
        }
    })
}
289 unmodified lines

})
}

// TestFactoryAIDroidSessionMethods verifies ReadSession, WriteSession, and GetSessionDir.
// TestFactoryAIDroidSessionMethods verifies ReadSession, Session, and GetSessionDir.
func TestFactoryAIDroidSessionMethods(t *testing.T) {
    t.Parallel()

37 unmodified lines

}
    })

t.Run("WriteSession round-trips with ReadSession", func(t *testing.T) {
    t.Run("Session round-trips with ReadSession", func(t *testing.T) {
        t.Parallel()

tmpDir := t.TempDir()
16 unmodified lines

session.SessionRef = restoredPath
        ctx := context.Background()
        if err := ag.WriteSession(ctx, session); err != nil {
            t.Fatalf("WriteSession() error = %v", err)
        if err := ag.Session(ctx, session); err != nil {
            t.Fatalf("Session() error = %v", err)
        }

restored, err := os.ReadFile(restoredPath)
186 unmodified lines

})
}

// TestOpenCodeSessionOperations verifies ReadSession/WriteSession via OpenCode agent interface.
// TestOpenCodeSessionOperations verifies ReadSession/Session via OpenCode agent interface.
func TestOpenCodeSessionOperations(t *testing.T) {
    t.Parallel()

45 unmodified lines

}
    })

t.Run("WriteSession validates input", func(t *testing.T) {
    t.Run("Session validates input", func(t *testing.T) {
        t.Parallel()

ag, _ := agent.Get("opencode")

if err := ag.WriteSession(context.Background(), nil); err == nil {
            t.Error("WriteSession(nil) should error")
        if err := ag.Session(context.Background(), nil); err == nil {
            t.Error("Session(nil) should error")
        }
        if err := ag.WriteSession(context.Background(), &agent.AgentSession{}); err == nil {
            t.Error("WriteSession with empty NativeData should error")
        if err := ag.Session(context.Background(), &agent.AgentSession{}); err == nil {
            t.Error("Session with empty NativeData should error")
        }
    })
}

Mcmd/entire/cli/integration_test/agent_test.go+24/-24

71 unmodified lines

72
73
74
75
75
76
77
78

71 unmodified lines

return nil, nil
}

func (m *mockLifecycleAgent) WriteSession(_ context.Context, _ *agent.AgentSession) error {
func (m *mockLifecycleAgent) Session(_ context.Context, _ *agent.AgentSession) error {
    return nil
}

Mcmd/entire/cli/lifecycle_test.go+1/-1

986 unmodified lines

987
988
989
990
991
990
991
992
993
994

986 unmodified lines

NativeData: logContent,
    }

// Write the session using the agent's WriteSession method
    if err := ag.WriteSession(ctx, agentSession); err != nil {
    // Write the session using the agent's Session method
    if err := ag.Session(ctx, agentSession); err != nil {
        logging.Error(ctx, "resume session failed during write",
            slog.String("checkpoint_id", checkpointID.String()),
            slog.String("session_id", sessionID),

Mcmd/entire/cli/resume.go+2/-2

60 unmodified lines

61
62
63
64
64
65
66
67
463 unmodified lines

531
532
533
534
534
535
536
537
134 unmodified lines

672
673
674
675
675
676
677
678
179 unmodified lines

858
859
860
861
861
862
863
864
60 unmodified lines

925
926
927
928
928
929
930
931
215 unmodified lines

1147
1148
1149
1150
1150
1151
1152
1153

60 unmodified lines

func (a *recordingResumeAgent) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // Not used by this test agent.
}
func (a *recordingResumeAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (a *recordingResumeAgent) Session(_ context.Context, session *agent.AgentSession) error {
    a.writtenSession = session
    return nil
}
463 unmodified lines

) {
    t.Helper()

if err := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteSession{
    if err := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.Session{
        CheckpointID: checkpointID,
        SessionID:    sessionID,
        CreatedAt:    createdAt,
134 unmodified lines

},
    }
    for _, session := range sessions {
        if err := store.Write(ctx, checkpoint.WriteSession{
        if err := store.Write(ctx, checkpoint.Session{
            CheckpointID: cpID,
            SessionID:    session.sessionID,
            CreatedAt:    session.createdAt,
179 unmodified lines

raw := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"payload"}]}}` + "\n")

v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := v1Store.Write(ctx, checkpoint.WriteSession{
    if err := v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "benign-session",
        Strategy:     "manual-commit",
60 unmodified lines

raw := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"resume v1 fallback"}]}}` + "\n")

v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := v1Store.Write(ctx, checkpoint.WriteSession{
    if err := v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    sessionID,
        Strategy:     "manual-commit",
215 unmodified lines

// Agent must be set so RestoreLogsOnly can resolve a session-write target.
    v1Store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := v1Store.Write(ctx, checkpoint.WriteSession{
    if err := v1Store.Write(ctx, checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "2025-01-01-test-session-uuid",
        Strategy:     "manual-commit",

Mcmd/entire/cli/resume_test.go+6/-6

961 unmodified lines

962
963
964
965
965
966
967
968

961 unmodified lines

func (manifestTokenTestAgent) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return &agent.AgentSession{}, nil
}
func (manifestTokenTestAgent) WriteSession(context.Context, *agent.AgentSession) error {
func (manifestTokenTestAgent) Session(context.Context, *agent.AgentSession) error {
    return nil
}
func (manifestTokenTestAgent) FormatResumeCommand(string) string { return "" }

Mcmd/entire/cli/review/manifest_test.go+1/-1

395 unmodified lines

396
397
398
399
399
400
401
402

395 unmodified lines

t.Fatalf("open repo: %v", err)
    }
    cpID := checkpointid.MustCheckpointID(checkpointID)
    err = checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteSession{
    err = checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.Session{
        CheckpointID:     cpID,
        SessionID:        checkpointID,
        Strategy:         "manual-commit",

Mcmd/entire/cli/review_context_test.go+1/-1

745 unmodified lines

746
747
748
749
749
750
751
752
38 unmodified lines

791
792
793
794
794
795
796
797

745 unmodified lines

SessionRef: sessionFile,
        NativeData: content,
    }
    if err := agent.WriteSession(ctx, agentSession); err != nil {
    if err := agent.Session(ctx, agentSession); err != nil {
        return "", fmt.Errorf("failed to write session: %w", err)
    }
    return sessionID, nil
38 unmodified lines

SessionRef: sessionFile,
        NativeData: content,
    }
    if err := agent.WriteSession(ctx, agentSession); err != nil {
    if err := agent.Session(ctx, agentSession); err != nil {
        return "", fmt.Errorf("failed to write session: %w", err)
    }
    return sessionID, nil

Mcmd/entire/cli/rewind.go+2/-2

1888 unmodified lines

1889
1890
1891
1892
1892
1893
1894
1895

1888 unmodified lines

}
    cpID := id.MustCheckpointID(cpHex)
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    if err := store.Write(context.Background(), checkpoint.WriteSession{
    if err := store.Write(context.Background(), checkpoint.Session{
        CheckpointID:     cpID,
        SessionID:        "status-test-session",
        Strategy:         "manual-commit",

Mcmd/entire/cli/status_test.go+1/-1

498 unmodified lines

499
500
501
502
502
503
504
505

498 unmodified lines

// and lists both IDs in SessionIDs.
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    for _, sid := range []string{archivedSessionID, latestSessionID} {
        require.NoError(t, store.Write(t.Context(), checkpoint.WriteSession{
        require.NoError(t, store.Write(t.Context(), checkpoint.Session{
            CheckpointID: cpID,
            SessionID:    sid,
            Strategy:     "manual-commit",

Mcmd/entire/cli/strategy/clean_test.go+1/-1

134 unmodified lines

135
136
137
138
138
139
140
141
148 unmodified lines

290
291
292
293
293
294
295
296

134 unmodified lines

// CondenseSession condenses a session's shadow branch to permanent storage.
// checkpointID is the 12-hex-char value from the Entire-Checkpoint trailer.
// Metadata is stored at sharded path: <checkpoint_id[:2]>/<checkpoint_id[2:]>/
// Uses checkpoint.PersistentStore.Write with a checkpoint.WriteSession request for persistent storage.
// Uses checkpoint.PersistentStore.Write with a checkpoint.Session request for persistent storage.
//
// For mid-session commits (no Stop/SaveStep called yet), the shadow branch may not exist.
// In this case, data is extracted from the live transcript instead.
148 unmodified lines

writeV1Start := time.Now()
    writeCtx, writeCommittedSpan := perf.Start(ctx, "write_committed_v1")
    if err := store.Write(writeCtx, cpkg.WriteSession(writeOpts)); err != nil {
    if err := store.Write(writeCtx, cpkg.Session(writeOpts)); err != nil {
        writeCommittedSpan.RecordError(err)
        writeCommittedSpan.End()
        return nil, fmt.Errorf("failed to write checkpoint metadata: %w", err)

Mcmd/entire/cli/strategy/manual_commit_condensation.go+2/-2

1157 unmodified lines

1158
1159
1160
1161
1161
1162
1163
1164
1665 unmodified lines

2830
2831
2832
2833
2833
2834
2835
2836

1157 unmodified lines

slog.Float64("agent_percentage", agentPercentage),
    )

if err := store.Write(ctx, checkpoint.BackfillAttribution{CheckpointID: checkpointID, Attribution: combined}); err != nil {
    if err := store.Write(ctx, checkpoint.CheckpointAttribution{CheckpointID: checkpointID, Attribution: combined}); err != nil {
        return fmt.Errorf("persisting combined attribution: %w", err)
    }

1665 unmodified lines

PrecomputedBlobs: precomputed,
        }

updateErr := store.Write(ctx, checkpoint.BackfillTranscript(updateOpts))
        updateErr := store.Write(ctx, checkpoint.SessionTranscript(updateOpts))
        if updateErr != nil {
            logging.Warn(logCtx, "finalize: failed to update checkpoint",
                slog.String("checkpoint_id", cpIDStr),

Mcmd/entire/cli/strategy/manual_commit_hooks.go+2/-2

133 unmodified lines

134
135
136
137
137
138
139
140

133 unmodified lines

t.Helper()
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    cpID := id.MustCheckpointID(cpIDString)
    require.NoError(t, store.Write(context.Background(), checkpoint.WriteSession{
    require.NoError(t, store.Write(context.Background(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    sessionID,
        Strategy:     "manual-commit",

Mcmd/entire/cli/strategy/manual_commit_opf_rewrite_test.go+1/-1

698 unmodified lines

699
700
701
702
702
703
704
705
74 unmodified lines

780
781
782
783
783
784
785
786

698 unmodified lines

}
        // Checkpoint metadata comes from the shared entire/checkpoints/v1 branch
        // and is attacker-influenceable. Reject path separators/absolute IDs before
        // they reach ResolveSessionFile + WriteSession, which would otherwise let a
        // they reach ResolveSessionFile + Session, which would otherwise let a
        // crafted session ID overwrite files outside the agent session directory.
        if err := validation.ValidateSessionID(sessionID); err != nil {
            fmt.Fprintf(errW, "  Warning: session %d has unsafe session ID %q, skipping: %v\n", i, sessionID, err)
74 unmodified lines

SessionRef: sessionFile,
            NativeData: content.Transcript,
        }
        if writeErr := sessionAgent.WriteSession(ctx, agentSession); writeErr != nil {
        if writeErr := sessionAgent.Session(ctx, agentSession); writeErr != nil {
            if totalSessions > 1 {
                fmt.Fprintf(errW, "    Warning: failed to write session: %v\n", writeErr)
                continue

Mcmd/entire/cli/strategy/manual_commit_rewind.go+2/-2

473 unmodified lines

474
475
476
477
477
478
479
480
3 unmodified lines

484
485
486
487
487
488
489
490

473 unmodified lines

// Earlier session carries the only usable prompt.
    store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
    require.NoError(t, store.Write(t.Context(), checkpoint.WriteSession{
    require.NoError(t, store.Write(t.Context(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-earlier",
        Strategy:     "manual-commit",
3 unmodified lines

AuthorEmail:  "test@test.com",
    }))
    // Latest session has no prompt at all.
    require.NoError(t, store.Write(t.Context(), checkpoint.WriteSession{
    require.NoError(t, store.Write(t.Context(), checkpoint.Session{
        CheckpointID: cpID,
        SessionID:    "session-latest",
        Strategy:     "manual-commit",

Mcmd/entire/cli/strategy/manual_commit_test.go+2/-2

615 unmodified lines

616
617
618
619
619
620
621
622
40 unmodified lines

663
664
665
666
666
667
668
669
27 unmodified lines

697
698
699
700
701
700
701

615 unmodified lines

) {
    t.Helper()

err := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs()).Write(context.Background(), cpkg.WriteSession{
    err := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs()).Write(context.Background(), cpkg.Session{
        CheckpointID: checkpointID,
        SessionID:    sessionID,
        CreatedAt:    createdAt,
40 unmodified lines

func (a *restoreLogsOnlyAgent) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // Not used by this test agent.
}
func (a *restoreLogsOnlyAgent) WriteSession(_ context.Context, session *agent.AgentSession) error {
func (a *restoreLogsOnlyAgent) Session(_ context.Context, session *agent.AgentSession) error {
    if err := os.MkdirAll(filepath.Dir(session.SessionRef), 0o750); err != nil {
        return err
    }
27 unmodified lines

func (f *fakeExternalAgent) ReadSession(_ *agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // test stub
}
func (f *fakeExternalAgent) WriteSession(_ context.Context, _ *agent.AgentSession) error { return nil }
func (f *fakeExternalAgent) FormatResumeCommand(_ string) string                         { return "" }
func (f *fakeExternalAgent) Session(_ context.Context, _ *agent.AgentSession) error { return nil }
func (f *fakeExternalAgent) FormatResumeCommand(_ string) string                    { return "" }

Mcmd/entire/cli/strategy/rewind_test.go+4/-4

48 unmodified lines

49
50
51
52
52
53
54
55

48 unmodified lines

return &agent.AgentSession{}, nil
}

func (s *stubTextGenerator) WriteSession(context.Context, *agent.AgentSession) error { return nil }
func (s *stubTextGenerator) Session(context.Context, *agent.AgentSession) error { return nil }

func (s *stubTextGenerator) FormatResumeCommand(string) string { return "" }

Mcmd/entire/cli/summarize/claude_test.go+1/-1

32 unmodified lines

33
34
35
36
37
36
37
38
39
40

32 unmodified lines

func (m *mockTextGenerator) ReadSession(*agent.HookInput) (*agent.AgentSession, error) {
    return nil, nil //nolint:nilnil // test stub
}
func (m *mockTextGenerator) WriteSession(context.Context, *agent.AgentSession) error { return nil }
func (m *mockTextGenerator) FormatResumeCommand(string) string                       { return "" }
func (m *mockTextGenerator) Session(context.Context, *agent.AgentSession) error { return nil }
func (m *mockTextGenerator) FormatResumeCommand(string) string                  { return "" }
func (m *mockTextGenerator) GenerateText(_ context.Context, prompt string, model string) (string, error) {
    m.prompt = prompt
    m.model = model

Mcmd/entire/cli/summarize/text_generator_test.go+2/-2