Skip to content

mcpx: takeover/upgrade/handoff unsupported on darwin; Linux-only tests break the darwin build #237

Open

Description

@dezren39

pkgs/mcpx (at 6081a86) builds and runs on aarch64-darwin, but its daemon handover features do not work there, and the test suite fails without exclusions. Found while vendoring it verbatim into the nix-darwin config (dezren39 ~/.config/nix, pkgs/mcpx), where it runs as a launchd agent.

What fails on darwin

  1. internal/daemon/takeover_test.go does not compile: syscall.SOCK_CLOEXEC is Linux-only (the unixPair helper, line 24). Because handoff_conns_test.go uses unixPair, the whole internal/daemon test package fails to build.
  2. Every takeover/upgrade/handoff test fails at runtime (takeover: EOF, or the successor never takes over), across internal/daemon, internal/e2e, internal/mcpclient and internal/pool:
    • daemon: TestAnIdleConnectionSurvivesATakeoverInProcess, TestACallInFlightAtTheHandoverIsAnsweredByTheOldDaemon, TestKeepAliveCallersLoseNoCallsAcrossATakeover, TestCallsIssuedDuringATakeoverNeverFail, TestAClientLeaseSurvivesADaemonTakeover, TestHandoffRecordsTheIdentityAPoolWasMadeWith, TestRegistryHandoffKeepsTheChildAcrossTheSuccessor, TestRegistryHandoffThatIsNotCommittedRestoresTheChild
    • e2e: TestAnIdleKeepAliveConnectionSurvivesATakeover, TestACallInFlightAtATakeoverIsAnsweredAndItsConnectionMovesOn, TestKeepAliveCallersLoseNoCallsAcrossARealTakeover, TestTakeoverKeepsTheChildAndTheListener, TestTakeoverRestartsAChangedServerAndKeepsTheRest, TestTakeoverLosesNoCallsWhileAClientKeepsCalling, TestClientLeaseSurvivesDaemonTakeover, TestUpgradeKeepsTheChildAndHandsMainPIDToTheSuccessor
    • mcpclient: TestDetachedChildKeepsItsPipesAndAdoptionResumesThem, TestHandoffDoesNotSplitAFrameAcrossTheTwoProcesses, TestClientHandoffCommitsOnlyWhenActivated
    • pool: TestDetachRefusesWhileACallIsInFlight
  3. TestExecChangeRestartsThatPoolAndNoOther passes functionally (the pool restarts) but verifies the new executable via /proc/<pid>/exe, which darwin lacks.

Everything else (adapter, api, cli, config, conformance, catalog, preflight, secrets, scripting, ...) passes on darwin.

Why it matters beyond tests

mcpx upgrade relies on the successor staying in the unit's cgroup and claiming MAINPID via NOTIFY_SOCKET. launchd has neither, so on macOS the only safe deploy is a plain restart (which ends every MCP child). The nix-darwin config does that today and skips the tests above (flake.nix, mcpxDarwinSkip).

Asks

  • Make the test helpers portable (no SOCK_CLOEXEC; os.Executable/proc_pidpath instead of /proc/<pid>/exe), or build-tag the Linux-only tests.
  • Decide whether takeover is supported on darwin at all. If yes, find what breaks it (fd passing over the unix socket looks like the common factor); if not, have mcpx upgrade refuse cleanly on darwin and document a launchd story (e.g. launchctl kickstart -k with children adopted on restart).

