---
model: claude-opus-4-6
service: claude
session: (ad-hoc, not tracked via conf.toml)
timestamp: 2026-04-13T19:21:16Z
git_ref: f851f28
scope: code
substantive: true
---

## Prompt

User provided a detailed implementation plan for
a new `test_tpt_bind_addrs.py` test suite covering
`open_root_actor(tpt_bind_addrs=...)` — the three
runtime code paths in `_root.py:385-450`:

1. Non-registrar, no explicit bind -> random addrs
2. Registrar, no explicit bind -> registry_addrs
3. Explicit bind given -> `wrap_address()` + merge

Plan specified 6 test functions (~10 parametrized
variants), predicted a type-mixing bug at line 446,
and asked for an in-flight fix if confirmed.

## Response summary

Created `tests/discovery/test_tpt_bind_addrs.py`
with 9 collected test variants across 6 functions:

- `test_registrar_root_tpt_bind_addrs` (3 variants:
  `bind-eq-reg`, `bind-subset-reg`,
  `bind-disjoint-reg`)
- `test_non_registrar_root_tpt_bind_addrs`
  (2 variants: `bind-same-bindspace`,
  `bind-disjoint`)
- `test_non_registrar_default_random_bind`
  (baseline, no explicit bind)
- `test_tpt_bind_addrs_as_maddr_str`
  (multiaddr string input)
- `test_registrar_merge_binds_union`
  (registrar + disjoint bind -> union)
- `test_open_nursery_forwards_tpt_bind_addrs`
  (`open_nursery(**kwargs)` forwarding)

Confirmed and fixed the predicted bug at
`_root.py:446`: the registrar merge path mixed
`Address` objects (`tpt_bind_addrs`) with raw tuples
(`uw_reg_addrs`) inside `set()`, preventing
deduplication and causing double-bind `OSError`.

Fix: wrap `uw_reg_addrs` before the set union:
```python
# before (broken)
tpt_bind_addrs = list(set(
    tpt_bind_addrs + uw_reg_addrs
))
# after (fixed)
tpt_bind_addrs = list(set(
    tpt_bind_addrs
    + [wrap_address(a) for a in uw_reg_addrs]
))
```

All 9 tests pass after the fix.

## Files changed

- `tests/discovery/test_tpt_bind_addrs.py` (new)
- `tractor/_root.py:446` (bug fix, 1 line)

## Human edits

N/A — pending review.
