fix(dispatch): make `dispatch --local` surface recent merged work (ENT-1188) · Entire
fix(dispatch): make dispatch --local surface recent merged work (ENT-1188)
b7fcfda→main·
alishakawaguchi·yesterday·2 files·+224 added/-21 removed
entire dispatch --local returned an empty/near-empty dispatch for everyone, while the server-side dispatch on entire.io worked. Two causes:
Branch scoping: branchLocalRevRange always used
<default>..HEAD, which is empty on an up-to-date default branch, so the reachable trailer set was empty and only checkpoints whose summary.Branch equalled the current branch survived (rare — work happens on feature branches merged into main).Stale local store (dominant): enumeration used store.List, which only sees checkpoints present in the local checkout. Recent checkpoints live in the sharded git-refs backend on the checkpoint remote and are never fetched locally (git pull only syncs refs/heads/, not refs/entire/checkpoints/), so recent windows came up empty.
Fix:
- branchLocalRevRange returns HEAD when the current branch is the default branch (nothing to exclude); the base..HEAD exclusion still applies to feature branches.
- Enumerate checkpoints reachable by commit trailer in the window, using the commit subject as the bullet (always available locally from git log) and preferring the richer local session summary only when the checkpoint is already present locally. Windowed by commit ("landed on branch") time. No per-checkpoint network fetch, so it stays fast.
Adds regression tests for the default-branch and missing-from-local-store cases.
Changes
2
cmd/entire/cli/dispatch
Mmode_local.go+107/-20
Mmode_local_test.go+117/-1
11 unmodified lines
// readLocalSummaryTitle returns the latest session's outcome (falling back to
// its intent) for use as a bullet title, or "" when no session summary is
// available.
func readLocalSummaryTitle(ctx context.Context, store checkpoint.PersistentStore, cid checkpointid.CheckpointID, summary *checkpoint.CheckpointSummary) string {
if summary == nil || len(summary.Sessions) == 0 {
return ""
}
latestIndex := len(summary.Sessions) - 1
metadata, err := store.ReadSessionMetadata(ctx, cid, latestIndex)
if err != nil || metadata == nil || metadata.Summary == nil {
return ""
}
if outcome := strings.TrimSpace(metadata.Summary.Outcome); outcome != "" {
return outcome
}
return strings.TrimSpace(metadata.Summary.Intent)
}
// reachableCheckpointIDsInRange maps each checkpoint ID referenced by a commit
// trailer in revRange (since <cutoff>) to the most recent commit time that
// references it. The commit time is the "landed on this branch" timestamp,
// used both for membership checks and to window checkpoints that are fetched
// on demand by ID (whose CheckpointSummary carries no CreatedAt of its own).
func reachableCheckpointIDsInRange(ctx context.Context, repoRoot, revRange string, since time.Time) (map[string]time.Time, error) {
cmd := exec.CommandContext(
ctx,
"git",
"--since="+since.UTC().Format(time.RFC3339),
"--grep",
"Entire-Checkpoint:",
"--format=%B%x00",
"--format=%cI%x00%B%x00%x00",
)
output, err := cmd.Output()
if err != nil {
return nil, fmt.Errorf("list HEAD checkpoint trailers: %w", err)
}
reachable := make(map[string]struct{})
for _, message := range strings.Split(string(output), "\x00") {
for _, checkpointID := range trailers.ParseAllCheckpoints(message) {
reachable[checkpointID.String()] = struct{}{}
}
}
return reachable, nil
}