feat(w7 p6): opt-in n0 DNS discovery for Discoverable presence

Wire the Discoverable presence posture to n0 DNS publish/lookup, the last
core piece of W7 (friends-first contacts). When a friend moves networks and
their saved address goes stale, they flip Discoverable to publish their
current address; everyone else resolves it by node id. Asymmetric: only the
mover publishes.

- src/discovery.rs (pure seam, +3 tests): lookup_plan(network_mode, want_publish)
  -> LookupPlan { resolver, publisher }. Relay-capable modes always resolve and
  publish only when Discoverable; DirectOnly (the explicit no-server posture)
  gets neither, overriding the toggle. DISCOVERY_TIMEBOX = 30 min.
- apply_discovery (core edge): clears + reinstalls the bound endpoint's
  address-lookup services at runtime (no endpoint rebuild). memory-lookup always;
  n0 PkarrResolver + DnsAddressLookup when resolver; PkarrPublisher when publisher.
  Toggling publish off drops the publisher (republish task ends; TTL-30s record
  expires). build_net_stack now binds uniformly with Minimal + per-mode relay and
  installs discovery via apply_discovery (drops the per-mode presets::N0 build).
- Toggle + time-box: SetPresenceMode re-applies discovery and arms/cancels a
  discovery_deadline; a select! branch fires at the deadline -> revert to Normal,
  stop publishing, and emit UiEvent::PresenceModeReverted so the GUI mirrors and
  persists it. Re-selecting Discoverable restarts the clock.

Decisions (user, 2026-06-16): 30-min auto-revert (not sticky); resolver always
on in relay-capable modes so a stationary friend in Normal can look up a mover.

266 lib tests green, clippy clean (--all-targets). Runtime smoke-tested: the new
Minimal+apply_discovery path binds and runs with no error/panic for both Normal
and Discoverable startup postures. Cross-network publish->lookup and the live
30-min revert still want a 2-machine field test (P7).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 16:24:46 -04:00
co-authored by Claude Opus 4.8
parent 3b02c2be0a
commit 22f0eed94d
6 changed files with 244 additions and 38 deletions
+6
View File
@@ -116,5 +116,11 @@ pub enum UiEvent {
/// joinable gathering (with a one-click ticket). Emitted by the outbound ping
/// scheduler; absence of a recent event = treat as offline.
FriendPresence { id: EndpointId, presence: FriendPresence },
/// The Discoverable time-box elapsed (W7 P6): the core auto-reverted our presence
/// posture to the carried `mode` (always `Normal`) and stopped publishing. The
/// GUI must mirror + persist this so its presence picker stops showing
/// Discoverable. Distinct from a user-driven change so the GUI knows to update
/// without having issued the command itself.
PresenceModeReverted { mode: PresenceMode },
Error(String),
}