fix(spawn): reject unknown harness with 400 instead of opaque 500#211
fix(spawn): reject unknown harness with 400 instead of opaque 500#211codebanditssss wants to merge 1 commit into
Conversation
An unknown --harness was only caught at the agent-registry lookup deep in Spawn, after the seed row and worktree were already created: the untyped error collapsed to INTERNAL_ERROR 500 and left a terminated orphan row. Validate the harness against the registry before any durable state is created and return a typed ErrUnknownHarness mapped to UNKNOWN_HARNESS (400). Sibling to #152 Bug 6 (unknown binary on PATH), which did not cover a harness with no registered adapter. Closes #210
Greptile SummaryFixes opaque 500s when
Confidence Score: 4/5Safe to merge; the early harness guard correctly prevents orphan rows and the 400 mapping is consistent with existing sentinel handling. The change is well-scoped and the new code paths are covered by tests. The one thing worth a second look is the unreachable late fallback in manager.go — it doesn't cause incorrect behaviour today, but it reads as if it still handles the unknown-harness case and could mislead someone who later rearranges the guard. backend/internal/session_manager/manager.go — the stale Important Files Changed
Sequence DiagramsequenceDiagram
participant CLI as ao CLI
participant Svc as session.Service
participant Mgr as session_manager.Manager
participant Reg as agents.Registry
participant DB as Store
CLI->>Svc: POST /spawn (harness: "bogus")
Svc->>Mgr: Spawn(cfg)
Mgr->>Mgr: loadProject()
Mgr->>Mgr: effectiveHarness()
Mgr->>Reg: Agent("bogus")
Reg-->>Mgr: nil, false
Mgr-->>Svc: ErrUnknownHarness (no DB write, no workspace)
Svc->>Svc: toAPIError → UNKNOWN_HARNESS
Svc-->>CLI: 400 UNKNOWN_HARNESS
Note over Mgr,DB: Before this PR: Store.CreateSession() called here,<br/>leaving an orphan row on harness miss
|
Closes #210.
Problem
ao spawn --harness <unknown>returned an opaqueINTERNAL_ERROR500. The harness was only resolved atm.agents.Agent(cfg.Harness)deep insideManager.Spawn— after the seed row, worktree, and provisioning. On a miss it returned a plain (untyped) error, sotoAPIErrorfell through to itsdefaultand the envelope collapsed it to 500. The late failure also left a terminated orphan row and a wasted worktree (the "create row before validating preconditions" pattern from #152).This is the unknown-harness-name sibling of #152 Bug 6 (unknown binary on PATH →
AGENT_BINARY_NOT_FOUND); that fix doesn't cover a harness with no registered adapter.Change
ErrUnknownHarness, mapped intoAPIError→apierr.Invalid("UNKNOWN_HARNESS", ...)(400).effectiveHarness, beforeCreateSession. No durable state is created for a doomed spawn — no orphan row, no worktree.Test
TestSpawn_RejectsUnknownHarness: returnsErrUnknownHarness, and asserts no session row, workspace, or runtime is created.TestToAPIErrorMapsWorkspaceBranchSentinels: adds theUNKNOWN_HARNESSmapping case.go build ./...and fullgo test ./...pass.--harness bogus-agentnow returnsunknown agent harness: "bogus-agent" (UNKNOWN_HARNESS)(exit 1) instead ofInternal server error; a valid--harness codexstill spawns.