--- model: claude-opus-4-7[1m] service: claude timestamp: 2026-04-17T03:58:05Z git_ref: 61a73ba diff_cmd: git diff 61a73ba~1..61a73ba --- Code generated in this turn was committed verbatim as `61a73bae` ("Mv `trio_proc`/`mp_proc` to per-backend submods"). Per diff-ref mode, per-file code is captured via the pointers below, each followed by a prose summary of what the AI generated. Non-code output (sanity-check results, design rationale) is included verbatim. ## Per-file generated content ### `tractor/spawn/_trio.py` (new, 292 lines) > `git diff 61a73ba~1..61a73ba -- tractor/spawn/_trio.py` Pure lift-and-shift of `trio_proc()` out of `tractor/spawn/_spawn.py` (previously lines 448–670). Added AGPL header + module docstring describing the backend; imports include local `from ._spawn import cancel_on_completion, hard_kill, soft_kill` which creates the bottom-of-module late-import pattern in the core file to avoid a cycle. All call sites, log-format strings, and body logic are byte-identical to the originals — no semantic change. ### `tractor/spawn/_mp.py` (new, 235 lines) > `git diff 61a73ba~1..61a73ba -- tractor/spawn/_mp.py` Pure lift-and-shift of `mp_proc()` out of `tractor/spawn/_spawn.py` (previously lines 672–842). Same AGPL header convention. Key difference from `_trio.py`: uses `from . import _spawn` (module import, not from-import) for `_ctx` and `_spawn_method` references — these are mutated at runtime by `try_set_start_method()`, so late binding via `_spawn._ctx` / `_spawn._spawn_method` is required for correctness. Also imports `cancel_on_completion`, `soft_kill`, `proc_waiter` from `._spawn`. ### `tractor/spawn/_spawn.py` (modified, 847 → 448 LOC) > `git diff 61a73ba~1..61a73ba -- tractor/spawn/_spawn.py` - removed `trio_proc()` body (moved to `_trio.py`) - removed `mp_proc()` body (moved to `_mp.py`) - pruned imports now unused in core: `sys`, `is_root_process`, `current_actor`, `is_main_process`, `_mp_main`, `ActorFailure`, `pretty_struct`, `_pformat` - added bottom-of-file late imports `from ._trio import trio_proc` and `from ._mp import mp_proc` with a one-line comment explaining why (circular dep) - `_methods` dict unchanged structurally; still binds `'trio' → trio_proc`, `'mp_spawn' → mp_proc`, `'mp_forkserver' → mp_proc` ### `tractor/spawn/__init__.py` (modified) > `git diff 61a73ba~1..61a73ba -- tractor/spawn/__init__.py` Docstring rewrite only — no code. New text describes the per-backend `Layout` with `- ._spawn` (core), `- ._trio` (default), `- ._mp` (two mp variants), and reiterates the "no eager import" NOTE. ### `tractor/_testing/pytest.py` (modified) > `git diff 61a73ba~1..61a73ba -- tractor/_testing/pytest.py` Two-line logical change (plus a comment): - `from typing import` grows `get_args` - `pytest_generate_tests()` replaces the hardcoded `('mp_spawn','mp_forkserver','trio')` tuple with `get_args(SpawnMethodKey)` via lazy import `from tractor.spawn._spawn import SpawnMethodKey` inside the function body (matching the project's existing lazy-import convention for the spawn module) ## Non-code output (verbatim) ### Design rationale for the file split From my Phase A plan turn (already captured in `20260417T034918Z_9703210_prompt_io.md`): - `_spawn.py` stays as the "core" rather than renamed to `_core.py` so external imports (`_testing/pytest.py:228` imports `try_set_start_method` from `tractor.spawn._spawn`) keep working without churn. - Per-backend extraction chosen over alternatives (e.g. splitting generic helpers further) because the immediate motivation is hosting a 3rd `_subint.py` sibling cleanly in Phase B. ### Sanity-check output (verbatim terminal excerpts) Post-extraction import probe: ``` extraction OK _methods: {'trio': 'tractor.spawn._trio.trio_proc', 'mp_spawn': 'tractor.spawn._mp.mp_proc', 'mp_forkserver': 'tractor.spawn._mp.mp_proc'} ``` Spawn-relevant test subset (`tests/test_local.py test_rpc.py test_spawning.py test_multi_program.py test_discovery.py`): ``` 37 passed, 1 skipped, 14 warnings in 55.37s ``` Full suite: ``` 350 passed, 14 skipped, 7 xfailed, 1 xpassed, 151 warnings in 437.73s (0:07:17) ``` No regressions vs. `main`. One transient `-x` early-stop `ERROR` on `test_close_channel_explicit_remote_registrar[trio-True]` was flaky (passed solo, passed without `-x`), not caused by this refactor. ### Commit message Also AI-drafted (via `/commit-msg`) — the 40-line message on commit `61a73bae` itself. Not reproduced here; see `git log -1 61a73bae`.