Key `TIPCAddress` instances by actor UUID

TIPC service names span the cluster while PIDs remain host-local.
Hashing only `(name, pid)` could therefore make same-named actors
on different hosts silently share one round-robin service name.

Derive the live-runtime seed from `Aid.uid` so the actor UUID
separates those names while keeping each identity reproducible.
Pin both properties with a deterministic regression test.

Review: PR #493 (copilot-pull-request-reviewer[bot],goodboy)
https://github.com/goodboy/tractor/pull/493

(this patch was generated in some part by `opencode` using
`gpt-5.6-sol` (`openai`))
wkt/pr493_review
Gud Boi 2026-08-18 13:28:02 -04:00
parent a19a639ddf
commit d52c78c106
2 changed files with 43 additions and 5 deletions

View File

@ -232,6 +232,43 @@ def test_get_random_collision_resistance():
assert all(addr.is_valid for addr in addrs)
def test_get_random_keys_live_actors_by_uuid(
monkeypatch: pytest.MonkeyPatch,
):
'''
TIPC names are cluster-wide while PIDs are host-local. Hashing
only `(actor name, pid)` therefore made same-named actors with
equal PIDs on different hosts publish one service name, where
TIPC silently round-robins connects between them.
Hold the actor name and PID fixed while changing only its UUID;
distinct instances prove the globally unique identity field is
now part of the derivation.
'''
monkeypatch.setattr(_tipc.os, 'getpid', lambda: 1616)
def get_addr(uuid: str) -> TIPCAddress:
actor = SimpleNamespace(
aid=Aid(
name='worker',
uuid=uuid,
pid=1616,
)
)
monkeypatch.setattr(
_tipc,
'current_actor',
lambda **kwargs: actor,
)
return TIPCAddress.get_random()
first: TIPCAddress = get_addr('actor-uuid-a')
second: TIPCAddress = get_addr('actor-uuid-b')
assert first._instance != second._instance
assert get_addr('actor-uuid-a')._instance == first._instance
def test_get_random_honors_bindspace():
addr: TIPCAddress = TIPCAddress.get_random(
bindspace=TIPC_NODE_SCOPE,

View File

@ -369,10 +369,11 @@ class TIPCAddress(
between them (verified). I.e. a collision manifests as
*silent crosstalk*, not an error.
So the instance is a `blake2b` digest of a per-call-unique
seed, giving a well-spread 32b value. Being a pure fn of the
seed it is also *reproducible*, which the (follow-up)
registrar-less discovery fast-path wants.
So the instance is a `blake2b` digest of the actor UUID, or
a per-call token outside a live runtime, giving a well-spread
32b value. Being a pure fn of the seed it is also
*reproducible*, which the (follow-up) registrar-less
discovery fast-path wants.
NOTE the residual risk is birthday-bounded: ~1.2e-2 for 10k
names sharing one `_stype`. See plan 01 §9 for the
@ -384,7 +385,7 @@ class TIPCAddress(
err_on_no_runtime=False,
)
if actor:
seed: str = f'{actor.aid.name}@{pid}'
seed: str = '.'.join(actor.aid.uid)
else:
if is_root_process():
prefix: str = 'no_runtime_root'