Harden worker federation and operator UI

This commit is contained in:
2026-07-29 13:30:55 +04:00
parent 95a96d87a5
commit 1ca9d64e89
35 changed files with 1195 additions and 581 deletions
+120
View File
@@ -21,9 +21,17 @@ type fakeAdapter struct {
boundary bool
ref string
releases int
leases int
approval struct {
called bool
grant bool
session herdr.Session
capture string
}
}
func (a *fakeAdapter) Lease(_ context.Context, _ string, worktree string) (herdr.Session, error) {
a.leases++
return herdr.Session{Harness: "h1", PaneID: "pane-1", Worktree: worktree}, nil
}
func (a *fakeAdapter) Bootstrap(context.Context, herdr.Session, string) error { return nil }
@@ -36,6 +44,13 @@ func (a *fakeAdapter) Occupancy(herdr.Session) (float64, error) { return a.occu
func (a *fakeAdapter) AtTurnBoundary(context.Context, herdr.Session) (bool, error) {
return a.boundary, nil
}
func (a *fakeAdapter) RespondApproval(_ context.Context, s herdr.Session, grant bool, capture string) error {
a.approval.called = true
a.approval.grant = grant
a.approval.session = s
a.approval.capture = capture
return nil
}
type worktrees struct{ path string }
@@ -45,6 +60,12 @@ type adapters struct{ a herdr.Adapter }
func (a adapters) Adapter(string) (herdr.Adapter, error) { return a.a, nil }
type promptFailureAdapter struct{ fakeAdapter }
func (a *promptFailureAdapter) LeasePrompt(_ context.Context, _ string, worktree, _ string) (herdr.Session, error) {
return herdr.Session{Harness: "h1", PaneID: "pane-created-before-timeout", Worktree: worktree}, errors.New("prompt delivery uncertain")
}
func run(t *testing.T, dir string, args ...string) {
t.Helper()
cmd := exec.Command("git", append([]string{"-C", dir}, args...)...)
@@ -53,6 +74,105 @@ func run(t *testing.T, dir string, args ...string) {
}
}
func TestPromptFailureRetainsLivePaneForBlockedTaskAcrossRestart(t *testing.T) {
s, err := store.Open(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := s.Append(domain.Event{ID: domain.NewID(), Type: "TaskCreated", TaskID: "blocked-live-pane", Surface: string(authz.System), Payload: mustJSON(map[string]any{
"source": "qa", "external_id": "prompt-timeout", "project": "p",
})}); err != nil {
t.Fatal(err)
}
task, ok := s.Task("blocked-live-pane")
if !ok {
t.Fatal("created task missing")
}
lease, err := s.Lease(task.ID, "h1", time.Minute)
if err != nil {
t.Fatal(err)
}
statePath := t.TempDir() + "/sessions.json"
a := &promptFailureAdapter{}
c := &orchestrator.Coordinator{Store: s, Worktrees: worktrees{path: t.TempDir()}, Adapters: adapters{a}, StatePath: statePath}
if err := c.Start(context.Background(), lease); err != nil {
t.Fatal(err)
}
if got, ok := s.Task(task.ID); !ok || got.State != domain.StateBlocked {
t.Fatalf("task state = %+v, want blocked", got)
}
if session, ok := c.Session(task.ID); !ok || session.PaneID != "pane-created-before-timeout" || session.HerdrID != "h1" {
t.Fatalf("retained session = %+v, present=%v", session, ok)
}
// A fresh coordinator must retain the mapping for a blocked task rather
// than treating it as an orphan after restart.
restarted := &orchestrator.Coordinator{Store: s, Worktrees: worktrees{path: t.TempDir()}, Adapters: adapters{a}, StatePath: statePath}
if err := restarted.Reconcile(context.Background()); err != nil {
t.Fatal(err)
}
if session, ok := restarted.Session(task.ID); !ok || session.PaneID != "pane-created-before-timeout" {
t.Fatalf("restarted session = %+v, present=%v", session, ok)
}
}
func TestRespondApprovalUsesOwningSessionAndPreservesCaptureBinding(t *testing.T) {
s, err := store.Open(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := s.Append(domain.Event{ID: domain.NewID(), Type: "TaskCreated", TaskID: "approval-task", Surface: string(authz.System), Payload: mustJSON(map[string]any{
"source": "qa", "external_id": "approval", "project": "p",
})}); err != nil {
t.Fatal(err)
}
lease, err := s.Lease("approval-task", "herdr-1", time.Minute)
if err != nil {
t.Fatal(err)
}
a := &fakeAdapter{}
c := &orchestrator.Coordinator{Store: s, Worktrees: worktrees{path: t.TempDir()}, Adapters: adapters{a}, StatePath: t.TempDir() + "/sessions.json"}
if err := c.Start(context.Background(), lease); err != nil {
t.Fatal(err)
}
const capture = "Approval required\n$ go test ./...\n[y/n]"
if err := c.RespondApproval(context.Background(), "approval-task", true, capture); err != nil {
t.Fatal(err)
}
if !a.approval.called || !a.approval.grant || a.approval.capture != capture {
t.Fatalf("approval invocation = %#v", a.approval)
}
if a.approval.session.HerdrID != "herdr-1" || a.approval.session.PaneID == "" {
t.Fatalf("approval used wrong session: %#v", a.approval.session)
}
}
func TestCoordinatorRefusesRemoteHerdrOperations(t *testing.T) {
s, err := store.Open(t.TempDir())
if err != nil {
t.Fatal(err)
}
if err := s.Append(domain.Event{ID: domain.NewID(), Type: "TaskCreated", TaskID: "remote", Surface: string(authz.System), Payload: mustJSON(map[string]any{
"source": "qa", "external_id": "remote", "project": "p",
})}); err != nil {
t.Fatal(err)
}
lease, err := s.Lease("remote", "remote", time.Minute)
if err != nil {
t.Fatal(err)
}
a := &fakeAdapter{}
c := &orchestrator.Coordinator{Store: s, Worktrees: worktrees{path: t.TempDir()}, Adapters: adapters{a}, LocalHerdr: func(id string) bool { return id == "local" }}
if err := c.Start(context.Background(), lease); err != nil {
t.Fatal(err)
}
if a.leases != 0 {
t.Fatal("remote adapter was started by coordinator")
}
if task, ok := s.Task("remote"); !ok || task.State != domain.StateBlocked {
t.Fatalf("remote task state = %#v, present=%v; want blocked", task, ok)
}
}
// TestRotationEmitsValidReleaseWithAnchorSHA guards the highest-priority spec
// defect noted in progress.md: automated rotation must emit a TaskReleased
// event that satisfies domain.ValidatePayload (handoff_ref + anchor_sha), not