Skip to content

v2.0.2 Release Changes#981

Merged
tvancott42 merged 18 commits into
mainfrom
dev
Jul 14, 2026
Merged

v2.0.2 Release Changes#981
tvancott42 merged 18 commits into
mainfrom
dev

Conversation

@tvancott42

@tvancott42 tvancott42 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Placeholder roll-up for the next patch release. More changes will be added before it ships.

Client Performance

  • Simplified view for VPN clients - Tailscale, Teleport, and UniFi remote-user-VPN clients (which never appear in the UniFi client list) now get a purpose-built dashboard: the same VPN logo used in path traces, the client name and IP, both speed-test buttons, live speed results, the speed map, and per-result path traces. Detection reuses the same classifier that drives the VPN hop in traces.
  • Clearer "device not found" copy on the local site - distinguishes "console unreachable" from "console fine but your device isn't listed yet," and surfaces the detected address.
  • Managed-site cold connection - when the on-site agent's tunnel is still coming up, the dashboard shows the device picker immediately and keeps probing in the background, auto-loading the moment identity resolves instead of stranding you until a manual refresh.

LAN Speed Test

  • Speed map auto-fit on new results and time-range changes - a freshly completed test, or changing the time range, now brings the visible results back into view (unless you've manually panned or zoomed). Applies to both the LAN Speed Test map and the Client Performance speed map.

Monitoring

  • Off-path transit networks get cleaned up - when your ISP re-routes and stops sending traffic through a transit network, the monitoring targets for it keep reporting loss and latency for a path you no longer use, dragging down ISP Health. The Setup tab's Upstream path discovery now notices when a transit ASN has been off your path for a sustained stretch and surfaces it in the review so you can pause its targets on save. Hand-added targets in that network are caught too, and nothing is ever deleted.
  • "Did you switch internet providers?" - when Upstream path discovery finds your access ISP itself changed (a whole new provider, not just a re-route), it asks. Confirm and it pauses all your old upstream targets in one step and adopts the freshly discovered path as the new baseline; decline and it leaves everything alone and won't ask again about that network. One trace, one save, no dangling old targets reporting 100% loss.
  • Right access ISP on silent first miles - some fiber and PPPoE setups have a first mile that doesn't announce itself (the ISP's own routers resolve to no ASN), which let Upstream path discovery crown the wrong provider as your access ISP - in one case a DNS resolver's own edge (Cloudflare) instead of the real ISP. Detection now anchors on your gateway's public WAN address, so the actual ISP is identified even when every early hop is silent, and those first-mile hops become monitorable targets instead of being mislabeled or dropped.
  • First-mile device picks the real WAN gateway - on a shared WAN segment (metro Ethernet, two sites on one carrier subnet), the first-mile device could be read from an unrelated neighbor on the same segment. It now uses the WAN's actual default gateway from the routing table, so the right upstream device is identified.
  • Flaky monitoring targets advisory clears itself when things recover - a target flagged in the Flaky monitoring targets advisory now drops off the list once its recent monitoring is clean again, instead of nagging for up to two days while the old bad data ages out. A target that was fully offline and comes back clears within about half an hour, while genuinely flaky partial loss still has to prove itself stable over a few hours.
  • Flaky monitoring targets advisory on ISP Health - the advisory (internet/transit targets whose loss skews ISP Health scoring) now also appears on the ISP Health tab where the score lives, not only on Live View, and it clears automatically once you disable the flagged targets.
  • Device-host naming in logs - ONT, cable modem, and cellular modem poll failures and stored host names now name the configured device host instead of the internal tunnel-proxy loopback, so logs point at the real device on agent-routed sites.
  • Agent versions without build metadata - agent version labels drop the +build suffix, matching the footer.

Reconnecting

  • Break out of a wedged reconnect spinner - if the "Reconnecting..." spinner is stuck (dead-but-open socket or stalled retries), the app probes the server every few seconds and reloads once it answers; if the server is down it waits and re-probes rather than reloading into a dead server.

Multi-Site

  • Current site opens its dashboard - clicking the site you're already on now opens its dashboard instead of doing nothing. Ctrl/cmd/shift/middle-click still opens the site in a new tab.

Settings

  • Settings polish - darker settings-table row hover so rows read differently from buttons, native form controls (number spinners, date/color pickers) rendered in dark chrome, and the site-name field is focused when you click its edit button.

tvancott42 and others added 18 commits July 12, 2026 20:11
The agent status line rendered the raw MinVer informational version
(v2.0.1+ed2714ca72415f2d08512e643c); strip the +hash for display the way
the footer does, keeping prerelease identifiers. The full version stays
stored on SiteAgents.LastVersion for diagnostics, and IsOlderThan already
ignored build metadata, so only the rendering changes.
* Add simplified Client Dashboard view for Tailscale/Teleport/VPN clients

VPN-sourced viewers (Tailscale CGNAT, Teleport, remote-user VPN) never appear
in the UniFi client list, so the dashboard previously showed Device Not Found.
They now get a simplified view: the same VPN logo used in speed-test traces,
client name + IP, the two speed-test buttons, results, and a working map.

