319d0c5e298e32a15d96f9b73f82214acc4dcb80
SetPresenceMode and the Discoverable time-box auto-revert both committed the new presence_mode to local state *before* apply_discovery and only log_msg'd on failure, so a failed off-transition could leave the n0 DNS PkarrPublisher running while the UI showed not-discoverable (privacy / reality mismatch — security-open-handoff S11, from the W7 P7 review). Fix (Codex, senior-reviewed): - discovery.rs: pure resolve_presence_transition(prev, requested, apply_ok) -> (mode, Option<error>) seam — on failure keep the previous (truthful) mode and surface a message. +4 unit tests. - apply_discovery now builds the replacement resolver/publisher services BEFORE clearing the service set, so a builder failure leaves the old posture fully intact (no partial state) — "keep previous mode" is then provably truthful. - Both SetPresenceMode and the time-box revert apply discovery first, route through the seam, commit only the truthful mode, and surface failures via the existing PresenceModeReverted (corrects the picker) + UiEvent::Error. No new wire/event variant. - A failed off-transition stays Discoverable and arms a 60s retry (DISCOVERY_REVERT_RETRY) so the beacon never stands stuck. - P3 notes documented: relay-resolve exposes n0 query metadata (by design); no explicit iroh unpublish API exists, so the bounded ~30s pkarr TTL linger is documented, not behavior-changed; DirectOnly stays no-n0. 306 lib tests / clippy --all-targets / release all green (re-run by senior). Runtime publish-stop behavior still wants a 2-machine / packet-capture check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>