The 8 `examples/debugging/` scripts driven by the pexpect'd
`test_debugger.py` REPL-flows (#477 removal),
- blocking one-shots (`subactor_error`, `subactor_breakpoint`,
`shielded_pause`): straight `to_actor.run(fn, an=an)` — the
boxed error/`BdbQuit` raises in the root's task.
- `multi_subactors`: introduces the "collect all errors" pattern
— each one-shot catches + stashes its `RemoteActorError` (vs
raising) so no child's crash cancels its siblings before
they've had their own REPL sessions, then a
`BaseExceptionGroup` of the lot raises at the end; preserves
the legacy teardown-reap REPL flow exactly (28/28 debugger
suite unchanged).
- `multi_nested_subactors_error_up_through_nurseries` +
`root_cancelled_but_child_is_in_tty_lock`: recursive
`spawn_until` levels each block on their one-shot child; the
parallel spawner-trees run as bg task-nursery one-shots where
the first tree's error cancels the other.
- `multi_subactor_root_errors` +
`root_timeout_while_child_crashed`: `start_actor()` + bg
`Portal.run()` tasks so the root's own error/timeout races the
already-crashed children, same as before.
- `sync_bp`: TODO-comment x-ref update only.
`test_debugger.py`: the nested-nurseries test's final-output
patterns update to the new relay shape — the LAST-released leaf
REPL's error chain wins each level's relay-vs-cancel race and
relays as a `collapse_eg()`-annotated collapsed chain, while the
sibling tree is cancelled + absorbed. (The legacy teardown-reap
grouped BOTH the `name_error` and bp-quit chains — explaining
the previously-mysterious "extra" `src_uid`/`relay_uid` patterns
noted in the old TODO.)
Gate: `tests/devx/test_debugger.py` = 28 passed, 6 skipped —
identical to the pre-migration baseline.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
4 example scripts of the #477 removal sweep, each exercised by
`test_docs_examples.py`,
- `actor_spawning_and_causality.py`: the simplest possible
`to_actor.run()` demo — private call-scoped nursery, block on
and print the one-shot's result.
- `remote_error_propagation.py`: blocking `to_actor.run(an=n)`
raises the boxed `AssertionError` in the caller's task,
cancelling the sibling daemons.
- `parallelism/single_func.py`: bg-burn a core in the parent via
a local task-nursery while the one-shot burns (and returns
from) a subactor.
- `a_trynamic_first_scene.py`: donny + gretchen wait on each
*other* so their one-shots run concurrently in a local
task-nursery against a shared `an` (mirrors the migrated
`test_trynamic_trio`).
Gate: all 4 green via the example-runner suite.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
The known-flaky dynamic pubsub test's 3 fire-and-forget spawn
sites (#477 removal),
- the forever-streaming `publisher` + N `consumer` one-shots now
bg-schedule as `to_actor.run(fn, an=n)` tasks in a local `trio`
task-nursery (`publisher`'s rendezvous name still derives from
`fn.__name__`).
- the simulated user-cancel raise (`KeyboardInterrupt` /
`TooSlowError` params) cancels the task-nursery, each one-shot
reaping its subactor via `to_actor.run()`'s shielded
`Portal.cancel_actor()`; `_run_and_match()`'s existing
`BaseExceptionGroup.split()` walk covers the (possibly nested)
relay shapes unchanged.
- spawns now issue concurrently rather than sequentially —
comment on the fork-backend budget updated to match.
Gate: both params x4 runs green on `trio` + x1 on `mp_spawn`;
full module green.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Final `test_cancellation.py` group of the `run_in_actor` removal
(#477) — cancel-mechanics tests, so clean conversions,
- `test_cancel_via_SIGINT_other_task`: the 3 keep-alive
`run_in_actor(sleep_forever)` one-shots become plain
`start_actor()` daemons (an idle daemon needs no "main" task,
and no longer shares a single dup'd `namesucka` name).
- `spawn_sub_with_sync_blocking_task`: the middle layer's spawn
becomes a blocking `to_actor.run(spin_for, an=an)` which parks
awaiting the sync-sleeping grandchild's result until cancelled
from above.
- `test_cancel_while_childs_child_in_sync_sleep`: the
fire-and-forget middle-actor spawn becomes a bg
`to_actor.run()` task in a local task-nursery; the root's
`assert 0` cancels it, driving the same
graceful-cancel-then-zombie-reap cascade on the sync-blocked
grandchild. The `man_cancel_outer` xfail param is unchanged.
Zero live `run_in_actor()` call-sites remain in this suite.
Gate: full `test_cancellation.py` module green on both `trio`
(18p/1xf) + `mp_spawn` (18p/1xf).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Third `test_cancellation.py` group of the `run_in_actor` removal
(#477),
- `spawn_and_error` fans out each level's erroring one-shots as
concurrent `to_actor.run(fn, an=an)` tasks in a local `trio`
task-nursery (recursing per spawner subactor), as does the
test-body's top-level spawner loop.
- the deterministic exact-breadth nested-BEG shape dies with the
legacy teardown-reap: each level now groups whatever subset of
sub-tree errors relay before the first one's cancel wins, and
a single-member group gets unwrapped by the runtime's own
`collapse_eg()` at every actor boundary — so a fully-raced
tree relays a bare `RemoteActorError` chain.
- loosen the shape walk accordingly: accept a lone
`RemoteActorError` or a 1..breadth group whose members box
`ExceptionGroup` (multi-relay), `AssertionError` (collapsed
leaf chain), `RemoteActorError` (re-boxed collapsed chain) or
`BaseExceptionGroup` (runtime reap-deadline `Cancelled`
upgrade); fold the windows-only tolerances into the same walk.
- raced sibling `trio.Cancelled`s are now ABSORBED by the
task-nursery instead of landing in the group, so the MTF
shape-mismatch xfail should consistently xpass — note added to
drop the marker once CI confirms.
- add an `else: pytest.fail()` so a silently-clean tree can no
longer pass.
Gate: both depths green on `trio` (10 consecutive runs) +
`mp_spawn`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`test_nested_multierrors`'s backend/depth budget `match` only
carries arms for the `trio` + `main_thread_forkserver` spawn
backends, so running under any other (e.g. `mp_spawn`) leaves
`timeout` unbound and crashes with an `UnboundLocalError` at the
headroom-scaling below. Add default per-depth arms riding the MTF
budgets (same per-spawn round-trip cost class).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Second `test_cancellation.py` group of the `run_in_actor` removal
(#477),
- one-shot subactors now run as concurrent `to_actor.run(fn,
an=an)` tasks in a local `trio` task-nursery, so their errors
raise WHILE the actor-nursery block is open (vs the legacy
teardown-reap) and the first error cancels sibling one-shots.
- wrap the task-nursery in `collapse_eg()` so the deterministic
single-error cases still surface a bare `RemoteActorError`.
- loosen the group-shape assertion: the relay-vs-cancel race
populates anywhere from 1 to `num_actors` `RemoteActorError`s
(the exact-`num_actors` BEG was `run_in_actor`'s
reap-all-at-teardown); group members are always
`RemoteActorError` now since sibling `trio.Cancelled`s are
absorbed by the task-nursery.
- move the daemon-portal call loop inside the task-nursery body
so the sleep-forever one-shot case is cancelled by the daemon
error raise.
- rename the `*run_in_actor*` param ids to `*one_shot*`.
Gate: 6 passed on both `trio` + `mp_spawn` backends.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Append two sections to the ria-removal plan capturing the
2026-07-02 hang episode + the resulting design pivot.
Regression writeup: the full-suite hang on
`test_tractor_cancels_aio` root-caused to the step-A reaper
hoist (`5cd190c5`), not the B2 handler merge. The happy-path
`_reap_ria_portals()` parks unbounded on `wait_for_result()`
after a user `portal.cancel_actor()`; the old spawn-backend
reaper raced `soft_kill()`'s scope-cancel, the hoist dropped
it. Records the `proc.poll()` death-watch fix + why poll (not
the event `wait_func`) bc `soft_kill` already awaits
`proc.sentinel` (a 2nd `wait_readable` -> `BusyResourceError`).
Pause writeup: user's insight that the hoist landed in the
wrong scope — result-waiting belongs in the `to_actor`
one-shot scope (`_invoke_in_subactor()`), beside `an` + a
local task-nursery + cancel-scope, where bounding the wait is
trivial + the hang dissolves. So the poll fix is likely
SUPERSEDED (flagged do-not-land); the anti-hang guard commit
(`d1fb4a1a`) stays red-first per the failing-test convention.
(this patch was generated in some part by `claude-code` using
`claude-opus-4-8` (`anthropic`))
First group of the `test_cancellation.py` `run_in_actor` removal
(#477),
- `test_remote_error` -> blocking `to_actor.run()` (single erroring
one-shot; a bad-arg `TypeError` still relays as a
`RemoteActorError`).
- `test_multierror` -> concurrent fan-out via
`gather_contexts([p.open_context(assert_err_ctx) ...])` over
`start_actor()` portals. NB `gather_contexts` is cancel-on-first
so the 2nd errorer is usually cancelled before relaying its own
exc and the pair collapses to a single `RemoteActorError` (vs the
legacy reap-all-at-teardown `BEG`-of-N) — the assertion now
accepts either shape.
- delete `test_multierror_fast_nursery` — a 25-actor stress test of
`run_in_actor`'s teardown-reap; no analogous surface under the
`to_actor` fan-out.
- add an `assert_err_ctx` `@context` shim for the `open_context`
fan-out.
Remaining `test_cancellation` groups (some_cancels_all, nested,
SIGINT, sync-blocking) still on `run_in_actor` — ported next.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Two sites migrated (#477 removal),
- `test_trynamic_trio`: donny + gretchen each wait on the *other*
to register, so they must run CONCURRENTLY — was two
non-blocking `run_in_actor()`s awaited after; now two
`to_actor.run()` one-shots scheduled into a local `trio`
task-nursery.
- the unregister-on-cancel cluster test: its non-streaming branch
spawned `run_in_actor(trio.sleep_forever)` purely to keep each
subactor alive + registered — a `start_actor()` daemon does that
without a "main" task, so the spawn loop collapses to the same
`start_actor()` the streaming branch already used.
Suite: 16 passed.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
`test_multi_actor_subs_arbiter_pub` used `run_in_actor()` to spawn
two forever-ish subscriber actors and hold their portals for a
later `cancel_actor()` (its `.result()` was commented out exactly
because `subs()` never cleanly returns). That deferred-spawn +
cancel shape isn't a blocking `to_actor.run()`, so convert to the
successor primitives (#477 removal),
- `start_actor()` per subscriber — keeps the portal for the
existing `cancel_actor()` teardown,
- run `subs()` on each via a background `Portal.run()` task in a
local `trio` nursery so both subscribe concurrently with the
test's `wait_for_actor` / topic checks,
- each bg runner swallows the `RemoteActorError`/`ContextCancelled`
that `cancel_actor()` relays; a trailing `tn.cancel_scope.cancel()`
drops any lingering runner.
Suite: 8 passed.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Migrate all 4 sites to blocking `tractor.to_actor.run()` (#477
removal),
- rename the two API-named tests to `test_to_actor_run_*`
(`same_func_in_child`, `can_skip_parent_main_inheritance`) —
they exercise the same spawn / `inherit_parent_main` path via
the successor API.
- the recursive `spawn()` helper drops its white-box
`an._children` / portal-`_peers` asserts (which probed
`run_in_actor`'s portal + nursery-tracking internals);
`to_actor.run()` returns the result and reaps internally, so
keep the user-facing `result == 10` check.
- `test_most_beautiful_word` drops the 2nd `wait_for_result()`
(the legacy result-cache re-fetch) — `to_actor.run()` delivers
the value once, no cache.
Suite: 9 passed.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Sole call-site: `run_in_actor(sleep_back_actor, ...)` ->
blocking `tractor.to_actor.run(..., an=n, ...)` (#477 removal).
The RPC-callback subactor is awaited in-caller instead of
reaped at nursery teardown; `name=`/`enable_modules=` map to
`to_actor.run()`'s same-named params, the rest to `**fn_kwargs`.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Sole call-site: an inlined `run_in_actor(...).result()` ->
blocking `tractor.to_actor.run(fn, an=an, ...)` (#477 removal).
Behaviour identical — the one-shot's result/error is awaited
in the caller's task rather than reaped at nursery teardown;
the enclosing `move_on_after` still cancels the sub in the
`error_in_child=False` case.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
First test-file of the #477 `.run_in_actor()` removal (blocking
`to_actor.run()` is the successor; the legacy non-blocking one-shot
is dropped, not replaced). All 9 call-sites migrated,
- blocking result/error/streaming-result tests -> `to_actor.run(fn,
an=an, ...)`; the "streaming" ones stream aio<->trio INSIDE the
subactor so the caller only awaits the final result.
- forever-task + cancel tests (`test_tractor_cancels_aio`,
`test_trio_cancels_aio`) -> `start_actor()` +
`Portal.open_context()` + cancel — can't block on a
never-returning task. Adds a small `sleep_forever_aio_ctx`
`@context` shim.
- greens the red `test_tractor_cancels_aio` anti-hang guard from
the prior commit: under the correctly-scoped API the wait is
bounded by the caller's cancel scope, so the hang is structurally
gone — not patched.
Suite: 34 passed, 2 xfailed (trio backend).
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Wrap `test_tractor_cancels_aio`'s `main()` in a
`trio.fail_after(9 * cpu_perf_headroom())` so a wedged remote
runtime can't hang the test forever. This is the blessed
anti-hang guard here bc `pytest-timeout`'s global cap is
intentionally off (it breaks `trio` under the fork backends,
per the `pyproject` NOTE).
The cap is generous + CPU-headroom-scaled bc it's an anti-hang
guard, not a perf assertion. Motivated by the
`._ria_nursery`-removal regression where a wedged ria-reaper
once hung this exact test indefinitely.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Step B2 of the `._ria_nursery` removal (issue #477; see
`ai/conc-anal/ria_nursery_removal_plan.md`). With the 2ndary
nursery gone (step B), the two nested error handlers in
`_open_and_supervise_one_cancels_all_nursery` collapse to one,
- the outer `except (Exception, BaseExceptionGroup,
trio.Cancelled)` existed to catch errors bubbling from the
old `._ria_nursery.__aexit__` reaper-group; that nursery no
longer exists.
- trace shows the outer handler's `raise` was already DEAD: the
inner handler records `errors[uid]` as its first action, so
`errors` is always non-empty by the time anything could reach
the outer handler, and the `finally`'s raise-from-`errors`
always superseded the outer `raise`.
- so fold both into a single `except BaseException as
_scope_err` guarding the lone daemon nursery; the `finally`
(unchanged) still raises the collected `errors` as a single
exc or `BaseExceptionGroup`.
- drop the now-unused `outer_err`/`inner_err` locals.
Behaviour-preserving (net ~30 lines lighter); the big diff is
the one-level de-indent of the handler body. The two remaining
`maybe_wait_for_debugger()` guards collapse to the single
pre-teardown wait.
Prompt-IO: ai/prompt-io/claude/20260702T222544Z_9201a2ed_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
Split from the step-B2 code commit to keep the runtime diff
free of `ai/` meta noise,
- `ai/conc-anal/ria_nursery_removal_plan.md`: add a "Step-B2
outcome" section — the dead-outer-`raise` trace, why the
merge is behavior-preserving, and the gate results.
- `ai/prompt-io/claude/20260702T222544Z_9201a2ed_*`: NLNet
provenance (log + unedited raw) for the step-B2 work.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Step B of the `._ria_nursery` removal (issue #477; see
`ai/conc-anal/ria_nursery_removal_plan.md`). With step A having
rerouted `.run_in_actor()` children onto the daemon nursery,
the 2ndary "run-in-actor" nursery spawns nothing and its stored
ref is never read — pure dead weight,
- collapse the inner `async with trio.open_nursery() as
ria_nursery` layer in
`_open_and_supervise_one_cancels_all_nursery`; `da_nursery` is
now the single nursery for ALL subactors.
- `ActorNursery.__init__` loses the `ria_nursery` param + the
`self._ria_nursery` attr; `start_actor()` loses its `nursery=`
escape-hatch (spawns via `self._da_nursery` directly).
- `._cancel_after_result_on_exit` stays — still the ria-child
discriminator for `_reap_ria_portals()`.
Behavior-preserving: a zero-task `trio.open_nursery()` only adds
a checkpoint. The two error handlers are KEPT (now nested under
the single nursery); merging them changes error/cancel
propagation and is deferred to its own PR (TODO left at the
outer `except`).
Prompt-IO: ai/prompt-io/claude/20260702T172233Z_5cd190c5_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
Split from the step-B code commit to keep the runtime diff
free of `ai/` meta noise,
- `ai/conc-anal/ria_nursery_removal_plan.md`: add a "Step-B
outcome" section — the empty-nursery collapse, why it's
behavior-preserving, the deliberate handler-merge deferral,
and the targeted-gate result.
- `ai/prompt-io/claude/20260702T172233Z_5cd190c5_*`: NLNet
provenance (log + unedited raw) for the step-B work.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
Step A of the `._ria_nursery` removal (issue #477 follow-up, see
`ai/conc-anal/ria_nursery_removal_plan.md`): `.run_in_actor()`
children now spawn via the default daemon nursery and their
result-reaping moves up into the `ActorNursery` machinery,
- new `_supervise._reap_ria_portals()`: one
`_spawn.cancel_on_completion()` task per ria child, run AFTER
`._join_procs` is set — replacing the per-child reaper task the
backends formerly spawned (keyed off
`._cancel_after_result_on_exit` membership) which required
routing such children into `._ria_nursery`.
- happy path: reap awaited right after `._join_procs.set()`,
preserving "collect ria results before daemon join" sequencing.
- error path: snapshot ria `(portal, subactor)` pairs (backend
`finally`s pop `._children` as procs reap), `await an.cancel()`,
THEN a 0.5s-bounded reap over the snapshot; anything collectable
is already queued in the local ctx and a parked reaper
self-cleans (`trio.Cancelled` results are never stashed). NB: a
concurrent reap+cancel variant deadlocked `test_multierror` and
a 3s bound blew `test_cancel_while_childs_child_in_sync_sleep`'s
deadline — deats in the plan doc's probe history.
- `spawn/_trio.py` + `spawn/_mp.py`: drop the membership branch,
per-child reaper nursery + now-unused `cancel_on_completion`
imports; the join phase is a bare `soft_kill()`.
`._ria_nursery` is now vestigial (zero spawn users): step B
deletes it + `start_actor()`'s `nursery=` escape hatch and merges
the supervisor's two error handlers.
Prompt-IO: ai/prompt-io/claude/20260702T165806Z_a34aaf98_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
Split from the step-A code commit to keep the runtime diff
free of `ai/` meta noise,
- `ai/conc-anal/ria_nursery_removal_plan.md`: agent-verified
machinery map + 3-step (A/B/C) design + probe history
(reap-relocation deadlock -> sequencing fix -> bound
tighten) + risk register for the `._ria_nursery` excision.
- `ai/prompt-io/claude/20260702T165806Z_a34aaf98_*`: NLNet
provenance (log + unedited raw) for the step-A work.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
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
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
Skip raw packet, decoded message, peer, and channel formatting when
transport logging is disabled. Keep message processing and wire
reads outside the guards so logging controls never affect IPC flow.
Also narrow the remaining pretty-struct TODO to require a
non-raising formatter with native-repr fallback.
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Remove the stale `Channel.from_addr()` design note now that its
`at_least_level()` guard avoids inactive pretty-rendering work.
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
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`))
Wrap `log.transport()` in `Channel.send()` and `log.runtime()` in
`PldRx.decode_pld()` with `log.at_least_level()` checks so that
expensive `pformat(payload)` / `repr(msg)` / `repr(pld)` calls are
skipped entirely when the respective log level is not active.
Previously the f-string arguments were eagerly evaluated before being
passed to the log method, even though `StackLevelAdapter.log()` would
then discard the message internally via its own `isEnabledFor()` check.
On high-frequency IPC paths this caused `pformat` to dominate CPU
usage (~60-70 %) as reported in #455.
This also restores the full diagnostic output (msg type, decoded
payload) that was temporarily commented out in 0373164 as a stopgap.
Resolves#455
Drop the stale sentinel experiment and fix the cancellation-path
comment. Document that cached regular `__aexit__()` failures are
always re-raised at the final consumer boundary.
Review: PR #488 (goodboy)
https://github.com/goodboy/tractor/pull/488
(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
Remove the unused `value` assignment after cache eviction and skip
unpacking stale resource state before raising its invariant error.
Review: PR #488 (Copilot)
https://github.com/goodboy/tractor/pull/488#pullrequestreview-4850557500
(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
W/o a live runtime `get_random()` named UDS socks purely by
`(prefix, pid)`, so two calls in one proc returned the SAME
`no_runtime_*@{pid}.sock` — the 2nd `.bind()` then tripped
`EADDRINUSE`. Append a per-call `uuid4().hex[:6]` token so
each call yields a distinct sockpath.
This fixes the 3 `tests.discovery.test_tpt_bind_addrs` uds
failures (one registrar + disjoint-bind, two non-registrar
binds) where `reg_addr` and a "random" bind addr aliased —
the uds CI job's only red, surfaced when this branch rebased
onto the newer base that carries those tests.
Scoped to the no-runtime branch ON PURPOSE: the runtime
`{name}@{pid}` convention stays deterministic so
`spawn._reap.unlink_uds_bind_addrs()` can still reconstruct
+ unlink a SIGKILL'd subactor's sock (#454).
Deats,
- `_uds.py`: add `uuid4` import + token in the no-runtime
branch
- `_testing.addr`: tighten `get_rando_addr()` docstring re the
intra-proc per-call token (not just pid-keyed namespacing)
(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
Standalone CLI companion to `cpu_perf_headroom()` (20cb99ec): idle
freq snapshots LIE — every static knob (`governor`, EPP,
`platform_profile`, `scaling_max_freq`) can read "performance"
while a firmware/EC power cap (AMD PPT/STAPM + friends) clamps the
package to ~30% the moment a sustained multi-core load lands,
masquerading as a `trio`-backend deadline-miss "regression" on
byte-identical code.
Deats,
- burns every core for `CPU_PERF_SECS` (default 4s) and samples the
ACHIEVED `scaling_cur_freq` steady-state (post boost-ramp) vs the
package max ceiling,
- exits 0 when the sustained fraction clears
`CPU_PERF_HEALTHY_FRAC` (default 0.45), 1 when throttled — so it
gates a suite run: `scripts/cpu-perf-check && pytest tests/ ...`,
- prints the static knobs first (to show they all read fine) then
the remediation list on failure (`platform_profile` bounce, USB-C
PD replug, `ryzenadj`, reboot) w/ the key reminder: do NOT bump
test budgets — the box is slow, not the code.
(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code