- Extract shared VPN classifier (ClassifyVpnClient) as the single source of
  truth for hop creation and dashboard identity
- Shared VpnIcon component reused by the trace and the identity bar
- IP-keyed speed-result lookup (VPN clients have no MAC)
- Skip live polling / GPS for VPN clients; Speed tab only
- Pre-select the map External layer for VPN clients
- Clearer Device Not Found copy on the default site based on console
  reachability, with the detected address surfaced

Default-site only; managed-site behavior is untouched.

* VPN client dashboard: drop the sole tab bar, rename to 'X Client'

- Hide the tab bar entirely for VPN clients (a single Speed tab looked odd);
  keep the time-range filter
- Name VPN clients 'Tailscale Client' / 'Teleport Client' / 'VPN Client'
- Drop the now-redundant name from row 2 (shown in the identity name)

* VPN client dashboard: refresh speed results live

VPN clients had no poll timer, so new speed tests only appeared after a manual
page refresh. Add a lightweight timer that reloads the Speed tab results/charts
on the same ~5s cadence as Wi-Fi clients, without the signal poll or L2 trace
(neither of which exists for VPN clients).

* Client Dashboard: auto-resolve managed-site identity on cold agent connect

On a managed site, the on-site agent's tunnel may still be coming up when the
dashboard first loads. The resolver then reports no agent target, so the whoami
identity probe was skipped and the viewer dropped to the device picker - only a
full page refresh (a warm connection) resolved identity.

Poll the resolver for a bounded window (~20s) so identity resolves automatically
once the agent's tunnel comes online, keeping the loading skeleton up meanwhile.
A reachable-but-unusable agent (e.g. untrusted certificate) still falls straight
to the picker.

* Managed-site identity: background-retry on cold agent/console connect

Replace the single whoami probe (and the earlier skeleton-blocking retry loop)
with: one immediate attempt, then show the picker right away AND keep probing
in the background (~1s, up to 30s), auto-loading the moment the agent's tunnel
and console are live. The viewer is never stranded on the picker waiting for a
manual refresh, and can still pick a device to stop the retry early.

Also close the site-switcher dropdown when the already-active site is clicked -
done in site-context.js after the modified-click guard, so ctrl/cmd/shift/middle
new-tab behavior is untouched (no Blazor @OnClick on the switch anchors).

* Fix intermittent 'Device Not Found' flash on managed-site identity resolve

