Clarify provisional child registration
Child monitors register before their IPC handshake so cancellation owns every started process, but the bare `None` portal arg obscured that `Portal(chan)` replaces the provisional entry after connection. Document that transition and name all `_register_child()` args in both spawn backends. Replace the MP test's positional-only lambda with a signature-accurate fake which asserts the provisional portal state. Caught-during: review remediation Found-via: `/run-tests` test_mp_late_registration_never_starts_process Review: PR #481 (goodboy) https://github.com/goodboy/tractor/pull/481#pullrequestreview-5012942328 Prompt-IO: ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.md (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))wkt/to_actor_subpkg
parent
e42ecb559d
commit
ce430fca64
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
model: openai/gpt-5.6-sol
|
||||
service: opencode
|
||||
session: d9d7df2c-7044-463f-8768-ec024718eac9
|
||||
timestamp: 2026-08-25T01:57:42Z
|
||||
git_ref: e42ecb55
|
||||
scope: code
|
||||
substantive: true
|
||||
raw_file: 20260825T015742Z_e42ecb55_prompt_io.raw.md
|
||||
---
|
||||
|
||||
## Prompt
|
||||
|
||||
Continue PR #481 review remediation after committing the `Aid` reap-map
|
||||
migration. The human selected "keep" for comments explaining why both
|
||||
spawn backends provisionally register children with `portal=None`.
|
||||
|
||||
## Response summary
|
||||
|
||||
Document that a child has no `Portal` until its IPC handshake yields a
|
||||
`Channel`, and make `portal=None` explicit at both registration calls.
|
||||
Identify the later replacement of each provisional entry with
|
||||
`Portal(chan)`. Update the MP registration test double to accept and
|
||||
assert the explicit provisional portal state. Name every registration
|
||||
argument consistently in both backends.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `tractor/spawn/_mp.py` - clarify provisional MP registration.
|
||||
- `tractor/spawn/_trio.py` - clarify provisional Trio registration.
|
||||
- `tests/test_to_actor.py` - model explicit provisional registration.
|
||||
|
||||
## Human edits
|
||||
|
||||
The human explicitly selected "keep" after receiving keep/defer/drop
|
||||
options for this paired clarification. During local review, the human
|
||||
then requested that `subactor` and `proc` also be passed by name in both
|
||||
backend calls. No direct source-line edits were made by the human.
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
model: openai/gpt-5.6-sol
|
||||
service: opencode
|
||||
timestamp: 2026-08-25T01:57:42Z
|
||||
git_ref: e42ecb55
|
||||
diff_cmd: git diff HEAD~1..HEAD
|
||||
---
|
||||
|
||||
Implement the approved PR #481 clarification for provisional child
|
||||
registration in both process-spawn backends.
|
||||
|
||||
> `git diff HEAD~1..HEAD -- tractor/spawn/_mp.py`
|
||||
|
||||
> `git diff HEAD~1..HEAD -- tractor/spawn/_trio.py`
|
||||
|
||||
Explain that `portal=None` is provisional because no `Portal` can exist
|
||||
until the child completes its IPC handshake and returns a `Channel`.
|
||||
Use an explicit keyword argument and identify the later replacement with
|
||||
`Portal(chan)`.
|
||||
|
||||
Run lint and the full `to_actor` runtime suite.
|
||||
|
|
@ -456,6 +456,24 @@ def test_mp_late_registration_never_starts_process(
|
|||
|
||||
process = FakeProcess()
|
||||
|
||||
def register_child(
|
||||
subactor: object,
|
||||
proc: object,
|
||||
portal: object|None,
|
||||
) -> tuple[trio.Event, trio.Event, bool]:
|
||||
'''
|
||||
Simulate provisional MP registration before child startup.
|
||||
|
||||
'''
|
||||
assert subactor
|
||||
assert proc is process
|
||||
assert portal is None
|
||||
return (
|
||||
trio.Event(),
|
||||
trio.Event(),
|
||||
True,
|
||||
)
|
||||
|
||||
class FakeContext:
|
||||
def get_start_method(self) -> str:
|
||||
return 'spawn'
|
||||
|
|
@ -465,11 +483,7 @@ def test_mp_late_registration_never_starts_process(
|
|||
return process
|
||||
|
||||
nursery = SimpleNamespace(
|
||||
_register_child=lambda *args: (
|
||||
trio.Event(),
|
||||
trio.Event(),
|
||||
True,
|
||||
),
|
||||
_register_child=register_child,
|
||||
)
|
||||
subactor = SimpleNamespace(
|
||||
aid=tractor.msg.Aid(
|
||||
|
|
|
|||
|
|
@ -141,14 +141,16 @@ async def mp_proc(
|
|||
# `multiprocessing` only (since no async interface): publish the
|
||||
# process and its reap coordination before start so cancellation
|
||||
# can own every subsequently started child.
|
||||
# No `Portal` exists until the IPC handshake returns `chan`.
|
||||
# Replace this provisional entry with `Portal(chan)` below.
|
||||
(
|
||||
reap_request,
|
||||
_,
|
||||
cancel_during_registration,
|
||||
) = actor_nursery._register_child(
|
||||
subactor,
|
||||
proc,
|
||||
None,
|
||||
subactor=subactor,
|
||||
proc=proc,
|
||||
portal=None,
|
||||
)
|
||||
if cancel_during_registration:
|
||||
raise RuntimeError(
|
||||
|
|
|
|||
|
|
@ -130,14 +130,17 @@ async def trio_proc(
|
|||
f' |_{proc}\n'
|
||||
)
|
||||
|
||||
# No `Portal` exists until the IPC handshake returns
|
||||
# `chan`. Replace this provisional entry with
|
||||
# `Portal(chan)` below.
|
||||
(
|
||||
reap_request,
|
||||
_,
|
||||
cancel_during_registration,
|
||||
) = actor_nursery._register_child(
|
||||
subactor,
|
||||
proc,
|
||||
None,
|
||||
subactor=subactor,
|
||||
proc=proc,
|
||||
portal=None,
|
||||
)
|
||||
if cancel_during_registration:
|
||||
cancelled_during_spawn = True
|
||||
|
|
|
|||
Loading…
Reference in New Issue