fix: make worker handoff rotation durable
This commit is contained in:
@@ -708,6 +708,7 @@ type activityAdapter struct {
|
||||
activityErr error
|
||||
reasonAsked []string
|
||||
deadEndsSeen []continuity.DeadEnd
|
||||
observed chan struct{}
|
||||
}
|
||||
|
||||
func (a *activityAdapter) Activity(context.Context, herdr.Session) ([]herdr.ToolCall, error) {
|
||||
@@ -717,6 +718,12 @@ func (a *activityAdapter) Activity(context.Context, herdr.Session) ([]herdr.Tool
|
||||
func (a *activityAdapter) RequestHandoffReason(_ context.Context, _ herdr.Session, reason string, deadEnds []continuity.DeadEnd) error {
|
||||
a.reasonAsked = append(a.reasonAsked, reason)
|
||||
a.deadEndsSeen = deadEnds
|
||||
if a.observed != nil {
|
||||
select {
|
||||
case a.observed <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -764,7 +771,7 @@ func TestActivityTriggersRequestReasonedHandoffWithoutReleasing(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("thrash requests a reasoned handoff and does not release, via TurnDecision", func(t *testing.T) {
|
||||
a := &activityAdapter{fakeAdapter: fakeAdapter{occupancy: 0, boundary: true}, calls: thrashCalls}
|
||||
a := &activityAdapter{fakeAdapter: fakeAdapter{occupancy: 0, boundary: true}, calls: thrashCalls, observed: make(chan struct{}, 1)}
|
||||
c, st, task := newCoordinator(a)
|
||||
decision, err := c.TurnDecision(context.Background(), task.ID)
|
||||
if err != nil {
|
||||
@@ -862,13 +869,15 @@ func TestActivityTriggersRequestReasonedHandoffWithoutReleasing(t *testing.T) {
|
||||
c, st, task := newCoordinator(a)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go c.Monitor(ctx, .8, time.Millisecond)
|
||||
done := make(chan error, 1)
|
||||
go func() { done <- c.Monitor(ctx, .8, time.Millisecond) }()
|
||||
|
||||
deadline := time.Now().Add(300 * time.Millisecond)
|
||||
for time.Now().Before(deadline) && len(a.reasonAsked) == 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
select {
|
||||
case <-a.observed:
|
||||
case <-time.After(300 * time.Millisecond):
|
||||
}
|
||||
cancel()
|
||||
<-done
|
||||
if len(a.reasonAsked) == 0 || a.reasonAsked[0] != "thrash" {
|
||||
t.Fatalf("reasonAsked=%v want a thrash request from rotate()", a.reasonAsked)
|
||||
}
|
||||
@@ -959,10 +968,17 @@ func (w specWorktrees) Spec(domain.Task) (string, string, bool) { re
|
||||
type conventionsAdapter struct {
|
||||
fakeAdapter
|
||||
notifications int
|
||||
observed chan struct{}
|
||||
}
|
||||
|
||||
func (a *conventionsAdapter) NotifyConventionsChanged(context.Context, herdr.Session) error {
|
||||
a.notifications++
|
||||
if a.observed != nil {
|
||||
select {
|
||||
case a.observed <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -991,7 +1007,7 @@ func TestConventionsDriftNotifiesActiveSession(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
task := s.Tasks()[0]
|
||||
a := &conventionsAdapter{fakeAdapter: fakeAdapter{occupancy: 0}}
|
||||
a := &conventionsAdapter{fakeAdapter: fakeAdapter{occupancy: 0}, observed: make(chan struct{}, 1)}
|
||||
c := &orchestrator.Coordinator{Store: s, Worktrees: specWorktrees{wtPath: worktree, repoPath: repo}, Adapters: adapters{a}, StatePath: t.TempDir() + "/sessions.json"}
|
||||
|
||||
leaseEvt, err := s.Lease(task.ID, "h1", time.Minute)
|
||||
@@ -1003,8 +1019,8 @@ func TestConventionsDriftNotifiesActiveSession(t *testing.T) {
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
go c.Monitor(ctx, .8, time.Millisecond)
|
||||
done := make(chan error, 1)
|
||||
go func() { done <- c.Monitor(ctx, .8, time.Millisecond) }()
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
if a.notifications != 0 {
|
||||
@@ -1015,10 +1031,12 @@ func TestConventionsDriftNotifiesActiveSession(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(time.Second)
|
||||
for time.Now().Before(deadline) && a.notifications == 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
select {
|
||||
case <-a.observed:
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
cancel()
|
||||
<-done
|
||||
if a.notifications == 0 {
|
||||
t.Fatal("session was never notified of the conventions-doc update")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user