Clearing _awaitingSiteIdentity before the async whoami attempt (and before the
picker's client list finished loading) left a window where a poll-timer re-render
showed the generic 'Device Not Found' card instead of the loading skeleton -
intermittently, and most visibly when switching to a site you're not physically
at (the whoami probe there runs to its full timeout).

Keep the skeleton up until a terminal state: clear the flag only on success, or
atomically with _showClientPicker when the picker becomes visible. Managed-site
only; the default/single-site path never enters this code.

* Speed test map: auto-fit when new results arrive

The map only re-fit when new markers happened to land fully off-screen; a new
result appearing outside the current view while other markers were visible was
never brought into view. Fit on data change (new result, or background
enrichment reclassifying one), gated by userHasZoomed so a manual pan/zoom is
still respected - the same guard the time slider and layer toggles already use.
Applies to both the VPN client map and the main LAN speed test map.

* Speed test map: re-enable auto-fit on time-filter change

* PWA: break out of a wedged reconnect spinner via a health-gated reload

* Flaky targets: surface the advisory on ISP Health and clear it once addressed

* Sites page: clicking the current site opens its dashboard instead of dead-clicking
…d flaky targets (#983)

* Pause off-path transit ASNs on discovery review, incl. dangling hand-added targets

A transit ASN with auto-discovered evidence that goes absent from 3
consecutive discovery runs is surfaced in the Upstream Discovery review
(pre-unchecked); committing pauses every enabled Transit target in the
ASN - auto and hand-added alike. Targets are paused, never deleted.

- Removal eligibility no longer requires the auto target to be enabled
  (a flaky auto target the user paused must still catch its dangling
  hand-added siblings), but does require >=1 enabled target in the ASN
  so a fully-paused ASN retires instead of pinning the daily recheck.
- The absence counters now advance once per completed discovery run,
  manual and scheduled alike, via a shared post-run evaluation staged
  on the tracer state; the scheduler reads the staged outcome.
- Commit clears surfaced ASNs miss counters so "Keep" re-nags only
  after fresh 3-run evidence; non-actionable confirmations (access and
  path tiers) prune so the recheck cadence recovers to 7 days.

* Surface off-path transit ASNs being tracked toward removal in the review

Before an absent transit ASN reaches the removal-confirm threshold, show a
read-only "Tracking possible removals" section in the Upstream Discovery
review: which ASN went off-path, how many consecutive runs it has been absent,
how many more are needed to confirm, and how many targets would be affected.
Makes the detection visible instead of silent until it suddenly confirms.

Staged by the same shared post-run evaluation as the confirmed-removal set, so
it stays accurate for manual and scheduled runs alike. Pending and confirmed
are mutually exclusive per ASN; informational only (no checkbox, no commit
action). RunsRemaining is run-count based for now - revisit the copy to express
remaining time once the per-ASN time gate lands.

* Rename review column "Keep" to "Keep Active"

Clearer that leaving it checked keeps the target monitoring, rather than
"keeping" the row in some list. Widen the column so the header fits.

* Time-gate absent-ASN miss increments to once per 6h

An off-path ASN's consecutive-miss counter now advances at most once per 6h per
ASN, so absence has to persist across real time rather than across however many
runs happen to fire. Three gated increments => a ~12h+ off-path floor before a
removal confirms - long enough to ride out maintenance drains, and immune to
rapid manual re-traces stacking the counter.

- Counter store carries a per-ASN last-increment timestamp ({"c":n,"t":iso});
  legacy bare-int values load as immediately gate-eligible, no migration.
- A gated run holds the count and timestamp; a confirmed ASN stays a removal
  candidate even when gated (a tight recheck can't un-confirm it).
- PendingRecheckInterval dropped 24h -> 6h to match the gate, so scheduled
  rechecks land just past it and real removals confirm in ~12-18h.
- EvaluateChange takes nowUtc + gate explicitly so it stays pure/testable.

* Widen "Keep Active" review column to 115px

* Prompt to reset upstream monitoring when discovery finds the access ISP changed

* Flaky targets: stop flagging a target once its recent bins are stable again

* Flaky targets: fast recovery for hard-down outage episodes

* Hard-down fast path: judge by median over-threshold bin so boundary bins don't defeat it
…ccess ISP on unannounced first miles (#984) (#985)

* Upstream path discovery: stop crowning a probe destination as the access ISP (#984)

The access-ISP pick was 'first hop with a resolvable ASN across the merged
pool'. Bell Canada's PPPoE first mile is RFC1918 plus public /16s Bell
deliberately does not announce in BGP (142.124/142.125), so every early hop
resolved to null and the first attributable hop was Cloudflare's own edge on
the 1.1.1.1 trace - Cloudflare became the 'access ISP' and Bell fell through
to the transit list.

Replaced with two signals (DetermineAccessAsn):
- The WAN IP's own ASN (the ISP's customer allocation) wins when resolvable
  and corroborated by any hop, or when no hop is attributable at all.
- Otherwise per-trace voting: each trace nominates its first attributed hop,
  skipping destination ASNs (a destination's edge only appears on traces
  toward itself; the real access ISP fronts essentially every trace).

Also positionally attribute the unannounced first mile: hops before the first
access-ASN hop on their own trace that sit in unattributed public or CGNAT
space are the ISP's aggregation layer and now join the access hop pool
(RFC1918 prefix hops stay excluded - bridged CPE / double-NAT risk).

Destination ASN/org resolution moved to a shared once-per-run step so the
access and transit passes use the same sets.

* WAN L2 neighbor: pick the routed default gateway, not the best-scoring ARP entry

On a shared WAN subnet (metro Ethernet, two sites on one carrier segment)
'ip neigh show dev <wan>' also lists unrelated same-subnet hosts, and the
heuristic scoring (subnet > address class > freshness) can rank a peer -
e.g. another site's gateway, REACHABLE while the real gateway is STALE -
above the true next hop.

Read the WAN's default gateway from 'ip route show table all' (UniFi policy
routing keeps each WAN's default in its own table; matching on the dev finds
it regardless of table number) and return that IP's neighbor entry outright,
still taking the MAC from ip neigh so the OUI/first-mile-device labeling is
unchanged. Scoring remains the fallback when no routed gateway is found
(on-link/PPPoE defaults have no via and no MAC).

* First-mile labeling honors the saved per-WAN access technology

Pre-existing (surfaced testing #984's fixes): re-running discovery suggested
'YELCOT cisco-access' on an install with GPON saved - the L2 hop label and
role ignored the stored technology until the dropdown was toggled.

Two cooperating causes:
- LoadPersistedAccessTechnologyAsync took the most-recent WanDiscoveryContexts
  row regardless of WAN or whether it held a technology, so on multi-WAN
  installs a fresher row for another WAN returned Unknown. It also never fell
  back to the legacy MonitoringSettings.AccessTechnology. Now: the traced
  WAN's own row first (re-checked in RunAsync once detection resolves the
  WAN), then any row with a known technology by recency, then the legacy
  settings column.
- Commit wrote State.AccessTechnology unconditionally, so a run that started
  with Unknown wiped the user's saved value (breaking the 'discovery only
  proposes' contract documented on SetAccessTechnologyAsync). Unknown is no
  longer written over a saved technology.
@tvancott42 tvancott42 merged commit bcb8c58 into main Jul 14, 2026
1 check passed
@tvancott42 tvancott42 changed the title v2.0.2 Release Changes (TBD) v2.0.2 Release Changes Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant