Skip to content

runner: Shutdown closes scoped MCP registries of wedged runs (audit #16) #645

Description

@dennisonbertram

Intent

Make Runner.Shutdown iterate r.runs and close scoped MCP registries so a wedged run's MCP subprocesses are torn down even when execute() never reaches a terminal-cleanup path.

Plan reference

Source finding

ScopedMCP subprocesses are not killed if a run is wedged at Shutdown (runner.go:3067-3091, mcp.go:662-665). closeScopedMCP only runs from the four terminal-cleanup paths. If execute() is blocked (e.g. a deadlock, or an MCP CallTool ignoring ctx), Runner.Shutdown only cancels cancelFuncs and does not iterate r.runs to close scoped registries.

Scope

  • Allowed files (test): internal/harness/runner_shutdown_mcp_test.go (new)
  • Allowed files (impl): internal/harness/runner.go, internal/harness/scoped_mcp.go
  • Dependencies: none
  • Complexity: low — Risk: low (idempotent Close)

Acceptance criteria

Use slice T05 in the plan as detailed acceptance criteria. Summary:

  • Failing test written first, compiles and fails on main.
  • Stub a wedged scoped MCP registry whose ClientManager.Close blocks until called. Start a run, wedge its execute goroutine by injecting a tool that blocks on a channel. Call Runner.Shutdown; assert ClientManager.Close was called and the underlying MCP subprocess (a fake os/exec recording KILL via cmd.Process.Kill) was signalled.
  • Impl: closeScopedMCP is already idempotent — set state.scopedMCPRegistry = nil at the end so re-entry is a no-op. In Shutdown, snapshot state.scopedMCPRegistry for every live *runState, then _ = reg.Close(shutdownCtx) after cancelling cancelFuncs. Add defer r.closeScopedMCP(runID) inside execute() so a panic still tears down MCP.
  • go test ./internal/harness/... -race green; ./scripts/test-regression.sh green.

Guardrails

  • Strict TDD; failing regression test must compile and fail on main first.
  • Worktree flow; own branch, merge via verify-and-merge.sh.
  • Update .context/harness-reliability/tracker.md on pick-up and merge.
  • Deterministic tests only — fake MCP registry + fake exec.
  • Append engineering-log entry on merge.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpMCP server/clientreliabilityReliability and resilience concernssmallSmall effort: < 4 hourswell-specifiedIssue is clear, scoped, and ready to implement

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions