checkpoint: unify ephemeral writes behind Write(EphemeralWriteRequest) · Entire
checkpoint: unify ephemeral writes behind Write(EphemeralWriteRequest)
3387cbb→main·
Soph·3w ago·9 files·+81 added/-44 removed
Mirror the persistent Write union on the shadow-branch store: a single ephemeralStore.Write(ctx, EphemeralWriteRequest) dispatches a sealed request union, replacing the two exported write methods. WriteTemporary -> writeCheckpoint (Write WriteCheckpoint{...}) WriteTemporaryTask -> writeTask (Write WriteTask{...})
Write returns WriteEphemeralResult{CommitHash, Skipped} for both requests. The EphemeralStore interface now exposes Read/Write/List, symmetric with the persistent surface. Callers (strategy, benchmarks, tests) migrated. No behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
Changes
9
cmd/entire/cli
benchutil
Mbench_test.go+5/-5
Mbenchutil.go+1/-1
checkpoint
Mcheckpoint.go+1/-2
Mcheckpoint_test.go+23/-23
Aephemeral_write.go+38
Mtemporary.go+4/-4
Mexplain_test.go+6/-6
strategy
Mmanual_commit_git.go+2/-2
Mmanual_commit_hooks.go+1/-1
62 unmodified lines
63
64
65
66
66
67
68
69
54 unmodified lines
124
125
126
127
127
128
129
130
42 unmodified lines
173
174
175
176
176
177
178
179
29 unmodified lines
209
210
211
212
212
213
214
215
40 unmodified lines
256
257
258
259
259
260
261
262
62 unmodified lines
// measure the first-checkpoint path (which runs collectChangedFiles).
// We use a unique session ID per iteration to get a fresh shadow branch.
sid := fmt.Sprintf("bench-first-%d", i)
_, writeErr := repo.Ephemeral.WriteTemporary(ctx, checkpoint.WriteEphemeralOptions{
_, writeErr := repo.Ephemeral.Write(ctx, checkpoint.WriteCheckpoint{
SessionID: sid,
BaseCommit: repo.HeadHash,
WorktreeID: repo.WorktreeID,
54 unmodified lines
ctx := context.Background()
b.ResetTimer()
for range b.N {
_, writeErr := repo.Ephemeral.WriteTemporary(ctx, checkpoint.WriteEphemeralOptions{
_, writeErr := repo.Ephemeral.Write(ctx, checkpoint.WriteCheckpoint{
SessionID: sessionID,
BaseCommit: repo.HeadHash,
WorktreeID: repo.WorktreeID,
42 unmodified lines
ctx := context.Background()
b.ResetTimer()
for range b.N {
_, writeErr := repo.Ephemeral.WriteTemporary(ctx, checkpoint.WriteEphemeralOptions{
_, writeErr := repo.Ephemeral.Write(ctx, checkpoint.WriteCheckpoint{
SessionID: sessionID,
BaseCommit: repo.HeadHash,
WorktreeID: repo.WorktreeID,
29 unmodified lines
ctx := context.Background()
b.ResetTimer()
for range b.N {
result, writeErr := repo.Ephemeral.WriteTemporary(ctx, checkpoint.WriteEphemeralOptions{
result, writeErr := repo.Ephemeral.Write(ctx, checkpoint.WriteCheckpoint{
SessionID: sessionID,
BaseCommit: repo.HeadHash,
WorktreeID: repo.WorktreeID,
40 unmodified lines
ctx := context.Background()
b.ResetTimer()
for range b.N {
_, writeErr := repo.Ephemeral.WriteTemporary(ctx, checkpoint.WriteEphemeralOptions{
_, writeErr := repo.Ephemeral.Write(ctx, checkpoint.WriteCheckpoint{
SessionID: sessionID,
BaseCommit: repo.HeadHash,
WorktreeID: repo.WorktreeID,
Mcmd/entire/cli/benchutil/bench_test.go+5/-5
360 unmodified lines
361
362
363
364
364
365
366
367
360 unmodified lines
b.Fatalf("write transcript: %v", err)
}
_, err := br.Ephemeral.WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{
_, err := br.Ephemeral.Write(context.Background(), checkpoint.WriteCheckpoint{
SessionID: sessionID,
BaseCommit: br.HeadHash,
WorktreeID: br.WorktreeID,
Mcmd/entire/cli/benchutil/benchutil.go+1/-1
60 unmodified lines
61
62
63
64
65
64
65
66
67
60 unmodified lines
// EphemeralStore provides the production shadow-branch checkpoint surface.
type EphemeralStore interface {
WriteTemporary(ctx context.Context, opts WriteEphemeralOptions) (WriteEphemeralResult, error)
WriteTemporaryTask(ctx context.Context, opts WriteEphemeralTaskOptions) (plumbing.Hash, error)
Write(ctx context.Context, req EphemeralWriteRequest) (WriteEphemeralResult, error)
Read(ctx context.Context, baseCommit, worktreeID string) (*ReadEphemeralResult, error)
List(ctx context.Context) ([]EphemeralInfo, error)
ListCheckpoints(ctx context.Context, baseCommit, worktreeID, sessionID string, limit int) ([]EphemeralCheckpointInfo, error)
}
Mcmd/entire/cli/checkpoint/checkpoint.go+1/-2
349 unmodified lines
350 351 352 353 353 354 355 356 15 unmodified lines
372 373 374 375 375 376 377 378 20 unmodified lines
399 400 401 402 402 403 404 405 1397 unmodified lines
1803 1804 1805 1806 1806 1807 1808 1809 121 unmodified lines
1931 1932 1933 1934 1934 1935 1936 1937 95 unmodified lines
2033 2034 2035 2036 2036 2037 2038 2039 109 unmodified lines
2149 2150 2151 2152 2152 2153 2154 2155 110 unmodified lines
2266 2267 2268 2269 2269 2270 2271 2272 94 unmodified lines
2367 2368 2369 2370 2370 2371 2372 2373 12 unmodified lines
2386 2387 2388 2389 2389 2390 2391 2392 95 unmodified lines
2488 2489 2490 2491 2491 2492 2493 2494 9 unmodified lines
2504 2505 2506 2507 2507 2508 2509 2510 88 unmodified lines
2599 2600 2601 2602 2602 2603 2604 2605 9 unmodified lines
2615 2616 2617 2618 2618 2619 2620 2621 100 unmodified lines
2722 2723 2724 2725 2725 2726 2727 2728 108 unmodified lines
2837 2838 2839 2840 2840 2841 2842 2843 92 unmodified lines
2936 2937 2938 2939 2939 2940 2941 2942 90 unmodified lines
3033 3034 3035 3036 3036 3037 3038 3039 1100 unmodified lines
4140 4141 4142 4143 4143 4144 4145 4146 281 unmodified lines
4428 4429 4430 4431 4431 4432 4433 4434 8 unmodified lines
4443 4444 4445 4446 4446 4447 4448 4449 85 unmodified lines
4535 4536 4537 4538 4538 4539 4540 4541 11 unmodified lines
4553 4554 4555 4556 4556 4557 4558 4559
349 unmodified lines
// First checkpoint should be created baseCommit := initialCommit.String() result1, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result1, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{"test.go"}, 15 unmodified lines }
// Second checkpoint with identical content should be skipped result2, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result2, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{"test.go"}, 20 unmodified lines
t.Fatalf("failed to modify test file: %v", err) }
result3, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result3, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{"test.go"}, 1397 unmodified lines
store := newEphemeralStore(repo, DefaultV1Refs()) baseCommit := initialCommit.String()
result, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{}, // Agent hasn't modified anything 121 unmodified lines
}
store := newEphemeralStore(repo, DefaultV1Refs()) result, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: initialCommit.String(), ModifiedFiles: tt.modifiedFiles(tempDir, mainFile), 95 unmodified lines
store := newEphemeralStore(repo, DefaultV1Refs()) baseCommit := initialCommit.String()
result, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{}, 109 unmodified lines
store := newEphemeralStore(repo, DefaultV1Refs()) baseCommit := initialCommit.String()
result, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{}, 94 unmodified lines
store := newEphemeralStore(repo, DefaultV1Refs()) baseCommit := initialCommit.String()
result, err := store.WriteTemporary(context.Background(), WriteEphemeralOptions{ result, err := store.Write(context.Background(), WriteCheckpoint{ SessionID: "test-session", BaseCommit: baseCommit, ModifiedFiles: []string{}, 1100 unmodified lines
store := newEphemeralStore(repo, DefaultV1Refs()) baseCommit := initialCommit.String()
_, err = store.WriteTemporaryTask(context.Background(), WriteEphemeralTaskOptions{ _, err = store.Write(context.Background(), WriteTask{ SessionID: "test-session", BaseCommit: baseCommit, ToolUseID: "toolu_test456", 281 unmodified lines
t.Chdir(tempDir)
store := newEphemeralStore(repo, DefaultV1Refs()) commitHash, err := store.WriteTemporaryTask(context.Background(), WriteEphemeralTaskOptions{ writeRes, err := store.Write(context.Background(), WriteTask{ SessionID: "test-session", BaseCommit: initialCommit.String(), ToolUseID: "toolu_symlink123", 8 unmodified lines
t.Fatalf("WriteTemporaryTask() error = %v", err) }
commit, err := repo.CommitObject(commitHash) commit, err := repo.CommitObject(writeRes.CommitHash) if err != nil { t.Fatalf("failed to get commit object: %v", err) } 85 unmodified lines
baseCommit := initialCommit.String()
// Write task checkpoint where subagent reports .env as modified commitHash, err := store.WriteTemporaryTask(context.Background(), WriteEphemeralTaskOptions{ writeRes, err := store.Write(context.Background(), WriteTask{ SessionID: "test-session", BaseCommit: baseCommit, ToolUseID: "toolu_test789", 11 unmodified lines
t.Fatalf("WriteTemporaryTask() error = %v", err) }
commit, err := repo.CommitObject(commitHash) commit, err := repo.CommitObject(writeRes.CommitHash) if err != nil { t.Fatalf("failed to get commit object: %v", err) }
Mcmd/entire/cli/checkpoint/checkpoint\_test.go+23/-23
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
package checkpoint
import ( "context" "fmt" )
// EphemeralWriteRequest is a single shadow-branch (ephemeral) write command. // The set is closed via the unexported marker; the store dispatches on the // concrete type, mirroring the persistent WriteRequest union. type EphemeralWriteRequest interface { isEphemeralWriteRequest() }
// WriteCheckpoint captures working-tree changes as a shadow-branch checkpoint. // (Former WriteTemporary.) type WriteCheckpoint WriteEphemeralOptions
// WriteTask records a completed subagent task as a shadow-branch checkpoint. // (Former WriteTemporaryTask.) type WriteTask WriteEphemeralTaskOptions
func (WriteCheckpoint) isEphemeralWriteRequest() {} func (WriteTask) isEphemeralWriteRequest() {}
// Write dispatches an ephemeral write request to the matching shadow-branch // operation. The result carries the created (or existing) commit hash. func (s *ephemeralStore) Write(ctx context.Context, req EphemeralWriteRequest) (WriteEphemeralResult, error) { switch r := req.(type) { case WriteCheckpoint: return s.writeCheckpoint(ctx, WriteEphemeralOptions(r)) case WriteTask: hash, err := s.writeTask(ctx, WriteEphemeralTaskOptions(r)) return WriteEphemeralResult{CommitHash: hash}, err default: return WriteEphemeralResult{}, fmt.Errorf("checkpoint: unsupported ephemeral write request %T", req) } }
Acmd/entire/cli/checkpoint/ephemeral\_write.go+38
48 unmodified lines
49 50 51 52 52 53 54 55 56 57 57 58 59 60 209 unmodified lines
270 271 272 273 273 274 275 276 276 277 278 279
48 unmodified lines
return hex.EncodeToString(h[:])[:WorktreeIDHashLength] }
// WriteTemporary writes a temporary checkpoint to a shadow branch.
// writeCheckpoint writes a temporary checkpoint to a shadow branch.
// Shadow branches are named entire/
209 unmodified lines
return results, nil }
// WriteTemporaryTask writes a task checkpoint to a shadow branch. // writeTask writes a task checkpoint to a shadow branch. // Task checkpoints include both code changes and task-specific metadata. // Returns the commit hash of the created checkpoint. func (s *ephemeralStore) WriteTemporaryTask(ctx context.Context, opts WriteEphemeralTaskOptions) (plumbing.Hash, error) { func (s *ephemeralStore) writeTask(ctx context.Context, opts WriteEphemeralTaskOptions) (plumbing.Hash, error) { // Validate base commit - required for shadow branch naming if opts.BaseCommit == "" { return plumbing.ZeroHash, errors.New("BaseCommit is required for task checkpoint") }
Mcmd/entire/cli/checkpoint/temporary.go+4/-4
526 unmodified lines
527 528 529 530 530 531 532 533 1988 unmodified lines
2522 2523 2524 2525 2525 2526 2527 2528 1374 unmodified lines
3903 3904 3905 3906 3906 3907 3908 3909 14 unmodified lines
3924 3925 3926 3927 3927 3928 3929 3930 100 unmodified lines
4031 4032 4033 4034 4034 4035 4036 4037 5 unmodified lines
4043 4044 4045 4046 4046 4047 4048 4049
526 unmodified lines
require.NoError(t, os.WriteFile(testFile, []byte("updated content"), 0o644))
result, err := checkpoint.NewEphemeralStore(repo, checkpoint.DefaultV1Refs()).WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ result, err := checkpoint.NewEphemeralStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: initialCommit.String()[:7], ModifiedFiles: []string{"temp.txt"}, 1988 unmodified lines
head, err := repo.Head() require.NoError(t, err)
result, err := checkpoint.NewEphemeralStore(repo, checkpoint.DefaultV1Refs()).WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ result, err := checkpoint.NewEphemeralStore(repo, checkpoint.DefaultV1Refs()).Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: head.Hash().String()[:7], ModifiedFiles: []string{"test.txt"}, 1374 unmodified lines
// Create first checkpoint (baseline copy) - this one gets filtered out store := checkpoint.NewEphemeralStore(repo, checkpoint.DefaultV1Refs()) baseCommit := initialCommit.String()[:7] _, err = store.WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ _, err = store.Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: baseCommit, ModifiedFiles: []string{"test.txt"}, 14 unmodified lines
}
// Create second checkpoint (has code changes, won't be filtered) _, err = store.WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ _, err = store.Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: baseCommit, ModifiedFiles: []string{"test.txt"}, 100 unmodified lines
t.Helper() metaDirAbs := filepath.Join(tmpDir, ".entire", "metadata", sessionID) // Baseline if _, err := store.WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ if _, err := store.Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: baseCommit, WorktreeID: worktreeID, ModifiedFiles: []string{"test.txt"}, MetadataDir: ".entire/metadata/" + sessionID, MetadataDirAbs: metaDirAbs, CommitMessage: "baseline", AuthorName: "Test", 5 unmodified lines
if err := os.WriteFile(testFile, []byte(sessionID+" changes"), 0o644); err != nil { t.Fatalf("failed to modify test file: %v", err) } if _, err := store.WriteTemporary(context.Background(), checkpoint.WriteEphemeralOptions{ if _, err := store.Write(context.Background(), checkpoint.WriteCheckpoint{ SessionID: sessionID, BaseCommit: baseCommit, WorktreeID: worktreeID, ModifiedFiles: []string{"test.txt"}, MetadataDir: ".entire/metadata/" + sessionID, MetadataDirAbs: metaDirAbs, CommitMessage: "code changes", AuthorName: "Test",