diff --git a/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.md b/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.md new file mode 100644 index 00000000..a1263daf --- /dev/null +++ b/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.md @@ -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. diff --git a/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.raw.md b/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.raw.md new file mode 100644 index 00000000..5edbcf6e --- /dev/null +++ b/ai/prompt-io/opencode/20260825T015742Z_e42ecb55_prompt_io.raw.md @@ -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. diff --git a/tests/test_to_actor.py b/tests/test_to_actor.py index 61216cc7..38abb78c 100644 --- a/tests/test_to_actor.py +++ b/tests/test_to_actor.py @@ -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( diff --git a/tractor/spawn/_mp.py b/tractor/spawn/_mp.py index 593d4e75..9e3b6879 100644 --- a/tractor/spawn/_mp.py +++ b/tractor/spawn/_mp.py @@ -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( diff --git a/tractor/spawn/_trio.py b/tractor/spawn/_trio.py index d7f49d94..57b242c1 100644 --- a/tractor/spawn/_trio.py +++ b/tractor/spawn/_trio.py @@ -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