feat(refinery): implement merge failure handling with labels and notifications

Add comprehensive failure handling for merge queue:
- Add FailureType enum with conflict, tests_fail, build_fail, flaky_test, push_fail
- Add handleFailure function that updates beads issue with labels and assignee
- Add notifyWorkerFailure for type-specific failure notifications
- Add retry logic for flaky tests (configurable via retry_flaky_tests)
- Add pushWithRetry with exponential backoff for transient push failures
- Add label support to beads UpdateOptions (AddLabels, RemoveLabels, SetLabels)

Failure actions by type:
- conflict: needs-rebase label, assign to worker
- tests_fail/build_fail: needs-fix label, assign to worker
- flaky_test: retry once, then treat as tests_fail
- push_fail: retry with backoff, needs-retry label

Closes gt-3x1.4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-19 14:48:30 -08:00
parent 8696413e09
commit 7a6f87ebb7
5 changed files with 466 additions and 78 deletions

View File

@@ -75,11 +75,14 @@ type CreateOptions struct {
// UpdateOptions specifies options for updating an issue.
type UpdateOptions struct {
Title *string
Status *string
Priority *int
Description *string
Assignee *string
Title *string
Status *string
Priority *int
Description *string
Assignee *string
AddLabels []string // Labels to add
RemoveLabels []string // Labels to remove
SetLabels []string // Labels to set (replaces all existing)
}
// SyncStatus represents the sync status of the beads repository.
@@ -277,6 +280,19 @@ func (b *Beads) Update(id string, opts UpdateOptions) error {
if opts.Assignee != nil {
args = append(args, "--assignee="+*opts.Assignee)
}
// Label operations: set-labels replaces all, otherwise use add/remove
if len(opts.SetLabels) > 0 {
for _, label := range opts.SetLabels {
args = append(args, "--set-labels="+label)
}
} else {
for _, label := range opts.AddLabels {
args = append(args, "--add-label="+label)
}
for _, label := range opts.RemoveLabels {
args = append(args, "--remove-label="+label)
}
}
_, err := b.run(args...)
return err