fix(witness,refinery): remove ZFC-violating state types
Remove Witness and Refinery structs that recorded observable state (State, PID, StartedAt, etc.) in violation of ZFC and "Discover, Don't Track" principles. Changes: - Remove Witness struct and State type alias from witness/types.go - Remove Refinery struct and State type alias from refinery/types.go - Remove deprecated run(*Refinery) method from refinery/manager.go - Update witness/types_test.go to remove tests for deleted types The managers already derive running state from tmux sessions (following the deacon pattern). The deleted types were vestigial and unused. Resolves: gt-r5pui Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -353,21 +353,6 @@ func parseTime(s string) time.Time {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
// run is deprecated - foreground mode now just prints a message.
|
|
||||||
// The Refinery agent (Claude) handles all merge processing.
|
|
||||||
// See: ZFC #5 - Move merge/conflict decisions from Go to Refinery agent
|
|
||||||
func (m *Manager) run(_ *Refinery) error { // ref unused: deprecated function
|
|
||||||
_, _ = fmt.Fprintln(m.output, "")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "╔══════════════════════════════════════════════════════════════╗")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "║ Foreground mode is deprecated. ║")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "║ ║")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "║ The Refinery agent (Claude) handles all merge decisions. ║")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "║ Use 'gt refinery start' to run in background mode. ║")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "╚══════════════════════════════════════════════════════════════╝")
|
|
||||||
_, _ = fmt.Fprintln(m.output, "")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeResult contains the result of a merge attempt.
|
// MergeResult contains the result of a merge attempt.
|
||||||
type MergeResult struct {
|
type MergeResult struct {
|
||||||
Success bool
|
Success bool
|
||||||
|
|||||||
@@ -1,49 +1,15 @@
|
|||||||
// Package refinery provides the merge queue processing agent.
|
// Package refinery provides the merge queue processing agent.
|
||||||
|
//
|
||||||
|
// ZFC-compliant: Running state is derived from tmux sessions, not stored in files.
|
||||||
|
// Merge queue is derived from beads merge-request issues.
|
||||||
package refinery
|
package refinery
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/steveyegge/gastown/internal/agent"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// State is an alias for agent.State for backwards compatibility.
|
|
||||||
type State = agent.State
|
|
||||||
|
|
||||||
// State constants - re-exported from agent package for backwards compatibility.
|
|
||||||
const (
|
|
||||||
StateStopped = agent.StateStopped
|
|
||||||
StateRunning = agent.StateRunning
|
|
||||||
StatePaused = agent.StatePaused
|
|
||||||
)
|
|
||||||
|
|
||||||
// Refinery represents a rig's merge queue processor.
|
|
||||||
type Refinery struct {
|
|
||||||
// RigName is the rig this refinery processes.
|
|
||||||
RigName string `json:"rig_name"`
|
|
||||||
|
|
||||||
// State is the current running state.
|
|
||||||
State State `json:"state"`
|
|
||||||
|
|
||||||
// PID is the process ID if running in background.
|
|
||||||
PID int `json:"pid,omitempty"`
|
|
||||||
|
|
||||||
// StartedAt is when the refinery was started.
|
|
||||||
StartedAt *time.Time `json:"started_at,omitempty"`
|
|
||||||
|
|
||||||
// CurrentMR is the merge request currently being processed.
|
|
||||||
CurrentMR *MergeRequest `json:"current_mr,omitempty"`
|
|
||||||
|
|
||||||
// PendingMRs tracks merge requests that have been submitted.
|
|
||||||
// Key is the MR ID.
|
|
||||||
PendingMRs map[string]*MergeRequest `json:"pending_mrs,omitempty"`
|
|
||||||
|
|
||||||
// LastMergeAt is when the last successful merge happened.
|
|
||||||
LastMergeAt *time.Time `json:"last_merge_at,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// MergeRequest represents a branch waiting to be merged.
|
// MergeRequest represents a branch waiting to be merged.
|
||||||
type MergeRequest struct {
|
type MergeRequest struct {
|
||||||
// ID is a unique identifier for this merge request.
|
// ID is a unique identifier for this merge request.
|
||||||
|
|||||||
@@ -1,46 +1,9 @@
|
|||||||
// Package witness provides the polecat monitoring agent.
|
// Package witness provides the polecat monitoring agent.
|
||||||
|
//
|
||||||
|
// ZFC-compliant: Running state is derived from tmux sessions, not stored in files.
|
||||||
|
// Configuration is sourced from role beads (hq-witness-role).
|
||||||
package witness
|
package witness
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/steveyegge/gastown/internal/agent"
|
|
||||||
)
|
|
||||||
|
|
||||||
// State is an alias for agent.State for backwards compatibility.
|
|
||||||
type State = agent.State
|
|
||||||
|
|
||||||
// State constants - re-exported from agent package for backwards compatibility.
|
|
||||||
const (
|
|
||||||
StateStopped = agent.StateStopped
|
|
||||||
StateRunning = agent.StateRunning
|
|
||||||
StatePaused = agent.StatePaused
|
|
||||||
)
|
|
||||||
|
|
||||||
// Witness represents a rig's polecat monitoring agent.
|
|
||||||
type Witness struct {
|
|
||||||
// RigName is the rig this witness monitors.
|
|
||||||
RigName string `json:"rig_name"`
|
|
||||||
|
|
||||||
// State is the current running state.
|
|
||||||
State State `json:"state"`
|
|
||||||
|
|
||||||
// PID is the process ID if running in background.
|
|
||||||
PID int `json:"pid,omitempty"`
|
|
||||||
|
|
||||||
// StartedAt is when the witness was started.
|
|
||||||
StartedAt *time.Time `json:"started_at,omitempty"`
|
|
||||||
|
|
||||||
// MonitoredPolecats tracks polecats being monitored.
|
|
||||||
MonitoredPolecats []string `json:"monitored_polecats,omitempty"`
|
|
||||||
|
|
||||||
// Config contains auto-spawn configuration.
|
|
||||||
Config WitnessConfig `json:"config"`
|
|
||||||
|
|
||||||
// SpawnedIssues tracks which issues have been spawned (to avoid duplicates).
|
|
||||||
SpawnedIssues []string `json:"spawned_issues,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// WitnessConfig contains configuration for the witness.
|
// WitnessConfig contains configuration for the witness.
|
||||||
type WitnessConfig struct {
|
type WitnessConfig struct {
|
||||||
// MaxWorkers is the maximum number of concurrent polecats (default: 4).
|
// MaxWorkers is the maximum number of concurrent polecats (default: 4).
|
||||||
@@ -58,5 +21,3 @@ type WitnessConfig struct {
|
|||||||
// IssuePrefix limits spawning to issues with this prefix (optional).
|
// IssuePrefix limits spawning to issues with this prefix (optional).
|
||||||
IssuePrefix string `json:"issue_prefix,omitempty"`
|
IssuePrefix string `json:"issue_prefix,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,93 +3,8 @@ package witness
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/steveyegge/gastown/internal/agent"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStateTypeAlias(t *testing.T) {
|
|
||||||
// Verify State is an alias for agent.State
|
|
||||||
var s State = agent.StateRunning
|
|
||||||
if s != agent.StateRunning {
|
|
||||||
t.Errorf("State type alias not working correctly")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestStateConstants(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
state State
|
|
||||||
parent agent.State
|
|
||||||
}{
|
|
||||||
{"StateStopped", StateStopped, agent.StateStopped},
|
|
||||||
{"StateRunning", StateRunning, agent.StateRunning},
|
|
||||||
{"StatePaused", StatePaused, agent.StatePaused},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
if tt.state != tt.parent {
|
|
||||||
t.Errorf("State constant %s = %v, want %v", tt.name, tt.state, tt.parent)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWitness_ZeroValues(t *testing.T) {
|
|
||||||
var w Witness
|
|
||||||
|
|
||||||
if w.RigName != "" {
|
|
||||||
t.Errorf("zero value Witness.RigName should be empty, got %q", w.RigName)
|
|
||||||
}
|
|
||||||
if w.State != "" {
|
|
||||||
t.Errorf("zero value Witness.State should be empty, got %q", w.State)
|
|
||||||
}
|
|
||||||
if w.PID != 0 {
|
|
||||||
t.Errorf("zero value Witness.PID should be 0, got %d", w.PID)
|
|
||||||
}
|
|
||||||
if w.StartedAt != nil {
|
|
||||||
t.Error("zero value Witness.StartedAt should be nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWitness_JSONMarshaling(t *testing.T) {
|
|
||||||
now := time.Now().Round(time.Second)
|
|
||||||
w := Witness{
|
|
||||||
RigName: "gastown",
|
|
||||||
State: StateRunning,
|
|
||||||
PID: 12345,
|
|
||||||
StartedAt: &now,
|
|
||||||
MonitoredPolecats: []string{"keeper", "valkyrie"},
|
|
||||||
Config: WitnessConfig{
|
|
||||||
MaxWorkers: 4,
|
|
||||||
SpawnDelayMs: 5000,
|
|
||||||
AutoSpawn: true,
|
|
||||||
},
|
|
||||||
SpawnedIssues: []string{"hq-abc123"},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(w)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("json.Marshal() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var unmarshaled Witness
|
|
||||||
if err := json.Unmarshal(data, &unmarshaled); err != nil {
|
|
||||||
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if unmarshaled.RigName != w.RigName {
|
|
||||||
t.Errorf("After round-trip: RigName = %q, want %q", unmarshaled.RigName, w.RigName)
|
|
||||||
}
|
|
||||||
if unmarshaled.State != w.State {
|
|
||||||
t.Errorf("After round-trip: State = %v, want %v", unmarshaled.State, w.State)
|
|
||||||
}
|
|
||||||
if unmarshaled.PID != w.PID {
|
|
||||||
t.Errorf("After round-trip: PID = %d, want %d", unmarshaled.PID, w.PID)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWitnessConfig_ZeroValues(t *testing.T) {
|
func TestWitnessConfig_ZeroValues(t *testing.T) {
|
||||||
var cfg WitnessConfig
|
var cfg WitnessConfig
|
||||||
|
|
||||||
@@ -174,57 +89,3 @@ func TestWitnessConfig_OmitEmpty(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestWitness_OmitEmpty(t *testing.T) {
|
|
||||||
w := Witness{
|
|
||||||
RigName: "gastown",
|
|
||||||
State: StateRunning,
|
|
||||||
// PID, StartedAt, MonitoredPolecats, SpawnedIssues left empty/nil
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(w)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("json.Marshal() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var raw map[string]interface{}
|
|
||||||
if err := json.Unmarshal(data, &raw); err != nil {
|
|
||||||
t.Fatalf("json.Unmarshal() to map error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty optional fields should be omitted
|
|
||||||
if _, exists := raw["pid"]; exists {
|
|
||||||
t.Error("Field 'pid' should be omitted when zero")
|
|
||||||
}
|
|
||||||
if _, exists := raw["started_at"]; exists {
|
|
||||||
t.Error("Field 'started_at' should be omitted when nil")
|
|
||||||
}
|
|
||||||
if _, exists := raw["monitored_polecats"]; exists {
|
|
||||||
t.Error("Field 'monitored_polecats' should be omitted when nil/empty")
|
|
||||||
}
|
|
||||||
if _, exists := raw["spawned_issues"]; exists {
|
|
||||||
t.Error("Field 'spawned_issues' should be omitted when nil/empty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWitness_WithMonitoredPolecats(t *testing.T) {
|
|
||||||
w := Witness{
|
|
||||||
RigName: "gastown",
|
|
||||||
State: StateRunning,
|
|
||||||
MonitoredPolecats: []string{"keeper", "valkyrie", "nux"},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(w)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("json.Marshal() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var unmarshaled Witness
|
|
||||||
if err := json.Unmarshal(data, &unmarshaled); err != nil {
|
|
||||||
t.Fatalf("json.Unmarshal() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(unmarshaled.MonitoredPolecats) != 3 {
|
|
||||||
t.Errorf("After round-trip: MonitoredPolecats length = %d, want 3", len(unmarshaled.MonitoredPolecats))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user