explain: address trail review comments (naming, test helpers, docs) · Entire

explain: address trail review comments (naming, test helpers, docs)

1d4cf22→main·

computermode·2w ago·2 files·+39 added/-36 removed

No behavior change — readability, consistency, and documentation only.

- rename meta/metaErr -> summary/summaryErr in the --generate fast-fail; checkpoint.ReadCheckpoint returns a *CheckpointSummary, not *Metadata, so summary reads truer (and matches the post-load check it replaced). Also restore the spinner doc-comment's adjacency to its startSpinner call. - document the cheap redundant metadata-only read on the non-imported --generate path; it's an acceptable tradeoff against the larger imported-path win (skipped blob prefetch + transcript load). - comment the intentional prose-vs-JSON truncation asymmetry at the prose call site (grouped view renders up to 2*limit and notes only on a real budget hit; JSON hard-caps the flat array at limit). - TestGetBranchCheckpoints_TruncationSignal now builds commits via the testutil git helpers (which set user identity + disable GPG signing) instead of raw go-git worktree commits, matching repo convention.

Sessions

c950a1e44d3cView transcript

[?
Enrich JSON Session Summary ExportClaude Code·Opus 4.8·3 steps](/content/gh/entireio/cli/session/f9a21902-da5f-4cf7-b03c-7e6064449562#timeline-c950a1e44d3c/index.html)

Changes

2

665 unmodified lines

666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
1 unmodified line

693
694
695
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
696
697
698
1701 unmodified lines

2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414

665 unmodified lines

return NewSilentError(fmt.Errorf("%w: %s matches %d checkpoints", errAmbiguousCommitPrefix, checkpointIDPrefix, len(matches)))
    
    // Fast-fail on imported checkpoints before the expensive content load.
    // --generate is read-only-rejected for imported history, so fetching
    // transcript blobs first (prefetch + ReadLatestSessionContent inside
    // loadCheckpointForExplain) is wasted work for a guaranteed rejection.
    // Imported lives in the checkpoint metadata, so a metadata-only
    // ReadCheckpoint settles it without reading any session content. On the
    // non-imported path loadCheckpointForExplain re-reads this summary, but
    // that extra metadata-only read is cheap and happens only under
    // --generate — the skipped blob prefetch + transcript load on the
    // imported path is the larger win.
    if generate {
        summary, summaryErr := checkpoint.ReadCheckpoint(ctx, lookup.store, fullCheckpointID)
        if summaryErr != nil {
            return fmt.Errorf("failed to read checkpoint: %w", summaryErr)
        }
        if summary.Imported {
            return fmt.Errorf("cannot generate a summary for imported checkpoint %s: imported history is read-only", fullCheckpointID)
        }
    }

// One spinner covers the entire data-loading pipeline: prefetch's
    // missing-blob analysis (which spawns one cat-file -e per blob and
    // can take seconds on a deep checkpoint subtree), the prefetch fetch
1 unmodified line

// reads, and getAssociatedCommits' git log walk. Stop strictly before
    // any write to w (stdout) so stderr spinner frames and stdout output
    // never interleave.
    // Fast-fail on imported checkpoints before the expensive content load.
    // --generate is read-only-rejected for imported history, so fetching
    // transcript blobs first (prefetch + ReadLatestSessionContent inside
    // loadCheckpointForExplain) is wasted work for a guaranteed rejection.
    // summary.Imported lives in the checkpoint metadata, so a metadata-only
    // ReadCheckpoint settles it without reading any session content.
    if generate {
        meta, metaErr := checkpoint.ReadCheckpoint(ctx, lookup.store, fullCheckpointID)
        if metaErr != nil {
            return fmt.Errorf("failed to read checkpoint: %w", metaErr)
        }
        if meta.Imported {
            return fmt.Errorf("cannot generate a summary for imported checkpoint %s: imported history is read-only", fullCheckpointID)
        }
    }

stopLoad := startSpinner(errW, fmt.Sprintf("Loading checkpoint %s", fullCheckpointID))

summary, content, err := loadCheckpointForExplain(ctx, lookup, fullCheckpointID)
1701 unmodified lines

// reports whether it hit its budget; we render everything it returns (it
    // already enforces the cap internally) and only surface a note when older
    // checkpoints were actually dropped.
    //
    // Note this prose view and the --json list path (runExplainListJSON)
    // truncate differently on purpose: getBranchCheckpoints budgets the live
    // and imported lists independently, so it can return up to 2*limit entries.
    // This grouped view renders them all and only notes when a budget was hit;
    // the JSON path hard-caps the flat array at limit (its array contract). So
    // e.g. 60 live + 60 imported shows 120 rows with no note here, but 100
    // entries with a note under --json. The `--limit only meaningful with
    // --json` flag help reflects that the cap is a JSON-path concept.
    points, truncated, err := getBranchCheckpoints(ctx, repo, branchCheckpointsLimit)
    if err != nil {
        // If context was cancelled (e.g. user hit Ctrl+C), exit silently

Mcmd/entire/cli/explain.go+29/-16

6528 unmodified lines

6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6535
6536
6537
6538
6539
6540
6541
6542
6543
6544
6545
6546
6547
6539
6540
6541
6542
6543
6544
5 unmodified lines

6550
6551
6552
6559
6560
6561
6562
6563
6564
6565
6553
6554
6555
6556
6557
6558

6528 unmodified lines

t.Chdir(tmpDir)

testutil.InitRepo(t, tmpDir)
testutil.WriteFile(t, tmpDir, "test.txt", "initial")
testutil.GitAdd(t, tmpDir, "test.txt")
testutil.GitCommit(t, tmpDir, "initial commit")

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

w, err := repo.Worktree()
require.NoError(t, err)

testFile := filepath.Join(tmpDir, "test.txt")
require.NoError(t, os.WriteFile(testFile, []byte("initial"), 0o644))
_, err = w.Add("test.txt")
require.NoError(t, err)
_, err = w.Commit("initial commit", &git.CommitOptions{
    Author: &object.Signature{Name: "Test", Email: "test@example.com", When: time.Now()},
})
require.NoError(t, err)

// Create 4 committed checkpoints, each its own commit carrying the trailer.
// Create 4 committed checkpoints, each on its own commit carrying the
// Entire-Checkpoint trailer. The testutil helpers configure user identity
// and disable GPG signing, matching repo convention.
store := checkpoint.NewGitStore(repo, checkpoint.DefaultV1Refs())
const total = 4
cpIDs := []string{"aa11aa11aa11", "bb22bb22bb22", "cc33cc33cc33", "dd44dd44dd44"}
5 unmodified lines

Strategy:     "manual-commit",
        Prompts:      []string{fmt.Sprintf("prompt %d", i)},
    }),
    require.NoError(t, os.WriteFile(testFile, []byte(fmt.Sprintf("change %d", i)), 0o644))
    _, err = w.Add("test.txt")
    require.NoError(t, err)
    _, err = w.Commit(trailers.FormatCheckpoint(fmt.Sprintf("checkpoint %d", i), cpID), &git.CommitOptions{
        Author: &object.Signature{Name: "Test", Email: "test@example.com", When: time.Now().Add(time.Duration(i) * time.Second)},
    })
    require.NoError(t, err)
    testutil.WriteFile(t, tmpDir, "test.txt", fmt.Sprintf("change %d", i))
    testutil.GitAdd(t, tmpDir, "test.txt")
    testutil.GitCommit(t, tmpDir, trailers.FormatCheckpoint(fmt.Sprintf("checkpoint %d", i), cpID))
}

t.Run("budget hit reports truncated and caps the slice", func(t *testing.T) {