checkpoint resume: simplify picker and prefix gate · Entire
checkpoint resume: simplify picker and prefix gate
c6659c5→main·
Rely on store.List's documented newest-first ordering instead of re-sorting, move the checkpoint-prefix shape gate into the id package next to the patterns it must not drift from, reuse the existing picker cancel sentinel, and share the repeated test repo setup.
Sessions
01KX48VMKTYXYNTAGAK3B2BCQNView transcript
Changes
4
cmd/entire/cli
checkpoint/id
Mid.go+14
Mid_test.go+24
Mcheckpoint_resume.go+11/-26
Mcheckpoint_resume_test.go+15/-48
43 unmodified lines
// a loose shape, not authoritative validation).
const CheckpointPattern = `(?:` + Pattern + `|` + ulidPattern + `)`
// prefixShapeRegex matches strings shaped like a checkpoint ID or a prefix of
// one: 1-12 lowercase hex characters (legacy) or 1-26 Crockford base32
// characters (ULID). Kept next to Pattern/ulidPattern so the alphabet and
// width bounds cannot drift from the full-ID patterns above.
var prefixShapeRegex = regexp.MustCompile(`^(?:[0-9a-f]{1,12}|[0-9ABCDEFGHJKMNPQRSTVWXYZ]{1,26})$`)
// CouldBePrefix reports whether s is shaped like a checkpoint ID or a prefix
// of one. It is a cheap gate for callers deciding whether a free-form target
// could name a checkpoint before paying for a store lookup; it is not
// validation (see Validate).
func CouldBePrefix(s string) bool {
return prefixShapeRegex.MatchString(s)
}
// ShortIDLength is the standard length for truncating IDs for display purposes.
// Used for tool use IDs, session IDs, and commit hashes in logs and messages.
const ShortIDLength = 12
func TestCouldBePrefix(t *testing.T) {
t.Parallel()
tests := []struct {
input string
want bool
}{
{"abc123", true},
{"abc123def456", true},
{"01HZXW5J8KQ2M3N4P5Q6R7S8T9", true},
{"01HZXW", true},
{"HEAD", true},
{"", false},
{"abc123def4567", false},
{"feature/foo", false},
{"abcdefI", false},
{"01hzxw5j8kq2m3n4p5q6r7s8t9x", false},
}
for _, tt := range tests {
if got := CouldBePrefix(tt.input); got != tt.want {
t.Errorf("CouldBePrefix(%q) = %v, want %v", tt.input, got, tt.want)
}
}
}
func TestRecentCheckpoints_SortsNewestFirstAndCaps(t *testing.T) {
t.Parallel()
base := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
var infos []checkpoint.CheckpointInfo
for i := range 25 {
infos = append(infos, checkpoint.CheckpointInfo{
CheckpointID: id.MustCheckpointID(fmt.Sprintf("%012x", i)),
CreatedAt: base.Add(time.Duration(i) * time.Hour),
})
}
got := recentCheckpoints(infos, 20)
if len(got) != 20 {
t.Fatalf("len = %d, want 20", len(got))
}
if !got[0].CreatedAt.After(got[19].CreatedAt) {
t.Errorf("not sorted newest first: got[0]=%v got[19]=%v", got[0].CreatedAt, got[19].CreatedAt)
}
if got[0].CreatedAt != base.Add(24*time.Hour) {
t.Errorf("newest = %v, want %v", got[0].CreatedAt, base.Add(24*time.Hour))
}
}
Jaeger's test repo setup for various test cases involving checkpoints and their management is also studied thoroughly.