Harden worker federation and operator UI
This commit is contained in:
@@ -170,11 +170,15 @@ type Coordinator struct {
|
||||
Worktrees Worktrees
|
||||
Adapters Adapters
|
||||
StatePath string
|
||||
mu sync.Mutex
|
||||
sessions map[string]herdr.Session
|
||||
loaded bool
|
||||
healthMu sync.RWMutex
|
||||
health MonitorHealth
|
||||
// LocalHerdr, when set, is the coordinator's machine-ownership boundary.
|
||||
// A coordinator must never operate a pane or checkout owned by another
|
||||
// machine; federation workers own those operations locally.
|
||||
LocalHerdr func(string) bool
|
||||
mu sync.Mutex
|
||||
sessions map[string]herdr.Session
|
||||
loaded bool
|
||||
healthMu sync.RWMutex
|
||||
health MonitorHealth
|
||||
// Hard is the occupancy threshold Monitor's periodic rotate() runs
|
||||
// against, mirrored here so TurnDecision (the synchronous, per-turn
|
||||
// counterpart driven by the Face-B stop hook) evaluates the same
|
||||
@@ -300,6 +304,9 @@ func (c *Coordinator) adapterFor(taskID string, session herdr.Session) (herdr.Ad
|
||||
if id == "" {
|
||||
id = session.Harness
|
||||
}
|
||||
if c.LocalHerdr != nil && !c.LocalHerdr(id) {
|
||||
return nil, fmt.Errorf("session %s is owned by non-local herdr %s", taskID, id)
|
||||
}
|
||||
return c.Adapters.Adapter(id)
|
||||
}
|
||||
|
||||
@@ -875,31 +882,20 @@ func (c *Coordinator) Start(ctx context.Context, e domain.Event) error {
|
||||
if err := json.Unmarshal(e.Payload, &p); err != nil || p.HarnessID == "" {
|
||||
return fmt.Errorf("orchestrator: invalid lease")
|
||||
}
|
||||
if c.LocalHerdr != nil && !c.LocalHerdr(p.HarnessID) {
|
||||
return c.block(t, "remote herdr must be operated by its federation worker")
|
||||
}
|
||||
a, err := c.Adapters.Adapter(p.HarnessID)
|
||||
if err != nil {
|
||||
return c.block(t, "adapter: "+err.Error())
|
||||
}
|
||||
var w string
|
||||
if creator, ok := a.(herdr.WorktreeCreator); ok {
|
||||
planner, planned := c.Worktrees.(WorktreeSpec)
|
||||
if !planned {
|
||||
return c.block(t, "worktree: repository specification unavailable")
|
||||
}
|
||||
repo, root, valid := planner.Spec(t)
|
||||
if !valid {
|
||||
return c.block(t, "worktree: repository and root required")
|
||||
}
|
||||
w, err = creator.CreateWorktree(ctx, repo, root, t.ID)
|
||||
} else {
|
||||
w, err = c.Worktrees.Create(ctx, t)
|
||||
}
|
||||
// Worktrees, including immutable TASK.md, are coordinator-local state.
|
||||
// A remote herdr must be driven by its federation worker instead of being
|
||||
// asked to create an opaque checkout that this coordinator cannot validate.
|
||||
w, err := c.Worktrees.Create(ctx, t)
|
||||
if err != nil {
|
||||
return c.block(t, "worktree: "+err.Error())
|
||||
}
|
||||
// Best-effort: TASK.md only exists for worktrees this process can read
|
||||
// locally (the GitWorktrees path). A herdr-hosted worktree on a remote
|
||||
// machine (WorktreeCreator path) is the same cross-host gap named in
|
||||
// AUDIT.md's federation-fork section — not solved here.
|
||||
taskFileSHA, _ := continuity.TaskFileHash(w)
|
||||
prompt := taskLaunchPrompt(t)
|
||||
var s herdr.Session
|
||||
@@ -983,7 +979,13 @@ func (c *Coordinator) rememberSession(taskID string, s herdr.Session) error {
|
||||
}
|
||||
|
||||
func (c *Coordinator) block(t domain.Task, reason string) error {
|
||||
b, _ := json.Marshal(map[string]string{"blocker": reason})
|
||||
p := map[string]string{"blocker": reason, "pane_state": "unknown"}
|
||||
if s, ok := c.Session(t.ID); ok {
|
||||
p["pane_id"] = s.PaneID
|
||||
p["harness_id"] = s.HerdrID
|
||||
p["pane_state"] = "open"
|
||||
}
|
||||
b, _ := json.Marshal(p)
|
||||
return c.Store.Append(domain.Event{ID: domain.NewID(), Type: "TaskBlocked", TaskID: t.ID, Version: t.Version + 1, Payload: b, Surface: string(authz.System)})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user