Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a753625
Wait for ctx exit in `maybe_open_context()`
goodboy Aug 4, 2026
55ec3db
Drop unused `_Cache` teardown bindings
goodboy Aug 8, 2026
daa661a
Clarify `maybe_open_context()` teardown notes
goodboy Aug 11, 2026
83b3488
Merge pull request #488 from goodboy/wkt/moc_teardown_completion
goodboy Aug 11, 2026
148a098
avoid format on the hot send path
mahmoudhas May 5, 2026
0e11ff7
Guard hot-path log calls to avoid payload rendering when disabled
May 8, 2026
67280c2
Honor log disable controls in hot-path guards
goodboy Aug 12, 2026
84ec895
Drop resolved channel log-guard TODO
goodboy Aug 12, 2026
935c8cf
Guard receive-path transport rendering
goodboy Aug 12, 2026
92c737a
Merge pull request #458 from mahmoudhas/fix/guard-hot-path-log-rendering
goodboy Aug 12, 2026
203a0f7
Add `.trionics.start_or_cancel()` test suite
goodboy Jul 2, 2026
1c7d0c7
Match Trio's startup error exactly
goodboy Aug 12, 2026
ae67e2f
Assert cancellation at the startup boundary
goodboy Aug 12, 2026
d887603
Merge pull request #479 from goodboy/wkt/start_or_cancel_tests_474
goodboy Aug 12, 2026
5c4d42c
Bump setuptools from 82.0.1 to 83.0.0
dependabot[bot] Jul 25, 2026
99f9bec
Merge pull request #487 from goodboy/dependabot/uv/setuptools-83.0.0
goodboy Aug 12, 2026
4b4cc76
Bump idna from 3.10 to 3.18
dependabot[bot] May 19, 2026
3ad7e7e
Merge pull request #459 from goodboy/dependabot/uv/idna-3.15
goodboy Aug 12, 2026
cfb1b42
Add `tractor.to_actor` one-shot task API subpkg
goodboy Jul 2, 2026
2cbdf1d
Add `tests/test_to_actor.py` one-shot API suite
goodboy Jul 2, 2026
452c59b
Add `to_actor` one-shot parallelism example
goodboy Jul 2, 2026
c800dfe
Add `_ria_nursery` removal plan + step-A prompt-io
goodboy Jul 2, 2026
8eb59fe
Hoist ria-reaping out of the spawn backends
goodboy Jul 2, 2026
a9309e4
Doc step-B outcome + prompt-io
goodboy Jul 2, 2026
ff599a2
Drop the vestigial `._ria_nursery`
goodboy Jul 2, 2026
e8b0a81
Doc step-B2 handler-merge + prompt-io
goodboy Jul 2, 2026
65ef081
Merge the supervise error handlers into one
goodboy Jul 2, 2026
af81b98
Add anti-hang `fail_after` cap to aio-cancel test
goodboy Jul 2, 2026
60847b8
Port `test_infected_asyncio` off `run_in_actor`
goodboy Jul 3, 2026
3a715a0
Port `test_runtime` off `run_in_actor`
goodboy Jul 3, 2026
5416568
Port `test_rpc` off `run_in_actor`
goodboy Jul 3, 2026
4fc7a00
Port `test_spawning` off `run_in_actor`
goodboy Jul 3, 2026
7fbbd65
Port `test_pubsub` off `run_in_actor`
goodboy Jul 3, 2026
b1ede9a
Port `test_registrar` off `run_in_actor`
goodboy Jul 3, 2026
c1f92ca
Port `test_cancellation` multierror cluster off `run_in_actor`
goodboy Jul 3, 2026
4c61537
Doc ria-reap hang fix + paused reaper re-scope
goodboy Jul 6, 2026
230b726
Port `test_some_cancels_all` off `run_in_actor`
goodboy Jul 6, 2026
60b816a
Fix unbound `timeout` under non-trio/MTF backends
goodboy Jul 6, 2026
721b25b
Port `test_nested_multierrors` off `run_in_actor`
goodboy Jul 6, 2026
b9ee783
Port SIGINT + sync-sleep cancel tests off `run_in_actor`
goodboy Jul 6, 2026
59cd73b
Port `test_dynamic_pub_sub` off `run_in_actor`
goodboy Jul 6, 2026
cd85b99
Port non-debugging examples off `run_in_actor`
goodboy Jul 6, 2026
81f72ef
Port debugging examples off `run_in_actor`
goodboy Jul 6, 2026
23b6997
Port docs off `run_in_actor` + `Portal.wait_for_result`
goodboy Jul 6, 2026
0936461
Fix stale `@pub` docstring example in `experimental`
goodboy Jul 6, 2026
057f070
Remove `run_in_actor()` + the ria reap cluster
goodboy Jul 6, 2026
3c86fd8
Fix mutual-rendezvous premature-reap race (#477)
goodboy Jul 6, 2026
238625b
Name every `ActorNursery` binding `an` in tests/examples
goodboy Jul 6, 2026
6e2ce2b
Doc the #477 migration outcome + one-shot-acm sketch
goodboy Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
460 changes: 460 additions & 0 deletions ai/conc-anal/ria_nursery_removal_plan.md

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions ai/prompt-io/claude/20260702T154255Z_65bf9df5_prompt_io.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
model: claude-fable-5
service: claude
session: f6c84722-471a-4458-9a80-e453fea9029f
timestamp: 2026-07-02T15:42:55Z
git_ref: 65bf9df5
scope: code
substantive: true
raw_file: 20260702T154255Z_65bf9df5_prompt_io.raw.md
---

## Prompt

Driver prompt file `ai/prompt-io/prompts/issue_477.md`:

> attempt to resolve
> https://github.com/goodboy/tractor/issues/477
> do it with /open-wkt.

(plus a hard stop-for-human-review deadline of 12:50PM
EST the same day)

Issue #477 asks to factor `ActorNursery.run_in_actor()`
(and possibly `Portal.run()`) out of the nursery
internals into a new `tractor.to_actor` wrapper
subpackage of "higher level one shot" single-remote-task
APIs, adopting the `trio.to_thread`/`anyio.to_process`
parlance, so that error collection/propagation moves up
into the caller's local `trio` scope and the nursery's
spawn machinery can eventually drop the
`._ria_nursery` coupling.

## Response summary

First-cut `tractor.to_actor` subpkg delivering the
one-shot API composed purely from the existing
daemon-spawn + portal primitives (`start_actor()` +
`Portal.run()` + `Portal.cancel_actor()`), leaving the
legacy `.run_in_actor()` machinery untouched (formal
deprecation deferred until in-repo usage migrates):

- `to_actor.run(fn, **fn_kwargs) -> Any`: spawn a
subactor, schedule `fn` as its lone remote task, wait
on and return its result, ALWAYS reaping the subactor
(shield-safe `finally`). Remote errors raise in the
caller's task as boxed `RemoteActorError`s.
- placement variants: `portal=` reuses a running actor
(no spawn/reap), `an=` spawns from a caller-managed
actor-nursery, neither opens a call-scoped private
`open_nursery()` (implicitly booting the runtime,
configurable via `runtime_kwargs`).
- fail-fast validation before any spawn: non-streaming
async fn required; `portal=`/`an=` mutually
exclusive; `runtime_kwargs` rejected alongside any
placement opt.
- `run_in_actor()` TODO/docstring now cross-reference
the successor API.

## Files changed

- `tractor/to_actor/__init__.py` — new subpkg,
re-exports `run`
- `tractor/to_actor/_api.py` — `run()` +
`_invoke_in_subactor()` + `_validate_one_shot_fn()`
- `tractor/__init__.py` — top-level `to_actor`
re-export
- `tractor/runtime/_supervise.py` — comment/docstring
pointers from `run_in_actor()` to the successor
- `tests/test_to_actor.py` — 11-test suite covering
all placement variants, error relay, the concurrent
worker-pool-ish pattern and arg validation
- `examples/parallelism/to_actor_one_shots.py` —
runnable demo (auto-collected by
`test_docs_examples.py`)

## Human edits

None yet — pending human review (work paused before the
12:50PM EST deadline per the driver prompt).
100 changes: 100 additions & 0 deletions ai/prompt-io/claude/20260702T154255Z_65bf9df5_prompt_io.raw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
model: claude-fable-5
service: claude
timestamp: 2026-07-02T15:42:55Z
git_ref: 65bf9df5
diff_cmd: git diff main..wkt/to_actor_subpkg
---

# Raw AI output (diff-ref mode)

All generated code is committed on the
`wkt/to_actor_subpkg` branch; per diff-ref mode each
file's verbatim content is reachable via the pointers
below rather than duplicated here.

## Generated files

> `git diff main..wkt/to_actor_subpkg -- tractor/to_actor/__init__.py`

New subpackage init: module docstring establishing the
`trio.to_thread`/`anyio.to_process` "run it over there"
parlance for actors, plus the single public re-export
`run as run` from `._api`.

> `git diff main..wkt/to_actor_subpkg -- tractor/to_actor/_api.py`

The one-shot invocation impl, composed entirely from the
lower level daemon-spawn + portal primitives as
prescribed by issue #477:

- `_validate_one_shot_fn()`: the `Portal.run()`
non-streaming-async-fn constraint checked up-front,
before any subactor is spawned.
- `_invoke_in_subactor()`: `an.start_actor()` ->
`Portal.run()` -> always-reap via
`Portal.cancel_actor()` in a `finally` (the cancel
req's bounded wait is internally shielded so the reap
also runs under caller-scope cancellation).
- `run()`: the public API. Placement options:
`portal=` (reuse a running actor, no spawn/reap),
`an=` (spawn from a caller-managed nursery), or
neither (private `open_nursery()` scoped to the call,
implicitly booting the runtime when needed, tunable
via pass-through `runtime_kwargs`). Spawn opts mirror
`ActorNursery.start_actor()`; `**fn_kwargs` are
relayed to the remote task. Errors raise in the
caller's task as boxed `RemoteActorError`s.
`runtime_kwargs` alongside any placement opt is a
hard `ValueError`, never silently ignored.

> `git diff main..wkt/to_actor_subpkg -- tractor/__init__.py`

Top-level `from . import to_actor as to_actor`
re-export.

> `git diff main..wkt/to_actor_subpkg -- tractor/runtime/_supervise.py`

Comment/docstring-only: the `run_in_actor()` deprecation
TODO now points at the implemented `.to_actor.run()`
successor (checkbox ticked) and the method docstring
gains a NOTE steering users to the new API; remaining
TODO items are the `DeprecationWarning` emission +
in-repo usage migration.

> `git diff main..wkt/to_actor_subpkg -- tests/test_to_actor.py`

11-test suite: private-nursery one-shot, implicit
runtime boot via `runtime_kwargs`, remote-error relay to
the caller's task (bare + caller-managed nursery),
caller-nursery spawn, portal reuse w/o implicit reap,
the concurrent worker-pool-ish pattern (local `trio`
nursery x shared `an`), and the four validation
rejections (sync fn, async-gen fn, `portal`+`an`
combo, `runtime_kwargs`+placement combo).

> `git diff main..wkt/to_actor_subpkg -- examples/parallelism/to_actor_one_shots.py`

Runnable example (auto-collected by
`test_docs_examples.py`): the fully-implicit one-shot
plus the concurrent worker-pool-ish prime-check pattern
against a shared caller-managed actor-nursery.

## Test runs (verbatim)

```
tests/test_to_actor.py .......... [100%]
============= 10 passed in 4.29s =============
```

Regression subset for touched modules
(`test_local.py test_rpc.py test_spawning.py
test_cancellation.py`):

```
38 passed, 1 xfailed, 24 warnings in 80.71s (0:01:20)
```

(warnings are pre-existing stdlib `os.fork()`
DeprecationWarnings from the mp spawn backends, not
introduced by this change)
80 changes: 80 additions & 0 deletions ai/prompt-io/claude/20260702T161624Z_65bf9df5_prompt_io.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
model: claude-fable-5
service: claude
session: f4da6654-63f9-4641-b567-f200da46d697
timestamp: 2026-07-02T16:16:24Z
git_ref: 65bf9df5
scope: tests
substantive: true
raw_file: 20260702T161624Z_65bf9df5_prompt_io.raw.md
---

## Prompt

> attempt to resolve
> https://github.com/goodboy/tractor/issues/474
> do it with /open-wkt.

Issue #474: "We need test suite for
`.trionics.start_or_cancel()`" — dig out the use case
from `modden` as a unit test (and provide motivation
for upstream `trio` to possibly provide better
porcelain around this case). The wrapper landed via
PR #464 with no tests.

## Response summary

New `tests/trionics/test_taskc.py` (9 tests) covering
`start_or_cancel()`, authored in wkt
`start_or_cancel_tests_474`.

Behaviour was first probed empirically (trio 0.29):
the lossy `RuntimeError('child exited without calling
task_status.started()')` only fires when the child
exits pre-`.started()` WITHOUT propagating the ambient
`Cancelled` — i.e. when the child (or lib code it
calls) absorbs the cancel in a graceful-teardown
pattern; a well-behaved child surfaces `Cancelled`
straight out of `.start()`. The `modden`
`progman.open_wks()` use case was reconstructed from
`modden/runtime/progman.py` accordingly.

Tests (each `use_start_or_cancel` parametrization also
pins upstream trio's current lossy behaviour as
wart-documentation):

- `test_sibling_err_not_masked_by_startup_rte` — the
`modden` case: sibling error OOB-cancels the shared
nursery scope; with the wrapper ONLY the root-cause
`ValueError` escapes; bare `.start()` adds the lossy
RTE alongside.
- `test_pure_oob_cancel_not_morphed_to_rte` — plain
ancestor `cs.cancel()`: wrapper → clean exit; bare
→ eg-wrapped RTE.
- `test_genuine_startup_rte_still_raised` — no
cancellation → protocol-bug RTE re-raised same as
bare.
- `test_childs_own_rte_never_demoted_to_cancel` — a
child's own `RuntimeError('never got started!')` /
`RuntimeError(1234)` under ambient cancel is never
demoted to `Cancelled` (exact-msg-match + str-guard
regression cover).
- `test_started_value_and_args_passthru` — happy path:
positional args, `name=`, `.started()` value.

Verified: 9/9 pass; 0 flakes across 50 hammer runs;
two impl mutations (checkpoint removed; guard relaxed
to substring match) each caught by exactly the
targeted tests; `tests/trionics/` +
`tests/test_trioisms.py` subset green (23 passed,
5 xfailed); ruff clean; 69-col style.

## Files changed

- `tests/trionics/test_taskc.py` — new
`start_or_cancel()` unit-test suite (gh #474).

## Human edits

Pending review — session paused pre-commit per user
deadline; nothing committed as of this entry.
107 changes: 107 additions & 0 deletions ai/prompt-io/claude/20260702T161624Z_65bf9df5_prompt_io.raw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
---
model: claude-fable-5
service: claude
timestamp: 2026-07-02T16:16:24Z
git_ref: 65bf9df5
diff_cmd: git diff main..wkt/start_or_cancel_tests_474
---

# Raw output — gh #474 `start_or_cancel()` test suite

## Generated test code

> `git diff main..wkt/start_or_cancel_tests_474 -- tests/trionics/test_taskc.py`

Prose summary of the generated module
(`tests/trionics/test_taskc.py`):

- module docstring framing the `trio.Nursery.start()`
startup-cancellation wart, the wrapper's repair, and
the intent that `use_start_or_cancel=False` params
double as upstream-trio wart-documentation (break on
a trio upgrade → upstream may have shipped porcelain,
re-audit the wrapper); cites gh #474 / PR #464 and
`modden`'s `progman.open_wks()` as the source use
case.
- shared children: `absorbs_cancel_pre_started()` (the
graceful-teardown cancel-absorber which triggers the
lossy RTE path) + `raise_val_err()` (fast-erroring
sibling).
- `test_sibling_err_not_masked_by_startup_rte`
(parametrized `use_start_or_cancel`): asserts eg
contains exactly one `ValueError` and, wrapper-case,
NO residual RTE (`eg.split(ValueError)` remainder is
`None`); bare-case, the residual RTE carries trio's
exact "child exited without calling" wording.
- `test_pure_oob_cancel_not_morphed_to_rte`
(parametrized): wrapper-case runs clean and asserts
`cs.cancelled_caught`; bare-case asserts the
eg-wrapped RTE.
- `test_genuine_startup_rte_still_raised`
(parametrized): no-cancel protocol bug → RTE with
trio's wording from both call forms.
- `test_childs_own_rte_never_demoted_to_cancel`
(parametrized `rte_arg` in `'never got started!'`,
`1234`): child cancels the ambient scope then raises
its own RTE synchronously (no checkpoint between →
deterministically under-cancellation at catch time);
asserts the RTE survives with `args[0]` intact.
- `test_started_value_and_args_passthru`: `.started()`
value, positional args and the `name=` kwarg (via
`trio.lowlevel.current_task().name`) all forward.

## Non-code output (verbatim highlights)

Behaviour probe (trio 0.29, scratchpad scripts) — the
decision basis for the test shapes:

```
== B-sibling-err use_soc=False
start raised: RuntimeError('child exited without
calling task_status.started()')
top-level: ExceptionGroup([ValueError('sibling blew
up!'), RuntimeError('child exited without calling
task_status.started()')])
== B-cs-cancel use_soc=False
top-level: ExceptionGroup([RuntimeError('child
exited without calling task_status.started()')])
== B-sibling-err use_soc=True
start raised: Cancelled()
top-level: ExceptionGroup([ValueError('sibling blew
up!')])
== B-cs-cancel use_soc=True
start raised: Cancelled()
top-level: clean return
== own-rte-under-cancel (both) -> RTE('never got
started!') propagates unchanged
```

Key finding: with a WELL-BEHAVED (non-absorbing) child
an OOB ancestor cancel surfaces `Cancelled` directly
from `.start()` on trio 0.29 — the lossy RTE requires
the child to absorb its cancel pre-`.started()`, which
is what `modden`'s `open_from_wks` teardown did. Trio's
nursery-exit wait defers cancel delivery to children,
so all tested shapes are deterministic (0 flakes / 50
runs).

Mutation verification:

```
mutation 1 (checkpoint_if_cancelled removed):
FAILED test_sibling_err_not_masked_by_startup_rte[True]
FAILED test_pure_oob_cancel_not_morphed_to_rte[True]
mutation 2 (guard relaxed to 'started' substring,
isinstance dropped):
FAILED test_childs_own_rte_never_demoted_to_cancel[never got started!]
FAILED test_childs_own_rte_never_demoted_to_cancel[1234]
```

Final runs:

```
tests/trionics/test_taskc.py: 9 passed in 0.03s
hammer: 0/50 runs failed
tests/trionics/ + tests/test_trioisms.py:
23 passed, 5 xfailed in 3.02s
```
Loading