mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-10-25 14:00:40 +00:00
e776a64fcd
* chore(deps): bump libopenapi to 0.40.1; hold mcp-go at 1.1.0 (TASK-3298) Replaces dependabot #1635, which also moved mcp-go 1.1.0 -> 1.1.1. That release (upstream #977) makes StdioServer.Listen cancel every in-flight request's context when it reads stdin EOF. For `pad mcp serve` fed a piped batch, each dispatcher-backed tool call and resource read then answers `context canceled` instead of its result (measured: 3 of 4 ids failed on a build of #1635, 0 of 4 on main). - go.mod/go.sum: pb33f/libopenapi 0.38.7 -> 0.40.1 (pulls pb33f/jsonpath 0.8.2 -> 0.8.3). Identical to #1635's change minus mcp-go. - .github/dependabot.yml: ignore mcp-go 1.1.1 only, not the dependency. - internal/mcp/stdio_eof_inflight_test.go: pins the behaviour. Three tool calls and one resource read are held inside a blocking dispatcher/fetcher, stdin is closed while all four are in flight, then they are released and every id must answer successfully. Passes 3/3 on mcp-go 1.1.0 and fails 3/3 on 1.1.1 (all four ids "context canceled"), run via a scratch -modfile. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 * test(mcp): release held calls on observed EOF, not a sleep (TASK-3298) Codex round 1 ondf883744(P2): a server that serves resources/read on the read loop, as mcp-go 1.1.0 does, cannot read EOF while the held fetch blocks it, so the 300ms sleep released everything before EOF was processed. A version that kept read-loop serving but cancelled at EOF would have passed. The pin now wraps stdin in a reader that signals when the server's own read returns io.EOF. Tool calls are released only after that signal (+200ms, so a cancel-at-EOF server cancels before the release can win). The resource read is released on the same signal, or after a 1s fallback when it blocks the read loop; EOF cannot cancel it in that shape. t.Cleanup now frees held calls and both pipes on a failure path. Controls, one run each, same tree: - mcp-go 1.1.0: PASS 5/5 under -race (1.2s each: the fallback path). - mcp-go 1.1.1: FAIL 3/3 under -race, all four ids "context canceled" (0.21s: the EOF-observed path). - mutant (1.1.0 patched to cancel at EOF, read-loop serving kept): FAIL 3/3, ids 10-12 "context canceled", id 20 answered. The previous version of this test PASSED 5/5 against the same mutant. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 * test(mcp): widen the EOF settle and state the pin's two bounds (TASK-3298) Codex round 2 on5889ff62(P2): the EOF signal fires inside Read, before the server handles EOF, so the release after it is a timed settle. A cancel-at-EOF server delayed past it would pass. Nothing observable separates "EOF handled" from "server never cancels", so the ordering cannot be made exact from outside mcp-go. The settle goes from 200ms to 500ms, and the comment now states the bound: the error runs one way only, and a server that keeps in-flight calls alive can never be failed by it. The same round's table found that a server running tool calls on the read loop fails the entry gate instead of exercising EOF. The comment now names that too: it means the pin's premise changed, not that EOF cancelled. Controls under -race, same tree: mcp-go 1.1.0 PASS 3/3; 1.1.1 FAIL 3/3; the cancel-at-EOF mutant with read-loop serving FAIL 3/3. Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9 * test(mcp): assert held calls saw no cancellation, not only the responses (TASK-3298) Codex round 3 on6e1d2685(P2): once the release channel is closed, a select does not prefer an already-cancelled ctx.Done, so a handler on a cancel-at-EOF server could take the release branch and answer success. Its population answer adds a second false-pass path: a server that cancels contexts yet still returns successful responses. Both handlers now read ctx.Err() after the select, whichever branch ran, and count a cancelled return. The test asserts that count is zero, a channel the JSON-RPC responses cannot mask. The entry-gate bound in the comment now names the whole population codex gave: tool calls on the read loop, fewer than three concurrent tool workers, or requests no longer reaching the injected handlers. Controls under -race: mcp-go 1.1.0 PASS 3/3; 1.1.1 FAIL 2/2 with "4 held call(s) returned with a cancelled context"; the cancel-at-EOF mutant FAIL 2/2 with 3 (its resource read returns before EOF). Claude-Session: https://claude.ai/code/session_016PXRzXhokr61CLbbu3Txj9