From 22049794924d8dd77036463b99965718d78b9807 Mon Sep 17 00:00:00 2001 From: goodboy Date: Fri, 14 Aug 2026 09:52:33 -0400 Subject: [PATCH] Widen `UnwrappedAddress` to admit proto-keyed addrs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SpawnSpec.reg_addrs`/`.bind_addrs` pinned the wire shape to a 2-tuple, so a `tipc` addr (`('tipc', stype, inst, scope)`) died at the child w/ `msgspec.ValidationError: Expected array of length 2, got 4` -> `invalid SpawnSpec IPC msg`. Point those fields at `UnwrappedAddress` (which `SpawnSpec`s own TODO already asked for) and widen the alias. XXX VARIADIC (`tuple[str|int, ...]`) rather than a union of the two concrete shapes, bc `msgspec` refuses a union holding more than one array-like type. ?TODO, the real fix is the full proto-key migration (contract §1.1) after which this becomes a tagged union keyed off elem 0 and per-proto validation comes back. Note the alias is declared TWICE — `.msg.types` re-declares it to dodge a circular import (`._addr` -> `.ipc._tcp` -> `.msg`) and *that* copy is what actually validates the wire msg. (this patch was generated in some part by `claude-code` using `claude-opus-5` (`anthropic`)) --- tractor/discovery/_addr.py | 20 +++++++++++++++++--- tractor/msg/types.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/tractor/discovery/_addr.py b/tractor/discovery/_addr.py index f0d36c2e..9be508f2 100644 --- a/tractor/discovery/_addr.py +++ b/tractor/discovery/_addr.py @@ -65,9 +65,22 @@ log = get_logger() # UnwrappedAddress = ( # tcp/udp/uds + # ('127.0.0.1', 1616) + # ('/run/user/1000/tractor', 'registry@1616.sock') + # + # ..and the explicitly proto-keyed (`multiaddr`-spelled) + # form, which is where ALL backends should eventually land + # per the note below, + # ('tipc', 1953628160, 1616, 2) + # + # XXX VARIADIC bc `msgspec` refuses a union of >1 array-like + # type, so the two shapes can't be spelled as a union. Keep + # in sync with `.msg.types.UnwrappedAddress` which + # re-declares this to dodge a circular import AND is what + # actually validates the `SpawnSpec` wire msg! tuple[ - str, # host/domain(tcp), filesys-dir(uds) - int|str, # port/path(uds) + str|int, + ..., ] # ?TODO? should we also include another 2 fields from # our `Aid` msg such that we include the runtime `Actor.uid` @@ -82,6 +95,7 @@ UnwrappedAddress = ( class Address(Protocol): proto_key: ClassVar[str] unwrapped_type: ClassVar[UnwrappedAddress] + # whether `.ipc._server.Endpoint.start_listener()` should # reconcile a bound `.addr` against its listener's # `socket.getsockname()`. @@ -182,7 +196,7 @@ class Address(Protocol): _address_types: bidict[str, Type[Address]] = { 'tcp': TCPAddress, - 'uds': UDSAddress + 'uds': UDSAddress, } diff --git a/tractor/msg/types.py b/tractor/msg/types.py index 4f3e33cc..f09eae5b 100644 --- a/tractor/msg/types.py +++ b/tractor/msg/types.py @@ -188,6 +188,31 @@ class Aid( __repr__ = pretty_struct.Struct.__repr__ +# NOTE, mirrors `.discovery._addr.UnwrappedAddress` but is +# re-declared here to dodge the circular import +# (`._addr` -> `.ipc._tcp` -> `.msg`). +# +# XXX this is the **wire** shape, so widening it is a wire-format +# change; keep the two decls in sync. +# XXX VARIADIC on purpose! `msgspec` rejects a union holding +# more than one array-like type ("Type unions may not contain +# more than one array-like (list, set, tuple) type"), so the two +# concrete shapes, +# +# ('127.0.0.1', 1616) # tcp +# ('/run/user/1000/tractor', 'x.sock') # uds +# ('tipc', 1953628160, 1616, 2) # proto-keyed (tipc) +# +# can't be spelled as `tuple[str, str|int]|tuple[str, int, int, +# int]`. Widen to one homogeneous variadic tuple instead. +# +# ?TODO, the real fix is the `UnwrappedAddress` proto-key +# migration (see `.discovery._addr`) after which this becomes a +# tagged union keyed off elem 0 and full per-proto validation +# comes back. +UnwrappedAddress = tuple[str|int, ...] + + class SpawnSpec( pretty_struct.Struct, tag=True, @@ -213,8 +238,8 @@ class SpawnSpec( # TODO: not just sockaddr pairs? # -[ ] abstract into a `TransportAddr` type? - reg_addrs: list[tuple[str, str|int]] - bind_addrs: list[tuple[str, str|int]]|None + reg_addrs: list[UnwrappedAddress] + bind_addrs: list[UnwrappedAddress]|None # TODO: caps based RPC support in the payload?