agentmux_cef\wrr/
classify.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Phase B.9.1 — class-name filter for the WRR Win32 event hook.
5//
6// Hook callbacks fire for every window-object event in the host
7// process: CEF browser top-levels (the ones we care about), CEF
8// subprocess HWNDs, OS-managed transient HWNDs (tooltips, IME
9// candidate lists, message-only windows), and so on. Forwarding
10// every event over the IPC pipe would flood the wire with noise
11// the reducer can't act on.
12//
13// `is_app_class` filters at the hook callback so only candidate
14// AgentMux top-level windows produce IPC traffic. The classifier
15// is allowlist-based — false negatives (a real window we silently
16// drop) are worse than false positives (a non-app HWND that the
17// reducer just ignores), so we keep the allowlist conservative
18// and let the reducer's `pending_hwnds` machinery age out spurious
19// entries.
20
21/// Phase B.9.1 — does this Win32 window class look like an
22/// AgentMux top-level window?
23///
24/// CEF's top-level windows in CEF 146 use the
25/// `Chrome_WidgetWin_*` class family (CEF Views wraps each native
26/// window in a Chromium widget host). AgentMux's main window
27/// shows up as `Chrome_WidgetWin_1`. Browser-pane child HWNDs and
28/// CEF subprocess HWNDs use `Chrome_RenderWidgetHostHWND` and
29/// related — those are explicitly excluded.
30pub fn is_app_class(class_name: &str) -> bool {
31    // Chromium widget host windows. CEF wraps every top-level
32    // CefWindow in one. The numeric suffix varies (`_0` `_1` etc.)
33    // depending on CEF init order.
34    if class_name.starts_with("Chrome_WidgetWin_") {
35        return true;
36    }
37    // CEF Views Native Window (rare in our build but possible).
38    if class_name == "CefBrowserWindow" {
39        return true;
40    }
41    false
42}
43
44/// Phase B.9.1 — explicit excludes for class names that LOOK
45/// app-like but should never produce drift. Currently empty
46/// because `is_app_class` is allowlist-based; kept as a hook for
47/// follow-up tuning if the allowlist gets too permissive.
48pub fn is_explicitly_excluded(_class_name: &str) -> bool {
49    false
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn chrome_widget_win_classes_match() {
58        assert!(is_app_class("Chrome_WidgetWin_0"));
59        assert!(is_app_class("Chrome_WidgetWin_1"));
60        assert!(is_app_class("Chrome_WidgetWin_42"));
61    }
62
63    #[test]
64    fn cef_browser_window_matches() {
65        assert!(is_app_class("CefBrowserWindow"));
66    }
67
68    #[test]
69    fn renderer_subprocess_class_is_filtered_out() {
70        assert!(!is_app_class("Chrome_RenderWidgetHostHWND"));
71        assert!(!is_app_class("Intermediate D3D Window"));
72    }
73
74    #[test]
75    fn unrelated_classes_filtered_out() {
76        assert!(!is_app_class("tooltips_class32"));
77        assert!(!is_app_class("Static"));
78        assert!(!is_app_class(""));
79    }
80}