# Recognize ULID checkpoint IDs alongside legacy hex

`4ec2c8d`→[main](/content/gh/entireio/cli/commits/main/index.html)·

Soph·2w ago·2 files·+214 added/-9 removed

The "understanding" layer for ULID checkpoint IDs: the id package now accepts,
validates, and shards both the legacy 12-char lowercase hex format and 26-char
Crockford base32 ULIDs. Purely additive — hex behavior is unchanged, and
generation still emits hex (emitting ULIDs is a separate, store-coupled change).

- ULIDPattern + ulidRegex; Kind/KindOf + CheckpointID.Kind classify legacy/ULID/
unknown.
- ShardFor: first two chars for legacy (preserves the v1 tree layout), LAST two
for ULID (leading chars are the timestamp and barely vary; the random suffix
shards evenly while the ID stays lexicographically sortable).
- CheckpointPattern = (hex\|ulid) for matching a checkpoint ID in free text (e.g.
the Entire-Checkpoint trailer). Pattern stays 12-hex — it is reused for run IDs
by investigate/provenance, which are not checkpoint IDs.
- Validate / NewCheckpointID / UnmarshalJSON accept either format (invalid only
when KindOf == KindUnknown); empty-string handling unchanged.

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

## Sessions

ab5934c248d2View transcript

## Changes

2

- cmd/entire/cli/checkpoint/id
- Mid.go+86/-9
- Mid_test.go+128

```go
// EmptyCheckpointID represents an unset or invalid checkpoint ID.
const EmptyCheckpointID CheckpointID = ""

// Pattern is the regex pattern for a valid checkpoint ID: exactly 12 lowercase hex characters.
const Pattern = `[0-9a-f]{12}`

// ULIDPattern is the regex pattern for a ULID checkpoint ID: exactly 26 Crockford
// base32 characters (digits plus uppercase A-Z excluding I, L, O, U). Future
// checkpoint IDs are expected to be ULIDs so they sort lexicographically by
// creation time.
const ULIDPattern = `[0-9ABCDEFGHJKMNPQRSTVWXYZ]{26}`

// CheckpointPattern matches a checkpoint ID in free text in either format
// (legacy 12-hex or ULID). Use this — not Pattern — when scanning text such as
// the Entire-Checkpoint commit trailer for a checkpoint ID.
const CheckpointPattern = `(?:` + Pattern + `|` + ULIDPattern + `)`

// ShortIDLength is the standard length for truncating IDs for display purposes.
const ShortIDLength = 12

// checkpointIDRegex validates the format: exactly 12 lowercase hex characters.
var checkpointIDRegex = regexp.MustCompile(`^` + Pattern + `$`)

// ulidRegex validates the ULID format: exactly 26 Crockford base32 characters.
var ulidRegex = regexp.MustCompile(`^` + ULIDPattern + `$`)

// Kind classifies a checkpoint ID by its storage format. The two valid kinds
// shard differently when stored as a git ref (see ShardFor).
type Kind int

const (
	// KindUnknown is a string matching neither the legacy hex nor the ULID format.
	KindUnknown Kind = iota
	// KindLegacy is a 12-character lowercase hex ID (the format Generate emits).
	KindLegacy
	// KindULID is a 26-character Crockford base32 ULID.
	KindULID
)

// KindOf classifies a checkpoint ID string.
func KindOf(s string) Kind {
	switch {
	case checkpointIDRegex.MatchString(s):
		return KindLegacy
	case ulidRegex.MatchString(s):
		return KindULID
	default:
		return KindUnknown
	}
}

// ShardFor returns the two-character shard for storing this ID under a
// per-checkpoint git ref (refs/entire/checkpoints/<shard>/<id>).
func (id CheckpointID) ShardFor() string {
	s := string(id)
	if len(s) < 2 {
		return s
	}
	if id.Kind() == KindULID {
		return s[len(s)-2:]
	}
	return s[:2]
}

// NewCheckpointID creates a CheckpointID from a string, validating its format.
func NewCheckpointID(s string) (CheckpointID, error) {
	if err := Validate(s); err != nil {
		return EmptyCheckpointID, err
	}
}

// Generate creates a new random 12-character hex checkpoint ID.
func Generate() (CheckpointID, error) {
	bytes := make([]byte, 6) // 6 bytes = 12 hex chars
	if _, err := rand.Read(bytes); err != nil {
	}
	return CheckpointID(hex.EncodeToString(bytes)), nil
}

// Validate checks if a string is a valid checkpoint ID format.
func Validate(s string) error {
	if !checkpointIDRegex.MatchString(s) {
		return fmt.Errorf("invalid checkpoint ID %q: must be 12 lowercase hex characters", s)
	}
	return nil
}
```
