Cancellation tests covered distinct hard-reap, deadline and scheduler
contracts, but their names and prose blurred public boolean outcomes,
transport closure and expected timeout behavior.
Document each deterministic unit seam and race ordering, distinguish
the five-second hang ceiling from normal teardown, and rename deadline
tests around their shared request-and-ack budget.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
The implicit-runtime test verified the caller started outside Tractor
but did not prove that the target ran inside an actor or that the
private runtime was gone when the call returned.
Assert an active actor inside the shared remote target and assert the
caller has no current actor again after the one-shot call completes.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
The retained-reference regression exercised generic message pointer
behavior but lived in the one-shot actor API suite and combined an
unrelated public trampoline alias assertion.
Move the pointer regression into a focused message-layer test module
and retain the alias contract as its own `to_actor` API test.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
The context and one-shot suites duplicated cancellation file markers
and filtering of registrar-owned runtime contexts.
Move those mechanics into `tests._helpers` while retaining each
endpoint's distinct startup handshake. Also update the startup-cancel
`Channel.send()` mock to accept and forward the new `send_deadline` arg.
Caught-during: review remediation
Found-via: `/run-tests` test_cancel_during_context_startup[trio]
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
`run()` described its actor-selection kwargs as placement controls,
but they determine who owns the actor lifetime and whether an existing
actor is reused or a new one is spawned.
Use lifetime-management terminology in the parameter comments and
docstring, and identify the existing-actor handle as `portal: Portal`.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Partial normalization assigned the optional Python 3.14 placeholder
sentinel separately from its only conditional consumer.
Bind the sentinel with a walrus expression directly in the guard while
retaining the `getattr()` fallback for older Python versions.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260825T021319Z_ce430fca_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Child monitors register before their IPC handshake so cancellation
owns every started process, but the bare `None` portal arg obscured
that `Portal(chan)` replaces the provisional entry after connection.
Document that transition and name all `_register_child()` args in both
spawn backends. Replace the MP test's positional-only lambda with a
signature-accurate fake which asserts the provisional portal state.
Caught-during: review remediation
Found-via: `/run-tests` test_mp_late_registration_never_starts_process
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
The fresh reap-coordination maps still used legacy `.uid` tuples even
though process monitors and channels carry complete `Aid` identities.
This extended the legacy key format into new private state.
Key both reap maps by `Aid` and derive `.uid` only when accessing the
existing `_children` map. UUID-based `Aid` hashing lets the subactor
and decoded channel identities resolve the same synchronization state.
Update registration tests to exercise the full identity keys.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260824T233957Z_5327b25e_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
`_try_cancel_then_kill()` repeated the same child/tree debugger
predicate before and after its cancel-RPC checkpoint. Inline
duplication obscured that lock state must be sampled at both points.
Factor the predicate into a local `child_in_debug()` sampler. Use it
for initial hard-kill protection and re-run it after the await before
debugger waiting, preserving dynamic lock-state behavior. Keep it
local since one input is supervisor-owned nursery configuration.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260824T225356Z_2f86dd1a_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
`._mark_child_reaped()` previously discarded the reap-request event
without checking that its completion-event peer existed. A one-sided
entry would silently lose process-reap synchronization.
Capture both pops and assert paired presence while allowing the valid
both-absent startup-failure path. Keep an unset request valid because
backend cancellation can reap immediately after registration.
Extend graceful and failed-cancel-ack runtime tests to require all
child and reap mappings empty before `to_actor.run()` returns.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260824T223614Z_88d538e3_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
A parent-side ctx cancel timeout previously bounded only the
remote `_cancel_task` ack. Complete-frame `send_all()` shielding
could hold request publication forever when a peer stopped reading.
Compute one absolute deadline and pass it through `._run_from_ns()`
so transport publication and the ack wait consume the same timeout
budget. Add a mock-clock regression which stalls the private RPC
under a nested shield and proves the transaction returns on time.
Review: PR #481 (goodboy)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328
Prompt-IO: ai/prompt-io/opencode/20260824T222033Z_ce38cb6f_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Target validation moved to a follow-up branch, so the guide should not
claim unstable callable forms are rejected before actor startup.
Describe module-global functions and `functools.partial()` wrappers
as portable stable-address forms without promising absent enforcement.
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
A child could pass the early `.start_actor()` guard, miss the
`.cancel()` child snapshot and register afterward. Its monitor
inherited a reap request without runtime cancellation and could wait
forever.
- publish child/reap events before sampling `_cancel_called`
- make MP abort before `proc.start()` when cancellation won
- kill a Trio child opened after cancellation won registration
- reject starts begun after nursery cancellation is already visible
- add deterministic registration and MP no-start regressions
- drop the touched Trio backend's stale `get_runtime_vars` import
Prompt-IO: ai/prompt-io/opencode/20260821T040803Z_3c1bbe73_prompt_io.md
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
A cancel RPC could stall forever in complete-frame transport
shielding before the peer received it, bypassing the outer ack
timeout and blocking graceful supervision.
- thread one absolute deadline from `Portal.cancel_actor()` through
the private `Start` publication path
- force-close a partial-frame stream before releasing its send lock
- keep ordinary sends unbounded and preserve pending cancellation
- document the current `Start -> StartAck -> CancelAck` exchange and
link the dedicated `Cancel` msg follow-up in #506
- cover partial publication and the shared send/ack timeout budget
Prompt-IO: ai/prompt-io/opencode/20260821T023537Z_ae6f2ac3_prompt_io.md
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
The guides described every placement as spawn-run-reap and omitted
the trampoline allowlist required when reusing an existing actor.
- distinguish call-owned children from caller-owned portal actors
- document stable module-global target addresses and allowlists
- add the #477 feature news fragment
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
The frame-publication shield added in `88a23449` checks for
pending cancellation only after a successful write. If actor
teardown closes the stream first, `ClosedResourceError` escaped
as `TransportClosed` and could defeat the caller's cancel scope.
Check for pending cancellation on the transport-error path before
normalizing the close. Genuine stream errors retain their existing
translation when no cancellation is active.
The cancellation-first path can swap which nested debugger
intermediary renders as the immediate source vs. relay. Keep
assertions over both actor levels while accepting either valid role.
Prompt-IO: ai/prompt-io/opencode/20260820T143845Z_559fd0f1_prompt_io.md
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
The Darwin-only debugger skip in `49fc92b0` passed the raw
`CI=true` env string to `skipif`, so `pytest` evaluated `true`
as Python source and failed at setup instead of skipping the
issue #320 node.
Cast `_ci_env` through `bool()` so the marker always receives
a boolean while retaining Linux coverage.
Prompt-IO: ai/prompt-io/opencode/20260820T135125Z_9f99043b_prompt_io.md
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
The rendered guides and executable examples still taught the legacy
`ActorNursery.run_in_actor()` result-portal model even though #481
adds its blocking, linked-context replacement.
Deats,
- migrate one-shots to direct results through `to_actor.run()`
- preserve named target inputs with `functools.partial()`
- use daemon actors where reciprocal dialogs need longer lifetimes
- link the new API from core, asyncio and clustering references
- retain only explicit legacy/removal notes
Prompt-IO: ai/prompt-io/opencode/20260820T023005Z_88a23449_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Both Darwin transports still hit the nested-debugger race tracked by
one actor-specific traceback record. Linux TCP and UDS remain stable.
Keep the full nested crash-REPL assertions on Linux and skip only this
known-racy node when macOS runs under CI.
Prompt-IO: ai/prompt-io/opencode/20260820T023004Z_88a23449_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Cancellation inside `send_all()` can publish a partial frame. Closing
the actor-wide stream preserved framing but destroyed every context
on the channel and replaced primary errors with `TransportClosed`.
Deats,
- shield complete frame publication, then deliver pending
cancellation
- keep the shared channel reusable after context-local cancellation
- absorb transport closure while reporting an unshippable overrun
- cover mid-frame cancellation and failed overrun error shipment
This deliberately defers cancellation until the current frame write
resolves; channel teardown remains the fallback for broken peers.
Prompt-IO: ai/prompt-io/opencode/20260819T234824Z_557065d8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
before hard-reap can print its T-800 marker. Pexpect also replaces
`child.before` at every prompt, hiding earlier nested tracebacks from
the final assertion.
Deats,
- assert cancel-timeout escalation through `proc.kill()`
- prove context-break teardown with EOF and a dead child process
- accumulate nested debugger output across every prompt boundary
Prompt-IO: ai/prompt-io/opencode/20260819T234823Z_557065d8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Treat `runtime_kwargs` as provided whenever it is not `None`.
Previously an empty dict bypassed placement validation and was
silently ignored when `an` or `portal` selected an existing runtime.
Reject both placement modes before actor startup for empty and
configured runtime kwargs while preserving empty-dict use when
`to_actor.run()` owns its private runtime.
Caught-during: review remediation
Found-via: `/code-review` P3 option-validation finding
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260819T020757Z_b38efed7_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Pass target inputs positionally and normalize every retained
`functools.partial()` layer, including Python 3.14 Placeholder
binding. Validate the complete target signature before startup.
Route each ordinary async fn through a static `@context` endpoint
so remote results, errors and caller cancellation remain linked.
Send namespace and function components separately, then resolve
through `Actor._get_rpc_func()` so the RPC module allowlist remains
authoritative. Retain client-created `NamespacePath` refs so
`to_tuple()` does not re-import their callable.
Owned actors enable the endpoint's `__name__` directly. Keep
`to_actor.MODULE` as the importer-facing alias used by caller-owned
portals while retaining the target module's authorization boundary.
Cover all placement modes, nested partials, argument collisions,
linked cancellation, remote errors and authorization failures.
Caught-during: review remediation
Found-via: `/run-tests` portal cancellation regression
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260818T193005Z_bf06b4f8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
`Actor.start_remote_task()` registers its caller context before
sending `Start`, but only cancellation cleaned that state.
Encoding, ack timeout, malformed ack and remote authorization
errors leaked it.
Protect the complete send, acknowledgement and validation phase.
Track successful publication, make a remote cancellation attempt
only when protocol-safe and always release the local context while
preserving the original startup error.
Cover both pre-publication serialization failure and a remote
`ModuleNotExposed` rejection without damaging a reused portal.
Caught-during: review remediation
Found-via: `/run-tests` startup-failure regressions
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260818T193004Z_bf06b4f8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Cancellation after `Start` publication but before `StartAck` can
strand the caller context and leave its remote task running.
Make one shielded, bounded task-cancel request before dropping
local startup state. Keep the private `cancel_on_startup` policy
outside public target kwargs and disable it for the `_cancel_task`
RPC itself so cleanup can not recursively cancel its own startup.
Release each private helper context on exit and prove the
caller-owned actor remains reusable after controlled startup
cancellation.
Caught-during: review remediation
Found-via: `/run-tests` test_cancel_during_context_startup
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260818T193003Z_bf06b4f8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Derive the `Actor._contexts` key from each `Context` in one
idempotent `Actor._drop_context()` helper instead of reconstructing
the peer UID and CID at every teardown site.
Use the helper for caller-side context exit and preserve a strict
identity assertion when the callee-side RPC task deregisters
itself. Keep channel closure and cancellation shielding with their
existing lifecycle owners.
Caught-during: review remediation
Found-via: staged P2 lifecycle review
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260818T193002Z_bf06b4f8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
`SendStream.send_all()` can raise `trio.Cancelled` after writing an
arbitrary prefix of the four-byte length header and payload. The
peer can no longer distinguish a following msg boundary.
Close the stream under a shield before propagating cancellation so
callers can not append another msg to an indeterminate byte stream.
Caught-during: review remediation
Found-via: prospective P2 cancellation review
Review: PR #481 (opencode)
https://github.com/goodboy/tractor/pull/481#pullrequestreview-4956692120
Prompt-IO: ai/prompt-io/opencode/20260818T193001Z_bf06b4f8_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Give each `ActorNursery` child its own reap request and
completion event. Owned one-shots now wait for process joining and
bookkeeping removal before returning.
Escalate unacknowledged cancellation with `proc.kill()` after an
active debugger releases. Latch nursery-wide teardown for monitors
that finish startup late, and snapshot children before cancellation
checkpoints permit concurrent removal.
Cover immediate managed-nursery cleanup, failed cancel
acknowledgements and late monitor registration across Trio TCP/UDS
and `mp_spawn`.
Caught-during: review remediation
Found-via: `/run-tests` test_late_child_reap_registration_is_released
Review: PR #481 (copilot-pull-request-reviewer)
https://github.com/goodboy/tractor/pull/481#discussion_r3514759131
Prompt-IO: ai/prompt-io/opencode/20260818T031532Z_4151b956_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Demo both flavors of the new API in a runnable script
(auto-collected by `test_docs_examples.py`),
- the fully-implicit one-shot which boots (and tears down) the
actor-runtime around a single `to_actor.run()` call,
- the concurrent "worker-pool-ish" prime-check pattern: a local
`trio` task nursery scheduling one-shots against a shared
caller-managed `an`, mirroring (in miniature) the neighboring
`concurrent_actors_primes.py` example per issue #477.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Cover every placement variant + failure mode of the new
`to_actor.run()`,
- private-nursery one-shot + implicit runtime boot via pass-through
`runtime_kwargs`,
- remote-error relay to the caller's task (bare and inside a
caller-managed `an`) as boxed `RemoteActorError`s,
- caller-nursery spawn + portal-reuse w/o implicit reap,
- the concurrent "worker-pool-ish" pattern: a local `trio` task
nursery scheduling one-shots against a shared `an`,
- the 4 pre-spawn validation rejections (sync fn, async-gen fn,
`portal`+`an` combo, `runtime_kwargs`+placement combo).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
First cut at the `to_thread`/`to_process`-style "run it over there"
wrapper layer from issue #477: a single-remote-task invocation API
decoupled from the `ActorNursery` spawn machinery, composed purely
from the lower level daemon-actor + portal primitives,
- `to_actor.run(fn, **fn_kwargs)` spawns a subactor via
`ActorNursery.start_actor()`, schedules `fn` as its lone task
with `Portal.run()` and ALWAYS reaps it via a `finally`-scoped
`Portal.cancel_actor()` (whose bounded cancel-req wait is
internally shielded so the reap also runs under caller-scope
cancellation).
- remote errors raise directly in the caller's task as boxed
`RemoteActorError`s, moving error collection/propagation up into
whatever local `trio` scope encloses the call.
- "placement" opts: `portal=` reuses a running actor (no
spawn/reap), `an=` spawns from a caller-managed actor-nursery,
neither opens a private call-scoped `open_nursery()` (implicitly
booting the runtime, tunable via pass-through `runtime_kwargs`).
- fail-fast validation BEFORE any spawn: non-streaming async fn
only (same constraint as `Portal.run()`), `portal=`/`an=` mutual
exclusion and no `runtime_kwargs` alongside a placement opt.
Also,
- x-ref the successor API from `.run_in_actor()`'s deprecation TODO
+ docstring; emitting a formal `DeprecationWarning` waits on
migrating in-repo usage.
- log prompt-io provenance per NLNet policy incl. the driver prompt
file.
Prompt-IO: ai/prompt-io/claude/20260702T154255Z_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
Once `pformat_caller_frame()` renders successfully, the default
`_mk_send_mte()` path still fails while formatting the valid IPC
msg spec and then constructs its error message as a one-element
tuple.
Pass `MsgCodec` to `pformat_msgspec()`, keep the assembled message
a string and exercise the complete path through a printable
`MsgTypeError` regression.
Prompt-IO: ai/prompt-io/opencode/20260820T150250Z_9afda1c6_prompt_io.md
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Just drop it — `pformat_boxed_tb()` spells its knobs
`tb_box_indent`/`tb_body_indent`, and that fn's default
(1-space box indent) is what the caller wanted anyway.
Regressed-by: 888af602 (`pformat_cs()` mv into `.devx.pformat`)
Found-via: `/run-tests` test_pformat_caller_frame_renders
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
`pformat_boxed_tb()` has never accepted an `indent` kwarg but
`pformat_caller_frame(box_tb=True)` has been passing one since
`888af602`. Nothing in the suite covered the branch, so the
`TypeError` only ever surfaced from `_mk_send_mte()` — i.e.
EVERY send-side `MsgTypeError` blew up while formatting itself
and masked the real msg-spec violation behind a bogus
`TypeError`.
Red on purpose per the test-first convention; the 1-line fix
lands next.
Also pin `pformat_boxed_tb()`s signature so a future typo'd
kwarg fails loudly at the call site instead of only when some
rare error path runs.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
Bring the transport helpers back in line with project style:
- restore single-quote strings and docstrings;
- drop the oversized helper divider and simplify comments;
- keep guarded `match` dispatch so a missing `socket.AF_UNIX`
remains safe when `HAS_UDS` is false.
Also, format the `HAS_UDS` conjunction with the project's
multiline branch convention.
Review: PR #475 (goodboy)
https://github.com/goodboy/tractor/pull/475
Prompt-IO: ai/prompt-io/opencode/20260817T231825Z_359fe75c_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Job-level `continue-on-error` made setup and import-smoke failures
non-blocking even though the smoke is the hard Windows support
signal.
Move tolerance to the `pytest` step so the incomplete suite remains
informational while install, dependency, and `HAS_UDS` smoke
failures fail the job. When only the known suite fails, the job and
PR rollup remain green with the failed step still visible.
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Modern Windows Python can expose `AF_UNIX`, so `trio.has_unix`
alone can register the UDS backend even though its credential and
lifecycle paths remain POSIX-only.
Gate `HAS_UDS` on `sys.platform` and make the Windows import smoke
step assert the TCP-only capability contract.
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
`test_parent_writer_child_reader` deadlocks on Windows (the
parent/child shared-mem transfer hangs at the larger frame size),
so the `windows-latest` CI leg ran to the 16-min job cap instead
of completing. It's a genuine nascent-Windows shm bug, not a
clean "unsupported", so it's `skipif`'d (not removed) and tracked
under #404; `test_child_attaches_alot` still runs on Windows.
- `@pytest.mark.skipif(platform.system() == 'Windows', ...)` on
the parametrized `test_parent_writer_child_reader` so the leg
completes + reports. linux/macOS unaffected (all 6 variants
still run).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
The five transport/address lookup maps each hand-guarded `uds`
with its own `if HAS_UDS:` block (3 in `ipc/_types`, 2 in
`discovery/_addr`) — easy to let drift so a backend half-registers
(known by address but not by key, listed but unroutable, &c).
- build one `_msg_transports` / `_address_protos` list per module
(TCP always, UDS only when `HAS_UDS`), then DERIVE every map
from it via each backend's ClassVars (`codec_key`,
`address_type`, `proto_key`). Adding a backend now touches one
list, and the maps can't disagree.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`tractor`'s infect-asyncio mode runs an `asyncio` loop under
`trio` guest-mode; on Windows the default `ProactorEventLoop` is
incompatible and the suite hangs/crashes mid-run (orphaned py
procs), so the `windows-latest` CI leg never finishes reporting.
- add a module-level `pytest.skip(allow_module_level=True)` gated
on `platform.system() == 'Windows'` to `test_infected_asyncio`
and `test_root_infect_asyncio`, before their asyncio-interop
imports. macOS/linux are unaffected (they run these fine).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`test_lifetime_stack_wipes_tmpfile` guards spawn+teardown with a
hard-coded `trio.move_on_after()` (1.6s / 1s) that isn't scaled
for slow CI. On a noisy macOS runner the `error_in_child=True`
case times out before the child error propagates, so the scope
cancels and `assert not cs.cancel_called` flips — reddening the
(required) macOS leg. Same unscaled-deadline class `main` already
fixed for `test_dynamic_pub_sub`.
- multiply the budget by `cpu_perf_headroom()` (`tests/conftest`),
the established deadline-headroom helper (3x on macOS CI, a
1.0 no-op locally / on un-throttled linux).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`tests/test_ringbuf.py` imports `tractor.ipc._ringbuf` at module
top, which pulls in `tractor.ipc._linux` whose module-level
`ffi.dlopen(None)` raises `OSError` on Windows (and any non-linux
host). That fires at COLLECTION, before the module's existing
`pytestmark = pytest.mark.skip` can apply, so it aborts the whole
pytest session — the new `windows-latest` CI leg never gets past
collection.
- guard the module with `pytest.skip(allow_module_level=True)`
gated on `platform.system() != 'Linux'`, placed before the
crashing import — same idiom as `tests/devx/test_debugger.py`.
- the `eventfd`-based ringbuf backend is linux-only by design, so
macOS skips cleanly too (previously it only skipped incidentally
via the absent `cffi` optional dep).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
The prior round gated UDS in four modules but `import tractor`
still crashed on Windows: `tractor.ipc._uds` does `from socket
import AF_UNIX` at module top, and several modules in the import
graph (`discovery._api`, `spawn._reap`, `discovery._multiaddr`,
`_testing.addr`) import `_uds` unconditionally. Instead of
guarding every importer, fix the root and collapse the per-module
probes to one capability flag.
- in `ipc/_uds.py`, guard the lone `AF_UNIX` import so the module
stays importable everywhere; expose `HAS_UDS = trio.has_unix`
as the single source of truth (the same predicate that gates
`trio.open_unix_socket()`).
- `ipc/_types.py`, `discovery/_addr.py` and `ipc/_server.py` now
import `UDSAddress`/`MsgpackUDSStream`/`HAS_UDS` directly and
gate the transport + address registries on `HAS_UDS`; drop the
duplicated `getattr(socket,'AF_UNIX')` / `platform.system()`
probes, the dead `HAS_AF_UNIX` conjunct, and the import-time
`log.warning()` spam.
- `devx/_stackscope.py` `enable_stack_on_sig()` early-returns
when `sig is None`, so a missing `SIGUSR1` (Windows) degrades
to a no-op instead of a `TypeError` from `getsignal()` /
`signal()`.
- add a `windows-latest` CI leg (UDS excluded; informational via
`continue-on-error` while support matures) plus an `import
tractor` smoke step as the hard signal for the import fix.
Because `_uds` is importable everywhere `UDSAddress` stays a real
class, so `isinstance()` checks and `wrap_address()` no longer
`AttributeError` on no-UDS hosts; actual socket use stays gated
on `has_unix`.
Review: https://github.com/goodboy/tractor/pull/475
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Windows (and any CPython that doesn't expose `socket.AF_UNIX`)
can't import the UDS transport backend nor `signal.SIGUSR1`, so
the unconditional imports break `import tractor` outright on
those hosts. Guard the platform-specific bits behind capability
probes and fall back to a TCP-only runtime when the UDS backend
is unavailable.
- across `discovery/_addr.py`, `ipc/_server.py` and
`ipc/_types.py`, gate on `getattr(socket, 'AF_UNIX', None)` +
`platform.system()` and import `UDSAddress` /
`MsgpackUDSStream` only when supported, leaving the names as
`None` otherwise.
- register the `'uds'` key in `_address_types`, its
default-loopback addr, and the transport lookup maps only when
the backend actually loads, so TCP keeps working standalone.
- in `devx/_stackscope.py`, import `SIGUSR1` conditionally and
set it to `None` on Windows.
Rebased onto the post-reorg tree where `_addr.py` now lives
under `tractor/discovery/`; adapt the relocated imports to the
package's `..ipc._uds` / `..ipc._tcp` paths (the original
single-dot paths would silently disable UDS on POSIX) and drop a
duplicated `TYPE_CHECKING` block and dead `import logging` left
by the move.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`_peer_closed_errno()` followed cause and context links but did not
descend through grouped exceptions. A reset below a group could
therefore escape as `trio.BrokenResourceError` instead of the
normalized `TransportClosed` boundary.
Walk the exception tree with cycle protection, requiring every
group branch to represent peer closure before normalization. Extend
the `MsgpackTransport.send()` regression to prove all-transport and
mixed-failure behavior.
Review: PR #480 (goodboy)
https://github.com/goodboy/tractor/pull/480
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Registrar election and multi-address probing are discovery-protocol
concerns, but their implementation lived in root-runtime ignition.
Move the bounded handshake probe and its concurrent address
classifier into `discovery._api`, leaving `open_root_actor()` to
consume the classified results.
Update probe tests for the canonical module and clarify that the
daemon-fixture regressions directly exercise their sibling
`conftest` plugin.
Review: PR #480 (goodboy)
https://github.com/goodboy/tractor/pull/480
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Linux previously accepted a pre-existing runtime bindspace without
checking its owner or mode, even though Darwin enforced both. Share
the POSIX directory guard so every managed root and subdir rejects
non-directories and foreign UIDs before changing permissions.
Normalize owner-controlled bindspaces to `0o700` and add Linux
regressions for mode repair, foreign ownership, and non-directory
paths.
Review: PR #480 (goodboy)
https://github.com/goodboy/tractor/pull/480
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))