Start the submission reflection loop after something can fill its map

The loop that reads merged pull requests was guarded by len(pullRequests) > 0
at a point 600 lines before the Gitea wiring that writes to that map. The
length was always zero, so the goroutine never started and a merged pull
request could never complete its task. Live on the first submission this
deployment made: PR #8 took a trusted comment and nothing moved.

Moving the block below the wiring fixes the ordering and avoids the race that
reading the map inside the tick would have introduced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVbaKucEYBjMqVeUgJUsc1
This commit is contained in:
2026-08-28 10:53:47 +04:00
parent 6ccc755999
commit 4af9880b86
+43 -39
View File
@@ -1073,45 +1073,6 @@ func main() {
}
}()
}
if len(pullRequests) > 0 {
// Submitted work is reconciled on its own loop, not behind
// Store.PreLease: an in-review task cannot be leased, so a pre-lease
// hook could never see the feedback that should make it leasable.
trust := human.Trust{
Accepted: splitList(os.Getenv("ORCHESTRA_REVIEW_ACTORS")),
Ignored: splitList(os.Getenv("ORCHESTRA_REVIEW_IGNORE_ACTORS")),
}
go func() {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for range ticker.C {
for _, t := range s.Tasks() {
if t.Submission == nil || (t.State != domain.StateInReview && t.State != domain.StateQueued) {
continue
}
source, ok := pullRequests[t.Submission.PR.Provider]
if !ok {
continue
}
project, ok := rr.Project(t.Project)
if !ok {
continue
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
state, err := source.PullRequest(ctx, t)
cancel()
if err != nil {
// Observable, and the task stays exactly where it was.
log.Printf("reflect submission %s: %v", t.ID, err)
continue
}
if _, err := operations.ReflectSubmission(s, project, t.ID, state, trust); err != nil {
log.Printf("reflect submission %s: %v", t.ID, err)
}
}
}
}()
}
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok\n")) })
mux.HandleFunc("/readyz", adminServer.Readiness)
mux.HandleFunc("/v1/providers/health", func(w http.ResponseWriter, r *http.Request) {
@@ -1718,6 +1679,49 @@ func main() {
}
}
}
// Started here, after the forge wiring above fills pullRequests. Guarding
// on the map before anything writes to it made this loop dead code: the
// length was always zero, so a merged pull request never completed its
// task, and moving the read into the tick would race the startup writes.
if len(pullRequests) > 0 {
// Submitted work is reconciled on its own loop, not behind
// Store.PreLease: an in-review task cannot be leased, so a pre-lease
// hook could never see the feedback that should make it leasable.
trust := human.Trust{
Accepted: splitList(os.Getenv("ORCHESTRA_REVIEW_ACTORS")),
Ignored: splitList(os.Getenv("ORCHESTRA_REVIEW_IGNORE_ACTORS")),
}
go func() {
ticker := time.NewTicker(time.Minute)
defer ticker.Stop()
for range ticker.C {
for _, t := range s.Tasks() {
if t.Submission == nil || (t.State != domain.StateInReview && t.State != domain.StateQueued) {
continue
}
source, ok := pullRequests[t.Submission.PR.Provider]
if !ok {
continue
}
project, ok := rr.Project(t.Project)
if !ok {
continue
}
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
state, err := source.PullRequest(ctx, t)
cancel()
if err != nil {
// Observable, and the task stays exactly where it was.
log.Printf("reflect submission %s: %v", t.ID, err)
continue
}
if _, err := operations.ReflectSubmission(s, project, t.ID, state, trust); err != nil {
log.Printf("reflect submission %s: %v", t.ID, err)
}
}
}
}()
}
// Reconciliation runs immediately before every lease, which is where
// ownership of a task begins. A configured source that cannot be read
// refuses the lease rather than letting a successor resume from an older