Skip to content

AI: smart unblock, TypeSafe anomaly triage, device identification (v1.34.0) - #6

Merged
Neoo-Blue merged 9 commits into
mainfrom
ai/triage-unblock
Sep 19, 2026
Merged

Neoo-Blue merged 9 commits into
mainfrom
ai/triage-unblock

Conversation

@Neoo-Blue

Copy link
Copy Markdown
Owner

What

Three TypeSafe-backed features on top of v1.33.0, plus fixes found in review.

Smart unblock (internal/ai/unblock.go, opt-in ai.typesafe.unblock / ai.typesafe.auto_unblock)

  • Every hour, the most-refused names from the last 24h are checked. A name is only considered if every list covering it (store.BlockSources, including wildcard parents) is an ads or tracking list, and every refusal in the window came from one of those lists. Malware, bypass, policy, service and operator blocks are never considered.
  • TypeSafe answers one choice question: what is the host's job (push, sign-in, app API, content, updates, ads, tracking, telemetry, dns, other). Its answer does not see which lists block the name: including that pushed the model toward "ad".
  • Suggest: combined push/sign-in/app/update/content probability of at least 0.8, and blocked by at most 3 lists. Suggestions go into the Blocklist specialist queue.
  • Auto: at least 0.9, blocked by at most 2 lists, and not "content". At most 3 per 24h, counted from local_rules with origin ai.
    • The allow is an exact name, origin ai. AutoAllow refuses when the operator has a rule on the name or a wildcard block on a parent.
    • Each automatic allow is announced as an event and shown on the Assistant page with Undo. Undo revokes only origin ai rules and marks the name dismissed.
    • An automatic allow is withdrawn after 7 days unless the name is still queried.

Anomaly triage. With TypeSafe on, each finding is judged on its own. The severity can only be lowered: unexplained ≥ 0.5 keeps it, 0.2 to 0.5 caps it at notice, below 0.2 makes it info. LAN addresses are redacted from the state sent to TypeSafe. If the key is refused, nothing is recorded and triage falls back to the chat model. Beaconing now skips private, loopback, multicast, link-local, CGNAT and broadcast destinations, and records the destination's port, country, operator and app.

Device identification (internal/ai/identify.go, opt-in ai.typesafe.identify)

  • Hypervisor OUIs (Proxmox, VMware, Xen, Parallels) are classified as server.
  • TypeSafe names the remaining devices from hostname, vendor and their 25 most-queried names. MAC, IP and client ID are never sent.
  • A class or OS is applied at probability ≥ 0.6 through ClientRegistry.SetClass, which never overwrites an existing classification.

Review fixes

  • ClientRegistry copies now clone Meta. Before, they shared the live map that DHCP writes under the lock: a fatal concurrent map access that predates this branch. A regression test fails under -race without the fix.

Testing

  • go vet ./... and go test -race ./... pass locally.
  • New tests:
    • unblock_test.go: the gates, and the daily cap.
    • typesafe_test.go: triage severities and no LAN or hardware addresses in the request.
    • identify_test.go.
    • clients_test.go: SetClass behaviour, and the Meta race.
    • TestLocalDestination.
  • Tuned against real data from the reference Pi node:
    • Blocked names: push, sign-in and app hosts scored at least 0.9; ads and telemetry scored at most 0.1.
    • 117 distinct anomaly findings: triage would have lowered all 12 warnings and 3 criticals.
  • Deployed to that node as v1.33.0-ai3.
    • First unblock pass: clientservices.googleapis.com and api.naea1.uds.lenovo.com allowed automatically; settings-win.data.microsoft.com suggested.
    • Device ID classified 16 devices.
    • The first 30 minutes of triage gave 1 warning, 16 notice and 5 info.

🤖 Generated with Claude Code

Neoo-Blue and others added 9 commits September 19, 2026 03:03
Hypervisor OUIs (Proxmox, VMware, Xen, Parallels) are servers. Devices the rules still cannot name are judged by TypeSafe from hostname, vendor and the names they look up; a class or OS is applied at 0.6 or better and never over a real classification. Opt-in via ai.typesafe.identify.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Beaconing skips local, broadcast and tailnet destinations and records the destination's port, country, operator and app. With TypeSafe on, each finding is judged on its own and can only be lowered from the detector's severity. The unblocker asks what the most-refused names are for; push, sign-in, app-API, update and content hosts blocked by three or fewer ad lists become allow suggestions, and with auto_unblock the clearest (two lists or fewer, not content) are allowed, three a day at most, announced, undoable, and withdrawn after a week unused. Bypass, malware, policy and the operator's own blocks are never touched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
# Conflicts:
#	internal/api/helpers.go
#	internal/app/app.go
#	internal/config/config.go
…o for automatic unblocks

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…usal from an ad list, operator wildcard blocks respected, LAN addresses redacted from triage

ClientRegistry handed out copies sharing the live Meta map that DHCP writes under the lock; the identifier (and API encoding) read it outside, a fatal concurrent map access. The unblocker kept only the oldest refusal's source from a newest-first log, so a name also refused by a policy could pass. AutoAllow ignored an operator's wildcard block on a parent. Port-scan and DGA findings carried LAN addresses in titles, details and evidence.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e; unblock reason grammar

The Samsung-TV example in the device question anchored a Samsung phone (Android push and connectivity checks plus one Samsung service) to tv at 0.87; with balanced hints it reads phone 0.68 and the real TV 0.89.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Neoo-Blue
Neoo-Blue merged commit 40def7d into main Sep 19, 2026
3 checks passed
@Neoo-Blue
Neoo-Blue deleted the ai/triage-unblock branch September 19, 2026 18:22
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