Skip to content

Fix uds addr corruption + exercise macOS CI#480

Open
goodboy wants to merge 4 commits into
mainfrom
wkt/uds_macos_473
Open

Fix uds addr corruption + exercise macOS CI#480
goodboy wants to merge 4 commits into
mainfrom
wkt/uds_macos_473

Conversation

@goodboy

@goodboy goodboy commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Fix uds addr corruption + exercise macOS CI

Motivation

The new examples/uds_transport_actor_tree.py (PR #460) reliably
fails on macOS CI but the docs-example harness swallows the
traceback: it only re-raises captured stderr when the LAST line
contains 'Error', and a tractor root-actor crash always ends with
the strict-EG collapse note ( ^^^ this exc was collapsed from a group ^^^ ) — so every possible crash reduces to a bare assert 1 == 0 in the CI logs. Worse, UDS-on-macOS is otherwise entirely
un-exercised: the test matrix explicitly excludes the macos-latest

  • uds combo, so the (skipped) example was the only thing that ever
    touched that path.

This branch lands the diagnosis plan from GH #473: surface the real
stderr, fix the one macOS UDS bug provable from linux, and turn on
the missing CI coverage so the next macOS run either goes green or
pins any remaining crasher layer with a full traceback.


Summary of changes

  • tests.test_docs_examples: always raise with the FULL subproc
    stderr (+stdout) whenever an example exits non-zero, regardless of
    stderr shape; un-skip the uds example on macOS+CI.
  • tractor.ipc._uds: fix accept-side addr corruption on no-autobind
    platforms (macOS!) — the (str, str) match arm in
    MsgpackUDSStream.get_stream_addrs() took getpeername()
    unconditionally, which is '' on the accept side without linux's
    SO_PASSCRED-triggered autobind, corrupting every accepted conn's
    laddr/raddr to Path(''). Proven + verified via a linux sim
    (nulling SO_PASSCRED).
    • also harden the bindspace mkdir() w/ parents=True, exist_ok=True (nested custom filedirs + racing actors).
  • .github/workflows/ci.yml: drop the matrix exclude so the full
    suite runs with --tpt-proto=uds on macos-latest.
  • ai/prompt-io/: session provenance log per the NLNet generative-AI
    policy.

TODOs before landing


Future follow up

Tracked in GH #473 — its remaining checkboxes get checked off
with commit ref-links as part of landing this.

(this pr content was generated in some part by claude-code)

goodboy added 4 commits July 2, 2026 12:29
The docs-example harness only re-raises captured subproc
stderr when the LAST line contains 'Error', but a `tractor`
root-actor crash always ends stderr with the strict-EG
collapse note `( ^^^ this exc was collapsed from a group ^^^ )`
— so every possible crash is swallowed down to a bare
`assert 1 == 0`, exactly what the macOS CI leg shows for the
UDS example in GH #473.

- raise with the FULL stderr (+stdout) whenever the example
  subproc exits non-zero, regardless of stderr shape.
- keep the legacy last-line 'Error' check for zero-rc runs
  which still emit error-ish output.

First task-bullet of GH #473.

Prompt-IO: ai/prompt-io/claude/20260702T155006Z_65bf9df5_prompt_io.md

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`MsgpackUDSStream.get_stream_addrs()` matches the
`(peername, sockname)` pair by type to find the listener's
fs-path, but the `(str, str)` arm unconditionally takes
`peername`: on platforms without linux's
`SO_PASSCRED`-triggered autobind (macOS!) the accept side's
`getpeername()` is `''`, so every accepted conn gets garbage
`Path('')` laddr/raddr structs.

Proven on linux by disabling `SO_PASSCRED` (no autobind ->
same `''` shape as darwin): the `uds_transport_actor_tree.py`
example reports `listener sock file: .` pre-fix and the real
registry sockpath post-fix.

- pick the non-empty name in the `(str, str)` arm: `peername`
  on the connect side, `sockname` on the accept side; raise
  `ValueError` on an (unexpected) empty pair.
- document the linux-autobind origin of the `bytes` arms
  which the original impl noted as "unclear".
- `start_listener()`: create the bindspace dir with
  `parents=True, exist_ok=True` (nested custom `filedir`s +
  racing actors).
- example docstring: peer-pid comes via `SO_PEERCRED` on
  linux but `LOCAL_PEERPID` on macOS.

May not be the (only) macOS crasher for GH #473 — it is
non-fatal on the linux sim — but with stderr surfacing now
in place the next macOS CI run pins any remaining layer.

Prompt-IO: ai/prompt-io/claude/20260702T155006Z_65bf9df5_prompt_io.md

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
UDS-on-macOS is otherwise un-exercised: the matrix
explicitly excludes the `macos-latest` + `uds` combo, so the
`uds_transport_actor_tree.py` example (skipped on macOS CI
since PR #460) is the only thing that ever touches that
path.

- drop the matrix `exclude` so the full suite runs with
  `--tpt-proto=uds` on `macos-latest`.
- un-skip the example on macOS+CI; with example-stderr
  surfacing in place a still-red run now yields the full
  traceback GH #473 asks for instead of a bare returncode
  assert.

Task-bullets 3 + 4 of GH #473.

Prompt-IO: ai/prompt-io/claude/20260702T155006Z_65bf9df5_prompt_io.md

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Provenance entry (+ unedited raw output) for the root-cause
session behind the prior three patches, per the NLNet
generative-AI policy tracked under `ai/prompt-io/`.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Copilot AI review requested due to automatic review settings July 2, 2026 16:44
@goodboy goodboy changed the title Wkt/uds macos 473 Fix uds addr corruption + exercise macOS CI Jul 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to root-cause and harden Unix Domain Socket (UDS) transport behavior on macOS (and surface failures better in CI), including enabling the macOS+UDS CI leg and removing the previous docs-example skip.

Changes:

  • Harden UDS listener bindspace directory creation (parents=True, exist_ok=True) and fix get_stream_addrs() for “no-autobind” platforms (macOS) so empty peername/sockname doesn’t produce Path('').
  • Improve docs-example test diagnostics by surfacing stdout/stderr on non-zero exits, and un-skip the UDS transport example on macOS CI.
  • Enable UDS coverage on macOS in the GitHub Actions CI matrix; update UDS example docs to note platform-specific peer PID mechanisms.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tractor/ipc/_uds.py Makes UDS bindspace creation more robust and fixes address selection logic on macOS/no-autobind platforms.
tests/test_docs_examples.py Changes the example-run harness to surface subprocess output and removes the macOS CI skip for the UDS example.
examples/uds_transport_actor_tree.py Updates example documentation to reflect Linux vs macOS peer PID mechanisms.
.github/workflows/ci.yml Enables macOS+UDS test coverage by removing the exclude from the CI matrix.
ai/prompt-io/claude/20260702T155006Z_65bf9df5_prompt_io*.md Adds prompt-IO logs documenting the investigation and changes for GH #473.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 168 to 171
try:
if not proc.poll():
_, err = proc.communicate(timeout=timeout)
out, err = proc.communicate(timeout=timeout)

Comment on lines 172 to 176
@@ -190,9 +176,34 @@ def test_example(
proc.kill()
proc.kill()
err = e.stderr

errmsg: str = err.decode() if err else ''
# `assert 1 == 0` in CI logs.. see GH #473.
rc: int|None = proc.returncode
if rc:
outmsg: str = out.decode() if out else ''
Comment on lines +193 to +203
if rc:
outmsg: str = out.decode() if out else ''
raise Exception(
f'Example script exited with rc={rc} !?\n'
f'\n'
f'stdout:\n'
f'{outmsg}\n'
f'\n'
f'stderr:\n'
f'{errmsg}\n'
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants