rewind picker reads prompts via topology · Entire

rewind picker reads prompts via topology

1fe0c6e→main·

pfleidi·1mo ago·2 files·+75 added/-1 removed

Switch the picker's metadata tree read from the v1 branch to checkpoint.ResolveCommittedRefs(ctx).Read so v1.1 mode reads prompts from the mirror, matching the rewind execution path and 'entire explain'.

Adds a TDD test that places checkpoint metadata only on the mirror ref (v1 re-pointed to the initial commit) and asserts the picker still finds the prompt.

Sessions

c84c63ff0261View transcript

[?
Finish Checkpoints v1.1 Topology CoverageClaude Code·Opus 4.7[1m]·1 step](/content/gh/entireio/cli/session/a38d5b65-e04c-4025-b7ec-8f2b68cd2df5#timeline-c84c63ff0261/index.html)

Changes

2

160 unmodified lines

161
162
163
164
164
165
166
167
168

160 unmodified lines

}

// Get metadata branch tree for reading session prompts (best-effort, ignore errors)
    metadataTree, _ := GetMetadataRefTree(repo, plumbing.NewBranchReferenceName(paths.MetadataBranchName)) //nolint:errcheck // Best-effort for session prompts
    readRef := cpkg.ResolveCommittedRefs(ctx).Read
    metadataTree, _ := GetMetadataRefTree(repo, readRef) //nolint:errcheck // Best-effort for session prompts

head, err := repo.Head()
    if err != nil {

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

19 unmodified lines

20
21
22
23
24
25
26
27
28
438 unmodified lines

467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543

19 unmodified lines

"github.com/entireio/cli/redact"
    "github.com/go-git/go-git/v6"
    "github.com/go-git/go-git/v6/plumbing"
    "github.com/go-git/go-git/v6/plumbing/filemode"
    "github.com/go-git/go-git/v6/plumbing/object"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/require"
)

438 unmodified lines

}
}

// In v1.1 mode the picker must read prompt text from the topology mirror,
// not v1.
func TestShadowStrategy_GetRewindPoints_V11ReadsPromptFromMirror(t *testing.T) {
    dir := t.TempDir()
    testutil.InitRepo(t, dir)
    testutil.WriteFile(t, dir, "f.txt", "init")
    testutil.GitAdd(t, dir, "f.txt")
    testutil.GitCommit(t, dir, "init")

repo, err := git.PlainOpen(dir)
    require.NoError(t, err)

baseRef, err := repo.Head()
    require.NoError(t, err)
    baseHash := baseRef.Hash()

cpID := id.MustCheckpointID("a1b2c3d4e5f6")
    const wantPrompt = "only-on-mirror"

// Build the checkpoint commit by hand: WriteCommitted lands prompt.txt
    // under <sharded>/0/, but ReadSessionPromptFromTree reads <sharded>/prompt.txt.
    promptBlob, promptErr := checkpoint.CreateBlobFromContent(repo, []byte(wantPrompt))
    require.NoError(t, promptErr)
    summaryJSON := `{"checkpoint_id":"` + cpID.String() + `","sessions":[]}`
    summaryBlob, summaryErr := checkpoint.CreateBlobFromContent(repo, []byte(summaryJSON))
    require.NoError(t, summaryErr)
    shardedPath := cpID.Path() // "a1/b2c3d4e5f6"
    treeEntries := map[string]object.TreeEntry{
        shardedPath + "/prompt.txt": {
            Name: shardedPath + "/prompt.txt",
            Mode: filemode.Regular,
            Hash: promptBlob,
        },
        shardedPath + "/metadata.json": {
            Name: shardedPath + "/metadata.json",
            Mode: filemode.Regular,
            Hash: summaryBlob,
        },
    }
    treeHash, treeErr := checkpoint.BuildTreeFromEntries(t.Context(), repo, treeEntries)
    require.NoError(t, treeErr)
    commitHash, commitErr := checkpoint.CreateCommit(t.Context(), repo, treeHash, plumbing.ZeroHash, "checkpoint commit", "Test", "test@test.com")
    require.NoError(t, commitErr)

// Mirror carries the checkpoint; v1 points at the initial commit (no metadata).
    v1Ref := plumbing.NewBranchReferenceName(paths.MetadataBranchName)
    mirrorRef := plumbing.ReferenceName(paths.MetadataRefName)
    require.NoError(t, repo.Storer.SetReference(plumbing.NewHashReference(mirrorRef, commitHash)))
    require.NoError(t, repo.Storer.SetReference(plumbing.NewHashReference(v1Ref, baseHash)))

// HEAD trailer drives the picker's log walk.
    testutil.WriteFile(t, dir, "g.txt", "feat")
    testutil.GitAdd(t, dir, "g.txt")
    testutil.GitCommit(t, dir, "feat\n\nEntire-Checkpoint: " + cpID.String())

t.Chdir(dir)
    settingsDir := filepath.Join(dir, ".entire")
    require.NoError(t, os.MkdirAll(settingsDir, 0o755))
    require.NoError(t, os.WriteFile(
        filepath.Join(settingsDir, paths.SettingsFileName),
        []byte(`{"enabled": true, "strategy_options": {"checkpoints_version": "1.1"}}`),
        0o644,
    ))

strat := NewManualCommitStrategy()
    points, err := strat.GetRewindPoints(t.Context(), 10)
    require.NoError(t, err)
    require.Len(t, points, 1)
    assert.Equal(t, wantPrompt, points[0].SessionPrompt, "prompt must come from the mirror, not v1")
}

func TestShadowStrategy_GetSessionInfo_NoShadowBranch(t *testing.T) {
    dir := t.TempDir()
    repo, err := git.PlainInit(dir, false)