Intent
Fix Registry.ReplaceByTag desyncing the mcpServerTools map on MCP-tagged tool hot-reload, which leaks tool entries and their captured mcpReg closures (keeping the *mcp.ClientManager subprocess alive) and leaves the named MCP server stuck "already connected" until runner restart.
Plan reference
Source finding
Registry.ReplaceByTag desyncs mcpServerTools map → tool entry leak and stuck "already connected" (internal/harness/registry.go:326-381). Hot-reloading an MCP-tagged tool doesn't update mcpServerTools, so a later UnregisterMCPServer for that name can't find the new entries; they and their captured mcpReg closures (which keep the *mcp.ClientManager → subprocess alive) leak forever. After one stuck run, the named MCP server becomes unusable until runner restart.
Scope
- Allowed files (test):
internal/harness/registry_mcp_test.go (extend)
- Allowed files (impl):
internal/harness/registry.go
- Dependencies: none
- Complexity: medium — Risk: medium (concurrent hot-swap of a tool while a call is in flight)
Acceptance criteria
Use slice T15 in the plan as detailed acceptance criteria. Summary:
- Failing tests written first, compile and fail on
main.
- Register an
mcp_*-tagged tool via RegisterMCPTools, then ReplaceByTag with a new handler. Assert mcpServerTools no longer contains the old entry's references and contains the new ones (or none, if the new tool isn't MCP-tagged). Then call UnregisterMCPServer(serverName); assert it removes the correct set.
- Start a slow handler, then
ReplaceByTag the same name; assert ReplaceByTag waits for the in-flight call to return (use a per-tool in-flight counter / WaitGroup) before swapping.
- Impl: per-tool
inflight sync.WaitGroup; ReplaceByTag calls tool.swapWg.Wait() on the old tool before deleting it. Recompute r.mcpServerTools in ReplaceByTag: enumerate r.tools, rebuild mcpServerTools[serverName] = set-of-tool-names from the survivors' tags.
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 tools/handlers.
- Append engineering-log entry on merge.
Intent
Fix
Registry.ReplaceByTagdesyncing themcpServerToolsmap on MCP-tagged tool hot-reload, which leaks tool entries and their capturedmcpRegclosures (keeping the*mcp.ClientManagersubprocess alive) and leaves the named MCP server stuck "already connected" until runner restart.Plan reference
docs/plans/2026-06-24-harness-reliability-plan.md— slice T15Source finding
Registry.ReplaceByTagdesyncsmcpServerToolsmap → tool entry leak and stuck "already connected" (internal/harness/registry.go:326-381). Hot-reloading an MCP-tagged tool doesn't updatemcpServerTools, so a laterUnregisterMCPServerfor that name can't find the new entries; they and their capturedmcpRegclosures (which keep the*mcp.ClientManager→ subprocess alive) leak forever. After one stuck run, the named MCP server becomes unusable until runner restart.Scope
internal/harness/registry_mcp_test.go(extend)internal/harness/registry.goAcceptance criteria
Use slice T15 in the plan as detailed acceptance criteria. Summary:
main.mcp_*-tagged tool viaRegisterMCPTools, thenReplaceByTagwith a new handler. AssertmcpServerToolsno longer contains the old entry's references and contains the new ones (or none, if the new tool isn't MCP-tagged). Then callUnregisterMCPServer(serverName); assert it removes the correct set.ReplaceByTagthe same name; assertReplaceByTagwaits for the in-flight call to return (use a per-tool in-flight counter /WaitGroup) before swapping.inflight sync.WaitGroup;ReplaceByTagcallstool.swapWg.Wait()on the old tool before deleting it. Recomputer.mcpServerToolsinReplaceByTag: enumerater.tools, rebuildmcpServerTools[serverName] = set-of-tool-namesfrom the survivors' tags.go test ./internal/harness/... -racegreen;./scripts/test-regression.shgreen.Guardrails
mainfirst.verify-and-merge.sh..context/harness-reliability/tracker.mdon pick-up and merge.