Move lead delivery and the Merge & continue hold onto the coordinator

This commit is contained in:
Ian Gulliver
2026-10-21 13:59:37 -07:00
parent 1734057293
commit 5c50fa857f
16 changed files with 270 additions and 190 deletions
+16 -69
View File
@@ -55,7 +55,11 @@ func (m *Manager) mergeToMain(ctx context.Context, l *live, raw json.RawMessage)
return "", err
}
login := sess.CreatedBy
if by := m.landingBy(l.taskID, l.id); by != "" {
by, err := m.store.LandingBy(ctx, l.taskID, l.id)
if err != nil {
return "", err
}
if by != "" {
login = by
}
user, err := m.store.GetUser(ctx, login)
@@ -187,29 +191,16 @@ func (m *Manager) MergeToMain(ctx context.Context, task api.Task, project api.Pr
unlock := m.lockDelivery(sess.Id)
defer unlock()
m.mu.Lock()
holder := m.landing[task.Id]
if holder.session == "" {
m.landing[task.Id] = landing{session: sess.Id, login: user.Login}
}
m.mu.Unlock()
if holder.session != "" {
return api.Task{}, fmt.Errorf("%w: task %s is already merging and continuing", ErrConflict, task.Id)
}
sessions, err := m.store.ListSessions(ctx, task.Id)
if err == nil {
for _, s := range sessions {
if s.Role == api.Implementer && s.State == api.AgentSessionStateRunning {
err = fmt.Errorf("%w: an agent on this task is mid-turn; merge when they're all idle", ErrConflict)
}
}
}
if err == nil {
m.clearMergeAfterReview(ctx, task.Id)
_, err = m.Send(ctx, sess.Id, "byre", landPrompt(project.DefaultBranch, title), "", "", "")
err = m.store.StartLanding(ctx, task.Id, sess.Id, user.Login)
if errors.Is(err, store.ErrStateChanged) {
return api.Task{}, fmt.Errorf("%w: %w", ErrConflict, err)
}
if err != nil {
m.endLanding(task.Id, sess.Id)
return api.Task{}, err
}
m.clearMergeAfterReview(ctx, task.Id)
_, err = m.launch(ctx, sess, task, "byre", landPrompt(project.DefaultBranch, title), "", "", nil)
if err != nil {
return api.Task{}, err
}
@@ -220,53 +211,9 @@ func (m *Manager) MergeToMain(ctx context.Context, task api.Task, project api.Pr
return m.store.GetTask(ctx, task.Id)
}
type landing struct {
session string
login string
}
func (m *Manager) heldForLanding(taskID, sessionID string) bool {
m.mu.Lock()
defer m.mu.Unlock()
holder := m.landing[taskID].session
return holder != "" && holder != sessionID
}
func (m *Manager) landingBy(taskID, sessionID string) string {
m.mu.Lock()
defer m.mu.Unlock()
if m.landing[taskID].session != sessionID {
return ""
}
return m.landing[taskID].login
}
func (m *Manager) endLanding(taskID, sessionID string) {
m.mu.Lock()
held := m.landing[taskID].session == sessionID
if held {
delete(m.landing, taskID)
}
m.mu.Unlock()
if held {
go m.releaseTeam(taskID, sessionID)
}
}
func (m *Manager) releaseTeam(taskID, landingID string) {
ctx := context.Background()
sessions, err := m.store.ListSessions(ctx, taskID)
func (m *Manager) deliverQueuedTurn(sessionID string) {
err := m.Deliver(context.Background(), sessionID)
if err != nil {
slog.Error("list sessions after merge and continue", "task", taskID, "err", err)
return
}
for _, s := range sessions {
if s.Id == landingID || s.Role != api.Implementer || s.State != api.AgentSessionStateIdle || m.interrupted(s.Id) {
continue
}
err = m.Deliver(ctx, s.Id)
if err != nil {
slog.Error("deliver after merge and continue", "session", s.Id, "err", err)
}
slog.Error("deliver queued message", "session", sessionID, "err", err)
}
}