feat(review): tell reviewers their time budget in the prompt · Entire
feat(review): tell reviewers their time budget in the prompt
5594b76·
peyton-alt·1w ago·4 files·+81 added/-1 removed
A reviewer that knows its deadline paces itself; one that doesn't runs
its full-depth pipeline and gets killed mid-verify with every finding
discarded — observed live: a claude-code review was ~90% done when the
timeout killed it and the run recorded nothing from those 10 minutes.
ComposeReviewPrompt now renders the effective per-reviewer timeout as a
pacing instruction. Only a positive RunConfig.ReviewerTimeout renders
(zero = unresolved, negative = disabled; inventing a default in either
case could contradict the orchestrator's real deadline), and the
multi-agent path now sets ReviewerTimeout on each per-agent RunConfig —
previously only the single-agent path carried it.
Co-Authored-By: Claude Fable 5 noreply@anthropic.com
Sessions
1013984a9665View transcript
Changes
4
cmd/entire/cli/review
Mcmd.go+1
Mcmd_test.go+6/-1
Mprompt.go+28
Mprompt_test.go+46
1205 unmodified lines
1206
1207
1208
1209
1210
1211
1212
1205 unmodified lines
CheckpointContext: checkpointContext,
ScopeContext: scopeCtx,
StartingSHA: headSHA,
ReviewerTimeout: timeout,
}, agentCfg),
})
}
Mcmd/entire/cli/review/cmd.go+1
800 unmodified lines
801
802
803
804
804
805
806
807
22 unmodified lines
830
831
832
833
834
835
836
837
838
839
840
800 unmodified lines
cmd := review.NewCommand(deps)
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
cmd.SetArgs([]string{"general", "--prompt", "Focus this run on regressions."})
cmd.SetArgs([]string{"general", "--prompt", "Focus this run on regressions.", "--timeout", "7m"})
if err := cmd.Execute(); err != nil {
t.Fatalf("unexpected error: %v", err)
}
22 unmodified lines
if tc.reviewer.got.StartingSHA == "" {
t.Fatalf("%s StartingSHA is empty", tc.name)
}
// The per-agent RunConfig must carry the effective timeout so the
// composed prompt can tell the child its deadline (time-budget hint).
if tc.reviewer.got.ReviewerTimeout != 7*time.Minute {
t.Fatalf("%s ReviewerTimeout = %v, want 7m", tc.name, tc.reviewer.got.ReviewerTimeout)
}
}
}
Mcmd/entire/cli/review/cmd_test.go+6/-1
9 unmodified lines
10
11
12
13
14
15
16
17
18
51 unmodified lines
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
9 unmodified lines
package review
import (
"fmt"
"strings"
"time"
reviewtypes "github.com/entireio/cli/cmd/entire/cli/review/types"
)
51 unmodified lines
if trimmed := strings.TrimRight(cfg.CheckpointContext, "\n\r "); trimmed != "" {
sections = append(sections, trimmed)
}
if hint := renderTimeBudgetHint(cfg.ReviewerTimeout); hint != "" {
sections = append(sections, hint)
}
return strings.Join(sections, "\n\n")
}
// renderTimeBudgetHint tells the agent its hard deadline so it can pace its
// review instead of running a full-depth pipeline and being killed mid-pass
// with all work discarded. Only a positive timeout renders: zero means the
// caller didn't resolve one, negative means timeouts are disabled, and
// inventing a default in either case could contradict the orchestrator's
// actual deadline.
func renderTimeBudgetHint(timeout time.Duration) string {
if timeout <= 0 {
return ""
}
deadline := timeout.String()
if timeout%time.Minute == 0 {
minutes := int(timeout / time.Minute)
unit := "minutes"
if minutes == 1 {
unit = "minute"
}
deadline = fmt.Sprintf("%d %s", minutes, unit)
}
return "Time budget: this review is cancelled after " + deadline +
". Pace yourself to deliver the final report comfortably within that limit — a complete report at reduced depth beats an unfinished deep pass."
}
// renderScopeContext renders the parent-computed scope enumeration. Handing
// agents the concrete commit/file lists (instead of only describing how to
// derive them) removes both the re-derivation cost at the start of every run