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>
128 lines
4.6 KiB
Go
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)
|