Task
dign peers renders a relay-reached peer's address as [::]:0 — the IPv6 unspecified address on
port 0, which is not an endpoint at all. Emit no address for such a peer so the renderer's existing
honest fallback shows instead.
Discovered during the light-client end-to-end verification on
https://github.com/DIG-Network/dig_ecosystem/issues/2760 (the 2026-08-19 measurement comment).
That epic is the discovery CONTEXT, not this ticket's family parent — no open orchestrator epic covers
the DIG peer-display surface today, and per CLAUDE.md §1.3 a 1:1 super-repo shadow for a trivial
repo-scoped fix would re-create the double-bookkeeping the queue split removed. This closes with its
own PR.
(Corrected: the first version of this body cited #836 as its parent. #836 is CLOSED and cannot parent
anything.)
Measured on a real machine, 2026-08-19
dig-node 0.126.2 (b92de34), installed as the OS service:
$ dign peers
dig-node peer network: running · 1 connected peer(s)
relay wss://relay.dig.net:443 — reservation held
peers:
• 62ecc368ecac7ccaa599e344e228355023fbe46d06759efe8a9e5223543f2a5c relay/outbound [::]:0
[::]:0 reads as an address. It is the absence of one.
Context — the honest fallback already exists and is unreachable
crates/dig-node-service/src/peers.rs:215 already handles this correctly:
let addr = p["address"].as_str().unwrap_or("(no address)");
That branch fires only when the field is absent. The producer never omits it —
crates/dig-node-core/src/peer.rs:328 stringifies unconditionally:
"address": addr.to_string(),
So for a peer reached over the relay, where connected_pool_peers() has no direct address to report,
the placeholder [::]:0 is emitted and the "(no address)" branch can never run. The renderer is
correct; the producer is what needs fixing. Guarding the display instead would leave the same
placeholder in control.peerStatus for every other consumer, including the extension.
Scope
At peer.rs:328, omit address when the socket address is unspecified or its port is 0, so the field
is genuinely absent rather than placeholder-filled. Keep the JSON shape otherwise identical — the key is
already read with .unwrap_or(..) downstream, so absence is the supported case, not a new one.
via already carries the useful truth for these peers (relay), and the relay line above prints the
reservation, so a person loses nothing by the address disappearing — they stop being told something
false.
Skill / reference of "good"
professional-ui's honesty rule and the ecosystem pattern of never implying a fact not held: a surface
must not present a placeholder that a person can mistake for real data. The same argument the dig-app
panes settled with BalanceReading's pending/known/unknown split — an unknown renders as unknown, not
as a plausible-looking zero.
§5.2 is not violated here and should not be cited: the IPv6-first ordering in peers.rs:199-200 is
correct, and is_ipv4() classifies [::]:0 as IPv6 which is technically right. The defect is
truthfulness, not address family.
Evidence
A test asserting a relay-reached peer with no direct address produces JSON without an address key,
and that the rendered line shows (no address). It must fail against today's code — which it will,
since today's code emits [::]:0.
Effort
Small. Two lines plus a test. No design fork.
Task
dign peersrenders a relay-reached peer's address as[::]:0— the IPv6 unspecified address onport 0, which is not an endpoint at all. Emit no address for such a peer so the renderer's existing
honest fallback shows instead.
Discovered during the light-client end-to-end verification on
https://github.com/DIG-Network/dig_ecosystem/issues/2760 (the 2026-08-19 measurement comment).
That epic is the discovery CONTEXT, not this ticket's family parent — no open orchestrator epic covers
the DIG peer-display surface today, and per CLAUDE.md §1.3 a 1:1 super-repo shadow for a trivial
repo-scoped fix would re-create the double-bookkeeping the queue split removed. This closes with its
own PR.
(Corrected: the first version of this body cited #836 as its parent. #836 is CLOSED and cannot parent
anything.)
Measured on a real machine, 2026-08-19
dig-node 0.126.2 (
b92de34), installed as the OS service:[::]:0reads as an address. It is the absence of one.Context — the honest fallback already exists and is unreachable
crates/dig-node-service/src/peers.rs:215already handles this correctly:That branch fires only when the field is absent. The producer never omits it —
crates/dig-node-core/src/peer.rs:328stringifies unconditionally:So for a peer reached over the relay, where
connected_pool_peers()has no direct address to report,the placeholder
[::]:0is emitted and the"(no address)"branch can never run. The renderer iscorrect; the producer is what needs fixing. Guarding the display instead would leave the same
placeholder in
control.peerStatusfor every other consumer, including the extension.Scope
At
peer.rs:328, omitaddresswhen the socket address is unspecified or its port is 0, so the fieldis genuinely absent rather than placeholder-filled. Keep the JSON shape otherwise identical — the key is
already read with
.unwrap_or(..)downstream, so absence is the supported case, not a new one.viaalready carries the useful truth for these peers (relay), and the relay line above prints thereservation, so a person loses nothing by the address disappearing — they stop being told something
false.
Skill / reference of "good"
professional-ui's honesty rule and the ecosystem pattern of never implying a fact not held: a surfacemust not present a placeholder that a person can mistake for real data. The same argument the dig-app
panes settled with
BalanceReading's pending/known/unknown split — an unknown renders as unknown, notas a plausible-looking zero.
§5.2 is not violated here and should not be cited: the IPv6-first ordering in
peers.rs:199-200iscorrect, and
is_ipv4()classifies[::]:0as IPv6 which is technically right. The defect istruthfulness, not address family.
Evidence
A test asserting a relay-reached peer with no direct address produces JSON without an
addresskey,and that the rendered line shows
(no address). It must fail against today's code — which it will,since today's code emits
[::]:0.Effort
Small. Two lines plus a test. No design fork.