Add git-refs per-checkpoint checkpoint backend · Entire

Add git-refs per-checkpoint checkpoint backend

878ac88·

Soph·2w ago·11 files·+1,143 added/-14 removed

Second slice of #1471: a git-backed store that keeps one commit per refs/entire/checkpoints// (tree root = checkpoint contents), sharing the treeWriter subtree core with the git-branch store.

- refs_store.go: gitRefsStore implements PersistentStore over per-checkpoint refs (orphan-then-parented history, stamps refs-v1, no Vercel merge, List enumerates local refs, optional AuthorReader). Reads resolve a ref → commit tree and use shared read helpers; writes build the subtree via the embedded treeWriter. - Share the tree-read helpers: the git-branch reader's Read/ReadSession now delegate to readSummaryFromCheckpointTree / readSession*FromTree free functions (no behavior change) so both backends read the same way, just navigating to the tree differently. - registry: BackendTypeGitRefs ("git-refs") registered built-in with gitBacked:true + gitRefsBackendFactory; OpenEnv/OpenOptions gain RefFetcher; PrimaryIsRefs helper. - pushqueue.go: flock-protected JSONL push-discovery queue in the git common dir (Enqueue/Drain/Remove); gitRefsStore.setRef enqueues best-effort. (Pre-push consumption lands in the next commit.) - CheckpointVersionRefsV1 = "refs-v1".

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

Sessions

a4baf5553823View transcript

Changes

11

// CheckpointVersionBranchV1 identifies the branch-backed checkpoint metadata format. const CheckpointVersionBranchV1 = "branch-v1"

// CheckpointVersionRefsV1 identifies the per-checkpoint-ref checkpoint metadata // format (one ref per checkpoint at refs/entire/checkpoints//). The // value follows the -v convention (cf. branch-v1) so // checkpointpolicy.ParseFormat parses it. const CheckpointVersionRefsV1 = "refs-v1"

// CheckpointVersionBranchV1 identifies the branch-backed checkpoint metadata format. const CheckpointVersionBranchV1 = apicheckpoint.CheckpointVersionBranchV1

// CheckpointVersionRefsV1 identifies the per-checkpoint-ref checkpoint metadata format. const CheckpointVersionRefsV1 = apicheckpoint.CheckpointVersionRefsV1

// Sentinel errors (re-exported so errors.Is keeps working across packages). var ( ErrCheckpointNotFound = apicheckpoint.ErrCheckpointNotFound )

// BlobFetchFunc fetches missing blob objects by hash from a remote. type BlobFetchFunc func(ctx context.Context, hashes []plumbing.Hash) error

// RefFetchFunc fetches a single checkpoint ref from the remote into the local // ref of the same name. The git-refs store uses it to resolve a checkpoint ref // that is not present locally (e.g. written on another machine). The checkpoint // package cannot resolve the remote target itself, so the CLI layer injects it. type RefFetchFunc func(ctx context.Context, ref plumbing.ReferenceName) error

// FetchingTree wraps a git tree to automatically fetch missing blobs on demand. // After a treeless fetch (--filter=blob:none), tree objects are available locally // but blob objects are not. Each File() call checks whether the target blob

// fetching off. BlobFetcher BlobFetchFunc

// RefFetcher is the CLI-level on-demand checkpoint-ref fetcher, used by the // git-refs backend to resolve a checkpoint ref missing locally. nil leaves // reads local-only; ignored by the git-branch backend. RefFetcher RefFetchFunc

// Refs overrides the default committed-ref topology. A non-nil value wins, // e.g. attach pins reads to Primary via PrimaryAsRead(). Refs *PersistentRefs }

// PrimaryIsRefs reports whether the configured primary backend is the git-refs // per-checkpoint store. It centralizes the topology check so push/pre-push code // does not compare backend-type strings itself. A nil config (default) is the // git-branch backend, so this returns false. func PrimaryIsRefs(cfg *settings.CheckpointsConfig) bool { return cfg != nil && cfg.Primary.Type == BackendTypeGitRefs }

// Stores is the facade returned by Open: the persistent store plus the git-only // ephemeral (shadow-branch) capability and resolved committed-ref topology. type Stores struct {

// default git-branch backend with no mirrors, preserving default behavior. func Open(ctx context.Context, repo *git.Repository, opts OpenOptions) (*Stores, error) { refs := resolveOpenRefs(ctx, opts) env := OpenEnv{Repo: repo, BlobFetcher: opts.BlobFetcher, Refs: refs} env := OpenEnv{Repo: repo, BlobFetcher: opts.BlobFetcher, RefFetcher: opts.RefFetcher, Refs: refs}

cfg, err := settings.LoadCheckpointsConfig(ctx) if err != nil { return nil, nil //nolint:nilnil,nilerr // Checkpoint directory not found }

return readSummaryFromCheckpointTree(checkpointTree) }

// readSummaryFromCheckpointTree reads the root CheckpointSummary from a checkpoint // tree (the tree holding metadata.json plus the numbered session dirs). It is // shared by the git-branch store (which descends to /) and the // git-refs store (whose ref tree is the checkpoint tree directly). It returns // (nil, nil) when metadata.json is absent so callers normalize a missing // checkpoint to ErrCheckpointNotFound via the contract. func readSummaryFromCheckpointTree(checkpointTree *FetchingTree) (*CheckpointSummary, error) { // Read root metadata.json as CheckpointSummary (auto-fetches blob if needed) metadataFile, err := checkpointTree.File(paths.MetadataFileName) if err != nil { return nil, err } return nil, nil //nolint:nilnil,nilerr // No ref means no checkpoint exists }

func (s *GitStore) ReadSessionPrompts(ctx context.Context, checkpointID id.CheckpointID, sessionIndex int) (string, error) {

// about reading from session trees. func readSessionContentFromTree(ctx context.Context, sessionTree *FetchingTree) (*SessionContent, error) { result := &SessionContent{}

// Read session-specific metadata (auto-fetches blob if needed) }

// List enumerates local checkpoint refs and reads each root summary, sorted most // recent first. Storage-level listing is local-refs-only for now (no remote // enumeration), matching the issue's first-version scope.

// GetCheckpointAuthor returns the author of the checkpoint ref's tip commit (the // most recent writer). Returns a zero Author when the ref is absent. func (s *gitRefsStore) GetCheckpointAuthor(ctx context.Context, checkpointID id.CheckpointID) (Author, error) { if err := ctx.Err(); err != nil { return Author{}, err //nolint:wrapcheck // Propagating context cancellation } ref, err := s.repo.Reference(RefName(checkpointID), true) if err != nil { return Author{}, nil //nolint:nilerr // no ref → unknown author } commit, err := s.repo.CommitObject(ref.Hash()) if err != nil { return Author{}, nil //nolint:nilerr // unreadable → unknown author } return Author{Name: commit.Author.Name, Email: commit.Author.Email}, nil }

"