Route checkpoint reads by ID kind across git backends · Entire
Route checkpoint reads by ID kind across git backends
4a1f5fa→main·Soph·1w ago·5 files·+414 added/-11 removed
Follow-up #1 from the ULID-emission review: reads resolved only against the configured primary store, so after a git-branch⇄git-refs flip (or during coexistence) a checkpoint stored in the other backend was reported missing. Now checkpoint.Open returns a kind-routing store that resolves id-keyed reads by the checkpoint's format:
- A ULID is read from the git-refs store only — never the branch (any backend).
- A hex ID is read from the active primary first; under a git-refs primary it also falls back to the git-branch store (a hex checkpoint may still sit on the pre-migration v1 branch, or have been migrated into refs).
- List unions both backends; GetCheckpointAuthor routes the same way (AuthorReader preserved). Writes are NOT kind-routed — they stay on the configured primary (+ mirrors); the minted ID already matches the primary's format.
The router is built once in Open, reusing the primary for its kind and building the sibling read store. All the general read paths (resume, explain, attribution, blame, tokens, attach) inherit routing for free.
Tests: routing_store_test.go covers ULID→refs (incl. "a ULID never reads from the branch"), hex→branch, hex-fallback and migrated-hex-in-refs under a refs primary, List union, session-read routing, and author routing. Updated open_config_test to the new "Persistent is always the routing store" invariant.
Verified: unit + integration (390) + canary both backends (git-branch, git-refs).
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
Sessions
fe977d819cd6View transcript
Changes
5
cmd/entire/cli/checkpoint
Mopen.go+32/-1
- Mopen_config_test.go+19/-10
- Arouting_store.go+186
- Arouting_store_test.go+166
docs/architecture
- Msessions-and-checkpoints.md+11
if err != nil {
return nil, err
}
writer := newFanoutStore(primary, mirrors)
// Read routing: resolve id-keyed reads by the checkpoint's format across both
// git backends (a ULID lives in refs, a hex ID on the branch or a migrated
// ref), so a coexisting / mid-migration repo reads either format without
// reconfiguring. Writes still go through writer (configured primary + mirrors).
branchStore, refsStore, err := buildKindReadStores(ctx, env, primaryType, primary)
if err != nil {
return nil, err
}
return &Stores{
Persistent: newFanoutStore(primary, mirrors),
Persistent: newKindRoutingStore(writer, branchStore, refsStore, primaryType),
ephemeral: newEphemeralStore(repo, refs),
refs: refs,
}, nil
}
// buildKindReadStores returns the git-branch and git-refs read stores used for
// id-kind read routing, reusing the already-built primary for whichever kind it
// is and constructing the sibling. A non-branch/refs git-backed primary (not a
// real configuration today, since buildPrimary only accepts git-backed backends)
// yields both freshly built git stores.
func buildKindReadStores(ctx context.Context, env OpenEnv, primaryType string, primary PersistentStore) (branch, refs PersistentStore, err error) {
switch primaryType {
case BackendTypeGitBranch:
branch = primary
refs, err = build(ctx, env, BackendTypeGitRefs, nil)
case BackendTypeGitRefs:
refs = primary
branch, err = build(ctx, env, BackendTypeGitBranch, nil)
default:
if branch, err = build(ctx, env, BackendTypeGitBranch, nil); err == nil {
refs, err = build(ctx, env, BackendTypeGitRefs, nil)
}
}
return branch, refs, err
}
// resolvePrimaryType returns the configured primary backend type, defaulting to
// the git-branch backend when none is configured.
func resolvePrimaryType(cfg *settings.CheckpointsConfig) string {
}
// kindRoutingStore resolves id-keyed reads across the two git backends so a repo
// running git-refs and git-branch side by side (or mid-migration between them)
// can read checkpoints of BOTH formats without reconfiguring:
//
// - A ULID checkpoint only ever lives in the git-refs store, so a ULID ID is
// read from refs and NEVER from the branch (regardless of the active backend).
// - A legacy-hex ID is read from the active (configured) primary first. When the
// active primary is git-refs, it also falls back to the git-branch store,
// because a hex checkpoint may still sit on the pre-migration v1 branch. Under
// a git-branch primary the branch is authoritative for hex, so refs is not
// consulted.
// - List unions both backends (disjoint ID spaces). Writes are NOT kind-routed:
// they go to the configured primary (+ mirrors) via writer, since a new
// checkpoint's ID is already minted to match the primary's format
// (see checkpoint.GenerateCheckpointID).
type kindRoutingStore struct {
writer PersistentStore // configured primary + mirrors (fanout); handles Write
branch PersistentStore // git-branch store; serves hex reads
refs PersistentStore // git-refs store; serves ULID reads (+ hex under refs primary)
primaryType string
}
// newKindRoutingStore wraps the write fanout plus the two git read stores. It
// preserves the optional AuthorReader capability (explain relies on it) when both
// read stores provide it — the built-in git backends always do.
func newKindRoutingStore(writer, branch, refs PersistentStore, primaryType string) PersistentStore {
s := &kindRoutingStore{writer: writer, branch: branch, refs: refs, primaryType: primaryType}
if _, ok := branch.(AuthorReader); ok {
if _, ok := refs.(AuthorReader); ok {
return &kindRoutingStoreWithAuthor{kindRoutingStore: s}
}
}
return s
}