Acceptance criteria

  • The internal/daemon test package compiles on aarch64-darwin (no unguarded Linux-only constants such as syscall.SOCK_CLOEXEC in test helpers, or darwin equivalents/build tags in their place)
  • Takeover/upgrade/handoff tests on darwin either pass, or the unsupported feature returns an explicit error and the tests skip with a stated reason — no bare takeover: EOF failures
  • The same suites still pass on Linux with no regressions
  • The fix is carried to the mcpx copy dezren39/nix consumes (cross-repo set rule — tracked from this issue, no duplicate filing)

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    source/humanFiled directly by a human
    priority/normalOrdinary priority (the default)
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 27, 2026
  2. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    Intake review

    Still live (verified this run): pkgs/mcpx/internal/daemon/takeover_test.go:24 on current main still uses syscall.SOCK_CLOEXEC in the unixPair helper, so the darwin test-compile failure stands; nothing found merged that ports the takeover/handoff suite to darwin.

    Related: dezren39/nix #366 (mcpx Go tests failing on macOS — the config-package sibling of this one; per the cross-repo set rule these darwin-mcpx items should be handled as a set, tracked from the repo where the fix lands), dezren39/nix #362 (downstream mcpx pin), code #241 (unrelated).

    Notes / risks: this is the largest item in this intake batch — the runtime failures (takeover: EOF, successor never taking over) suggest darwin differences in fd passing / listener handover, not just test portability. Effort classed l. The compile fix alone (build tags or a darwin socketpair helper) is a separable first step that at least makes the failure modes visible per-test.

    Suggested approach: first make the test packages compile on darwin (portable socketpair helper), then triage the runtime failures by subsystem (daemon, e2e, mcpclient, pool) and decide per feature: port, or explicit unsupported-error + skip with reason.

    — fleet monitor intake (repo-fleet-monitor, 2026-10-26 20:19 CDT run)

  3. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed on Nov 1, 2026
  5. 66 remaining items

  6. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    state: triaged (coverage pass)
    Coverage pass 2026-11-03: reviewed in the fleet-wide per-issue pass (drift / overlap / already-handled / stale / blockers / ordering). Verdict: still live; queued in repo-health-code-pilot as small_fix at priority 40 (priority/normal). If this is already handled at current main, the triage closes it with evidence; if it needs splitting, the triage files the split.
    Found via: coverage pass 2026-11-03

  7. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  8. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    task: 7592
    lane: code-h
    stage: handed_off
    execution_lane: opencode

    Task 7592 (small_fix: #237 — mcpx takeover/upgrade/handoff unsupported on darwin) re-claimed by lane code-h at 2026-11-03T15:00Z; execution-lane assignment returned opencode with no session bound yet. Handing off to the opencode claimant per the worker runbook — this lane does not work the task directly. Claim labels synced on #237 (work/assigned, queue/claimed, status/in-progress added; queue/queued and status/needs-triage removed).

  9. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    New evidence from the nix-side aarch64-darwin verification (dezren39/darwin-nix#471, queue task 8082):

    One-off macos-15 workflow run https://github.com/dezren39/nix/actions/runs/41657026522 built .#packages.aarch64-darwin.mcpx at mcpx pin 282064c (reached via dezren39/nix's flake.lock). Compilation passed and all mcpx test packages passed except internal/pool:

    • --- FAIL: TestHandoffCarriesExecIdentityForRelativeCommand (0.01s)
    • handoff_exec_test.go:39: detach: server "fake": child 11053: open /proc/11053/stat: no such file or directory

    Same family as the /proc/<pid>/exe case already listed here (item 3): the pool handoff exec-identity path also reads /proc/<pid>/stat, which darwin lacks — so the aarch64-darwin package build currently fails in its check phase on this test. Adding it here rather than filing a duplicate; nix#471 stays open and its re-verification is parked pending a fix here reaching the pin.

  10. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · findings

    Verdict: still live, but the compile half is done. At current main:

    • pkgs/mcpx/internal/daemon/takeover_test.go:24 no longer uses syscall.SOCK_CLOEXEC — it is only named in a comment. PR test(mcpx): darwin test-compile portability for internal/daemon (#237) #3288 ("test(mcpx): darwin test-compile portability for internal/daemon", merged 2026-11-01T03:54:46Z) added the portable helper plus exe_bytes_{darwin,linux}_test.go and scripts/darwin-compile-check.sh. So acceptance item 1 (internal/daemon test package compiles on aarch64-darwin) is satisfied.
    • Anything else in pkgs/mcpx with go:build darwin is deliberate per-platform code (config/git discovery, tty echo), not a skip.

    Remaining, ordered:

    1. /proc-based exec identity still breaks the darwin check — new evidence (2026-11-03) from mcpx: aarch64-darwin build verification still owed for the pinned mcpx-src input (from #469/#468) dezren39/darwin-nix#471 / queue task 8082: the aarch64-darwin package build fails in internal/pool with TestHandoffCarriesExecIdentityForRelativeCommand: handoff_exec_test.go:39: detach: server "fake": child 11053: open /proc/11053/stat: no such file or directory. Same family as item 3 in this issue (/proc/<pid>/exe), now also gates the nix package's checkPhase. Concrete, portable fix needed (ps/proc_pidpath/os.Executable, or build-tag the check).
    2. Support-or-refuse decision for takeover/upgrade/handoff on darwin — the issue's real ask, unchanged. mcpx upgrade still assumes cgroup MAINPID/NOTIFY_SOCKET; launchd has neither. This needs a design decision (support via fd-passing fixes, or explicit refusal + documented launchctl kickstart -k story) — it is effort/l, not a small fix.
    3. Cross-repo carry — after 1/2, update the mcpxDarwinSkip/checkPhase coupling in dezren39/nix (nix#471 tracks the verification; no duplicate filing here).

    Packet note: task 7592 arrived as small_fix with effort/l labels on the issue and triage-shaped acceptance; it was not worked as an implementation in this launch. The next execution packet should be scoped to item 1 only, with item 2 as its own decision task.

  11. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/lLarge: multi-day or open-ended; expect staged check-inskind/bugSomething isn't working (prefixed form of the classic bug label)meta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/humanFiled directly by a humantask/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions