Repository navigation
Home network: compare both machines' networks over the relay (#219) - #221
Merged
Merged
Conversation
When Home network sync can't find a linked machine, the Sync & backup line now names it and, when this machine can tell, why: a VPN or virtual adapter carrying the broadcasts, no network, Windows calling the network Public, macOS Local Network access off, another Patch Pilot version, or another rig's Patch Pilot on the network. It no longer says "In sync" while nobody is here. The details list each machine and a checklist. - patchpilot_local::lan_diagnosis: pure diagnose() over gathered facts, adapter classification (name and Windows description), egress kind, bind error wording; tested with hand-built facts. - patchpilot_local::netinfo: read-only probes (UDP connect + local_addr, sysinfo interfaces, PowerShell adapter description and profile with a 5 s deadline at below-normal priority). - lan::read tells this rig, another version, another rig and noise apart. - sync.rs keeps the relay's list of linked machines, so machines added from an export file or removed never show as missing. - lan.rs gathers facts on the existing 10 s beacon thread, looks at the network only while a machine is missing and none is here, and tells the UI only when the diagnosis changes. Decision #123 (amends #94). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # app/CHANGELOG.md
Each linked machine keeps a small sealed net/<machine id> report on the relay: Home network on, its subnets, whether its broadcasts leave through a VPN, and which linked machines it hears. Sent on change and, only while a machine is missing or can't hear this one, every 5 minutes. The others use it to say why they can't find that machine: Home network off there, asleep or closed, VPN there, a different network, one-way hearing (firewall), or the same network with neither hearing the other. Decision #124 (Proposed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A matching subnet alone no longer counts as the same network: most routers use the same few ranges. The relay now answers a PUT with the client's address, and "blocked" needs the same public address too (same family, neither side's internet through a VPN); a different one means "different network". - Report age is judged by when it reached the relay, on this machine's clock (relay x-age header), never the other machine's clock. - "Can't hear this machine" waits until the other machine had listened 30 s when it made its report, so a quick restart isn't deafness. - Peers count as here by the wall clock (a Mac's Instant stops in sleep). - A port that won't open is "can't listen", not "Home network off". - A definite reason from the other machine beats this machine's guesses; the deaf line names only this machine's own VPN/virtual adapter. - A report counts as sent only once the relay took it, so failures retry. - Network facts older than 90 s are left out of reports, and a machine heard here lately is never called quiet. - sync no longer assumes the home-network state exists at startup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A missing machine's report names a reason only if it reached the relay after this machine last heard that machine, and while this machine is online: a report made before it slept, quit or moved said "hears this machine" and was read as a firewall problem. - "It hears this machine" and "blocked" need its own sends known fine (no VPN, no failed broadcast) and a report made since this machine started listening. - A virtual adapter there is its own reason, not "a VPN". - An unknown report age (older relay) names only "off"; "last checked in" counts from when the machine was last heard if that's later. - Machines whose report says Home network is off no longer keep the others heartbeating or looking at their network. - Windows adapter descriptions are looked up whenever the network is looked at (cached 10 min), so a VPN called "Ethernet 4" isn't missed. - Network facts and their schedule use the wall clock; listening_since is fixed once, so a healthy machine's report doesn't look changed. - The public address is forgotten when subnets change, and a report is sent again at once when an upload reveals a new one; no report is asked for while offline (the session start sends one). - Line and details agree on which cause or reason is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- "It hears this machine" needs a report made at least 55 s after this machine last heard it and after this run started (its list keeps a machine 45 s); other reasons need 20 s, two beacons, not one. - "Different network" by subnets comes before "it hears this machine", so a machine that moved isn't read as a firewall problem. - "Blocked" and "it hears this machine" also need this machine's own broadcasts to go out fine; a send that fails without an OS code counts. - The public address is forgotten at the start of each relay session. - The live connection counts as offline when a ping goes unanswered, so reports aren't trusted over a connection that died silently; a stale report nudge doesn't put the same report twice. - This machine's network facts older than 90 s are ignored by the diagnosis too; a clock stepped back means "look again". - An adapter Windows couldn't describe counts as unknown (retried each minute), not the home network. - A cause here gives way when every missing machine has a reason on its own side (incl. another network), so a laptop at a café isn't told to make its Wi-Fi Private; one that gave way marks nothing on the checklist. - Missing and deaf at once is said plainly; the deaf cause is found then. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- This machine's VPN explains a machine here that can't hear it, in its own field; it's no longer named as why another machine is missing. - Advice about this machine's network (Public, a VPN for the internet) is left out while a missing machine reports from a network this machine can't confirm is its own: a laptop at a café isn't told to make the café's Wi-Fi Private, even when the addresses can't be compared. - Waking from sleep (a beacon round over 30 s late) drops the reports read before and restarts the relay session at once; nothing from before sleep counts as current until it's read again. - One unanswered ping is enough to count the connection as dead (timed by the ticks themselves). - A VPN carrying the other machine's internet traffic, on this range and hearing nothing, is named as a likely reason; "it hears this machine" needs no VPN for the internet on either side. - While a machine here can't hear this one, reports go out every minute, and a fresh report that doesn't list this machine prompts a network look straight away, so "a firewall here" shows in about a minute, not six. - A Windows adapter with no description counts as unknown even when its network profile is known. - Machines whose report says Home network is off aren't "in sync"; with someone here, each missing machine's own reason is in the line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
bfieser
added a commit
that referenced
this pull request
Nov 7, 2026
4 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #219. Stacked on #218: this PR's base is
sync/216-lan-diagnosis. Please review and merge #218 first; this PR then retargets tomain.Why
#218 lets a machine say why it can't find a linked machine on the home network, but only from what it can see itself. One machine alone can't tell that the other one is on another Wi-Fi, has a VPN on, isn't using Home network sync, is asleep, or can't hear it. The other machine can.
What the user sees
New per-machine reasons on the Sync & backup line and in its details:
A wrong reason is worse than none. A reason is named only when both machines' data agree and the other machine's report is current. "Current" means fresh, reached the relay after this machine last heard that machine, and this machine is online and hasn't just woken from sleep. Advice about this machine's own network (e.g. "set it to Private") is left out while the missing machine may be on another network.
How
net/<machine id>: a small sealed relay object (crates/local/src/net_report.rs) holding:It's separate from the
machine/bundle so network changes don't re-send the scan and every Primary Rig version.When it's sent (
app/src-tauri/src/lan.rs): on change (at most every 30 s); every 5 min while a machine that might still turn up is missing; every minute while a machine here can't hear this one. Nothing is sent while everything works. A report counts as sent only once the relay took it, so failures retry.Relay (
app/src-tauri/src/sync.rs): reads each linked machine's report once per session (one row read each, decision Release 0.4.2, with "Bring over all Reaper scripts" #113), then on livechangedevents.Connection health (
sync.rs): the live connection now counts as offline when a ping goes unanswered. Waking from sleep restarts the session, so reports from before sleep are never judged as current.Rules (
crates/local/src/lan_diagnosis.rs):why()gives the per-machine reason,deaflists machines that can't hear this one, anddeaf_causesays why when this machine can tell. No timing rule compares two machines' clocks.UI:
app/src/Backup.tsxandapp/src/api.ts. The line and the details use the same rule for which reason wins.Relay change (deploys from
mainvia relay.yml)relay/src/index.ts:ip, fromCF-Connecting-IP).x-age(how long the relay has held the object).The relay sees the address anyway and stores nothing more. Older apps ignore both. Against the currently deployed relay this PR still works; it just has no public address (so no "same range, other router" or "blocked") and judges report age by when it fetched.
Decision
#124 is Proposed. It is the last row of
docs/decisions.mdand spells out every rule and threshold. Please look at it in particular: it adds a relay change, and it shares subnets and public addresses between the user's own machines, end-to-end encrypted like everything on the relay.Review
Before opening this, the change went through four review rounds: one independent reviewer, then three multi-agent rounds in which each finding was checked by separate skeptics. That turned up about 40 real issues, mostly reasons that could be wrong in edge cases (sleep, quick restarts, the same address range at a café, IPv4 vs IPv6, VPN variants, clocks). All are fixed and covered by tests.
Testing
cargo fmt --check,cargo clippy -D warningsandcargo teston both workspaces: 486 core tests, 26 new; app tests pass.npm run build(app);npm test+typecheck(relay, 14 tests, 1 new).wrangler dev, including the new "reports travel with their age" and "the live connection answers pings".🤖 Generated with Claude Code