Keep `_stream_name_events()` non-blocking so a slow memory-channel
consumer cannot back up the kernel topology queue. Raise
`TIPCNameEventOverflow` and end the subscription rather than drop a
transition or let the socket reader stall. Discovery consumers must
then resubscribe and rebuild their name-table view.
Also,
- document topology semantics and scope with Linux references
- diagram the `.connect()`/`.getpeername()` withdrawal schedules
- explain the child-service and callable requirements in the
two-host example
Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Stop labeling topology events with caller-supplied scope that the
kernel never reports. Event addresses now carry an explicit unknown
scope instead of fabricated reachability.
Apply memory-channel backpressure rather than silently dropping
publish/withdraw transitions, and close the stream after delivering
the terminal event from a finite subscription.
Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Reject TIPC availability outside Linux before probing the fallback
socket-family integer, which can alias an unrelated family on
another OS.
Keep dialled sockets under setup ownership through transport
construction, then reuse the constructor's tolerant peer
observation. A peer withdrawing after `.connect()` can no longer
trigger a second raw `getpeername()` or leak setup resources.
Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
TIPC service names span the cluster while PIDs remain host-local.
Hashing only `(name, pid)` could therefore make same-named actors
on different hosts silently share one round-robin service name.
Derive the live-runtime seed from `Aid.uid` so the actor UUID
separates those names while keeping each identity reproducible.
Pin both properties with a deterministic regression test.
Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Restrict proto-key matching to numeric 3- or 4-element
descriptors so a UDS directory named `tipc` stays UDS.
Route `/tipc` parsing through `TIPCAddress.from_addr()` to
normalize zone scope and report malformed input clearly. Also
align UDS unwrapped metadata with its actual `(str, str)` shape.
Keep the TIPC test module portable by importing `SOL_TIPC` from
the backend's UAPI fallback instead of the host `socket` module.
Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Second half of layer B: an `@acm` yielding a `trio` receive-chan
of `TIPCNameEvent` fed by a nursery-spawned reader on a
`SOCK_SEQPACKET` conn to `TIPC_TOP_SRV`.
This is the bit that makes #378's "end game cluster proto" claim
real — the kernel *tells* us when any actor anywhere in the
cluster publishes or withdraws a service name, so a registrar
never has to poll `find_actor()`. Groundwork for the push
registry in `discovery/_registry.py` (gh #184, #216).
Deats,
- `filt` selects granularity; `TIPC_SUB_SERVICE` is one event
per *name*, `TIPC_SUB_PORTS` one per *publisher* — the latter
makes the §2.3 duplicate-name/round-robin crosstalk case
externally observable, which is how a push-registry could
ever detect it.
- a full event buf **drops** w/ a loud warning rather than
blocking the reader; stalling it just backs up the kernel's
own queue and loses the event less visibly.
- `SOCK_SEQPACKET` is fine here bc this sock never goes through
`MsgpackTransport` — the contract's "`SOCK_STREAM` only" rule
is about `MsgTransport` streams, not this.
XXX teardown order is load-bearing: cancel the nursery BEFORE
closing the fd. `.close()`ing out from under a pending
`.recv()` races — trio's retry can land on an already-freed fd
and raise a bare `OSError(EBADF)` instead of the
`ClosedResourceError` the reader guards for, which then escapes
the nursery as an eg.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
First half of plan 01 §5.2 (layer B): the `struct` layouts and
the `TIPCNameEvent` type for the kernel's *push-based* name
table, w/o any socket plumbing yet. Pure-python, so it tests
w/o a loaded `tipc` module.
Deats,
- `_SUBSCR_FMT = '=5I8s'` (28B `struct tipc_subscr`) and
`_EVENT_FMT = '=10I8s'` (48B `struct tipc_event`).
- `_mk_subscr()` masks the timeout: python exposes
`TIPC_WAIT_FOREVER` as **`-1`** which `struct` flat refuses
to pack into an unsigned `'I'`.
- `_decode_name_event()` *drops* runt frames and unknown event
codes rather than raising — a confused kernel must not be
able to kill the reader task.
XXX two corrections to what the plan §5.2 sketch claimed, both
verified against a live kernel,
- the event is **48B** (`4+4+4+8+28`), NOT 40.
- native (`'='`) byte-order is **accepted**; publish+withdraw
both round-tripped w/ the 28B subscription echoed back
intact. So the proposed `_detect_topsrv_endianness()` `'>'`
retry-probe is unnecessary and is NOT implemented.
Note the event carries no *scope* — the name-table doesn't
report one — so the decoded `.addr` echoes the subscription's
own rather than pretending to observe it.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
`mk_maddr()`/`parse_maddr()` learn,
/tipc/<stype>/<instance>/<scope>
mirroring how `uds` maps onto the spec-legal `/unix`.
XXX `str`-ONLY for now: there is no registered `/tipc` proto
in the multiaddr table (upstream track gh #483 +
multiformats/py-multiaddr#107) and `Multiaddr()` rejects an
unregistered name outright. `MsgTransport.maddr`s return type
is already `Multiaddr|str` (and `MsgpackUDSStream` already
exercises the `str` branch), so this fits — but it IS why gh
`parse_maddr()` therefore special-cases the `/tipc/` prefix
BEFORE handing anything to `Multiaddr()`.
Also drive the maddr mapping-table tests off `_address_types`
instead of a hardcoded len/dict so the next backend can't
fail them for the wrong reason.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
Wire the backend through every registration site (contract §2)
so `--tpt-proto tipc` is a first-class suite mode,
- `_state.TransportProtocolKey` gains the key
- `_addr._address_types` + `._default_lo_addrs`
- `_addr.wrap_address()` gets a `case ('tipc', *_)`; being a
4-elem seq it can't collide w/ `tcp`s or `uds`s 2-tuple
cases, so NO ordering hazard (and a bare seq-pattern matches
the `list` form `msgpack` decodes to).
- `_types`: the `Address` union, `_msg_transports`,
`_key_to_transport`, `_addr_to_transport` and the
`transport_from_stream()` family match. That last one keys
off `._tipc.AF_TIPC` (which carries the uapi fallback) NOT
`socket.AF_TIPC` which is linux-only.
Test-harness side,
- `get_rando_addr()` gains a `tipc` branch; `.get_random()`
already salts w/ `uuid4`+pid so both within- and cross-proc
isolation come for free.
- the `tpt_protos` fixture calls an addr-type's optional
`.is_available()` and `pytest.fail()`s w/ its reason. Keeps
a module-less box from turning `--tpt-proto tipc` into a few
hundred confusing connect-timeouts. Generic on purpose —
plans 02/03 need the same hook.
- the discovery `daemon` fixture's readiness probe learns to
dial a TIPC service name (it previously assumed tcp-or-uds
and blew up on the 4-tuple).
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
Wire `.connect_to()` (dial by service name), `.connected()`
and `.get_stream_addrs()` on top of `MsgpackTransport` so
`trio.SocketStream` + the existing `<I`-prefix framing carry
`msgpack` msgs over TIPC unchanged.
XXX both ends of a connected TIPC sock answer `TIPC_ADDR_ID`
port-ids and a port-id carries NO service name, so,
- the *dialling* side re-asserts the name it actually dialled
over `._raddr` (same move as `MsgpackUDSStream`s peer-pid
re-assign),
- the *accepting* side keeps a `TIPC_NAME_UNKNOWN` sentinel
plus the observed `(node, ref)`. It doesn't need more — the
`Aid` from `._do_handshake()` already carries the peer's
logical identity.
Also normalize dial failures: TIPC answers an unpublished-name
lookup with `EHOSTUNREACH`, which python maps to a **bare**
`OSError` and NOT a `ConnectionError` subtype the way
`ECONNREFUSED` maps to `ConnectionRefusedError`. The
discovery-ping path needs the `ConnectionError` shape, so the
`_reraise_as_connerr()` wrap is load-bearing, not polish.
XXX ALSO tolerate a dead peer in `.get_stream_addrs()`!
Unlike tcp/uds — where the kernel keeps answering the peer
addr until *we* close — TIPC answers `ENOTCONN` once the peer
is gone. Since `MsgpackTransport.__init__()` calls
`.get_stream_addrs()` (via `Channel.from_stream()`) BEFORE the
handshake, an unguarded `OSError` there escapes
`handle_stream_from_peer()`s handshake tolerance (contract §4)
and tears down the WHOLE actor. Any connect-then-drop peer — a
port scan, a liveness probe, a cancelled dial — was a remote
actor-kill. A dead peer must cost us an addr, not the runtime.
Deats,
- `TIPC_IMPORTANCE` exposed as a `.connect_to()` kwarg — TIPC
can rank a conn's traffic under congestion, which no other
backend can do. Defaulted to the kernel default for now;
wiring the parent<->child chan to `HIGH` is a follow-up.
- `TIPC_DEST_DROPPABLE = 0` so undeliverable msgs surface as
errors instead of being silently dropped.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
First slice of the `AF_TIPC` tpt backend: the addr type, the
`is_tipc_available()` capability predicate and the
name-publishing listener. No `MsgTransport` yet.
An actor's TIPC addr is a *service name* `(stype, instance)`:
`.bind()`ing the singleton `TIPC_ADDR_NAMESEQ` range IS the
service registration (it shows up in `tipc nametable show`)
and a peer's `.connect()`-by-name IS the lookup — so the
kernel does discovery for us, no registrar hop.
Deats,
- `.unwrap()` is proto-keyed as `('tipc', stype, inst, scope)`
using the `multiaddr` proto spelling so `wrap_address()`
can't confuse it with `tcp`s or `uds`s 2-tuples.
- `.rebind_from_sockname = False` bc `getsockname()` answers
a port-id; `.from_addr()` raises on a bare `TIPC_ADDR_ID`
rather than fabricate an un-dialable addr.
- `.bindspace` is the TIPC *scope*, i.e. literally the set of
hosts a published name is reachable from. `ZONE` scope is
deprecated/aliased so fold it to `CLUSTER` on input.
- mod stays importable on non-linux (uapi-value fallbacks,
the `_uds.SO_PASSCRED` precedent) bc `._addr` builds its
registration tables at import time.
XXX a `.get_random()` clash does NOT raise `EADDRINUSE` —
TIPC accepts multiple publishers of one name and round-robins
connects between them (verified against a live kernel), so a
collision is *silent crosstalk*. Hence the `blake2b` digest
and its (birthday-bounded) collision test.
Also,
- a generic `.is_available() -> (ok, why_not)` classmethod;
deliberately spelled generically (NOT `is_tipc_*`) so the
sibling env-dependent backends — `quic`/`iroh` (gh #353)
and the `wg` netns bindspace (gh #482) — get the same gate
for free. Its consumer lands w/ the reg tables.
- register a `tipc` pytest mark; the kernel-touching cases
self-skip unless `sudo modprobe tipc` has been run.
(this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`))
Guard test for `.start_listener()`s post-bind
`getsockname()`-vs-`.addr` round-trip, landed *before* that
reconciliation gets gated on an opt-out `ClassVar`.
- tcp: a `port=0` bind MUST still learn the kernel-picked
port, since the reconciliation is the only path that ever
does.
- uds: the sock-file path must survive the `.from_addr()`
round-trip unchanged.
(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`))
Replace the pre-start wall-clock sleep with an indefinite
checkpoint so cancellation ordering cannot race a timer in slow CI.
Record that `Cancelled` escapes each `start_or_cancel()` await
before the enclosing nursery or cancel scope handles it.
Review: PR #479 (goodboy)
https://github.com/goodboy/tractor/pull/479
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Compare the complete canonical `Nursery.start()` protocol error
before re-surfacing ambient cancellation. Preserve child-owned
`RuntimeError` objects whose messages only resemble Trio's wording.
Cover the colliding prefix and assert the original error remains the
exception group's sole leaf.
Review: PR #479 (goodboy)
https://github.com/goodboy/tractor/pull/479
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Resolve#474 with a new `tests/trionics/test_taskc.py` (9
tests) covering the `trio.Nursery.start()` wrapper landed in
PR #464, incl. the `modden.runtime.progman.open_wks()` use
case dug out as a minimal repro.
Deats,
- the lossy `RuntimeError('child exited without calling
task_status.started()')` only fires when the child absorbs
its ambient cancel pre-`.started()` (graceful-teardown
pattern); a well-behaved child surfaces `Cancelled` direct
from `.start()` on `trio` 0.29 - verified empirically 1st.
- `test_sibling_err_not_masked_by_startup_rte`: the `modden`
case; ONLY the root-cause sibling `ValueError` escapes the
nursery with the wrapper vs. bare-`.start()`'s lossy
riding-along startup-RTE noise.
- `test_pure_oob_cancel_not_morphed_to_rte`: plain ancestor
`cs.cancel()` exits clean vs. bare's eg-wrapped RTE.
- `test_genuine_startup_rte_still_raised`: sans cancellation
the protocol-bug RTE re-raises same as bare.
- `test_childs_own_rte_never_demoted_to_cancel`: exact-msg +
`isinstance`-guard regression cover; a child's own
`RuntimeError('never got started!')`/`RuntimeError(1234)`
never demotes to a `Cancelled`.
- `test_started_value_and_args_passthru`: positional args,
`name=` and `.started()`-value forwarding.
Also,
- `use_start_or_cancel=False` params pin upstream `trio`'s
current lossy behaviour as wart-documentation: a break on
a `trio` upgrade likely means new upstream porcelain and
the wrapper deserves a re-audit.
- verified 0 flakes over 50 hammer runs + 2 impl mutations
each caught by exactly the targeted tests.
Prompt-IO: ai/prompt-io/claude/20260702T161624Z_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
Use `Logger.isEnabledFor()` in `at_least_level()` so logger-local
and global disable controls short-circuit payload rendering.
Add `Channel.send()` coverage for effective-level, per-logger, and
global suppression while ensuring transport remains unchanged.
Caught-during: review remediation
Found-via: `/run-tests` test_log_guard_skips_payload_formatting
Review: PR #458 (goodboy)
https://github.com/goodboy/tractor/pull/458#issuecomment-5258207470
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Block the final user on its cached resource's `__aexit__()` and
raise regular cleanup errors at that user's ctx boundary.
Deats,
- serialize user registration and teardown under each cache-key lock
- keep queued entrants on the same lock through resource replacement
- preserve `Cancelled`, `KeyboardInterrupt`, and `SystemExit` flow
- cover successful, failing, cancelled, and re-entry teardown paths
Prompt-IO: ai/prompt-io/opencode/20260804T030309Z_65bf9df5_prompt_io.md
(this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
Copilot's 2nd-pass review (PR #468) caught a regression I landed in
the uds fix: `UDSAddress.get_random()` put the per-call token AFTER
`@{pid}` (`no_runtime_*@{pid}.{token}.sock`), which breaks the
`tractor._testing._reap` matcher
`^(?P<name>.+)@(?P<pid>\d+)\.sock$` — so no-runtime orphan socks
stopped matching and never got reaped/attributed. Move the token
INTO the name (`{prefix}.{token}@{pid}.sock`) so the canonical
`@{pid}.sock` suffix stays intact for both that regex and the
`spawn._reap` reconstruction; also bump the token to 8 hex chars.
Also two robustness nits from the same review,
- `tests.conftest._measure_sustained_headroom()`: guard `frac <= 0`
before `1./frac` — a 0/parked-core freq read would
`ZeroDivisionError`, get swallowed by the broad `except` into a
1.0 (no-throttle), defeating the probe on the exact broken box it
should flag; read 0 as max throttle.
- `scripts/cpu-perf-check`: mark the burn procs `daemon=True` and
wrap sampling in `try/finally` so a Ctrl-C / error reaps them
instead of leaving stray CPU hogs.
Regressed-by: 09c50f49 (uds no-runtime token placed after `@pid`)
Found-via: Copilot review #4595803812 (`_testing._reap` regex)
Review: PR #468 (Copilot)
https://github.com/goodboy/tractor/pull/468#pullrequestreview-4595803812
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Finish TODO #2 from PR #468: the last raw `cpu_scaling_factor()`
call-sites still used the static-only check (blind to the
sustained-load power-cap). Point them at the `cpu_perf_headroom()`
SUPERSET — it calls `cpu_scaling_factor()` internally + the
session-cached throttle probe, so it's always >= the old factor
(never LESS headroom, so CI stays green).
Migrated,
- `test_spawning`: the `fail_after(1 * ...)` smoke deadline
(#465-added).
- `test_inter_peer_cancellation`: `this_fast` budget.
- `test_docs_examples`: example-run `timeout`.
- `test_resource_cache`: fan-out `timeout`.
`test_cancellation` already used `cpu_perf_headroom()`; only its
explanatory comments still name the static helper.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Both `_burn()` impls (the `cpu-perf-check` script + the
`_measure_sustained_headroom()` probe in `tests.conftest`) grew `x`
~x**2 per iter, so the loop quickly went bigint alloc/mul-bound — a
noisy CPU load + needless memory across N procs. Mask each step to
64-bit for a steady, fixed-width ALU burn (still pegs every core,
which is all the freq probe needs).
Also, `_read_mhz()` opened the sysfs freq files without a ctx-mgr;
`with open(...)` so the FD closes deterministically (matches the
script's own `_read()`).
Review: PR #468 (Copilot)
https://github.com/goodboy/tractor/pull/468
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`cpu_perf_headroom()` is a strict SUPERSET of `cpu_scaling_factor()`
— it folds in static cpu-freq scaling + the slow-CI bump AND the
sustained-load power-cap throttle probe. Point the timing-deadline
call sites at it so they're robust to sustained throttling too (the
gremlin behind mass `trio` deadline-miss flakes),
- `test_legacy_one_way_streaming`: `time_quad_ex` cancel-deadline +
`test_a_quadruple_example`'s `this_fast` smoke bound.
- `test_cancellation`: `test_cancel_via_SIGINT_other_task` +
`test_fast_graceful_cancel_*` deadlines.
`cpu_perf_headroom >= cpu_scaling_factor` always, so never less
headroom (CI stays green); `cpu_scaling_factor()` remains the
internal static component.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Mass `trio` deadline-miss failures on byte-identical code turned
out to be a firmware/EC power-cap (AMD PPT/STAPM) clamping the
all-core sustained clock while every static knob (`governor`,
`scaling_max_freq`, EPP, platform-profile) still read "performance"
— invisible to the existing `cpu_scaling_factor()` check. See
`scripts/cpu-perf-check` + the
`ai/conc-anal/trio_033_cancel_cascade_slowdown_depth3_issue.md`
notes.
Deats,
- add `_measure_sustained_headroom()` to `tests/conftest.py`: a
one-shot ~0.9s all-core burn (explicit `fork`-ctx `mp` procs)
sampling achieved-vs-max freq AFTER the boost window; under a 0.6
gate it returns the full inverse fraction (capped 4x), else 1.0;
best-effort 1.0 on non-linux or any error,
- add `cpu_perf_headroom()`: `max()` of the static scaling factor
and the (session-cached) sustained probe,
- inflate deadline budgets by it in `test_dynamic_pub_sub`, both
`test_clustering` cases, the
`test_multi_nested_subactors_error_through_nurseries` pexpect
waits + `test_nested_multierrors`,
- `xfail(strict=False)` `test_nested_multierrors` depth=3 under
throttle: the deep tree trips tractor's INTERNAL reap deadlines
(`soft_kill`/`hard_kill` `terminate_after=1.6`) minting a
`Cancelled` inside the runtime — not fixable by test-budget
inflation; auto-clears once the box un-throttles.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`uds_transport_actor_tree.py` (new in 759d46dd) reliably fails on
macOS CI with a bare `returncode 1`. The example forces
`enable_transports=['uds']`, and UDS-on-macOS is otherwise
un-exercised by the matrix (there's no `tpt_proto=uds` macOS job),
so it's the first thing to surface a macOS UDS-path issue.
It passes cleanly on Linux, and the peer-cred paths are already
platform-guarded + graceful (`get_peer_info`/SO_PEERCRED on linux
vs `get_peer_pid`/LOCAL_PEERPID elsewhere) - so the crash is deeper
in the macOS UDS stack. The test swallows the subproc stderr (only
re-raises when the last line has "Error"), so the exact failure
can't be pinned from CI logs; needs a macOS box to root-cause.
Skip it on `_friggin_macos and ci_env` (same shape as the existing
`full_fledged_streaming_service` skip) so #460 lands green; the
macOS UDS root-cause is a follow-up.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
The `.uid`->`.aid` migration (prior commits) re-assembled the
legacy uid pair by hand as `(x.aid.name, x.aid.uuid)`.
`Aid.uid` (`msg/types.py`) is the non-deprecated canonical
property returning exactly that pair, so swap to `x.aid.uid`
everywhere — byte-identical, just DRY + consistent.
Covers the 5 review-flagged source sites (`msg._ops`,
`devx.debug._sync`, `experimental._pubsub`, `_exceptions`)
plus the ~22 unflagged identical sites (`_streaming` f-string
logs + 6 test modules); also tightens the `_exceptions`
`our_uid` annotation to `tuple[str, str]`.
Review: PR #469 (copilot-pull-request-reviewer)
https://github.com/goodboy/tractor/pull/469#pullrequestreview-4575979601
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`test_cancel_via_SIGINT_other_task` opened its nursery with the
now-deprecated `strict_exception_groups=False`. Under strict EGs
(trio's default since 0.25) the SIGINT-induced `KeyboardInterrupt`
surfaces wrapped in a `BaseExceptionGroup` — alongside the child
tasks' `Cancelled`s, so it's MULTI-exc and `collapse_eg()` can't
fold it back to a bare KI (the `# why no work!?` the author hit).
Drop the deprecated flag, use a default (strict) nursery, and
assert the result is a bare `KeyboardInterrupt` OR a
`BaseExceptionGroup` whose `.subgroup(KeyboardInterrupt)` is
non-empty.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Mirror the core swap on the test side: every `Channel`/`Actor`
`.uid` access now reads the non-deprecated `.aid` struct's
`(.name, .uuid)` (or `.aid.name` for a `.uid[0]`), keeping the
compared / printed value byte-identical while silencing the
self-inflicted `DeprecationWarning`. Touches
`test_context_stream_semantics`, `test_spawning`, `test_local`,
`test_advanced_streaming`, `msg.test_ext_types_msgspec`,
`discovery.test_multi_program`, `test_infected_asyncio`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`tests.test_cancellation` asserted on `ActorNursery.cancelled`,
which now warns + redirects to `.cancel_called`. Swap to the
non-deprecated property so the suite stops tripping its own
`DeprecationWarning`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`tests.devx.test_tooling`'s end-of-tree `expect()` patterns use
a literal `\(` (pexpect regex), which Python 3.12+ flags as an
invalid escape sequence. Make them raw strings so the `\(` is
preserved verbatim and no `SyntaxWarning` fires.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Under `trio>=0.33`'s strict exception-groups a lone
`error_parent` arrives wrapped in a 1-exc `ExceptionGroup`
instead of collapsing to the bare exc, so it skips the
`except error_parent` arm and lands in the group arm — where
`is_multi_cancelled()` is (correctly) `False`, tripping the
assert. Also accept `beg.subgroup(error_parent) is not None`.
Review: PR #465 (copilot + self CI-triage)
https://github.com/goodboy/tractor/pull/465#pullrequestreview-4548191641
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Flat `trio.fail_after(1)` wraps a whole actor spawn + IPC
round-trip in `test_most_beautiful_word` — sub-second on a
warm box, but slow/noisy CI runners (esp. macOS) blow the
1s deadline with a `trio.TooSlowError`. Scale the budget by
`cpu_scaling_factor()`: a strict `1s` locally (factor
`1.0`), CI/CPU-throttle headroom (~3x) on macOS.
Review: PR #465 (copilot + self CI-triage)
https://github.com/goodboy/tractor/pull/465#pullrequestreview-4548191641
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Two version-compat fixes for the `devx` debugger
test-suite, both about matching upstream output that
got more verbose w/ recent lib releases.
ANSI stripping (`tests/devx/conftest.py`),
- Add `ansi_strip(text)` helper + `_ansi_re` pattern
(regex per https://stackoverflow.com/a/14693789).
- Apply inside `in_prompt_msg()` + `assert_before()` so
substring matches against REPL/traceback output stay
robust to color leakage.
- Motivated by py3.13's colored tracebacks +
`pdbp`/pygments highlighting leaking ANSI even when
`PYTHON_COLORS=0` is set in the `spawn` fixture (not
every renderer in the spawned subproc honors it).
- Replaces the longstanding inline TODO that linked
the SO answer w/o impl'ing.
trio 0.30+ `Cancelled._create(` match (`test_debugger`),
- In `test_shield_pause` swap the two
`"raise Cancelled._create()"` assertion patterns →
`"raise Cancelled._create("` (open-paren form, no
closing).
- trio >=0.30 raises a multi-line
`raise Cancelled._create(source=.., reason=..,
source_task=..)` w/ cancel-reason metadata, so the
legacy bare-`()` form no longer matches. Inline
comment documents the trio-version pivot.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 3854cf5ecb)
(cherry picked from commit c07cf2546b)
A `trio.Nursery.start()`-style wrapper around
`trio.run_process()` that surfaces rc!=0 errors
deterministically, ALWAYS isolates the parent
controlling-tty, and optionally live-relays the child's
std-streams to `log.<level>` per-line. Suits both
short-lived test-runners + long-lived daemons.
`supervise_run_process()`,
- Deterministic rc!=0: pass `check=False` to `trio`
and do our OWN post-drain rc-check from the
supervisor coro body AFTER `own_tn.__aexit__` — NOT
inside the internal nursery, since that would
race-cancel the still-draining relay reader and lose
stderr lines. (Re)build + raise a BARE
`subprocess.CalledProcessError`: `.stderr=` for
programmatic callers + an `add_note()`'d
`|_.stderr:` block for human teardown logs. No
nursery-eg-wrapped CPE to `collapse_eg` around.
- Parent controlling-tty isolation: `stdin=DEVNULL`
always, `stdout=DEVNULL` unless relayed/overridden
(via `stdout=` kwarg w/ `_UNSET` sentinel so explicit
`None` = inherit still works). Prevents a spawned
program from clobbering the launching tty's scrollback
w/ control-seqs.
- Live per-line relay: `relay_stdout=True`/
`relay_stderr=True` → relayed to `log.<relay_level>`
(default `'io'`, our custom level 21). Picked to sort
just above stdlib `INFO`=20 so it shows at usual
`info`/`devx` levels yet stays separately filterable;
`runtime`=15 was REJECTED as a default since it'd be
silently filtered at usual verbosity — footgun for
daemon supervisors whose whole point is visibility.
STREAMED, not buffered-until-exit.
- Non-blocking `tn.start()` semantics: live
`trio.Process` handed up via
`task_status.started()` immediately (else
`tn.start()` would block till child exit, losing
the long-lived-daemon use case). Supervise/relay bg
tasks run to completion in this coro.
- `**run_process_kwargs` forwarded verbatim (env, shell,
cwd, start_new_session, executable, ...); MANAGED keys
(`stdin`/`stdout`/`stderr`/`check`) win on conflict.
- Crash-handling layer intentionally NOT baked in —
compose `maybe_open_crash_handler()` ON TOP at the
call-site.
`_relay_stream_lines()` helper,
- Concurrent pipe-drain reader. MANDATORY whenever piping
w/o `capture_*` since nothing else drains the OS pipe —
child blocks on `write()` once kernel buf (~64KiB) fills
→ deadlock.
- Modes (combine freely): `emit`-only live relay,
`accum`-only silent drain+capture (for the CPE note),
or both. Per-line splitting handles cross-chunk
residuals + flushes any trailing un-newline-term'd line
at EOF.
`_add_stderr_note()` helper,
- Attaches an indented `|_.stderr:` note to a CPE via
`add_note()` for legible rc!=0 reporting at teardown.
Tests (`tests/trionics/test_subproc.py`),
- Hermetic `trio`-only (no actor-runtime).
- `test_stdout_relayed_per_line`: per-line stdout relay.
- `test_parent_tty_isolated`: child fd1 is OUR pipe (no
`/dev/pts/*`), fd0 pinned to `/dev/null`.
- `test_no_deadlock_on_big_unnewlined_output`: 200KiB
no-newline output completes under `fail_after(2)` —
exercises the concurrent drain (without it, the child
blocks at ~64KiB).
- `test_stderr_relay_and_cpe_rebuild`: rc!=0 w/
`relay_stderr=True` → bare `CalledProcessError` w/ the
`.stderr` note + per-line live relay.
- `test_nonrelay_cpe_note`: rc!=0 w/o relay → same
deterministic post-drain CPE w/ `.stderr` note (silent
drain+capture path).
Re-export `supervise_run_process` from `tractor.trionics`.
Prompt-IO: ai/prompt-io/claude/20260601T231429Z_0e3e008b_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
(cherry picked from commit f595acc76c)
(cherry picked from commit 6df9ee11bc)
Make the sub-actor proc-title prefix a single
authoritative constant (`_proctitle._def_prefix`) so
the reap-recognition markers and `xontrib` banner pick
it up automatically — one place to flip the prefix
shape going fwd.
Deats,
- `_proctitle._def_prefix: str = '_subactor'`. New
module-level const consumed by everything that needs
to know the prefix.
- `set_actor_proctitle(actor, prefix=_def_prefix)`:
takes an explicit `prefix` arg (default = the const)
so callers can override per-spawn if they want.
- Default proc-title format:
`'tractor[<reprol>]'` → `f'{prefix}[<reprol>]'`
i.e. `_subactor[<reprol>]` by default.
- `_testing/_reap.py`: cmdline + comm markers source
the prefix from `_proctitle._def_prefix` instead of
the hardcoded `'tractor['`. So
`_is_tractor_subactor()` tracks the const
automatically.
- `xontrib/tractor_diag.xsh`: `acli.reap` orphan-mode
banner now interpolates the
`_TRACTOR_PROC_CMDLINE_MARKERS` tuple directly so
the human-readable mode line stays in sync if the
prefix shape changes again.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 3a45dbd503)
(cherry picked from commit fd8d39c0ce)
Follow-up to f595acc7 (`supervise_run_process`) which
called `log.io(...)` for std-stream relay assuming an
`IO=21` level existed. Add the registration via a new
factory + tests covering both the factory and the new
level.
`add_log_level()` factory,
- One call wires the four (otherwise hand-synced) pieces:
- `CUSTOM_LEVELS[NAME]` — drives the `stacklevel` bump
in `StackLevelAdapter.log()` + `get_logger()`'s
per-level audit.
- `logging.addLevelName()` — stdlib name registration.
- `STD_PALETTE[NAME]` + `BOLD_PALETTE['bold'][NAME]` —
color entries consumed by `get_console_log()`'s
`ColoredFormatter` build.
- Same-named (lowercase) emit method bound on
`StackLevelAdapter` so `log.<name>('msg')` works +
`get_logger()`'s per-level method audit passes.
- Idempotent: re-registering an existing name is a
no-op-ish refresh that won't clobber an already-bound
method.
- Method binding uses a default-arg `_level=value` so
the level int is captured (not late-bound across
multiple registrations).
`IO=21` level (first user),
- Purple. Used by `tractor.trionics._subproc`'s
std-stream relay (see f595acc7).
- Value 21 picked to sit just ABOVE stdlib `INFO`=20 so
it's SHOWN BY DEFAULT at usual `info`/`devx` console
levels — a `runtime`=15 relay would be silently
filtered (footgun for daemon supervisors whose whole
point is visibility). Still distinctly labeled +
filterable.
Tests (`tests/test_log_sys.py`),
- `test_io_custom_level_registered`: validates the IO
level is fully wired (`CUSTOM_LEVELS`, `addLevelName`,
both palettes, `StackLevelAdapter.io()` callable);
emits a record + sanity-asserts `21 >= INFO(20)`.
- `test_add_log_level_pluggable`: registers a fresh
`XLVL=19` (cyan) via `add_log_level()`, asserts all
four wires + the bound `xlog.xlvl()` emit, then
try/finally cleans up the module-global mutations so
later `get_logger()` audits don't trip on a
half-removed level.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 7bd7dd50c7)
(cherry picked from commit 93558fe3c9)
The `cpu_scaling_factor()` CI bump (2x) wasn't enough for the
macOS runners — slower + noisier than linux for our multi-actor
cancel-cascade timing — so `test_nested_multierrors[depth=3]` and
`test_fast_graceful_cancel_*` flaked there (linux + sdist green),
- make the CI headroom platform-aware: 3x on macOS, 2x on linux
(keeps the proven linux budget; depth=3 inner 12*3=36s still
fits under the 40s outer wall).
- give `test_fast_graceful_cancel_*` the `cpu_scaling_factor()`
headroom it was missing entirely (was a bare `timeout=2.9`).
Verified locally w/ `CI=1` (2x linux path; 3x macOS path confirmed
via forced `_non_linux`).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
All 5 flagged items were valid (4 real bugs + 1 dead assert),
- fix an inverted `sys.version_info < (3, 14)` guard in
`ipc._linux` — the "`cffi` has no 3.14 support" import note now
fires on 3.14+ (where it applies) instead of on older pys.
- use `os.environ.get('PYTHON_COLORS')` in the `sync_bp` example
so it doesn't `KeyError` when run outside the test harness.
- correct `dump_task_tree()`'s docstring: the `/tmp` + `/dev/tty`
tee is gated on `write_file`/`write_tty`, not "unconditional".
- tidy the `ActorTooSlowError` message spacing in `cancel_actor`.
- replace a tautological `applied is True or applied is False` in
`test_patches` with `isinstance(applied, bool)` (the value is
order-dependent across the module).
Review: PR #462 (copilot-pull-request-reviewer)
https://github.com/goodboy/tractor/pull/462#pullrequestreview-4527179852
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
GH Actions (and most shared) CI runners are slow + noisy and —
unlike a throttled local box — don't expose CPU-freq scaling via
sysfs, so `cpu_scaling_factor()` read `1.0` and the timing-
sensitive deadlines/asserts that key off it got NO headroom on
CI (a class of `TooSlowError` / `assert diff < this_fast` flakes),
- add a flat `_ci_env` x2 bump inside `cpu_scaling_factor()` so
every test already using it (quad streaming, SIGINT-cancel,
docs examples, ...) gets CI headroom for free — compounds with
any local-throttle factor.
- route the `time_quad_ex` cancel-deadline through it instead of
a bespoke per-test `ci_env` bump.
- fix a real bug in `test_nested_multierrors`: its OUTER
`@tractor_test(timeout=10)` was *smaller* than the inner
`fail_after_w_trace` budget (trio depth=3 = 12s), so the outer
wall fired first and pre-empted the snapshot-capturing inner
deadline -> `FAILED` instead of dumping. Bump the outer to `40`
(> max inner budget) and scale the inner budgets by
`cpu_scaling_factor()` too.
Verified locally with `CI=1` (quad + both `test_nested_multierrors`
depths + `test_cancel_via_SIGINT_other_task` green).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Same trio 0.29 → 0.33 cancel-cascade slowdown that hit
`test_nested_multierrors` (ea67f1b6) — bumps the
`trio`-backend (non-debug, non-forking) budget in
`test_echoserver_detailed_mechanics` from 1s → 4s.
- The 1s budget raced the ~1s teardown deadline. On a
deadline-fire trio 0.33 injects
`Cancelled(source='deadline')` (cancel-reason
metadata) that wraps the mid-stream KBI in a
`BaseExceptionGroup`, breaking the bare
`pytest.raises(KeyboardInterrupt)` below.
- Bump matches the forking-spawner branch (4s).
- Inline NOTE references the tracking issue
`ai/conc-anal/trio_033_cancel_cascade_slowdown_depth3_issue.md`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit d7da502d93)
(cherry picked from commit d0144e52cb)
trio 0.29 → 0.33 lock bump (c7741bba) slowed the
depth=3 cancel-cascade in `test_nested_multierrors`
from <6s to ~7-8s; the 6s deadline was firing and its
`Cancelled(source='deadline')` (trio 0.33's new
cancel-reason metadata) collapsed a BEG branch,
breaking the `RemoteActorError` assertion downstream.
- Split the `('trio', _)` case-match into per-depth
arms: `('trio', 1)` keeps 6s (still finishes in
~3s); `('trio', 3)` → 12s.
- Updated inline NOTE explains the version pivot +
links the tracking issue
`ai/conc-anal/trio_033_cancel_cascade_slowdown_depth3_issue.md`.
- Existing MTF/`subint_forkserver` budgets unchanged.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit ea67f1b67b)
(cherry picked from commit 57b3ea59ea)
Strip the trailing `pkg_path` token ONLY when it duplicates the
caller's leaf-*module* name (which the console header already
shows via `{filename}`), instead of blindly dropping the last
token. This keeps genuine, possibly-*nested* sub-PACKAGE parts
addressable as their own sub-loggers.
- detect a true leaf-mod by comparing the caller's `__name__`
vs `__package__` (a pkg `__init__` has them equal -> its
trailing token is a real sub-pkg, NOT a leaf to strip).
- `name='devx.debug'` now -> `tractor.devx.debug`, DISTINCT
from a bare `devx` -> `tractor.devx`; the old unconditional
`pkg_path = subpkg_path` collapsed both to `tractor.devx` and
silently broke per-sub-pkg level control via the logging-spec.
- `get_logger(__name__)` leaf-strip still works (cosmetic, bc
the leaf-mod is in the `{filename}` header field).
Also,
- update the `LogSpec` caveat: sub-PACKAGE granularity now
addressable at ANY depth; leaf *modules* intentionally aren't
(they're the `{filename}`); top-level mods (eg. `to_asyncio`)
still emit on the root logger.
- adjust `test_root_pkg_not_duplicated_in_logger_name` to the
new literal explicit-`name` contract (no leaf-collapse).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 9c36363b01)
Two coupled changes that let downstream projects (eg. `modden`) inherit
the test-harness loglevel plumbing for free via
`tractor._testing.pytest`:
Plugin lift (`tests/conftest.py` → `_testing/pytest.py`),
- mv `pytest_addoption(--ll)`, the `loglevel` autouse
fixture, and `test_log` fixture out of the test-suite-
local conftest into the reusable plugin.
- add `--tl`/`--tractor-loglevel` as a DISTINCT flag from
`--ll`: `--ll` is the consuming-project's OWN app
loglevel (scoped to its pkg-hierarchy), `--tl` is the
`tractor.*` runtime loglevel. `--tl` falls back to
`--ll` when unset (preserves current `tractor`-suite
behavior).
- add `testing_pkg_name` session fixture (default
`'tractor'`) — downstream projects override to e.g.
`'modden'` so `--ll` scopes to their own hierarchy
instead of `tractor.*`.
- `loglevel` fixture now yields the resolved
tractor-runtime level (passed to
`open_root_actor(loglevel=<.>)` by `@tractor_test`)
AND separately applies `--ll` to the
`testing_pkg_name` hierarchy when that isn't
`tractor`. `test_log` scopes the per-test logger to
`testing_pkg_name`.
`tractor.log` "logging-spec" mini-DSL,
- `LogSpec = str|bool`. Accepted forms:
- `True` → enable `pkg_name` root at `default_level`
(fallback `'cancel'`).
- `False` → no-op.
- bare level eg. `'info'` → root-logger at that level.
- `'sub:info,x:cancel'` → per-sub-logger filter-spec;
each `<name>` is RELATIVE to `pkg_name` (must NOT
include the pkg-token).
- `parse_logspec()` → `{sublog|None: level}` mapping.
`None` key = root-logger. Mixed bare-level + filters
in one spec is rejected w/ a helpful err msg; so is
embedding the `pkg_name` token in a sub-name.
- `apply_logspec()` → `(primary_level, {name: log})`:
parses then enables a `colorlog` stderr handler per
named (sub)logger. Authoritative sub-logger filters
get `propagate=False` so they don't double-emit
through a parallel root-level handler.
- !GRANULARITY CAVEAT! sub-logger names match at
sub-pkg granularity, not leaf-module — so `devx.debug`
collapses to the same `tractor.devx` logger as a bare
`devx`, and top-level lib modules (eg.
`tractor.to_asyncio`) emit under the *root* logger
rather than a phantom `to_asyncio` child. Documented
inline on `LogSpec`.
Other,
- `tests/conftest.py` keeps a NOTE pointing to the
plugin for future-debugging clarity (don't remove
silently — the lift is the relevant signal).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 19a77708ba)
Adopt the `_testing.trace` CM helpers in two MTF-hang-prone
tests so on-timeout we get a fresh
`ptree`/`wchan`/`py-spy` diag snapshot on disk instead of
opaque pytest timeout-kills. Same shape as bd07a95d for
`test_dynamic_pub_sub`.
Deats,
- `test_echoserver_detailed_mechanics`:
* inner `trio.fail_after` → `fail_after_w_trace`. Adds
`fail_after_w_trace: FailAfterWTraceFactory` fixture
param.
* mv per-backend `timeout` calc to top of test body (was
interleaved w/ helper defs).
* factor deep
`open_nursery`/`open_context`/`open_stream` body into
`_body()` so the wrapping `main()` stays a 2-liner —
keeps the nested-CM block at its natural indent level
instead of pushing it under yet another `async with`.
* drop `with_timeout: bool` knob + `fa_main()` helper
(knob was hard-coded `True`).
- `test_sigint_closes_lifetime_stack`:
* outer `signal.alarm`/`try`/`finally` → single
`afk_alarm_w_trace(10)` CM. Adds
`afk_alarm_w_trace: AfkAlarmWTraceFactory` fixture
param.
* drop `_AFK_CAP_S` + `armed_alarm` vars (CM owns both).
* explanatory comment refreshed to mention
`AFKAlarmTimeout` + the disk-snapshot side effect.
Other,
- Drop debug `return 1e3` short-circuit from `delay()`
fixture — snuck in as a scratch line, was clobbering the
proper `debug_mode`-branched return.
- Top-level import: `FailAfterWTraceFactory`,
`AfkAlarmWTraceFactory` from `tractor._testing.trace`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 1cafaecf52)
Replace inline `trio.fail_after` + manual `signal.alarm` guard with the
`_testing.trace` CM helpers that auto-capture a full ptree/wchan/py-spy
diag snapshot to disk on timeout.
Deats,
- inner guard: `trio.fail_after` → `fail_after_w_trace` (async CM,
captures on `TooSlowError`).
- outer AFK guard: raw `signal.alarm` → `afk_alarm_w_trace` (sync
CM, captures on `SIGALRM`), only armed under fork backends.
Extracts `_run_and_match()` helper to keep branching clean.
- bump `fail_after_s` from 4/12 → 8/20 to stop borderline flakes
while diag harness accumulates evidence.
- drop `_DIAG_CAP_S` var + manual signal import (now internal to
`afk_alarm_w_trace`).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit bd07a95d80)
Deats,
- `pytestmark`: enrich `skipon_spawn_backend('subint')` reason with
conc-anal doc refs + GH#379 link, add `reap_subactors_per_test`,
`track_orphaned_uds_per_test`,
`detect_runaway_subactors_per_test` fixtures
- `test_nested_multierrors`: parametrize over `depth` `{1, 3}`, add
MTF `xfail(strict=False)` with detailed race-window comment
explaining the BEG shape mismatch, wrap body in
`fail_after_w_trace` with per-backend timeout budget, bump
`@tractor_test(timeout=10)`, drop old multiprocessing depth
special-casing
- `test_multierror_fast_nursery`: wrap in
`fail_after_w_trace(30.0)`, accept `TooSlowError` in
`pytest.raises`, surface explicit `pytest.fail` on hang
- `test_cancel_while_childs_child_in_sync_sleep`: swap
`spawn_backend` param for `is_forking_spawner`, widen
`fail_after` delay for fork-based spawners
- `test_remote_error`, `test_multierror`,
`test_cancel_infinite_streamer`, `test_some_cancels_all`: add
`set_fork_aware_capture` fixture param
- Drop commented-out per-test `skipon_spawn_backend` blocks (now
covered by module-level `pytestmark`)
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 32955db02e)
Deats,
- `test_echoserver_detailed_mechanics`: add `is_forking_spawner`
param, wrap `main()` in `fa_main()` with per-backend
`trio.fail_after` (4s fork / 1s trio) to cap cancel-cascade
teardown that compounds under forkserver.
- `test_sigint_closes_lifetime_stack`: swap `start_method` param
for `is_forking_spawner`, pre-init `tmp_file`/`ctx` to `None` so
KBI firing before `open_context` body doesn't `UnboundLocalError`,
add `pytest.fail` guard for the spawn-time IPC race case, arm
`signal.alarm` AFK-safety cap (10s) under fork backends
Also,
- `pytestmark`: add `track_orphaned_uds_per_test` +
`detect_runaway_subactors_per_test` fixtures.
- `delay()`: hardcode `return 1e3` at top (debug override still in
place).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 7ee0dc2e8f)
For forking spawner backends that is.
(this commit msg was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit b10011a36e)
- `skipon_spawn_backend('subint')`: expand reason with specific
analysis doc refs + GH issue #379 umbrella link.
- add `track_orphaned_uds_per_test` fixture via `usefixtures` to
blame-attribute UDS sock-file orphans left by SIGKILL cancel
cascades.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
(cherry picked from commit 7d0a53d205)