Describe the bug
__canonical__ is per-registry and diverges between registries on 7 ports, so AppType.get(port, proto=<multi-bit>) can return a different service than the member it was asked to round-trip. It is silent, and == cannot detect it.
Reproduction
On 932cb48d1, sweeping all 10,625 multi-transport members in one process — zero mints, zero exceptions, and exactly one service mismatch:
m = <UDP.accessbuilder: 888 [tcp|udp]> UDP.get(888).svc = 'accessbuilder'
AppType.get(888, proto=m.proto) -> <TCP.cddbp: 888 [tcp]>
result is m: False result == m: True result.svc == m.svc: False
result.proto = 1 (tcp) vs m.proto = 3 (tcp|udp)
__canonical__ diverges on ports 113, 465, 512, 631, 750, 888, 999; 888 is the only one where the divergent member is multi-transport and is its own registry's answer.
Expected behavior
get(m.port, proto=m.proto) should return m's service, or refuse. It currently returns a different service and claims a narrower transport, and == reports True because AppType.__eq__ compares self.port == other — so a caller checking equality sees no problem.
System information
- OS Version: Linux 5.10 (Amazon Linux 2 int)
- Python Version: 3.14.7
- Python Implementation: CPython
pcapkit Version: checkout at 932cb48d1
Additional context
Found while verifying #736's acceptance criterion after #754 (#736 is otherwise closed — 10,624 of 10,625 round-trip correctly). Distinct mechanism from #736's displacement.
This is the case #732 already predicted. Its recorded note says the fix for multi-transport lookup is to make _dispatch refuse a multi-bit proto rather than silently pick LSB-first — that would turn this from a wrong answer into an error. Worth deciding alongside #732's deferred TransportProtocol retype rather than patching __canonical__ per port.
Describe the bug
__canonical__is per-registry and diverges between registries on 7 ports, soAppType.get(port, proto=<multi-bit>)can return a different service than the member it was asked to round-trip. It is silent, and==cannot detect it.Reproduction
On
932cb48d1, sweeping all 10,625 multi-transport members in one process — zero mints, zero exceptions, and exactly one service mismatch:__canonical__diverges on ports 113, 465, 512, 631, 750, 888, 999; 888 is the only one where the divergent member is multi-transport and is its own registry's answer.Expected behavior
get(m.port, proto=m.proto)should returnm's service, or refuse. It currently returns a different service and claims a narrower transport, and==reportsTruebecauseAppType.__eq__comparesself.port == other— so a caller checking equality sees no problem.System information
pcapkitVersion: checkout at932cb48d1Additional context
Found while verifying #736's acceptance criterion after #754 (#736 is otherwise closed — 10,624 of 10,625 round-trip correctly). Distinct mechanism from #736's displacement.
This is the case #732 already predicted. Its recorded note says the fix for multi-transport lookup is to make
_dispatchrefuse a multi-bitprotorather than silently pick LSB-first — that would turn this from a wrong answer into an error. Worth deciding alongside #732's deferredTransportProtocolretype rather than patching__canonical__per port.