checkpoint: rename committed types to persistent vocabulary · Entire
Log in
checkpoint: rename committed types to persistent vocabulary
a030158→main·
Soph·3w ago·45 files·+309 added/-309 removed
Type-level rename (no method or behavior changes yet): CommittedStore -> PersistentStore CommittedReader -> PersistentReader CommittedListReader -> PersistentListReader WriteCommittedOptions -> WriteOptions UpdateCommittedOptions -> UpdateOptions CommittedMetadata -> Metadata CommittedInfo -> CheckpointInfo
'Committed' collides with git's commit vocabulary (these records are literally stored as git commits); 'persistent' names the actual durability property. Method names and the Stores facade field are renamed in following commits.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
de0c61e39335View transcript
Changes
45
cmd/entire/cli
Mattach.go+2/-2
Mattach_test.go+2/-2
Mattribution_test.go+13/-13
benchutil
Mbench_test.go+1/-1
checkpoint
Mbackwards_compat_test.go+1/-1
Mblob_resolver_test.go+1/-1
Mcheckpoint.go+14/-14
Mcheckpoint_test.go+69/-69
Mcommitted.go+30/-30
Mcommitted_opf_trailer_test.go+1/-1
Mcommitted_phantom_paths_test.go+2/-2
Mcommitted_read_store_test.go+1/-1
Mcommitted_reader_resolve.go+13/-13
Mcommitted_reader_resolve_test.go+2/-2
Mcommitted_tripwire_test.go+2/-2
Mcommitted_update_test.go+19/-19
Mcommitted_write.go+4/-4
Mopen.go+1/-1
Mstore.go+4/-4
dispatch
Mmode_local_test.go+3/-3
Mexplain.go+7/-7
Mexplain_export.go+6/-6
Mexplain_export_test.go+17/-17
Mexplain_test.go+38/-38
Mhead_checkpoint_flags_test.go+1/-1
integration_test
Mattribution_test.go+3/-3
Mmanual_commit_workflow_test.go+1/-1
Mreview_test.go+2/-2
Mtestenv.go+12/-12
Mtranscript_offset_test.go+1/-1
Mresume.go+2/-2
Mresume_test.go+8/-8
Mreview_context.go+5/-5
Mreview_context_test.go+4/-4
Mstatus_test.go+1/-1
strategy
Mclean_test.go+1/-1
Mcommon.go+4/-4
Mmanual_commit.go+1/-1
Mmanual_commit_condensation.go+2/-2
Mmanual_commit_condensation_test.go+2/-2
Mmanual_commit_hooks.go+1/-1
Mmanual_commit_opf_rewrite_test.go+1/-1
Mmanual_commit_rewind.go+1/-1
Mmanual_commit_test.go+2/-2
Mrewind_test.go+1/-1
61 unmodified lines
62
63
64
65
65
66
67
68
248 unmodified lines
317
318
319
320
320
321
322
323
61 unmodified lines
// openAttachStore opens the committed store for the resolved topology. refs is
// passed explicitly so attach preserves PrimaryAsRead() pinning.
func openAttachStore(ctx context.Context, repo *git.Repository, refs cpkg.CommittedRefs) (cpkg.CommittedStore, error) { //nolint:ireturn // committed store capability preserves attach's read-ref override
func openAttachStore(ctx context.Context, repo *git.Repository, refs cpkg.CommittedRefs) (cpkg.PersistentStore, error) { //nolint:ireturn // committed store capability preserves attach's read-ref override
stores, err := cpkg.Open(ctx, repo, cpkg.OpenOptions{Refs: &refs})
if err != nil {
return nil, fmt.Errorf("open checkpoint store: %w", err)
248 unmodified lines
return fmt.Errorf("failed to redact transcript: %w", redactErr)
}
writeOpts := cpkg.WriteCommittedOptions{
writeOpts := cpkg.WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
Strategy: strategy.StrategyNameManualCommit,
Mcmd/entire/cli/attach.go+2/-2
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.WriteCommitted(context.Background(), cpkg.WriteCommittedOptions{
if writeErr := store.WriteCommitted(context.Background(), cpkg.WriteOptions{
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.WriteCommitted(context.Background(), cpkg.WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), cpkg.WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
Strategy: strategy.StrategyNameManualCommit,
Mcmd/entire/cli/attach_test.go+2/-2
90 unmodified lines
91
92
93
94
94
95
96
97
63 unmodified lines
161
162
163
164
164
165
166
167
25 unmodified lines
193
194
195
196
196
197
198
199
21 unmodified lines
221
222
223
224
224
225
226
227
16 unmodified lines
244
245
246
247
247
248
249
250
28 unmodified lines
279
280
281
282
282
283
284
285
23 unmodified lines
309
310
311
312
312
313
314
315
7 unmodified lines
323
324
325
326
326
327
328
329
33 unmodified lines
363
364
365
366
366
367
368
369
30 unmodified lines
400
401
402
403
403
404
405
406
36 unmodified lines
443
444
445
446
446
447
448
449
450
451
452
453
453
454
455
456
73 unmodified lines
530
531
532
533
533
534
535
536
90 unmodified lines
func TestAttributionBlameShowsHumanAndAICheckpointLines(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "a1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "a1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-ai-12345678",
Prompts: []string{"Add an agent-owned helper."},
FilesTouched: []string{"auth.py"},
63 unmodified lines
func TestAttributionBlameLongShowsDetailedColumns(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "a2b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "a2b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-ai-12345678",
Prompts: []string{"Add an agent-owned helper."},
FilesTouched: []string{"auth.py"},
25 unmodified lines
func TestAttributionBlameMarksMixedCheckpoint(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "b1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "b1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-mixed-12345678",
Prompts: []string{"Change agent code, then keep a user tweak."},
FilesTouched: []string{"auth.py"},
21 unmodified lines
func TestAttributionWhyLineShowsPromptAndCheckpoint(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "c1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "c1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-why-12345678",
Prompts: []string{"Create a line that can be explained."},
FilesTouched: []string{"auth.py"},
16 unmodified lines
func TestAttributionBlameJSONIsStable(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "d1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "d1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-json-12345678",
Prompts: []string{"Add JSON attributed line."},
FilesTouched: []string{"auth.py"},
28 unmodified lines
func TestAttributionBlameJSONLineFilterPrunesCheckpoints(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "e1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "e1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-filter-12345678",
Prompts: []string{"Add the second line only."},
FilesTouched: []string{"auth.py"},
23 unmodified lines
func TestAttributionBlameMixedUsesFileMatchingCheckpoint(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "f1b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "f1b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-auth-12345678",
Prompts: []string{"Add auth line."},
FilesTouched: []string{"auth.py"},
7 unmodified lines
MetricVersion: 2,
},
})
writeAttributionCheckpoint(t, repoRoot, "f2b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "f2b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-other-12345678",
Prompts: []string{"Mixed update in another file."},
FilesTouched: []string{"other.py"},
33 unmodified lines
Sessions: []checkpoint.SessionFilePaths{{Metadata: "metadata.json"}},
},
content: &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
SessionID: "session-ai",
FilesTouched: []string{"auth.py"},
Agent: agent.AgentTypeClaudeCode,
30 unmodified lines
func TestAttributionBlameScopesMixedToSessionNotCheckpoint(t *testing.T) {
repoRoot := newAttributionRepo(t)
writeAttributionCheckpoint(t, repoRoot, "a9b2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "a9b2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-scoped-12345678",
Prompts: []string{"Agent-only edit to auth.py."},
FilesTouched: []string{"auth.py"},
36 unmodified lines
// One checkpoint, two sessions, neither recording a touch to auth.py (e.g.
// the file was renamed after the checkpoint). Attribution must fall back to
// a session and flag that the agent/prompt shown is approximate.
writeAttributionCheckpoint(t, repoRoot, "aab2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "aab2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-one-12345678",
Prompts: []string{"Edit the first file."},
FilesTouched: []string{"old_name.py"},
Agent: agent.AgentTypeClaudeCode,
CheckpointsCount: 1,
})
writeAttributionCheckpoint(t, repoRoot, "aab2c3d4e5f6", checkpoint.WriteCommittedOptions{
writeAttributionCheckpoint(t, repoRoot, "aab2c3d4e5f6", checkpoint.WriteOptions{
SessionID: "session-two-12345678",
Prompts: []string{"Edit a second file."},
FilesTouched: []string{"other.py"},
73 unmodified lines
return repoRoot
}
func writeAttributionCheckpoint(t *testing.T, repoRoot, checkpointID string, opts checkpoint.WriteCommittedOptions) {
func writeAttributionCheckpoint(t *testing.T, repoRoot, checkpointID string, opts checkpoint.WriteOptions) {
t.Helper()
repo, err := git.PlainOpen(repoRoot)
require.NoError(t, err)
Mcmd/entire/cli/attribution_test.go+13/-13
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
err = repo.Store.WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: fmt.Sprintf("bench-session-%d", i),
Strategy: "manual-commit",
Mcmd/entire/cli/benchutil/bench_test.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.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session-002",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/blob_resolver_test.go+1/-1
157 unmodified lines
158
159
160
161
162
161
162
163
164
165
79 unmodified lines
245
246
247
248
249
248
249
250
251
252
61 unmodified lines
314
315
316
317
317
318
319
320
321
321
322
323
324
5 unmodified lines
330
331
332
333
333
334
335
336
39 unmodified lines
376
377
378
379
380
379
380
381
382
383
30 unmodified lines
414
415
416
417
417
418
419
420
7 unmodified lines
428
429
430
431
432
431
432
433
434
435
77 unmodified lines
513
514
515
516
516
517
518
519
20 unmodified lines
540
541
542
543
543
544
545
546
157 unmodified lines
Timestamp time.Time
}
// WriteCommittedOptions contains options for writing a committed checkpoint.
type WriteCommittedOptions struct {
// WriteOptions contains options for writing a committed checkpoint.
type WriteOptions struct {
// CheckpointID is the stable 12-hex-char identifier
CheckpointID id.CheckpointID
79 unmodified lines
TranscriptIdentifierAtStart string // Last identifier when checkpoint started (UUID for Claude, message ID for Gemini)
CheckpointTranscriptStart int // Transcript line offset at start of this checkpoint's data
// CheckpointTranscriptStart is written to both CommittedMetadata.CheckpointTranscriptStart
// and the deprecated CommittedMetadata.TranscriptLinesAtStart for backward compatibility.
// CheckpointTranscriptStart is written to both Metadata.CheckpointTranscriptStart
// and the deprecated Metadata.TranscriptLinesAtStart for backward compatibility.
// TokenUsage contains the token usage for this checkpoint
TokenUsage *types.TokenUsage
61 unmodified lines
HasInvestigation bool
}
// UpdateCommittedOptions contains options for updating an existing committed checkpoint.
// UpdateOptions contains options for updating an existing committed checkpoint.
// Uses replace semantics: the transcript and prompts are fully replaced,
// not appended. At stop time we have the complete session transcript and want every
// checkpoint to contain it identically.
type UpdateCommittedOptions struct {
type UpdateOptions struct {
// CheckpointID identifies the checkpoint to update
CheckpointID id.CheckpointID
5 unmodified lines
Transcript redact.RedactedBytes
// Prompts contains the raw user prompts (replaces existing).
// See WriteCommittedOptions.Prompts.
// See WriteOptions.Prompts.
Prompts []string
// Agent identifies the agent type (needed for transcript chunking)
39 unmodified lines
return p != nil && !p.ContentHashBlob.IsZero() && len(p.ChunkHashes) > 0
}
// CommittedInfo contains summary information about a committed checkpoint.
type CommittedInfo struct {
// CheckpointInfo contains summary information about a committed checkpoint.
type CheckpointInfo struct {
// CheckpointID is the stable 12-hex-char identifier
CheckpointID id.CheckpointID
30 unmodified lines
// as opposed to just the metadata/summary.
type SessionContent struct {
// Metadata contains the session-specific metadata
Metadata CommittedMetadata
Metadata Metadata
// Transcript is the session transcript content
Transcript []byte
7 unmodified lines
Prompts string
}
// CommittedMetadata contains the metadata stored in metadata.json for each checkpoint.
type CommittedMetadata struct {
// Metadata contains the metadata stored in metadata.json for each checkpoint.
type Metadata struct {
CLIVersion string `json:"cli_version,omitempty"`
CheckpointID id.CheckpointID `json:"checkpoint_id"`
SessionID string `json:"session_id"`
77 unmodified lines
// GetTranscriptStart returns the transcript line offset at which this checkpoint's data begins.
// Returns 0 for new checkpoints (start from beginning). For data written by older CLI versions,
// falls back to the deprecated TranscriptLinesAtStart field.
func (m CommittedMetadata) GetTranscriptStart() int {
func (m Metadata) GetTranscriptStart() int {
if m.CheckpointTranscriptStart > 0 {
return m.CheckpointTranscriptStart
}
20 unmodified lines
// <checkpoint-id[:2]>/<checkpoint-id[2:]>/
// ├── metadata.json # This CheckpointSummary
// ├── 1/ # First session
// │ ├── metadata.json # Session-specific CommittedMetadata
// │ ├── metadata.json # Session-specific Metadata
// │ ├── full.jsonl
// │ ├── prompt.txt
// │ └── content_hash.txt
Mcmd/entire/cli/checkpoint/checkpoint.go+14/-14
141 unmodified lines
142
143
144
145
145
146
147
148
60 unmodified lines
209
210
211
212
212
213
214
215
11 unmodified lines
227
228
229
230
230
231
232
233
50 unmodified lines
284
285
286
287
287
288
289
290
2 unmodified lines
293
294
295
296
296
297
298
299
258 unmodified lines
558
559
560
561
561
562
563
564
80 unmodified lines
645
646
647
648
648
649
650
651
39 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
114 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
16 unmodified lines
1513
1514
1515
1516
1516
1517
1518
1519
32 unmodified lines
1552
1553
1554
1555
1555
1556
1557
1558
30 unmodified lines
1589
1590
1591
1592
1592
1593
1594
1595
5 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
88 unmodified lines
3586
3587
3588
3589
3589
3590
3591
3592
28 unmodified lines
3621
3622
3623
3624
3624
3625
3626
3627
47 unmodified lines
3675
3676
3677
3678
3678
3679
3680
3681
9 unmodified lines
3691
3692
3693
3694
3694
3695
3696
3697
3698
3699
3700
3700
3701
3702
3703
29 unmodified lines
3733
3734
3735
3736
3736
3737
3738
3739
32 unmodified lines
3772
3773
3774
3775
3775
3776
3777
3778
3779
3780
3781
3781
3782
3783
3784
166 unmodified lines
3951
3952
3953
3954
3954
3955
3956
3957
36 unmodified lines
3994
3995
3996
3997
3997
3998
3999
4000
45 unmodified lines
4046
4047
4048
4049
4049
4050
4051
4052
524 unmodified lines
4577
4578
4579
4580
4580
4581
4582
4583
4584
4585
4586
4587
4587
4588
4589
4590
25 unmodified lines
4616
4617
4618
4619
4619
4620
4621
4622
4623
4624
4624
4625
4626
4627
17 unmodified lines
4645
4646
4647
4648
4648
4649
4650
4650
4651
4652
4653
4654
4655
4656
4657
4657
4658
4659
4660
39 unmodified lines
4700
4701
4702
4703
4703
4704
4705
4706
89 unmodified lines
4796
4797
4798
4799
4799
4800
4801
4801
4802
4803
4804
23 unmodified lines
4828
4829
4830
4831
4831
4832
4833
4834
32 unmodified lines
4867
4868
4869
4870
4870
4871
4872
4873
5 unmodified lines
4879
4880
4881
4882
4882
4883
4884
4885
16 unmodified lines
4902
4903
4904
4905
4905
4906
4907
4908
13 unmodified lines
4922
4923
4924
4925
4926
4925
4926
4927
4928
4929
1 unmodified line
4931
4932
4933
4934
4934
4935
4936
4937
141 unmodified lines
sessionID := "test-session-123"
agentType := agent.AgentTypeClaudeCode
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
Strategy: "manual-commit",
60 unmodified lines
if err != nil {
t.Fatalf("failed to read session metadata.json: %v", err)
}
var sessionMetadata CommittedMetadata
var sessionMetadata Metadata
if err := json.Unmarshal([]byte(sessionContent), &sessionMetadata); err != nil {
t.Fatalf("failed to parse session metadata.json: %v", err)
}
11 unmodified lines
// readLatestSessionMetadata reads the session-specific metadata from the latest session subdirectory.
// This is where session-specific fields like Summary are stored.
func readLatestSessionMetadata(t *testing.T, repo *git.Repository, checkpointID id.CheckpointID) CommittedMetadata {
func readLatestSessionMetadata(t *testing.T, repo *git.Repository, checkpointID id.CheckpointID) Metadata {
t.Helper()
ref, err := repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true)
50 unmodified lines
t.Fatalf("failed to read session metadata.json: %v", err)
}
var metadata CommittedMetadata
var metadata Metadata
if err := json.Unmarshal([]byte(content), &metadata); err != nil {
t.Fatalf("failed to parse session metadata.json: %v", err)
}
2 unmodified lines
}
// Note: Tests for Agents array and SessionCount fields have been removed
// as those fields were removed from CommittedMetadata in the simplification.
// as those fields were removed from Metadata in the simplification.
// TestWriteTemporary_Deduplication verifies that WriteTemporary skips creating
// a new commit when the tree hash matches the previous checkpoint.
258 unmodified lines
}
cpID := id.MustCheckpointID("abcdef123456")
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "test-session-id",
Strategy: "manual-commit",
80 unmodified lines
t.Fatalf("failed to read metadata.json: %v", err)
}
var metadata CommittedMetadata
var metadata Metadata
if err := json.Unmarshal([]byte(content), &metadata); err != nil {
t.Fatalf("failed to parse metadata.json: %v", err)
}
39 unmodified lines
// Write a committed checkpoint with branch information
checkpointID := id.MustCheckpointID("a1b2c3d4e5f6")
store := NewGitStore(repo, DefaultV1Refs())
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "test-session-summary",
Strategy: "manual-commit",
114 unmodified lines
// Create entire/checkpoints/v1 branch on the remote with a checkpoint
remoteStore := NewGitStore(remoteRepo, DefaultV1Refs())
cpID := id.MustCheckpointID("abcdef123456")
err = remoteStore.WriteCommitted(context.Background(), WriteCommittedOptions{
err = remoteStore.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "test-session-id",
Strategy: "manual-commit",
62 unmodified lines
authorName := "Alice Developer"
authorEmail := "alice@example.com"
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "test-session-author",
Strategy: "manual-commit",
78 unmodified lines
checkpointID := id.MustCheckpointID("a1a2a3a4a5a6")
// Write first session
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-one",
Strategy: "manual-commit",
9 unmodified lines
}
// Write second session to the same checkpoint ID
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-two",
Strategy: "manual-commit",
58 unmodified lines
checkpointID := id.MustCheckpointID("b1b2b3b4b5b6")
// Write first session with specific stats
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-one",
Strategy: "manual-commit",
13 unmodified lines
}
// Write second session with overlapping and new files
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
Strategy: "manual-commit",
62 unmodified lines
}
for _, s := range sessions {
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: s.id,
Strategy: "manual-commit",
44 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
checkpointID := id.MustCheckpointID(cpIDStr)
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "codex-session",
Strategy: "manual-commit",
43 unmodified lines
// Write three sessions
for i := range 3 {
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: sid,
Strategy: "manual-commit",
16 unmodified lines
}
// Find our checkpoint
var found *CommittedInfo
var found *CheckpointInfo
for i := range checkpoints {
if checkpoints[i].CheckpointID == checkpointID {
found = &checkpoints[i]
32 unmodified lines
checkpointID := id.MustCheckpointID("313233343536")
// Write session without prompts
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "no-prompts-session",
Strategy: "manual-commit",
30 unmodified lines
}
// TestWriteCommitted_SessionWithSummary verifies that a non-nil Summary
// in WriteCommittedOptions is persisted in the session-level metadata.json.
// in WriteOptions is persisted in the session-level metadata.json.
// Regression test for ENT-243 where Summary was omitted from the struct literal.
func TestWriteCommitted_SessionWithSummary(t *testing.T) {
repo, _ := setupBranchTestRepo(t)
5 unmodified lines
Outcome: "Bug was fixed",
}
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "summary-session",
Strategy: "manual-commit",
32 unmodified lines
// Write three sessions
for i := range 3 {
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-X",
Strategy: "manual-commit",
13 unmodified lines
}
// Write session "Y"
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-Y",
Strategy: "manual-commit",
13 unmodified lines
}
// Write session "X" again with updated data (should replace, not append)
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-X",
Strategy: "manual-commit",
88 unmodified lines
checkpointID := id.MustCheckpointID("dedb07654321")
// Write session "X" with initial data
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-X",
Strategy: "manual-commit",
8 unmodified lines
}
// Write session "X" again with updated data
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-X",
Strategy: "manual-commit",
54 unmodified lines
checkpointID := id.MustCheckpointID("dedc0abcdef1")
// Write session A at index 0
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-A",
Strategy: "manual-commit",
7 unmodified lines
}
// Write session B at index 1
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-A",
Strategy: "manual-commit",
49 unmodified lines
checkpointID := id.MustCheckpointID("dedd0abcdef2")
// Write session A with prompts and context
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-A",
Strategy: "manual-commit",
8 unmodified lines
}
// Write session B with prompts
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-B",
Strategy: "manual-commit",
8 unmodified lines
}
// Overwrite session A WITHOUT prompts
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-A",
Strategy: "manual-commit",
47 unmodified lines
t.Fatalf("redact.JSONLBytes() error = %v", err)
}
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "redact-transcript-session",
Strategy: "manual-commit",
24 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
checkpointID := id.MustCheckpointID("aabbccddeef2")
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "redact-prompt-session",
Strategy: "manual-commit",
88 unmodified lines
}
// TestWriteCommitted_CLIVersionField verifies that versioninfo.Version is written
// to both the root CheckpointSummary and session-level CommittedMetadata.
// to both the root CheckpointSummary and session-level Metadata.
func TestWriteCommitted_CLIVersionField(t *testing.T) {
t.Parallel()
28 unmodified lines
checkpointID := id.MustCheckpointID("b1c2d3e4f5a6")
sessionID := "test-session-version"
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
Strategy: "manual-commit",
47 unmodified lines
t.Errorf("CheckpointSummary.CLIVersion = %q, want %q", summary.CLIVersion, versioninfo.Version)
}
// Verify session-level metadata.json (CommittedMetadata) has CLIVersion
// Verify session-level metadata.json (Metadata) has CLIVersion
sessionTree, err := checkpointTree.Tree("0")
if err != nil {
t.Fatalf("failed to get session tree: %v", err)
9 unmodified lines
t.Fatalf("failed to read session metadata.json: %v", err)
}
var sessionMetadata CommittedMetadata
var sessionMetadata Metadata
if err := json.Unmarshal([]byte(sessionContent), &sessionMetadata); err != nil {
t.Fatalf("failed to parse session metadata.json: %v", err)
}
if sessionMetadata.CLIVersion != versioninfo.Version {
t.Errorf("CommittedMetadata.CLIVersion = %q, want %q", sessionMetadata.CLIVersion, versioninfo.Version)
t.Errorf("Metadata.CLIVersion = %q, want %q", sessionMetadata.CLIVersion, versioninfo.Version)
}
}
29 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
checkpointID := id.MustCheckpointID("c1d2e3f4a5b6")
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "test-session-model",
Strategy: "manual-commit",
32 unmodified lines
t.Fatalf("failed to read session metadata.json: %v", err)
}
if sessionMetadata.Model != "" {
t.Errorf("CommittedMetadata.Model = %q, want empty string", sessionMetadata.Model)
t.Errorf("Metadata.Model = %q, want empty string", sessionMetadata.Model)
}
if !strings.Contains(sessionContent, `"model": ""`) {
t.Errorf("session metadata.json should contain an explicit empty model field, got:\n%s", sessionContent)
166 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
checkpointID := id.MustCheckpointID("aabbccddeef7")
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "update-summary-session",
Strategy: "manual-commit",
45 unmodified lines
t.Fatalf("failed to write transcript: %v", err)
}
err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "jsonl-fallback-session",
Strategy: "manual-commit",
524 unmodified lines
}
// TestCommittedMetadata_ReviewFields pins the JSON wire format for review
// fields on CommittedMetadata. Any refactor that silently drops or renames
// fields on Metadata. Any refactor that silently drops or renames
// these JSON tags would break the entire/checkpoints/v1 branch format. We
// assert on the actual marshalled JSON keys (not just round-trip identity)
// because a coordinated rename of struct field + tag would otherwise pass
// the round-trip but break on-disk readers of older checkpoints.
func TestCommittedMetadata_ReviewFields(t *testing.T) {
t.Parallel()
m := CommittedMetadata{
m := Metadata{
Kind: "agent_review",
ReviewSkills: []string{"/skill1", "/skill2"},
ReviewPrompt: "Review this branch.",
25 unmodified lines
}
// TestCommittedMetadata_InvestigateFields pins the JSON wire format for the
// investigate fields on CommittedMetadata. Mirrors
// investigate fields on Metadata. Mirrors
// TestCommittedMetadata_ReviewFields: any silent rename or removal of these
// JSON tags would corrupt the entire/checkpoints/v1 branch format.
func TestCommittedMetadata_InvestigateFields(t *testing.T) {
t.Parallel()
m := CommittedMetadata{
m := Metadata{
Kind: "agent_investigate",
InvestigateRunID: "abcdef012345",
InvestigateTopic: "Why is checkout flaky?",
17 unmodified lines
t.Errorf(`expected "investigate_topic" present, got %v`, raw["investigate_topic"])
}
// Zero-value CommittedMetadata must omit all the investigate keys
// Zero-value Metadata must omit all the investigate keys
// (omitempty tags) so older checkpoints aren't tagged as investigations.
bZero, err := json.Marshal(CommittedMetadata{})
bZero, err := json.Marshal(Metadata{})
if err != nil {
t.Fatalf("marshal zero: %v", err)
}
zs := string(bZero)
for _, key := range []string{"investigate_run_id", "investigate_topic"} {
if strings.Contains(zs, `"`+key+`"`) {
t.Errorf(`expected zero-value CommittedMetadata to omit %q, got %s`, key, zs)
t.Errorf(`expected zero-value Metadata to omit %q, got %s`, key, zs)
}
}
}
39 unmodified lines
func TestRedactBlobBytes_JSONMetadata(t *testing.T) {
t.Parallel()
meta := CommittedMetadata{
meta := Metadata{
Kind: "agent_review",
ReviewPrompt: "credential leak: key=AKIAYRWQG5EJLPZLBYNP",
Summary: &Summary{
89 unmodified lines
return summary
}
// readSessionMetadataAtIndex reads the per-session CommittedMetadata for
// readSessionMetadataAtIndex reads the per-session Metadata for
// session at numbered subfolder `index` (0-based) under the checkpoint.
func readSessionMetadataAtIndex(t *testing.T, repo *git.Repository, checkpointID id.CheckpointID, index int) CommittedMetadata {
func readSessionMetadataAtIndex(t *testing.T, repo *git.Repository, checkpointID id.CheckpointID, index int) Metadata {
t.Helper()
ref, err := repo.Reference(plumbing.NewBranchReferenceName(paths.MetadataBranchName), true)
if err != nil {
23 unmodified lines
if err != nil {
t.Fatalf("read session metadata.json: %v", err)
}
var meta CommittedMetadata
var meta Metadata
if err := json.Unmarshal([]byte(content), &meta); err != nil {
t.Fatalf("parse session metadata.json: %v", err)
}
32 unmodified lines
}
// TestWriteCommitted_PropagatesHasInvestigation verifies that
// WriteCommittedOptions.HasInvestigation flows into CheckpointSummary, and
// WriteOptions.HasInvestigation flows into CheckpointSummary, and
// that on a second write into the SAME checkpoint, the existing-summary
// OR-merge keeps HasInvestigation true even when the second session is not
// itself an investigation. Mirrors the existing HasReview merge behaviour.
5 unmodified lines
checkpointID := id.MustCheckpointID("aabbccddeeff")
// First session: investigate session, sets HasInvestigation=true.
if err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), WriteOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "ordinary-session-2",
Strategy: "manual-commit",
13 unmodified lines
}
// TestCommittedMetadata_InvestigateFieldsRoundTrip verifies that
// WriteCommittedOptions investigate fields are written into the per-session
// CommittedMetadata and round-trip on read.
// WriteOptions investigate fields are written into the per-session
// Metadata and round-trip on read.
func TestCommittedMetadata_InvestigateFieldsRoundTrip(t *testing.T) {
t.Parallel()
1 unmodified line
store := NewGitStore(repo, DefaultV1Refs())
checkpointID := id.MustCheckpointID("11223344aabb")
if err := store.WriteCommitted(context.Background(), WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: checkpointID,
SessionID: "investigate-roundtrip",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/checkpoint_test.go+69/-69
54 unmodified lines
55
56
57
58
58
59
60
61
124 unmodified lines
186
187
188
189
189
190
191
192
3 unmodified lines
196
197
198
199
199
200
201
202
24 unmodified lines
227
228
229
230
230
231
232
233
57 unmodified lines
291
292
293
294
294
295
296
297
298
299
300
300
301
302
303
87 unmodified lines
391
392
393
394
394
395
396
397
30 unmodified lines
428
429
430
431
432
431
432
433
434
435
45 unmodified lines
481
482
483
484
484
485
486
487
165 unmodified lines
653
654
655
656
656
657
658
659
59 unmodified lines
719
720
721
722
722
723
724
725
159 unmodified lines
885
886
887
888
889
890
888
889
890
891
892
893
894
895
896
896
897
898
899
88 unmodified lines
988
989
990
991
991
992
993
994
20 unmodified lines
1015
1016
1017
1018
1018
1019
1020
1021
185 unmodified lines
1207
1208
1209
1210
1210
1211
1212
1213
1214
1215
1216
1217
1217
1218
1219
1220
1220
1221
1222
1223
14 unmodified lines
1238
1239
1240
1241
1242
1241
1242
1243
1244
1245
34 unmodified lines
1280
1281
1282
1283
1283
1284
1285
1286
1286
1287
1288
1289
1290
1290
1291
1292
1293
1294
1294
1295
1296
1296
1297
1298
1298
1299
1300
1301
135 unmodified lines
1437
1438
1439
1440
1440
1441
1442
1443
54 unmodified lines
// For task checkpoints (IsTask=true), additional files are written under tasks/<tool-use-id>/:
// - For incremental checkpoints: checkpoints/NNN-<tool-use-id>.json
// - For final checkpoints: checkpoint.json and agent-<agent-id>.jsonl
func (s *GitStore) WriteCommitted(ctx context.Context, opts WriteCommittedOptions) error {
func (s *GitStore) WriteCommitted(ctx context.Context, opts WriteOptions) error {
// Validate identifiers to prevent path traversal and malformed data
if opts.CheckpointID.IsEmpty() {
return errors.New("invalid checkpoint options: checkpoint ID is required")
124 unmodified lines
}
// writeTaskCheckpointEntries writes task-specific checkpoint entries and returns the task metadata path.
func (s *GitStore) writeTaskCheckpointEntries(ctx context.Context, opts WriteCommittedOptions, basePath string, entries map[string]object.TreeEntry) (string, error) {
func (s *GitStore) writeTaskCheckpointEntries(ctx context.Context, opts WriteOptions, basePath string, entries map[string]object.TreeEntry) (string, error) {
taskPath := basePath + "tasks/" + opts.ToolUseID + "/"
if opts.IsIncremental {
3 unmodified lines
}
// writeIncrementalTaskCheckpoint writes an incremental checkpoint file during task execution.
func (s *GitStore) writeIncrementalTaskCheckpoint(opts WriteCommittedOptions, taskPath string, entries map[string]object.TreeEntry) (string, error) {
func (s *GitStore) writeIncrementalTaskCheckpoint(opts WriteOptions, taskPath string, entries map[string]object.TreeEntry) (string, error) {
incData, err := redact.JSONLBytes(opts.IncrementalData)
if err != nil {
return "", fmt.Errorf("failed to redact incremental checkpoint: %w", err)
24 unmodified lines
}
// writeFinalTaskCheckpoint writes the final checkpoint.json and subagent transcript.
func (s *GitStore) writeFinalTaskCheckpoint(ctx context.Context, opts WriteCommittedOptions, taskPath string, entries map[string]object.TreeEntry) (string, error) {
func (s *GitStore) writeFinalTaskCheckpoint(ctx context.Context, opts WriteOptions, taskPath string, entries map[string]object.TreeEntry) (string, error) {
checkpoint := taskCheckpointData{
SessionID: opts.SessionID,
ToolUseID: opts.ToolUseID,
57 unmodified lines
// basePath/
// ├── metadata.json # CheckpointSummary (aggregated stats)
// ├── 1/ # First session
// │ ├── metadata.json # CommittedMetadata (session-specific, includes initial_attribution)
// │ ├── metadata.json # Metadata (session-specific, includes initial_attribution)
// │ ├── full.jsonl
// │ ├── prompt.txt
// │ └── content_hash.txt
// ├── 2/ # Second session
// └── ...
func (s *GitStore) writeStandardCheckpointEntries(ctx context.Context, opts WriteCommittedOptions, basePath string, entries map[string]object.TreeEntry) error {
func (s *GitStore) writeStandardCheckpointEntries(ctx context.Context, opts WriteOptions, basePath string, entries map[string]object.TreeEntry) error {
// Read existing summary to get current session count
var existingSummary *CheckpointSummary
metadataPath := basePath + paths.MetadataFileName
87 unmodified lines
// writeSessionToSubdirectory writes a single session's files to a numbered subdirectory.
// Returns the absolute file paths from the git tree root for the sessions map.
func (s *GitStore) writeSessionToSubdirectory(ctx context.Context, opts WriteCommittedOptions, sessionPath string, entries map[string]object.TreeEntry) (SessionFilePaths, error) {
func (s *GitStore) writeSessionToSubdirectory(ctx context.Context, opts WriteOptions, sessionPath string, entries map[string]object.TreeEntry) (SessionFilePaths, error) {
filePaths := SessionFilePaths{}
// Clear any existing entries at this path so stale files from a previous
30 unmodified lines
filePaths.Prompt = "/" + sessionPath + paths.PromptFileName
}
// Write session-level metadata.json (CommittedMetadata with all fields including initial_attribution)
sessionMetadata := CommittedMetadata{
// Write session-level metadata.json (Metadata with all fields including initial_attribution)
sessionMetadata := Metadata{
CheckpointID: opts.CheckpointID,
SessionID: opts.SessionID,
Strategy: opts.Strategy,
45 unmodified lines
// writeCheckpointSummary writes the root-level CheckpointSummary with aggregated statistics.
// sessions is the complete sessions array (already built by the caller).
func (s *GitStore) writeCheckpointSummary(opts WriteCommittedOptions, basePath string, entries map[string]object.TreeEntry, sessions []SessionFilePaths) error {
func (s *GitStore) writeCheckpointSummary(opts WriteOptions, basePath string, entries map[string]object.TreeEntry, sessions []SessionFilePaths) error {
checkpointsCount, filesTouched, tokenUsage, err := s.reaggregateFromEntries(basePath, len(sessions), entries)
if err != nil {
return fmt.Errorf("failed to aggregate session stats: %w", err)
165 unmodified lines
return totalCount, allFiles, totalTokens, nil
}
func checkpointCreatedAt(opts WriteCommittedOptions) time.Time {
func checkpointCreatedAt(opts WriteOptions) time.Time {
if opts.CreatedAt.IsZero() {
return time.Now().UTC()
}
59 unmodified lines
// writeTranscript writes the transcript and content hash to the checkpoint entries.
// Returns (true, nil) if files were written, (false, nil) if transcript was empty.
func (s *GitStore) writeTranscript(ctx context.Context, opts WriteCommittedOptions, basePath string, entries map[string]object.TreeEntry) (bool, error) {
func (s *GitStore) writeTranscript(ctx context.Context, opts WriteOptions, basePath string, entries map[string]object.TreeEntry) (bool, error) {
logCtx := logging.WithComponent(ctx, "checkpoint")
transcriptBytes := opts.Transcript.Bytes()
159 unmodified lines
return out
}
// readMetadataFromBlob reads CommittedMetadata from a blob hash.
func (s *GitStore) readMetadataFromBlob(hash plumbing.Hash) (*CommittedMetadata, error) {
return readJSONFromBlob[CommittedMetadata](s.repo, hash)
// readMetadataFromBlob reads Metadata from a blob hash.
func (s *GitStore) readMetadataFromBlob(hash plumbing.Hash) (*Metadata, error) {
return readJSONFromBlob[Metadata](s.repo, hash)
}
// buildCommitMessage constructs the commit message with proper trailers.
// The commit subject is always "Checkpoint: <id>" for consistency.
// If CommitSubject is provided (e.g., for task checkpoints), it's included in the body.
func (s *GitStore) buildCommitMessage(opts WriteCommittedOptions, taskMetadataPath string) string {
func (s *GitStore) buildCommitMessage(opts WriteOptions, taskMetadataPath string) string {
var commitMsg strings.Builder
// Subject line is always the checkpoint ID for consistent formatting
88 unmodified lines
// ReadSessionMetadata reads only the metadata.json for a specific session within a checkpoint.
// This is a lightweight read that avoids fetching transcript/prompt blobs.
// sessionIndex is 0-based.
func (s *GitStore) ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*CommittedMetadata, error) {
func (s *GitStore) ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*Metadata, error) {
if err := ctx.Err(); err != nil {
return nil, err //nolint:wrapcheck // Propagating context cancellation
}
20 unmodified lines
return nil, fmt.Errorf("failed to read session metadata: %w", err)
}
var metadata CommittedMetadata
var metadata Metadata
if err := json.Unmarshal([]byte(content), &metadata); err != nil {
return nil, fmt.Errorf("failed to parse session metadata: %w", err)
}
185 unmodified lines
// Scans sharded paths: <id[:2]>/<id[2:]>/ directories containing metadata.json.
//
func (s *GitStore) ListCommitted(ctx context.Context) ([]CommittedInfo, error) {
func (s *GitStore) ListCommitted(ctx context.Context) ([]CheckpointInfo, error) {
if err := ctx.Err(); err != nil {
return nil, err //nolint:wrapcheck // Propagating context cancellation
}
tree, err := s.getSessionsBranchTree()
if err != nil {
return []CommittedInfo{}, nil //nolint:nilerr // No sessions branch means empty list
return []CheckpointInfo{}, nil //nolint:nilerr // No sessions branch means empty list
}
var checkpoints []CommittedInfo
var checkpoints []CheckpointInfo
// Scan sharded structure: <2-char-prefix>/<remaining-id>/metadata.json
_ = WalkCheckpointShards(ctx, s.repo, tree, func(checkpointID id.CheckpointID, cpTreeHash plumbing.Hash) error { //nolint:errcheck // callback never returns errors
14 unmodified lines
return checkpoints, nil
}
func readCommittedInfoFromCheckpointTree(checkpointID id.CheckpointID, checkpointTree *object.Tree) CommittedInfo {
info := CommittedInfo{
func readCommittedInfoFromCheckpointTree(checkpointID id.CheckpointID, checkpointTree *object.Tree) CheckpointInfo {
info := CheckpointInfo{
CheckpointID: checkpointID,
}
34 unmodified lines
return info
}
func readCommittedMetadataFromCheckpointTree(checkpointTree *object.Tree, sessionIndex int) (CommittedMetadata, bool) {
func readCommittedMetadataFromCheckpointTree(checkpointTree *object.Tree, sessionIndex int) (Metadata, bool) {
sessionTree, treeErr := checkpointTree.Tree(strconv.Itoa(sessionIndex))
if treeErr != nil {
return CommittedMetadata{}, false
return Metadata{}, false
}
sessionMetadataFile, fileErr := sessionTree.File(paths.MetadataFileName)
if fileErr != nil {
return CommittedMetadata{}, false
return Metadata{}, false
}
sessionContent, contentErr := sessionMetadataFile.Contents()
if contentErr != nil {
return CommittedMetadata{}, false
return Metadata{}, false
}
var sessionMetadata CommittedMetadata
var sessionMetadata Metadata
if err := json.Unmarshal([]byte(sessionContent), &sessionMetadata); err != nil {
return CommittedMetadata{}, false
return Metadata{}, false
}
return sessionMetadata, true
}
135 unmodified lines
// with the complete session transcript (from prompt to stop event).
//
// Returns ErrCheckpointNotFound if the checkpoint doesn't exist.
func (s *GitStore) UpdateCommitted(ctx context.Context, opts UpdateCommittedOptions) error {
func (s *GitStore) UpdateCommitted(ctx context.Context, opts UpdateOptions) error {
if opts.CheckpointID.IsEmpty() {
return errors.New("invalid update options: checkpoint ID is required")
}
Mcmd/entire/cli/checkpoint/committed.go+30/-30
45 unmodified lines
46
47
48
49
49
50
51
52
45 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
cpID := id.MustCheckpointID("a1b2c3d4e5f6")
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "regression-no-opf-trailer",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/committed_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.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session-no-transcript",
Strategy: "manual-commit",
39 unmodified lines
cpID := id.MustCheckpointID("e5f6a1b2c3d4")
// Write a checkpoint WITH a transcript
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session-with-transcript",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/committed_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.WriteCommitted(context.Background(), WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/committed_read_store_test.go+1/-1
6 unmodified lines
7
8
9
10
11
10
11
12
13
14
15
16
17
18
19
20
16
17
18
19
20
21
22
23
24
24
25
26
27
28
29
28
29
30
31
32
5 unmodified lines
38
39
40
41
41
42
43
44
10 unmodified lines
55
56
57
58
58
59
60
61
5 unmodified lines
67
68
69
70
70
71
72
73
6 unmodified lines
"github.com/entireio/cli/cmd/entire/cli/checkpoint/id"
)
// CommittedReader provides read access to committed checkpoint data.
type CommittedReader interface {
// PersistentReader provides read access to committed checkpoint data.
type PersistentReader interface {
ReadCommitted(ctx context.Context, checkpointID id.CheckpointID) (*CheckpointSummary, error)
ReadSessionContent(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*SessionContent, error)
}
// CommittedListReader provides read and list access to committed checkpoint data.
type CommittedListReader interface {
CommittedReader
ListCommitted(ctx context.Context) ([]CommittedInfo, error)
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*CommittedMetadata, error)
// PersistentListReader provides read and list access to committed checkpoint data.
type PersistentListReader interface {
PersistentReader
ListCommitted(ctx context.Context) ([]CheckpointInfo, error)
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*Metadata, error)
ReadSessionPrompts(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (string, error)
}
// CommittedStore provides the production committed checkpoint storage surface.
// PersistentStore provides the production committed checkpoint storage surface.
// Writes go through the unified Writer.Write(ctx, WriteRequest); the concrete
// per-operation methods (WriteCommitted/UpdateCommitted/...) remain on GitStore
// as the implementation Write dispatches to.
type CommittedStore interface {
CommittedListReader
type PersistentStore interface {
PersistentListReader
ReadSessionMetadataAndPrompts(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*SessionContent, error)
Writer
}
5 unmodified lines
// ReadCommittedCheckpoint reads a committed checkpoint summary and normalizes
// a nil store response into ErrCheckpointNotFound.
func ReadCommittedCheckpoint(ctx context.Context, reader CommittedReader, checkpointID id.CheckpointID) (*CheckpointSummary, error) {
func ReadCommittedCheckpoint(ctx context.Context, reader PersistentReader, checkpointID id.CheckpointID) (*CheckpointSummary, error) {
if err := ctx.Err(); err != nil {
return nil, err //nolint:wrapcheck // Propagating context cancellation
}
10 unmodified lines
// ReadLatestSessionContent reads the latest session from an already-resolved
// committed reader and summary.
func ReadLatestSessionContent(ctx context.Context, reader CommittedReader, checkpointID id.CheckpointID, summary *CheckpointSummary) (*SessionContent, error) {
func ReadLatestSessionContent(ctx context.Context, reader PersistentReader, checkpointID id.CheckpointID, summary *CheckpointSummary) (*SessionContent, error) {
if summary == nil || len(summary.Sessions) == 0 {
return nil, ErrCheckpointNotFound
}
5 unmodified lines
return content, nil
}
func ReadRawSessionLogForCheckpoint(ctx context.Context, reader CommittedReader, checkpointID id.CheckpointID) ([]byte, string, error) {
func ReadRawSessionLogForCheckpoint(ctx context.Context, reader PersistentReader, checkpointID id.CheckpointID) ([]byte, string, error) {
if err := ctx.Err(); err != nil {
return nil, "", err //nolint:wrapcheck // Propagating context cancellation
}
Mcmd/entire/cli/checkpoint/committed_reader_resolve.go+13/-13
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.WriteCommitted(ctx, WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(ctx, WriteOptions{
CheckpointID: cpID,
SessionID: "session-a",
Strategy: "manual-commit",
1 unmodified line
AuthorName: "Test",
AuthorEmail: "test@example.com",
}))
require.NoError(t, store.WriteCommitted(ctx, WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(ctx, WriteOptions{
CheckpointID: cpID,
SessionID: "session-b",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/committed_reader_resolve_test.go+2/-2
39 unmodified lines
40
41
42
43
43
44
45
46
17 unmodified lines
64
65
66
67
67
68
69
70
39 unmodified lines
}
basePath := checkpointID.Path() + "/"
oldMetadata := CommittedMetadata{
oldMetadata := Metadata{
CheckpointID: checkpointID,
SessionID: "session-old",
Strategy: "manual-commit",
17 unmodified lines
},
}
opts := WriteCommittedOptions{
opts := WriteOptions{
CheckpointID: checkpointID,
SessionID: "session-new",
Strategy: "manual-commit",
Mcmd/entire/cli/checkpoint/committed_tripwire_test.go+2/-2
50 unmodified lines
51
52
53
54
54
55
56
57
15 unmodified lines
73
74
75
76
76
77
78
79
17 unmodified lines
97
98
99
100
100
101
102
103
18 unmodified lines
122
123
124
125
125
126
127
128
20 unmodified lines
149
150
151
152
152
153
154
155
14 unmodified lines
170
171
172
173
173
174
175
176
22 unmodified lines
199
200
201
202
202
203
204
205
10 unmodified lines
216
217
218
219
219
220
221
222
21 unmodified lines
244
245
246
247
247
248
249
250
36 unmodified lines
287
288
289
290
290
291
292
293
8 unmodified lines
302
303
304
305
305
306
307
308
22 unmodified lines
331
332
333
334
334
335
336
337
152 unmodified lines
490
491
492
493
493
494
495
496
6 unmodified lines
503
504
505
506
506
507
508
509
100 unmodified lines
610
611
612
613
613
614
615
616
21 unmodified lines
638
639
640
641
641
642
643
644
5 unmodified lines
650
651
652
653
653
654
655
656
30 unmodified lines
687
688
689
690
690
691
692
693
2 unmodified lines
696
697
698
699
699
700
701
702
50 unmodified lines
store := NewGitStore(repo, DefaultV1Refs())
cpID := id.MustCheckpointID("a1b2c3d4e5f6")
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session-001",
Strategy: "manual-commit",
15 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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: redact.AlreadyRedacted(fullTranscript),
17 unmodified lines
t.Parallel()
_, store, cpID := setupRepoForUpdate(t)
err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: redact.AlreadyRedacted(fullTranscript),
20 unmodified lines
t.Parallel()
_, store, _ := setupRepoForUpdate(t)
err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: id.MustCheckpointID("deadbeef1234"),
SessionID: "session-001",
Transcript: redact.AlreadyRedacted([]byte("should fail")),
14 unmodified lines
}
// Update only transcript
err = store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err = store.UpdateCommitted(context.Background(), UpdateOptions{
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.WriteCommitted(context.Background(), WriteCommittedOptions{
err := store.WriteCommitted(context.Background(), WriteOptions{
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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err = store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: redact.AlreadyRedacted(fullTranscript),
21 unmodified lines
repo, store, cpID := setupRepoForUpdate(t)
// Update transcript
err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: redact.AlreadyRedacted([]byte("new full transcript content\n")),
36 unmodified lines
t.Parallel()
_, store, _ := setupRepoForUpdate(t)
err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "nonexistent-session",
Transcript: redact.AlreadyRedacted(fullTranscript),
22 unmodified lines
t.Fatalf("ReadCommitted() before error = %v", err)
}
err = store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err = store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: redact.AlreadyRedacted([]byte("updated\n")),
152 unmodified lines
// Write initial checkpoint
store := NewGitStore(repo, DefaultV1Refs())
cpID := id.MustCheckpointID("a1b2c3d4e5f6")
err = store.WriteCommitted(context.Background(), WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), WriteOptions{
CheckpointID: cpID,
SessionID: "session-001",
Strategy: "manual-commit",
6 unmodified lines
}
// Call UpdateCommitted — this is the operation under test
err = store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
err = store.UpdateCommitted(context.Background(), UpdateOptions{
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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
if err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: transcript,
21 unmodified lines
transcript := redact.AlreadyRedacted([]byte("stable transcript content\n"))
if err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
if err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: transcript,
5 unmodified lines
// should never touch the chunking function.
calls := installChunkCounter(t)
if err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
if err := store.UpdateCommitted(context.Background(), UpdateOptions{
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.UpdateCommitted(context.Background(), UpdateCommittedOptions{
if err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: first,
2 unmodified lines
}
hashBefore := readTranscriptBlobHash(t, repo, cpID)
if err := store.UpdateCommitted(context.Background(), UpdateCommittedOptions{
if err := store.UpdateCommitted(context.Background(), UpdateOptions{
CheckpointID: cpID,
SessionID: "session-001",
Transcript: second,
Mcmd/entire/cli/checkpoint/committed_update_test.go+19/-19
23 unmodified lines
24
25
26
27
27
28
29
30
31
32
32
33
34
35
25 unmodified lines
61
62
63
64
64
65
66
66
67
68
69
23 unmodified lines
// WriteSession 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 WriteCommitted.)
type WriteSession WriteCommittedOptions
type WriteSession WriteOptions
// BackfillTranscript replaces a session's transcript, prompts, and skill
// events at stop time without clobbering sibling fields. (Maps to the former
// UpdateCommitted.)
type BackfillTranscript UpdateCommittedOptions
type BackfillTranscript UpdateOptions
// BackfillSummary rewrites only the summary of the checkpoint's latest
// session. (Maps to the former UpdateSummary.)
25 unmodified lines
func (s *GitStore) Write(ctx context.Context, req WriteRequest) error {
switch r := req.(type) {
case WriteSession:
return s.WriteCommitted(ctx, WriteCommittedOptions(r))
return s.WriteCommitted(ctx, WriteOptions(r))
case BackfillTranscript:
return s.UpdateCommitted(ctx, UpdateCommittedOptions(r))
return s.UpdateCommitted(ctx, UpdateOptions(r))
case BackfillSummary:
return s.UpdateSummary(ctx, r.CheckpointID, r.Summary)
case BackfillAttribution:
Mcmd/entire/cli/checkpoint/committed_write.go+4/-4
23 unmodified lines
24
25
26
27
27
28
29
30
23 unmodified lines
// temporary capability and resolved committed-ref topology.
type Stores struct {
// Primary is the committed store that serves committed reads and writes.
Primary CommittedStore
Primary PersistentStore
temporary TemporaryStore
refs CommittedRefs
Mcmd/entire/cli/checkpoint/open.go+1/-1
7 unmodified lines
8
9
10
11
12
13
14
11
12
13
14
15
16
17
7 unmodified lines
)
var (
_ CommittedStore = (*GitStore)(nil)
_ AuthorReader = (*GitStore)(nil)
_ Writer = (*GitStore)(nil)
_ TemporaryStore = (*ephemeralStore)(nil)
_ PersistentStore = (*GitStore)(nil)
_ AuthorReader = (*GitStore)(nil)
_ Writer = (*GitStore)(nil)
_ TemporaryStore = (*ephemeralStore)(nil)
)
// GitStore is the committed (persistent) checkpoint store. Writes target
Mcmd/entire/cli/checkpoint/store.go+4/-4
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: parsedID,
SessionID: "session-1",
Strategy: "manual-commit",
60 unmodified lines
if err != nil {
t.Fatal(err)
}
err = store.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: parsedID,
SessionID: "session-1",
Strategy: "manual-commit",
435 unmodified lines
t.Fatal(err)
}
err = store.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
err = store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "session-1",
Strategy: "manual-commit",
Mcmd/entire/cli/dispatch/mode_local_test.go+3/-3
88 unmodified lines
89
90
91
92
93
92
93
94
95
96
1474 unmodified lines
1571
1572
1573
1574
1574
1575
1576
1576
1577
1578
1579
177 unmodified lines
1757
1758
1759
1760
1760
1761
1762
1763
284 unmodified lines
2048
2049
2050
2051
2051
2052
2053
2054
104 unmodified lines
2159
2160
2161
2162
2162
2163
2164
2165
88 unmodified lines
type explainCheckpointLookup struct {
repo *git.Repository
store checkpoint.CommittedStore
committed []checkpoint.CommittedInfo
store checkpoint.PersistentStore
committed []checkpoint.CheckpointInfo
}
func (l *explainCheckpointLookup) Close() error {
1474 unmodified lines
// into ambiguousMatch entries enriched with timestamps and session IDs from
// the loaded committed-checkpoint listing. Caps at 5 entries to keep the
// failure block readable when a short prefix collides on many checkpoints.
func buildAmbiguousCheckpointMatches(ids []id.CheckpointID, committed []checkpoint.CommittedInfo) []ambiguousMatch {
func buildAmbiguousCheckpointMatches(ids []id.CheckpointID, committed []checkpoint.CheckpointInfo) []ambiguousMatch {
const maxMatches = 5
infoByID := make(map[id.CheckpointID]checkpoint.CommittedInfo, len(committed))
infoByID := make(map[id.CheckpointID]checkpoint.CheckpointInfo, len(committed))
for _, info := range committed {
infoByID[info.CheckpointID] = info
}
177 unmodified lines
// otherwise the same compact shape is returned as plain text.
func formatCheckpointHeader(
summary *checkpoint.CheckpointSummary,
meta checkpoint.CommittedMetadata,
meta checkpoint.Metadata,
cpID id.CheckpointID,
commits []associatedCommit,
author checkpoint.Author,
284 unmodified lines
}
// Build map of checkpoint ID -> committed info
committedByID := make(map[id.CheckpointID]checkpoint.CommittedInfo)
committedByID := make(map[id.CheckpointID]checkpoint.CheckpointInfo)
for _, info := range committedInfos {
if !info.CheckpointID.IsEmpty() {
committedByID[info.CheckpointID] = info
104 unmodified lines
return points, nil
}
func readLatestCommittedSessionPrompt(ctx context.Context, store checkpoint.CommittedListReader, cpID id.CheckpointID, sessionCount int) string {
func readLatestCommittedSessionPrompt(ctx context.Context, store checkpoint.PersistentListReader, cpID id.CheckpointID, sessionCount int) string {
if sessionCount <= 0 {
return ""
}
Mcmd/entire/cli/explain.go+7/-7
282 unmodified lines
283
284
285
286
286
287
288
289
95 unmodified lines
385
386
387
388
388
389
390
391
30 unmodified lines
422
423
424
425
425
426
427
427
428
429
430
1 unmodified line
432
433
434
435
435
436
437
438
4 unmodified lines
443
444
445
446
446
447
448
449
282 unmodified lines
// checkpointExportJSON is the metadata-only envelope returned by
// `entire checkpoint explain --json`. It exposes only existing CheckpointSummary
// and CommittedMetadata fields — no schema invention, no transcript bytes.
// and Metadata fields — no schema invention, no transcript bytes.
//
// `partial` is true when any session metadata read failed; the offending
// entries surface their cause via Sessions[].error. Consumers that don't
95 unmodified lines
// plus the list of session indexes that failed to read; a non-empty failed
// list means envelope.Partial is true. Extracted from runExplainCheckpointJSON so
// the envelope-building behavior can be tested independently of git storage.
func buildCheckpointJSONEnvelope(ctx context.Context, reader checkpoint.CommittedReader, summary *checkpoint.CheckpointSummary, cpID id.CheckpointID) (checkpointExportJSON, []int) {
func buildCheckpointJSONEnvelope(ctx context.Context, reader checkpoint.PersistentReader, summary *checkpoint.CheckpointSummary, cpID id.CheckpointID) (checkpointExportJSON, []int) {
envelope := checkpointExportJSON{
CheckpointID: cpID.String(),
Strategy: summary.Strategy,
30 unmodified lines
// readSessionMetadataForExport reads only metadata.json for a session — no
// transcript or prompt bytes. GitStore exposes a metadata-only reader, so this
// never depends on transcript availability.
func readSessionMetadataForExport(ctx context.Context, reader checkpoint.CommittedReader, cpID id.CheckpointID, idx int) (*checkpoint.CommittedMetadata, error) {
func readSessionMetadataForExport(ctx context.Context, reader checkpoint.PersistentReader, cpID id.CheckpointID, idx int) (*checkpoint.Metadata, error) {
if r, ok := reader.(interface {
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.CommittedMetadata, error)
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.Metadata, error)
}); ok {
meta, err := r.ReadSessionMetadata(ctx, cpID, idx)
if err != nil {
1 unmodified line
}
return meta, nil
}
// CommittedReader doesn't promise a metadata-only method; fall back
// PersistentReader doesn't promise a metadata-only method; fall back
// to the heavier ReadSessionContent path. Reachable only if a third
// store implementation is added without exposing metadata reads.
content, err := reader.ReadSessionContent(ctx, cpID, idx)
4 unmodified lines
return &meta, nil
}
func sessionMetadataToJSON(idx int, meta *checkpoint.CommittedMetadata) checkpointSessionJSON {
func sessionMetadataToJSON(idx int, meta *checkpoint.Metadata) checkpointSessionJSON {
out := checkpointSessionJSON{
Index: idx,
SessionID: meta.SessionID,
Mcmd/entire/cli/explain_export.go+6/-6
59 unmodified lines
60
61
62
63
63
64
65
66
15 unmodified lines
82
83
84
85
85
86
87
88
38 unmodified lines
127
128
129
130
130
131
132
133
32 unmodified lines
166
167
168
169
169
170
171
172
22 unmodified lines
195
196
197
198
198
199
200
201
15 unmodified lines
217
218
219
220
220
221
222
223
13 unmodified lines
237
238
239
240
240
241
242
243
18 unmodified lines
262
263
264
265
265
266
267
268
21 unmodified lines
290
291
292
293
293
294
295
296
297
298
298
299
300
301
35 unmodified lines
337
338
339
340
340
341
342
343
80 unmodified lines
424
425
426
427
427
428
429
430
58 unmodified lines
489
490
491
492
492
493
494
495
36 unmodified lines
532
533
534
535
535
536
537
538
160 unmodified lines
699
700
701
702
702
703
704
705
706
707
707
708
709
710
23 unmodified lines
734
735
736
737
737
738
739
740
59 unmodified lines
return repo
}
func writeCheckpointForExport(t *testing.T, repo *git.Repository, cpID id.CheckpointID, opts checkpoint.WriteCommittedOptions) {
func writeCheckpointForExport(t *testing.T, repo *git.Repository, cpID id.CheckpointID, opts checkpoint.WriteOptions) {
t.Helper()
if opts.CheckpointID.IsEmpty() {
opts.CheckpointID = cpID
15 unmodified lines
repo := setupExportRepo(t)
cpID := id.MustCheckpointID("aaaa11112222")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-json",
Transcript: redact.AlreadyRedacted([]byte(`{"type":"user","message":{"content":[{"type":"text","text":"hi"}]}}` + "\n")),
})
38 unmodified lines
runGit(t, tmpDir, "clone", "--branch", "main", bareDir, localDir)
targetID := id.MustCheckpointID("aaaa99998888")
writeCheckpointForExport(t, producerRepo, targetID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, producerRepo, targetID, checkpoint.WriteOptions{
SessionID: "remote-v1-session",
Transcript: redact.AlreadyRedacted([]byte(`{"type":"user","message":{"content":[{"type":"text","text":"remote"}]}}` + "\n")),
})
32 unmodified lines
cpID := id.MustCheckpointID("777711112222")
v1 := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
require.NoError(t, v1.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
require.NoError(t, v1.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "session-v1-only",
Strategy: "manual-commit",
22 unmodified lines
repo := setupExportRepo(t)
cpID := id.MustCheckpointID("bbbb11112222")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-no-leak",
Transcript: redact.AlreadyRedacted([]byte(`{"type":"user","message":{"content":[{"type":"text","text":"SECRET-RAW"}]}}` + "\n")),
})
15 unmodified lines
cpID := id.MustCheckpointID("cccc11112222")
raw := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"stored line"}]}}` + "\n")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-stored",
Transcript: redact.AlreadyRedacted(raw),
})
13 unmodified lines
cpID := id.MustCheckpointID("dddd11112222")
raw := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"hello raw"}]}}` + "\n")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-raw",
Transcript: redact.AlreadyRedacted(raw),
})
18 unmodified lines
cpID := id.MustCheckpointID("ffff11112222")
raw0 := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"hello session 0"}]}}` + "\n")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-zero",
Transcript: redact.AlreadyRedacted(raw0),
})
21 unmodified lines
rawSession0 := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"SESSION-ZERO-MARKER"}]}}` + "\n")
rawSession1 := []byte(`{"type":"user","message":{"content":[{"type":"text","text":"SESSION-ONE-DIFFERENT-MARKER"}]}}` + "\n")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-zero",
Transcript: redact.AlreadyRedacted(rawSession0),
})
// Second fixture write with the same checkpoint ID appends session 1.
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-one",
Transcript: redact.AlreadyRedacted(rawSession1),
})
35 unmodified lines
repo := setupExportRepo(t)
cpID := id.MustCheckpointID("eeee11112222")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-only",
Transcript: redact.AlreadyRedacted([]byte(`{"type":"user","message":{"content":[{"type":"text","text":"hi"}]}}` + "\n")),
})
80 unmodified lines
repo := setupExportRepo(t)
cpID := id.MustCheckpointID("aaaabbbb1234")
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteCommittedOptions{
writeCheckpointForExport(t, repo, cpID, checkpoint.WriteOptions{
SessionID: "session-via-commit",
Transcript: redact.AlreadyRedacted([]byte(`{"type":"user","message":{"content":[{"type":"text","text":"hi"}]}}` + "\n")),
})
58 unmodified lines
require.Empty(t, stdout.String(), "must not emit JSON when no mode is set")
}
// stubCommittedReader is a minimal CommittedReader that returns canned
// stubCommittedReader is a minimal PersistentReader that returns canned
// metadata or errors per session index. Used to exercise the partial-failure
// path in buildCheckpointJSONEnvelope without corrupting a real git tree.
type stubCommittedReader struct {
36 unmodified lines
reader := &stubCommittedReader{
summary: summary,
contents: map[int]*checkpoint.SessionContent{
0: {Metadata: checkpoint.CommittedMetadata{
0: {Metadata: checkpoint.Metadata{
SessionID: "good-session",
Agent: "Claude Code",
}},
160 unmodified lines
}
// TestSessionMetadataToJSON_CopiesInvestigateFields pins that
// sessionMetadataToJSON copies the investigate fields from CommittedMetadata
// sessionMetadataToJSON copies the investigate fields from Metadata
// into the per-session JSON struct.
func TestSessionMetadataToJSON_CopiesInvestigateFields(t *testing.T) {
t.Parallel()
meta := &checkpoint.CommittedMetadata{
meta := &checkpoint.Metadata{
SessionID: "investigate-session",
Kind: "agent_investigate",
InvestigateRunID: "0123456789ab",
23 unmodified lines
reader := &stubCommittedReader{
summary: summary,
contents: map[int]*checkpoint.SessionContent{
0: {Metadata: checkpoint.CommittedMetadata{
0: {Metadata: checkpoint.Metadata{
SessionID: "investigate-session",
Kind: "agent_investigate",
InvestigateRunID: "0123456789ab",
Mcmd/entire/cli/explain_export_test.go+17/-17
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
1218 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
25 unmodified lines
2807
2808
2809
2810
2810
2811
2812
2813
62 unmodified lines
2876
2877
2878
2879
2879
2880
2881
2882
49 unmodified lines
2932
2933
2934
2935
2935
2936
2937
2938
26 unmodified lines
2965
2966
2967
2968
2968
2969
2970
2971
38 unmodified lines
3010
3011
3012
3013
3013
3014
3015
3016
64 unmodified lines
3081
3082
3083
3084
3084
3085
3086
3087
207 unmodified lines
3295
3296
3297
3298
3298
3299
3300
3301
26 unmodified lines
3328
3329
3330
3331
3331
3332
3333
3334
10 unmodified lines
3345
3346
3347
3348
3348
3349
3350
3351
10 unmodified lines
3362
3363
3364
3365
3365
3366
3367
3368
20 unmodified lines
3389
3390
3391
3392
3392
3393
3394
3395
10 unmodified lines
3406
3407
3408
3409
3409
3410
3411
3412
10 unmodified lines
3423
3424
3425
3426
3426
3427
3428
3429
14 unmodified lines
3444
3445
3446
3447
3447
3448
3449
3450
1205 unmodified lines
4656
4657
4658
4659
4659
4660
4661
4662
25 unmodified lines
4688
4689
4690
4691
4691
4692
4693
4694
26 unmodified lines
4721
4722
4723
4724
4724
4725
4726
4727
265 unmodified lines
4993
4994
4995
4996
4996
4997
4998
4999
24 unmodified lines
5024
5025
5026
5027
5027
5028
5029
5030
253 unmodified lines
5284
5285
5286
5287
5287
5288
5289
5290
469 unmodified lines
5760
5761
5762
5763
5763
5764
5765
5766
214 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()).WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "session-auto",
Strategy: "manual-commit",
254 unmodified lines
id.MustCheckpointID("e7aaaaaaaaaa"),
id.MustCheckpointID("e7bbbbbbbbbb"),
} {
require.NoError(t, store.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(ctx, checkpoint.WriteOptions{
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()).WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: collisionID,
SessionID: "session-collision",
Strategy: "manual-commit",
1218 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()).WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(context.Background(), checkpoint.WriteOptions{
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()).WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(ctx, checkpoint.WriteOptions{
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()).WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "session-v1",
Strategy: "manual-commit",
51 unmodified lines
`{"type":"assistant","message":{"content":"raw reply"}}` + "\n",
)
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
require.NoError(t, v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: v1ID,
SessionID: "session-v1",
Strategy: "manual-commit",
25 unmodified lines
},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-21-test-session",
CreatedAt: time.Date(2026, 1, 21, 10, 30, 0, 0, time.UTC),
62 unmodified lines
},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-21-test-session",
CreatedAt: time.Date(2026, 1, 21, 10, 30, 0, 0, time.UTC),
49 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-21-test-session",
CreatedAt: time.Date(2026, 1, 21, 10, 30, 0, 0, time.UTC),
26 unmodified lines
},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-21-test-session",
CreatedAt: time.Date(2026, 1, 21, 10, 30, 0, 0, time.UTC),
38 unmodified lines
FilesTouched: []string{"file1.go", "file2.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: cpID,
SessionID: "2026-01-22-test-session",
CreatedAt: time.Date(2026, 1, 22, 10, 30, 0, 0, time.UTC),
64 unmodified lines
cpID := id.MustCheckpointID("abc123456789")
summary := &checkpoint.CheckpointSummary{CheckpointID: cpID}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: cpID,
SessionID: "2026-01-22-test-session",
CreatedAt: time.Date(2026, 1, 22, 10, 30, 0, 0, time.UTC),
207 unmodified lines
summary := &checkpoint.CheckpointSummary{
TokenUsage: &agent.TokenUsage{InputTokens: 18432},
}
meta := checkpoint.CommittedMetadata{
meta := checkpoint.Metadata{
SessionID: "2026-04-29-7f3c1a",
CreatedAt: time.Date(2026, 4, 29, 14, 22, 8, 0, time.UTC),
}
26 unmodified lines
t.Parallel()
cpID := id.MustCheckpointID("a3b2c4d5e6f7")
meta := checkpoint.CommittedMetadata{
meta := checkpoint.Metadata{
SessionID: "s",
CreatedAt: time.Date(2026, 4, 29, 14, 22, 8, 0, time.UTC),
}
10 unmodified lines
t.Parallel()
t.Parallel()
cpID := id.MustCheckpointID("a3b2c4d5e6f7")
meta := checkpoint.CommittedMetadata{
meta := checkpoint.Metadata{
SessionID: "s",
CreatedAt: time.Date(2026, 4, 29, 14, 22, 8, 0, time.UTC),
}
20 unmodified lines
t.Parallel()
t.Parallel()
t.Parallel()
cpID := id.MustCheckpointID("a3b2c4d5e6f7")
meta := checkpoint.CommittedMetadata{
meta := checkpoint.Metadata{
SessionID: "s",
CreatedAt: time.Date(2026, 4, 29, 14, 22, 8, 0, time.UTC),
TokenUsage: nil,
14 unmodified lines
t.Parallel()
cpID := id.MustCheckpointID("a3b2c4d5e6f7")
meta := checkpoint.CommittedMetadata{
meta := checkpoint.Metadata{
SessionID: "s",
CreatedAt: time.Date(2026, 4, 29, 14, 22, 8, 0, time.UTC),
TokenUsage: &agent.TokenUsage{InputTokens: 1234},
1205 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-30-test-session",
CreatedAt: time.Date(2026, 1, 30, 10, 30, 0, 0, time.UTC),
25 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-30-test-session",
CreatedAt: time.Date(2026, 1, 30, 10, 30, 0, 0, time.UTC),
26 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-30-test-session",
CreatedAt: time.Date(2026, 1, 30, 10, 30, 0, 0, time.UTC),
265 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-30-test-session",
CreatedAt: time.Date(2026, 1, 30, 10, 30, 0, 0, time.UTC),
24 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-01-30-test-session",
CreatedAt: time.Date(2026, 1, 30, 10, 30, 0, 0, time.UTC),
253 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-02-04-test-session",
CreatedAt: time.Date(2026, 2, 4, 10, 30, 0, 0, time.UTC),
469 unmodified lines
FilesTouched: []string{"main.go"},
}
content := &checkpoint.SessionContent{
Metadata: checkpoint.CommittedMetadata{
Metadata: checkpoint.Metadata{
CheckpointID: "abc123def456",
SessionID: "2026-02-04-test-session",
CreatedAt: time.Date(2026, 2, 4, 10, 30, 0, 0, time.UTC),
214 unmodified lines
// Write committed checkpoint metadata so getBranchCheckpoints can find it
store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
if err := store.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: sessionID,
Strategy: "manual-commit",
Mcmd/entire/cli/explain_test.go+38/-38
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "head-flags-session",
Strategy: "manual-commit",
Mcmd/entire/cli/head_checkpoint_flags_test.go+1/-1
163 unmodified lines
164
165
166
167
167
168
169
170
136 unmodified lines
307
308
309
310
310
311
312
313
540 unmodified lines
854
855
856
857
857
858
859
860
163 unmodified lines
t.Fatalf("Failed to read metadata content: %v", err)
}
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(metadataContent), &metadata); err != nil {
t.Fatalf("Failed to parse metadata.json: %v", err)
}
136 unmodified lines
t.Fatalf("Failed to read metadata content: %v", err)
}
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(metadataContent), &metadata); err != nil {
t.Fatalf("Failed to parse metadata.json: %v", err)
}
540 unmodified lines
t.Fatalf("Failed to read metadata content: %v", err)
}
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(metadataContent), &metadata); err != nil {
t.Fatalf("Failed to parse metadata.json: %v", err)
}
Mcmd/entire/cli/integration_test/attribution_test.go+3/-3
691 unmodified lines
692
693
694
695
695
696
697
698
691 unmodified lines
if !found {
t.Fatal("session metadata.json should be readable")
}
var sessionMetadata checkpoint.CommittedMetadata
var sessionMetadata checkpoint.Metadata
if err := json.Unmarshal([]byte(sessionMetadataContent), &sessionMetadata); err != nil {
t.Fatalf("failed to parse session metadata.json: %v", err)
}
Mcmd/entire/cli/integration_test/manual_commit_workflow_test.go+1/-1
289 unmodified lines
290
291
292
293
293
294
295
296
1 unmodified line
298
299
300
301
301
302
303
304
289 unmodified lines
return summary
}
func readSessionMetadata(t *testing.T, env *TestEnv, checkpointID string) checkpoint.CommittedMetadata {
func readSessionMetadata(t *testing.T, env *TestEnv, checkpointID string) checkpoint.Metadata {
t.Helper()
content, found := env.ReadFileFromBranch(paths.MetadataBranchName, SessionMetadataPath(checkpointID))
1 unmodified line
t.Fatalf("session metadata not found for %s", checkpointID)
}
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(content), &metadata); err != nil {
t.Fatalf("failed to parse session metadata: %v\n%s", err, content)
}
Mcmd/entire/cli/integration_test/review_test.go+2/-2
947 unmodified lines
948
949
950
951
951
952
953
954
586 unmodified lines
1541
1542
1543
1544
1544
1545
1546
1547
3 unmodified lines
1551
1552
1553
1554
1554
1555
1556
1557
57 unmodified lines
1615
1616
1617
1618
1618
1619
1620
1621
3 unmodified lines
1625
1626
1627
1628
1628
1629
1630
1630
1631
1632
1633
1634
1635
1635
1636
1637
1638
1639
1640
1640
1641
1642
1643
1644
1645
1645
1646
1647
1648
1649
1650
1650
1651
1652
1653
4 unmodified lines
1658
1659
1660
1661
1661
1662
1663
1664
1665
1666
1667
1668
1668
1669
1670
1671
947 unmodified lines
if !found {
return false
}
var meta checkpoint.CommittedMetadata
var meta checkpoint.Metadata
if err := json.Unmarshal([]byte(content), &meta); err != nil {
return false
}
586 unmodified lines
// ValidateCheckpoint performs comprehensive validation of a checkpoint on the metadata branch.
// It validates:
// - Root metadata.json (CheckpointSummary) structure and expected fields
// - Session metadata.json (CommittedMetadata) structure and expected fields
// - Session metadata.json (Metadata) structure and expected fields
// - Transcript file (full.jsonl) is valid JSONL and contains expected content
// - Content hash file (content_hash.txt) matches SHA256 of transcript
// - Prompt file (prompt.txt) contains expected prompts
3 unmodified lines
// Validate root metadata.json (CheckpointSummary)
env.validateCheckpointSummary(v)
// Validate session metadata.json (CommittedMetadata)
// Validate session metadata.json (Metadata)
env.validateSessionMetadata(v)
// Validate transcript is valid JSONL
57 unmodified lines
}
}
// validateSessionMetadata validates the session-level metadata.json (CommittedMetadata).
// validateSessionMetadata validates the session-level metadata.json (Metadata).
func (env *TestEnv) validateSessionMetadata(v CheckpointValidation) {
env.T.Helper()
3 unmodified lines
env.T.Fatalf("Session metadata not found at %s", metadataPath)
}
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(content), &metadata); err != nil {
env.T.Fatalf("Failed to parse CommittedMetadata: %v\nContent: %s", err, content)
env.T.Fatalf("Failed to parse Metadata: %v\nContent: %s", err, content)
}
// Validate checkpoint_id
if metadata.CheckpointID.String() != v.CheckpointID {
env.T.Errorf("CommittedMetadata.CheckpointID = %q, want %q", metadata.CheckpointID, v.CheckpointID)
env.T.Errorf("Metadata.CheckpointID = %q, want %q", metadata.CheckpointID, v.CheckpointID)
}
// Validate session_id
if v.SessionID != "" && metadata.SessionID != v.SessionID {
env.T.Errorf("CommittedMetadata.SessionID = %q, want %q", metadata.SessionID, v.SessionID)
env.T.Errorf("Metadata.SessionID = %q, want %q", metadata.SessionID, v.SessionID)
}
// Validate strategy
if v.Strategy != "" && metadata.Strategy != v.Strategy {
env.T.Errorf("CommittedMetadata.Strategy = %q, want %q", metadata.Strategy, v.Strategy)
env.T.Errorf("Metadata.Strategy = %q, want %q", metadata.Strategy, v.Strategy)
}
// Validate created_at is not zero
if metadata.CreatedAt.IsZero() {
env.T.Error("CommittedMetadata.CreatedAt should not be zero")
env.T.Error("Metadata.CreatedAt should not be zero")
}
// Validate files_touched
4 unmodified lines
}
for _, expected := range v.FilesTouched {
if !touchedSet[expected] {
env.T.Errorf("CommittedMetadata.FilesTouched missing %q, got %v", expected, metadata.FilesTouched)
env.T.Errorf("Metadata.FilesTouched missing %q, got %v", expected, metadata.FilesTouched)
}
}
}
// Validate checkpoints_count
if v.CheckpointsCount > 0 && metadata.CheckpointsCount != v.CheckpointsCount {
env.T.Errorf("CommittedMetadata.CheckpointsCount = %d, want %d", metadata.CheckpointsCount, v.CheckpointsCount)
env.T.Errorf("Metadata.CheckpointsCount = %d, want %d", metadata.CheckpointsCount, v.CheckpointsCount)
}
}
Mcmd/entire/cli/integration_test/testenv.go+12/-12
103 unmodified lines
104
105
106
107
107
108
109
110
103 unmodified lines
content, found := env.ReadFileFromBranch(paths.MetadataBranchName, metadataPath)
require.True(t, found, "Session metadata should exist for checkpoint %s", checkpointID2)
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
require.NoError(t, json.Unmarshal([]byte(content), &metadata))
t.Logf("Checkpoint 2: checkpoint_transcript_start=%d (commit 1 offset was %d)",
Mcmd/entire/cli/integration_test/transcript_offset_test.go+1/-1
349 unmodified lines
350
351
352
353
354
353
354
355
356
357
349 unmodified lines
}
type checkpointInfoReader interface {
checkpoint.CommittedReader
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.CommittedMetadata, error)
checkpoint.PersistentReader
ReadSessionMetadata(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.Metadata, error)
}
func readCheckpointInfoFromStore(ctx context.Context, store checkpointInfoReader, checkpointID id.CheckpointID) (*strategy.CheckpointInfo, error) {
Mcmd/entire/cli/resume.go+2/-2
530 unmodified lines
531
532
533
534
534
535
536
537
64 unmodified lines
602
603
604
605
605
606
607
608
16 unmodified lines
625
626
627
628
628
629
630
631
4 unmodified lines
636
637
638
639
639
640
641
642
29 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
530 unmodified lines
) {
t.Helper()
if err := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
if err := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
CreatedAt: createdAt,
64 unmodified lines
oldID: {Sessions: []checkpoint.SessionFilePaths{{Metadata: "old"}}},
newID: {Sessions: []checkpoint.SessionFilePaths{{Metadata: "new"}}},
},
metadata: map[id.CheckpointID][]checkpoint.CommittedMetadata{
metadata: map[id.CheckpointID][]checkpoint.Metadata{
oldID: {{
SessionID: "old-session",
CreatedAt: time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC),
16 unmodified lines
type resumeCheckpointInfoReaderStub struct {
summaries map[id.CheckpointID]*checkpoint.CheckpointSummary
metadata map[id.CheckpointID][]checkpoint.CommittedMetadata
metadata map[id.CheckpointID][]checkpoint.Metadata
}
func (r *resumeCheckpointInfoReaderStub) ReadCommitted(_ context.Context, checkpointID id.CheckpointID) (*checkpoint.CheckpointSummary, error) {
4 unmodified lines
return nil, checkpoint.ErrCheckpointNotFound
}
func (r *resumeCheckpointInfoReaderStub) ReadSessionMetadata(_ context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.CommittedMetadata, error) {
func (r *resumeCheckpointInfoReaderStub) ReadSessionMetadata(_ context.Context, checkpointID id.CheckpointID, sessionIndex int) (*checkpoint.Metadata, error) {
sessions := r.metadata[checkpointID]
if sessionIndex < 0 || sessionIndex >= len(sessions) {
return nil, checkpoint.ErrCheckpointNotFound
29 unmodified lines
},
}
for _, session := range sessions {
if err := store.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
if err := store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
if err := v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
if err := v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
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.WriteCommitted(ctx, checkpoint.WriteCommittedOptions{
if err := v1Store.WriteCommitted(ctx, checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: "2025-01-01-test-session-uuid",
Strategy: "manual-commit",
Mcmd/entire/cli/resume_test.go+8/-8
28 unmodified lines
29
30
31
32
32
33
34
35
237 unmodified lines
273
274
275
276
276
277
278
279
27 unmodified lines
307
308
309
310
310
311
312
313
313
314
315
316
9 unmodified lines
326
327
328
329
329
330
331
332
28 unmodified lines
)
type reviewContextSessionMetadataReader interface {
ReadSessionMetadata(ctx context.Context, checkpointID checkpointid.CheckpointID, sessionIndex int) (*checkpoint.CommittedMetadata, error)
ReadSessionMetadata(ctx context.Context, checkpointID checkpointid.CheckpointID, sessionIndex int) (*checkpoint.Metadata, error)
}
type reviewContextSessionMetadataPromptsReader interface {
237 unmodified lines
func reviewCheckpointDetail(
ctx context.Context,
reader checkpoint.CommittedReader,
reader checkpoint.PersistentReader,
cpID checkpointid.CheckpointID,
summary *checkpoint.CheckpointSummary,
) string {
27 unmodified lines
func readReviewContextSessionMetadata(
ctx context.Context,
reader checkpoint.CommittedReader,
reader checkpoint.PersistentReader,
cpID checkpointid.CheckpointID,
sessionIndex int,
) (*checkpoint.CommittedMetadata, error) {
) (*checkpoint.Metadata, error) {
if r, ok := reader.(reviewContextSessionMetadataReader); ok {
return r.ReadSessionMetadata(ctx, cpID, sessionIndex) //nolint:wrapcheck // Best-effort prompt context.
}
9 unmodified lines
func readReviewContextSessionPrompts(
ctx context.Context,
reader checkpoint.CommittedReader,
reader checkpoint.PersistentReader,
cpID checkpointid.CheckpointID,
sessionIndex int,
) (string, error) {
Mcmd/entire/cli/review_context.go+5/-5
120 unmodified lines
121
122
123
124
124
125
126
127
268 unmodified lines
396
397
398
399
399
400
401
402
49 unmodified lines
452
453
454
455
455
456
457
458
23 unmodified lines
482
483
484
485
485
486
487
488
120 unmodified lines
cpID := checkpointid.MustCheckpointID("d1b2c3d4e5f6")
reader := &countingReviewContextReader{
metadata: checkpoint.CommittedMetadata{
metadata: checkpoint.Metadata{
CheckpointID: cpID,
SessionID: "session-1",
},
268 unmodified lines
t.Fatalf("open repo: %v", err)
}
cpID := checkpointid.MustCheckpointID(checkpointID)
err = checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
err = checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs()).WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: checkpointID,
Strategy: "manual-commit",
49 unmodified lines
}
type countingReviewContextReader struct {
metadata checkpoint.CommittedMetadata
metadata checkpoint.Metadata
prompts string
metadataErr error
promptErr error
23 unmodified lines
context.Context,
checkpointid.CheckpointID,
int,
) (*checkpoint.CommittedMetadata, error) {
) (*checkpoint.Metadata, error) {
r.metadataCalls++
return &r.metadata, r.metadataErr
}
Mcmd/entire/cli/review_context_test.go+4/-4
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
if err := store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
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.WriteCommitted(t.Context(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(t.Context(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: sid,
Strategy: "manual-commit",
Mcmd/entire/cli/strategy/clean_test.go+1/-1
315 unmodified lines
316
317
318
319
319
320
321
322
272 unmodified lines
595
596
597
598
598
599
600
601
241 unmodified lines
843
844
845
846
846
847
848
849
58 unmodified lines
908
909
910
911
911
912
913
914
315 unmodified lines
return checkpointInfosFromCommitted(committed), nil
}
func checkpointInfosFromCommitted(committed []checkpoint.CommittedInfo) []CheckpointInfo {
func checkpointInfosFromCommitted(committed []checkpoint.CheckpointInfo) []CheckpointInfo {
result := make([]CheckpointInfo, 0, len(committed))
for _, c := range committed {
result = append(result, CheckpointInfo{
272 unmodified lines
// sessionMetadataLite contains only the fields needed from session-level metadata.json.
// Using a minimal struct avoids allocating large nested objects (Summary, Attribution,
// TokenUsage, etc.) that CommittedMetadata carries but callers never need here.
// TokenUsage, etc.) that Metadata carries but callers never need here.
type sessionMetadataLite struct {
SessionID string `json:"session_id"`
Agent types.AgentType `json:"agent,omitempty"`
241 unmodified lines
metadataPath := checkpointPath + "/" + paths.MetadataFileName
if file, err := tree.File(metadataPath); err == nil {
if content, err := file.Contents(); err == nil {
var metadata checkpoint.CommittedMetadata
var metadata checkpoint.Metadata
if err := json.Unmarshal([]byte(content), &metadata); err == nil && metadata.Agent != "" {
return metadata.Agent
}
58 unmodified lines
//
// Falls back through earlier sessions when the latest has no prompt.
// Avoids reading full transcripts — only reads prompt.txt files.
// sessionCount is the number of sessions in the checkpoint (from CommittedInfo.SessionCount).
// sessionCount is the number of sessions in the checkpoint (from CheckpointInfo.SessionCount).
func ReadLatestSessionPromptFromCommittedTree(tree *object.Tree, cpID id.CheckpointID, sessionCount int) string {
cpPath := cpID.Path()
cpTree, err := tree.Tree(cpPath)
Mcmd/entire/cli/strategy/common.go+4/-4
51 unmodified lines
52
53
54
55
55
56
57
58
51 unmodified lines
// topology. Writes target refs.Primary; reads target refs.Read. The strategy's
// blob fetcher is wired in so reads can fetch blobs on demand after a treeless
// fetch.
func (s *ManualCommitStrategy) getCheckpointStore(ctx context.Context, repo *git.Repository) (checkpoint.CommittedStore, error) { //nolint:ireturn // committed store capability is the abstraction boundary
func (s *ManualCommitStrategy) getCheckpointStore(ctx context.Context, repo *git.Repository) (checkpoint.PersistentStore, error) { //nolint:ireturn // committed store capability is the abstraction boundary
stores, err := s.getCheckpointStores(ctx, repo)
if err != nil {
return nil, err
Mcmd/entire/cli/strategy/manual_commit.go+1/-1
134 unmodified lines
135
136
137
138
138
139
140
141
113 unmodified lines
255
256
257
258
258
259
260
261
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.CommittedStore.WriteCommitted for committed storage.
// Uses checkpoint.PersistentStore.WriteCommitted for committed 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.
113 unmodified lines
// pre-push rewrite path, never here.
skillEvents := mergeSkillEvents(state.SkillEvents, withSkillEventTurnID(sessionData.SkillEvents, state.TurnID))
writeOpts := cpkg.WriteCommittedOptions{
writeOpts := cpkg.WriteOptions{
CheckpointID: checkpointID,
SessionID: state.SessionID,
Strategy: StrategyNameManualCommit,
Mcmd/entire/cli/strategy/manual_commit_condensation.go+2/-2
457 unmodified lines
458
459
460
461
461
462
463
464
82 unmodified lines
547
548
549
550
550
551
552
553
457 unmodified lines
// when state.Kind is KindAgentInvestigate, condensation propagates the kind
// through to CheckpointSummary.HasInvestigation on the metadata branch and
// writes the per-session investigate fields into the per-session
// CommittedMetadata. Mirrors the (untested) review-tagging path so future
// Metadata. Mirrors the (untested) review-tagging path so future
// regressions in either flow are caught here.
//
// Tests in this file use t.Chdir for CWD-based git resolution, so this
82 unmodified lines
}
sessionBytes, err := sessionMeta.Contents()
require.NoError(t, err)
var meta checkpoint.CommittedMetadata
var meta checkpoint.Metadata
require.NoError(t, json.Unmarshal([]byte(sessionBytes), &meta))
require.Equal(t, string(session.KindAgentInvestigate), meta.Kind, "per-session Kind")
Mcmd/entire/cli/strategy/manual_commit_condensation_test.go+2/-2
2819 unmodified lines
2820
2821
2822
2823
2823
2824
2825
2826
2819 unmodified lines
continue
}
updateOpts := checkpoint.UpdateCommittedOptions{
updateOpts := checkpoint.UpdateOptions{
CheckpointID: cpID,
SessionID: state.SessionID,
Transcript: redactedTranscript,
Mcmd/entire/cli/strategy/manual_commit_hooks.go+1/-1
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.WriteCommitted(context.Background(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(context.Background(), checkpoint.WriteOptions{
CheckpointID: cpID,
SessionID: sessionID,
Strategy: "manual-commit",
Mcmd/entire/cli/strategy/manual_commit_opf_rewrite_test.go+1/-1
859 unmodified lines
860
861
862
863
863
864
865
866
859 unmodified lines
// about each session, including whether local logs have newer timestamps.
// repoRoot is used to compute per-session agent directories.
// Sessions without agent metadata are skipped (cannot determine target directory).
func (s *ManualCommitStrategy) classifySessionsForRestore(ctx context.Context, repoRoot string, store cpkg.CommittedReader, checkpointID id.CheckpointID, summary *cpkg.CheckpointSummary) []SessionRestoreInfo {
func (s *ManualCommitStrategy) classifySessionsForRestore(ctx context.Context, repoRoot string, store cpkg.PersistentReader, checkpointID id.CheckpointID, summary *cpkg.CheckpointSummary) []SessionRestoreInfo {
var sessions []SessionRestoreInfo
totalSessions := len(summary.Sessions)
Mcmd/entire/cli/strategy/manual_commit_rewind.go+1/-1
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.WriteCommitted(t.Context(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(t.Context(), checkpoint.WriteOptions{
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.WriteCommitted(t.Context(), checkpoint.WriteCommittedOptions{
require.NoError(t, store.WriteCommitted(t.Context(), checkpoint.WriteOptions{
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
615 unmodified lines
) {
t.Helper()
err := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs()).WriteCommitted(context.Background(), cpkg.WriteCommittedOptions{
err := cpkg.NewGitStore(repo, cpkg.DefaultV1Refs()).WriteCommitted(context.Background(), cpkg.WriteOptions{
CheckpointID: checkpointID,
SessionID: sessionID,
CreatedAt: createdAt,
Mcmd/entire/cli/strategy/rewind_test.go+1/-1