# review: match live token sessions by planned runs

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

dipree·3w ago·4 files·+191 added/-43 removed

## Sessions

aaadf42f4f2bView transcript

[?\
Checkout the hand off doc that I just added.Pi·Opus 4.8·3 steps](/content/gh/entireio/cli/session/019eca64-8c2c-7b00-90c6-3aa49738c497#timeline-aaadf42f4f2b/index.html)

## Changes

4

- cmd/entire/cli/review

- Mcmd.go+29/-7

- Mmanifest.go+78/-25

- Mmanifest_test.go+60

- Mrun_multi.go+24/-11

```
14 unmodified lines

15
16
17
18
19
20
21
11 unmodified lines

33
34
35
36
37
38
39
1170 unmodified lines

1210
1211
1212
1211
1212
1213
1214
1213
1214
1215
1216
1217
1218
1219
266 unmodified lines

1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1492
1501
1502
1503
1494
1504
1505
1506
1497
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522

14 unmodified lines

"io"
	"log/slog"
	"os"
	"slices"
	"sort"
	"strings"
	"sync"
11 unmodified lines

"github.com/entireio/cli/cmd/entire/cli/logging"
	"github.com/entireio/cli/cmd/entire/cli/paths"
	reviewtypes "github.com/entireio/cli/cmd/entire/cli/review/types"
	"github.com/entireio/cli/cmd/entire/cli/session"
	"github.com/entireio/cli/cmd/entire/cli/settings"

1170 unmodified lines

defer tuiSink.Wait()
	}

summary, waitErr := RunMulti(runCtx, reviewers, reviewtypes.RunConfig{
		EnrichAgentRun:  reviewAgentRunTokenEnricher(worktreeRoot, headSHA),
		ReviewerTimeout: timeout,
	}, sinks)

runMultiCfg := reviewtypes.RunConfig{ReviewerTimeout: timeout}
	runMultiCfg.EnrichAgentRun = reviewAgentRunTokenEnricherForRuns(worktreeRoot, headSHA, plannedAgentRunsForReviewers(reviewers, runMultiCfg))
	runMultiCfg.EnrichSummary = reviewSummaryTokenEnricher(worktreeRoot, headSHA)

summary, waitErr := RunMulti(runCtx, reviewers, runMultiCfg, sinks)
	if shouldAbortMultiReview(summary, waitErr) && runCtx.Err() == nil && ctx.Err() == nil {
		return multiReviewFailureError(waitErr)
	}

266 unmodified lines

}

func reviewAgentRunTokenEnricher(worktreeRoot, headSHA string) func(context.Context, reviewtypes.AgentRun) reviewtypes.AgentRun {
	return reviewAgentRunTokenEnricherForRuns(worktreeRoot, headSHA, nil)
}

func reviewAgentRunTokenEnricherForRuns(worktreeRoot, headSHA string, planned []reviewtypes.AgentRun) func(context.Context, reviewtypes.AgentRun) reviewtypes.AgentRun {
	var mu sync.Mutex
	usedSessions := map[string]bool{}
	claimedPlan := make([]bool, len(planned))
	planned = slices.Clone(planned)
	runStartedAt := time.Now()
	return func(ctx context.Context, run reviewtypes.AgentRun) reviewtypes.AgentRun {
		mu.Lock()
		defer mu.Unlock()
		enriched, err := hydrateReviewAgentRunTokensFromCurrentStateWithUsed(ctx, worktreeRoot, headSHA, run, agent.GetByAgentType, usedSessions)

store, err := session.NewStateStore(ctx)
		if err != nil {
			logging.Debug(ctx, "review agent token hydration skipped", slog.String("error", err.Error()))
			logging.Debug(ctx, "review agent token hydration skipped", slog.String("error", fmt.Errorf("create session state store: %w", err).Error()))
			return run
		}
		return enriched
		states, err := store.List(ctx)
		if err != nil {
			logging.Debug(ctx, "review agent token hydration skipped", slog.String("error", fmt.Errorf("list session states: %w", err).Error()))
			return run
		}

if enriched, ok, sessionID := hydrateReviewAgentRunTokensFromStatesWithPlan(ctx, worktreeRoot, headSHA, run, states, agent.GetByAgentType, planned, runStartedAt, claimedPlan); ok {
			if sessionID != "" {
				usedSessions[sessionID] = true
			}
			return enriched
		}
		return hydrateReviewAgentRunTokensFromStatesWithUsed(ctx, worktreeRoot, headSHA, run, states, agent.GetByAgentType, usedSessions)
	}
}
```

Mcmd/entire/cli/review/cmd.go+29/-7

```
250 unmodified lines

251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
254
255
256
14 unmodified lines

271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
298
336
337
338
301
302
303
339
340
341
342
343
344
345
305
306
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362

250 unmodified lines

return hydrateReviewSummaryTokensFromStates(ctx, worktreeRoot, headSHA, summary, states, lookup), nil
}

func hydrateReviewAgentRunTokensFromCurrentStateWithUsed(
	ctx context.Context,
	worktreeRoot string,
	headSHA string,
	run reviewtypes.AgentRun,
	lookup agentTypeLookup,
	usedSessions map[string]bool,
) (reviewtypes.AgentRun, error) {
	store, err := session.NewStateStore(ctx)
	if err != nil {
		return run, fmt.Errorf("create session state store: %w", err)
	}
	states, err := store.List(ctx)
	if err != nil {
		return run, fmt.Errorf("list session states: %w", err)
	}
	return hydrateReviewAgentRunTokensFromStatesWithUsed(ctx, worktreeRoot, headSHA, run, states, lookup, usedSessions), nil
}

func hydrateReviewAgentRunTokensFromStates(
	ctx context.Context,
	worktreeRoot string,
	headSHA string,
	run reviewtypes.AgentRun,
	lookup agentTypeLookup,
	usedSessions map[string]bool,
) reviewtypes.AgentRun {
	enriched, _ := hydrateReviewAgentRunTokensFromSession(ctx, run, matchReviewSessionStateWithUsed(worktreeRoot, headSHA, run, states, usedSessions), lookup)
	return enriched
}

func hydrateReviewAgentRunTokensFromStatesWithPlan(
	ctx context.Context,
	worktreeRoot string,
	headSHA string,
	run reviewtypes.AgentRun,
	states []*session.State,
	lookup agentTypeLookup,
	planned []reviewtypes.AgentRun,
	runStartedAt time.Time,
	claimedPlan []bool,
) (reviewtypes.AgentRun, bool, string) {
	idx, ok := claimReviewAgentRunPlanIndex(run, planned, claimedPlan)
	if !ok {
		return run, false, ""
	}
	if runStartedAt.IsZero() {
		runStartedAt = run.StartedAt
	}
	matched := matchSessionsToRuns(worktreeRoot, headSHA, reviewtypes.RunSummary{
		StartedAt: runStartedAt,
		AgentRuns: planned,
	}, states)
	if idx >= len(matched) {
		return run, true, ""
	}
	enriched, sessionID := hydrateReviewAgentRunTokensFromSession(ctx, run, matched[idx], lookup)
	return enriched, true, sessionID
}

func hydrateReviewAgentRunTokensFromSession(
	ctx context.Context,
	run reviewtypes.AgentRun,
	st *session.State,
	lookup agentTypeLookup,
) (reviewtypes.AgentRun, string) {
	if st == nil || st.SessionID == "" {
		return run, ""
	}
	tokens := reviewTokensFromTokenUsage(reviewTokenUsageForSession(ctx, st, lookup))
	if tokens.In == 0 && tokens.Out == 0 {
		return run, st.SessionID
	}
	run.Tokens = tokens
	return run, st.SessionID
}

func matchReviewSessionStateWithUsed(
	worktreeRoot string,
	headSHA string,
	run reviewtypes.AgentRun,
	states []*session.State,
	usedSessions map[string]bool,
) *session.State {
	if usedSessions == nil {
		usedSessions = map[string]bool{}
	}
	st := matchReviewSessionState(worktreeRoot, headSHA, run.StartedAt, agentNameForRun(run), run.Model, states, usedSessions)
	if st == nil || st.SessionID == "" {
		return run
		return st
	}
	usedSessions[st.SessionID] = true
	tokens := reviewTokensFromTokenUsage(reviewTokenUsageForSession(ctx, st, lookup))
	if tokens.In == 0 && tokens.Out == 0 {
		return run
	return st
}
}

func claimReviewAgentRunPlanIndex(run reviewtypes.AgentRun, planned []reviewtypes.AgentRun, claimed []bool) (int, bool) {
	if len(planned) == 0 || len(claimed) != len(planned) {
		return -1, false
	}
	run.Tokens = tokens
	return run
	for i, candidate := range planned {
		if claimed[i] || !sameReviewAgentRunSlot(candidate, run) {
			continue
		}
		claimed[i] = true
		return i, true
	}
	return -1, false
}

func sameReviewAgentRunSlot(a, b reviewtypes.AgentRun) bool {
	return strings.TrimSpace(a.Name) == strings.TrimSpace(b.Name) &&
		strings.TrimSpace(agentNameForRun(a)) == strings.TrimSpace(agentNameForRun(b)) &&
		strings.TrimSpace(a.Model) == strings.TrimSpace(b.Model)
}

func hydrateReviewSummaryTokensFromStates(
```

Mcmd/entire/cli/review/manifest.go+78/-25

```
889 unmodified lines

890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955

889 unmodified lines

}

func TestHydrateReviewAgentRunTokensFromStatesWithPlanClaimsExplicitBeforeDefault(t *testing.T) {
	t.Parallel()
	const (
		(sessDefault = "sess-default")
		(sessOpus    = "sess-opus")
	)
	started := time.Date(2026, 5, 7, 10, 0, 0, 0, time.UTC)
	defaultRun := reviewtypes.AgentRun{
		Name:      "claude-code",
		AgentName: "claude-code",
		StartedAt: started,
	}
	opusRun := reviewtypes.AgentRun{
		Name:      "claude-code",
		AgentName: "claude-code",
		Model:     "opus",
		StartedAt: started,
	}
	planned := []reviewtypes.AgentRun{defaultRun, opusRun}
	states := []*session.State{
		{
			SessionID:    sessDefault,
			Kind:         session.KindAgentReview,
			WorktreePath: "/repo",
			BaseCommit:   "abc123",
			StartedAt:    started.Add(time.Second),
			AgentType:    agenttypes.AgentType("Claude Code"),
			ModelName:    "claude-sonnet-4-5",
			TokenUsage:   &agent.TokenUsage{InputTokens: 20, OutputTokens: 2},
		},
		{
			SessionID:    sessOpus,
			Kind:         session.KindAgentReview,
			WorktreePath: "/repo",
			BaseCommit:   "abc123",
			StartedAt:    started.Add(2 * time.Second), // newer: a naive default match would grab this
			AgentType:    agenttypes.AgentType("Claude Code"),
			ModelName:    "claude-opus-4-1",
			TokenUsage:   &agent.TokenUsage{InputTokens: 10, OutputTokens: 1},
		},
	}

claimed := make([]bool, len(planned))
	defaultFirst, ok, sessionID := hydrateReviewAgentRunTokensFromStatesWithPlan(context.Background(), "/repo", "abc123", defaultRun, states, nil, planned, started, claimed)
	if !ok {
				t.Fatal("default run did not claim a planned slot")
	}
	if sessionID != sessDefault || defaultFirst.Tokens.In != 20 || defaultFirst.Tokens.Out != 2 {
				t.Fatalf("default run matched session %q tokens %+v, want %s tokens 20/2", sessionID, defaultFirst.Tokens, sessDefault)
	}

opusSecond, ok, sessionID := hydrateReviewAgentRunTokensFromStatesWithPlan(context.Background(), "/repo", "abc123", opusRun, states, nil, planned, started, claimed)
	if !ok {
				t.Fatal("opus run did not claim a planned slot")
	}
	if sessionID != sessOpus || opusSecond.Tokens.In != 10 || opusSecond.Tokens.Out != 1 {
				t.Fatalf("opus run matched session %q tokens %+v, want %s tokens 10/1", sessionID, opusSecond.Tokens, sessOpus)
	}
}

func TestBuildLocalReviewManifestFromSummary_DisambiguatesSameModelDifferentThinking(t *testing.T) {
	started := time.Date(2026, 5, 7, 10, 0, 0, 0, time.UTC)
	summary := reviewtypes.RunSummary{
```

Mcmd/entire/cli/review/manifest_test.go+60

```
112 unmodified lines

113
114
115
116
117
117
118
119
120
121
122
123
124
118
119
126
127
128
120
121
122
123
124
125
167 unmodified lines

293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

112 unmodified lines

return summary, nil
	}

plannedRuns := plannedAgentRunsForReviewers(reviewers, cfg)
	states := make([]*perAgentState, len(reviewers))
	for i, r := range reviewers {
		// Mirror Run's fallback: when a reviewer carries no model metadata, use
		// the run config's model so session-to-manifest matching still sees the
		// model that was actually requested.
		model := reviewerModelName(r)
		if model == "" {
			model = cfg.Model
		}
for i, run := range plannedRuns {
		states[i] = &perAgentState{
			name:      r.Name(),
			agentName: reviewerActualAgentName(r),
			model:     model,
			name:      run.Name,
			agentName: run.AgentName,
			model:     run.Model,
			startedAt: time.Now(),
		}
	}
167 unmodified lines

return summary, firstErr
}

func plannedAgentRunsForReviewers(reviewers []reviewtypes.AgentReviewer, cfg reviewtypes.RunConfig) []reviewtypes.AgentRun {
	planned := make([]reviewtypes.AgentRun, len(reviewers))
	for i, r := range reviewers {
		// Mirror Run's fallback: when a reviewer carries no model metadata, use
		// the run config's model so session-to-manifest matching still sees the
		// model that was actually requested.
		model := reviewerModelName(r)
		if model == "" {
			model = cfg.Model
		}
		planned[i] = reviewtypes.AgentRun{
			Name:      r.Name(),
			AgentName: reviewerActualAgentName(r),
			Model:     model,
		}
	}
	return planned
}

func startFailureTerminal(parentCtx, agentCtx context.Context, agentIdx int, startErr error) taggedEvent {
	return taggedEvent{agentIdx: agentIdx, terminal: &agentTerminal{
		startErr:   startErr,
