Files
gastown/internal/protocol/refinery_handlers.go
george 58207a00ec refactor(mrqueue): remove mrqueue package, use beads for MRs (gt-dqi)
Remove the mrqueue side-channel from gastown. The merge queue now uses
beads merge-request wisps exclusively, not parallel .beads/mq/*.json files.

Changes:
- Delete internal/mrqueue/ package (~830 lines removed)
- Move scoring logic to internal/refinery/score.go
- Update Refinery engineer to query beads via ReadyWithType("merge-request")
- Add MRInfo struct to replace mrqueue.MR
- Add ClaimMR/ReleaseMR methods using beads assignee field
- Update HandleMergeReady to not create duplicate queue entries
- Update gt refinery commands (claim, release, unclaimed) to use beads
- Stub out MQEventSource (no longer needed)

The Refinery now:
- Lists MRs via beads.ReadyWithType("merge-request")
- Claims via beads.Update(..., {Assignee: worker})
- Closes via beads.CloseWithReason("merged", mrID)
- Blocks on conflicts via beads.AddDependency(mrID, taskID)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 23:48:56 -08:00

128 lines
4.6 KiB
Go

package protocol
import (
"fmt"
"io"
"os"
"github.com/steveyegge/gastown/internal/mail"
)
// DefaultRefineryHandler provides the default implementation for Refinery protocol handlers.
// It receives MERGE_READY messages from the Witness and acknowledges verified work.
// Note: The Refinery now queries beads directly for merge requests (via ReadyWithType).
type DefaultRefineryHandler struct {
// Rig is the name of the rig this refinery processes.
Rig string
// WorkDir is the working directory for operations.
WorkDir string
// Router is used to send mail messages.
Router *mail.Router
// Output is where to write status messages.
Output io.Writer
}
// NewRefineryHandler creates a new DefaultRefineryHandler.
func NewRefineryHandler(rig, workDir string) *DefaultRefineryHandler {
return &DefaultRefineryHandler{
Rig: rig,
WorkDir: workDir,
Router: mail.NewRouter(workDir),
Output: os.Stdout,
}
}
// SetOutput sets the output writer for status messages.
func (h *DefaultRefineryHandler) SetOutput(w io.Writer) {
h.Output = w
}
// HandleMergeReady handles a MERGE_READY message from Witness.
// When a polecat's work is verified and ready, the Refinery acknowledges receipt.
//
// NOTE: The merge-request bead is created by `gt done`, so we no longer need
// to add to the mrqueue here. The Refinery queries beads directly for ready MRs.
func (h *DefaultRefineryHandler) HandleMergeReady(payload *MergeReadyPayload) error {
_, _ = fmt.Fprintf(h.Output, "[Refinery] MERGE_READY received for polecat %s\n", payload.Polecat)
_, _ = fmt.Fprintf(h.Output, " Branch: %s\n", payload.Branch)
_, _ = fmt.Fprintf(h.Output, " Issue: %s\n", payload.Issue)
_, _ = fmt.Fprintf(h.Output, " Verified: %s\n", payload.Verified)
// Validate required fields
if payload.Branch == "" {
return fmt.Errorf("missing branch in MERGE_READY payload")
}
if payload.Polecat == "" {
return fmt.Errorf("missing polecat in MERGE_READY payload")
}
// The merge-request bead is created by `gt done` with gt:merge-request label.
// The Refinery queries beads directly via ReadyWithType("merge-request").
// No need to add to mrqueue - that was a duplicate tracking file.
_, _ = fmt.Fprintf(h.Output, "[Refinery] ✓ Work verified - Refinery will pick up MR via beads query\n")
return nil
}
// SendMerged sends a MERGED message to the Witness.
// Called by the Refinery after successfully merging a branch.
func (h *DefaultRefineryHandler) SendMerged(polecat, branch, issue, targetBranch, mergeCommit string) error {
msg := NewMergedMessage(h.Rig, polecat, branch, issue, targetBranch, mergeCommit)
return h.Router.Send(msg)
}
// SendMergeFailed sends a MERGE_FAILED message to the Witness.
// Called by the Refinery when a merge fails.
func (h *DefaultRefineryHandler) SendMergeFailed(polecat, branch, issue, targetBranch, failureType, errorMsg string) error {
msg := NewMergeFailedMessage(h.Rig, polecat, branch, issue, targetBranch, failureType, errorMsg)
return h.Router.Send(msg)
}
// SendReworkRequest sends a REWORK_REQUEST message to the Witness.
// Called by the Refinery when a branch has conflicts.
func (h *DefaultRefineryHandler) SendReworkRequest(polecat, branch, issue, targetBranch string, conflictFiles []string) error {
msg := NewReworkRequestMessage(h.Rig, polecat, branch, issue, targetBranch, conflictFiles)
return h.Router.Send(msg)
}
// NotifyMergeOutcome is a convenience method that sends the appropriate message
// based on the merge result.
type MergeOutcome struct {
// Success indicates whether the merge was successful.
Success bool
// Conflict indicates the failure was due to conflicts (needs rebase).
Conflict bool
// FailureType categorizes the failure (e.g., "tests", "build").
FailureType string
// Error is the error message if the merge failed.
Error string
// MergeCommit is the SHA of the merge commit on success.
MergeCommit string
// ConflictFiles lists files with conflicts (if Conflict is true).
ConflictFiles []string
}
// NotifyMergeOutcome sends the appropriate protocol message based on the outcome.
func (h *DefaultRefineryHandler) NotifyMergeOutcome(polecat, branch, issue, targetBranch string, outcome MergeOutcome) error {
if outcome.Success {
return h.SendMerged(polecat, branch, issue, targetBranch, outcome.MergeCommit)
}
if outcome.Conflict {
return h.SendReworkRequest(polecat, branch, issue, targetBranch, outcome.ConflictFiles)
}
return h.SendMergeFailed(polecat, branch, issue, targetBranch, outcome.FailureType, outcome.Error)
}
// Ensure DefaultRefineryHandler implements RefineryHandler.
var _ RefineryHandler = (*DefaultRefineryHandler)(nil)