Skip to content

Commit 73e1584

Browse files
authored
GH-2179: Wire SubIssueMergeWaitFn in main.go and harness.go
Wire the merge-wait callback so epic sub-issues block until their PR merges before the next sub-issue starts execution. - main.go gateway mode: create MergeWaiter gated on waitForMerge config - main.go polling mode: same pattern using polling client - harness.go: immediate-success stub for both polling and gateway - parity_test.go: add HasSubIssueMergeWait to allChecks and always-true assertions
1 parent fa0e772 commit 73e1584

File tree

4 files changed

+60
-1
lines changed

4 files changed

+60
-1
lines changed

.agent/tasks/gh-2179.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# GH-2179: Wire SubIssueMergeWaitFn in main.go and harness.go
2+
3+
**Created:** 2026-04-04
4+
**Status:** Done
5+
**Parent:** GH-2177
6+
7+
## Changes
8+
9+
### `cmd/pilot/main.go`
10+
- **Gateway mode** (~line 700): After `SetOnSubIssuePRCreated`, wire `SetSubIssueMergeWait` with a `MergeWaiter` closure gated on `waitForMerge`. Uses `client` (gateway GitHub client) and splits `cfg.Adapters.GitHub.Repo` for owner/repo.
11+
- **Polling mode** (~line 2116): Same pattern after `SetOnSubIssuePRCreated`. Uses `client` (polling GitHub client) with `pollInterval`/`prTimeout` from execution config.
12+
13+
### `internal/wiring/harness.go`
14+
- Both `NewPollingHarness` and `NewGatewayHarness` wire an immediate-success stub: `func(_ context.Context, _ int) error { return nil }`
15+
16+
### `internal/wiring/parity_test.go`
17+
- Added `HasSubIssueMergeWait` to `allChecks` (18 total, was 17)
18+
- Added always-true assertion in `TestHarnessFieldsWithMinimalConfig`

cmd/pilot/main.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,21 @@ Examples:
699699
gwRunner.SetOnSubIssuePRCreated(gwAutopilotController.OnPRCreated)
700700
}
701701

702+
// Wire sub-issue merge-wait so epic sub-issues block until their PR merges (GH-2179)
703+
if waitForMerge {
704+
gwRepoParts := strings.SplitN(cfg.Adapters.GitHub.Repo, "/", 2)
705+
if len(gwRepoParts) == 2 {
706+
mergeWaiter := github.NewMergeWaiter(client, gwRepoParts[0], gwRepoParts[1], &github.MergeWaiterConfig{
707+
PollInterval: pollInterval,
708+
Timeout: prTimeout,
709+
})
710+
gwRunner.SetSubIssueMergeWait(func(ctx context.Context, prNumber int) error {
711+
_, err := mergeWaiter.WaitForMerge(ctx, prNumber)
712+
return err
713+
})
714+
}
715+
}
716+
702717
// GH-726: Wire processed issue persistence for gateway poller
703718
if gwAutopilotStateStore != nil {
704719
pollerOpts = append(pollerOpts, github.WithProcessedStore(gwAutopilotStateStore))
@@ -2097,6 +2112,21 @@ func runPollingMode(cfg *config.Config, projectPath string, replace, dashboardMo
20972112
if autopilotController != nil {
20982113
runner.SetOnSubIssuePRCreated(autopilotController.OnPRCreated)
20992114
}
2115+
2116+
// Wire sub-issue merge-wait so epic sub-issues block until their PR merges (GH-2179)
2117+
if waitForMerge && cfg.Adapters.GitHub.Repo != "" {
2118+
parts := strings.SplitN(cfg.Adapters.GitHub.Repo, "/", 2)
2119+
if len(parts) == 2 {
2120+
mergeWaiter := github.NewMergeWaiter(client, parts[0], parts[1], &github.MergeWaiterConfig{
2121+
PollInterval: pollInterval,
2122+
Timeout: prTimeout,
2123+
})
2124+
runner.SetSubIssueMergeWait(func(ctx context.Context, prNumber int) error {
2125+
_, err := mergeWaiter.WaitForMerge(ctx, prNumber)
2126+
return err
2127+
})
2128+
}
2129+
}
21002130
}
21012131

21022132
// Start stale label cleanup for default repo if enabled

internal/wiring/harness.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package wiring
55

66
import (
7+
"context"
78
"path/filepath"
89
"testing"
910

@@ -140,6 +141,9 @@ func NewPollingHarness(t *testing.T, cfg *config.Config) *Harness {
140141
// OnSubIssuePRCreated callback → autopilot
141142
h.Runner.SetOnSubIssuePRCreated(ctrl.OnPRCreated)
142143

144+
// SubIssueMergeWait — immediate success for tests (GH-2179)
145+
h.Runner.SetSubIssueMergeWait(func(_ context.Context, _ int) error { return nil })
146+
143147
return h
144148
}
145149

@@ -252,6 +256,9 @@ func NewGatewayHarness(t *testing.T, cfg *config.Config) *Harness {
252256
// OnSubIssuePRCreated callback → autopilot
253257
h.Runner.SetOnSubIssuePRCreated(ctrl.OnPRCreated)
254258

259+
// SubIssueMergeWait — immediate success for tests (GH-2179)
260+
h.Runner.SetSubIssueMergeWait(func(_ context.Context, _ int) error { return nil })
261+
255262
return h
256263
}
257264

internal/wiring/parity_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ func TestPollingGatewayParity(t *testing.T) {
5555
},
5656
}
5757

58-
// All 17 Has* accessors on Runner.
58+
// All 18 Has* accessors on Runner.
5959
type hasCheck struct {
6060
field string
6161
get func(*Harness) bool
@@ -65,6 +65,7 @@ func TestPollingGatewayParity(t *testing.T) {
6565
{"HasLogStore", func(h *Harness) bool { return h.Runner.HasLogStore() }},
6666
{"HasMonitor", func(h *Harness) bool { return h.Runner.HasMonitor() }},
6767
{"HasOnSubIssuePRCreated", func(h *Harness) bool { return h.Runner.HasOnSubIssuePRCreated() }},
68+
{"HasSubIssueMergeWait", func(h *Harness) bool { return h.Runner.HasSubIssueMergeWait() }},
6869
{"HasModelRouter", func(h *Harness) bool { return h.Runner.HasModelRouter() }},
6970
{"HasQualityCheckerFactory", func(h *Harness) bool { return h.Runner.HasQualityCheckerFactory() }},
7071
{"HasLearningLoop", func(h *Harness) bool { return h.Runner.HasLearningLoop() }},
@@ -140,6 +141,9 @@ func TestHarnessFieldsWithMinimalConfig(t *testing.T) {
140141
if !h.Runner.HasOnSubIssuePRCreated() {
141142
t.Error("HasOnSubIssuePRCreated should be true")
142143
}
144+
if !h.Runner.HasSubIssueMergeWait() {
145+
t.Error("HasSubIssueMergeWait should be true")
146+
}
143147
if !h.Runner.HasModelRouter() {
144148
t.Error("HasModelRouter should be true")
145149
}

0 commit comments

Comments
 (0)