Skip to content

Commit 29892be

Browse files
committed
Answer the review, and make the 750-line limit a gate
The review of this session's range found four things: a second USB priming race (a poller outliving stop() could overwrite a snapshot poll_once had written, so the next poll reported its devices as removed), the stub generator bounding only the def line, the Windows key tables being an unrecorded cross-project contract, and the delegation table claiming an exemption clause meant for lookup tables. The file-length limit is checked now instead of remembered: the test reads Progress.md's exemption lists and fails on an unlisted file over the limit, a listed file that grew, or a row whose file shrank under it. It immediately caught webrtc_panel.py five lines over its ceiling, so the trusted-viewers group moved out and the ceiling came down.
1 parent 4022565 commit 29892be

14 files changed

Lines changed: 344 additions & 53 deletions

File tree

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ Anything agreed but not done — deferred follow-ups, known gaps, half-delivered
123123

124124
Cyclomatic complexity ≤ 10 · cognitive complexity ≤ 15 · function ≤ 75 lines · parameters ≤ 7 · nesting ≤ 4 · file ≤ 750 lines · line ≤ 120 chars · no duplicated block ≥ 10 lines.
125125

126-
**What actually enforces these.** `quality.yml` has five jobs — `lint` (ruff), `security` (bandit), `pytest-headless` (the suite plus the coverage floor), `typing-stable-api` (mypy) and `dependency-review` — and of the limits in this section only line length is rejected by one of them (ruff). Complexity is measured by `radon cc -nc` in the pre-commit list below and read by a human. The file-length limit is enforced by nobody — treat this section as a review standard, not a gate, and do not describe it as CI-enforced.
126+
**What actually enforces these.** `quality.yml` has five jobs — `lint` (ruff), `security` (bandit), `pytest-headless` (the suite plus the coverage floor), `typing-stable-api` (mypy) and `dependency-review`. Of the limits in this section, line length is rejected by ruff (`[tool.ruff] line-length = 120` with `E501`; it exempts a line ending in a pragma, which cannot wrap), and the file-length limit by `test/unit_test/headless/test_file_length_budget.py`, which reads the exemption list in `Progress.md` and fails on a file over the limit that is not listed, on a listed file that grew past its recorded ceiling, and on a row whose file is now under the limit. Complexity is measured by `radon cc -nc` in the pre-commit list below and read by a human — that part is a review standard, not a gate.
127127

128128
**Scope of the file-length limit.** It applies to:
129129

‎Progress.md‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@
1919

2020
`CLAUDE.md` §Size and complexity limits 規定:超標檔案只能列在這裡,列不進來的就是缺陷。
2121
清單上的檔案**可以改、可以變短,但不得再變長**——要再長就得先拆。
22-
行數為 2026-08-19 實測(`len(text.splitlines())`);`webrtc_panel.py` 於
23-
2026-08-22 拆出 `advanced_group.py` 後降到 2,545,上限跟著往下走。
22+
行數為實測(`len(text.splitlines())`);`webrtc_panel.py` 於 2026-08-22 拆出
23+
`advanced_group.py`、2026-09-23 拆出 `trusted_group.py` 後降到 2,530,上限跟著往下走。
24+
**這張表現在有測試在守**:`test/unit_test/headless/test_file_length_budget.py` 比對本表與樹,
25+
超標未列、列上的檔案變長、或已經縮到線內卻還留著的列,都會紅。
2426

2527
| 檔案 | 行數 | 為何還沒拆 |
2628
| --- | ---: | --- |
27-
| `gui/remote_desktop/webrtc_panel.py` | 2,545 | 單一 Qt 面板,但已含連線、監視器選擇、頻寬自適應、麥克風、錄影五組互動狀態。應拆成 panel + 各控制器。 |
29+
| `utils/mcp_server/tools/_handlers_executor_bridge.py` | 1,448 | 2026-09-23 拆 `_handlers.py` 時新建。252 個純委派(中位數 3 行):`from action_executor import _x` 再 `return _x(...)`,沒有分支。**不套用 flat data tables 條款**——那一條講的是「一個對照表或清單」,這裡是 252 個函式定義。再切下去只能照 MCP 工廠領域分(159 個領域),那會把同一種委派散進十幾個檔,而它們之間沒有語意邊界。規則照舊:只准變短。 |
30+
| `gui/remote_desktop/webrtc_panel.py` | 2,530 | 單一 Qt 面板,但已含連線、監視器選擇、頻寬自適應、麥克風、錄影五組互動狀態。應拆成 panel + 各控制器。 |
2831
| `utils/accessibility/backends/windows_backend.py` | 923 | 已拆出 `windows_query.py`(170)與 `windows_state.py`(98)。剩下的是同一套 UIA COM 生命週期管理,再拆會把 `CoInitialize`/介面釋放的配對邏輯切散。**2026-08-24 從 918 長到 923**:見下面的說明。 |
2932

3033
**本質豁免(依 `CLAUDE.md` 的「flat data tables」條款,不算既有豁免)**:
3134
`utils/mcp_server/tools/_factories.py`(8,975,MCP 工具註冊表)、
32-
`utils/mcp_server/tools/_handlers_executor_bridge.py`(1,448,252 個純委派,中位數 3 行:`from action_executor import _x` 再 `return _x(...)`,沒有分支)、
3335
`utils/executor/action_executor.py`(8,131,`AC_*` 分派表)、
3436
`gui/script_builder/command_schema.py`(5,051,每個 `AC_*` 的參數 schema)、
3537
`je_auto_control/__init__.py`(1,970,門面 re-export)、

‎architecture.md‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,16 @@ wrapper/auto_control_record.record → OS listener (e.g. windows/record/win32_in
124124

125125
| Consumer | How it uses this repo | What it relies on |
126126
| --- | --- | --- |
127-
| Jeffrey_RPA | Editable install of **this working tree**: uncommitted changes here reach it immediately. Single facade `JeffreyRPA/_gui_control.py`. | Top-level names (e.g. `click_mouse`, `hotkey`, `write`, `screen_size`, `get_pixel`, `post_click_to_window`) and internal paths `je_auto_control.wrapper.auto_control_window`, `je_auto_control.wrapper.auto_control_keyboard.WRITE_CONTROL_KEYS`, `je_auto_control.utils.monitor_layout` (`logical_virtual_rect`, `enumerate_monitors`). |
127+
| Jeffrey_RPA | Editable install of **this working tree**: uncommitted changes here reach it immediately. Single facade `JeffreyRPA/_gui_control.py`. | Top-level names (e.g. `click_mouse`, `hotkey`, `write`, `screen_size`, `get_pixel`, `post_click_to_window`) and internal paths `je_auto_control.wrapper.auto_control_window`, `je_auto_control.wrapper.auto_control_keyboard.WRITE_CONTROL_KEYS`, `je_auto_control.utils.monitor_layout` (`logical_virtual_rect`, `enumerate_monitors`), and `wrapper.platform_wrapper.keyboard_keys_table` / `mouse_keys_table` — it validates every key name a user types against the keyboard table and reverse-looks-up recorded virtual keys through it, so a name removed there becomes a rejected hotkey over in that repo. |
128128
| PyBreeze | Subprocess `python -m je_auto_control --execute_str <json>` / `--execute_file <path>`; on Windows the JSON string arrives double-encoded. | Legacy CLI flags; also embeds `je_auto_control.gui.main_widget.AutoControlGUIWidget` and calls `record` / `stop_record` in-process. |
129129
| TestPioneer | Optional extra `gui = ["je_auto_control"]`; `parallel_run` starts `python -m je_auto_control --execute_file <path>`. | `execute_action`, `execute_files`, `RecordingThread`; the `--execute_file` flag. |
130130

131131
**Guarded by** `test/unit_test/headless/test_cross_project_contracts.py`: every legacy CLI flag (short and long, run as a
132132
real child process, including PyBreeze's double-encoded `--execute_str`), the facade names in the three rows above
133133
(Jeffrey_RPA's list is every `ac.<name>` in `_gui_control.py`), the `auto_control_window` functions Jeffrey_RPA calls,
134-
its three internal imports, and `AutoControlGUIWidget`. The test only knows what this table knows: when a consumer
135-
starts relying on something new, add it to both.
134+
its three internal imports, the two key tables (shape everywhere, Windows key names on Windows), and
135+
`AutoControlGUIWidget`. The test only knows what this table knows: when a consumer starts relying on something
136+
new, add it to both.
136137

137138
**Outbound (optional):** `utils/webrunner_bridge/bridge.py` imports WebRunner's *internal*
138139
`je_web_runner.utils.executor.action_executor.executor` lazily, for `AC_web_*` commands and `gui/webrunner_tab.py`.

‎architecture_explore.md‎

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ iOS(WebDriverAgent)。核心能力是滑鼠/鍵盤控制、影像辨識、
1919

2020
| 指標 | 數值 |
2121
| --- | ---: |
22-
| Python 模組總數(含周邊子專案) | 1,042 |
23-
| 程式碼總行數 | 141,928 |
22+
| Python 模組總數(含周邊子專案) | 1,043 |
23+
| 程式碼總行數 | 142,003 |
2424
| `je_auto_control/utils/` 子套件數 | 310 |
2525
| `AC_*` 動作指令數(`known_commands()` 實測) | 773 |
2626
| 套件門面 `__all__` 公開名稱數 | 1,238 |
@@ -268,7 +268,7 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
268268

269269
### 5.4.1 執行引擎與腳本資產
270270

271-
> 24 個套件、約 12,991 行。
271+
> 24 個套件、約 13,002 行。
272272
273273
| 模組 | 行數 | 職責 |
274274
| --- | ---: | --- |
@@ -293,7 +293,7 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
293293
| `utils/script_vars/` | 190 | 執行期變數作用域與 `${var}` / `${secrets.*}` 插值 |
294294
| `utils/skill_library/` | 116 | 具名可重用 action 序列(skill)的持久化倉庫 |
295295
| `utils/state_machine/` | 181 | 宣告式有限狀態機驅動 action JSON |
296-
| `utils/stubs/` | 276 | 為 `AC_*` 指令面產生型別 stub |
296+
| `utils/stubs/` | 287 | 為 `AC_*` 指令面產生型別 stub |
297297
| `utils/test_record/` | 66 | 全域測試紀錄單例,記錄每個動作的參數與例外 |
298298
| `utils/work_queue/` | 182 | 交易式工作佇列(dispatcher/performer),支撐大量批次執行 |
299299

@@ -510,15 +510,15 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
510510

511511
### 5.4.10 遠端桌面與 USB
512512

513-
> 6 個套件、約 18,006 行。
513+
> 6 個套件、約 18,020 行。
514514
515515
| 模組 | 行數 | 職責 |
516516
| --- | ---: | --- |
517517
| `utils/admin/` | 334 | 多主機管理主控台:平行輪詢 N 個 AutoControl REST 端點 |
518518
| `utils/config_sync/` | 246 | 透過訊令伺服器做跨機器設定同步 |
519519
| `utils/device_matrix/` | 138 | 行動裝置矩陣:同一 action list 於多台裝置平行執行 |
520520
| `utils/remote_desktop/` | 12,039 | **遠端桌面子系統**(56 檔/11.7K LOC):TCP/WebSocket/WebRTC 三條傳輸路徑、主機與檢視端、訊令伺服器、TURN/中繼、多檢視者、錄影、信任清單、TOTP、稽核鏈 |
521-
| `utils/usb/` | 4,321 | 跨平台 USB 列舉/熱插拔/裝置直通(WinUSB、IOKit、libusb 後端 + ACL + WebRTC DataChannel 通道) |
521+
| `utils/usb/` | 4,335 | 跨平台 USB 列舉/熱插拔/裝置直通(WinUSB、IOKit、libusb 後端 + ACL + WebRTC DataChannel 通道) |
522522
| `utils/usbip/` | 928 | USB/IP 線路協定主機端(協定封包、TCP 伺服器、libusb URB 後端) |
523523

524524
### 5.4.11 伺服器、網路協定與外部整合
@@ -715,7 +715,7 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
715715
| `tools/_handlers_runs.py` | 110 | 同一種 adapter,執行主題:executor、執行歷史、錄製、動作檔。 |
716716
| `tools/_handlers_scheduling.py` | 200 | 同一種 adapter,排程主題:排程器、觸發器、熱鍵常駐。 |
717717
| `tools/_handlers_remote.py` | 66 | 同一種 adapter,遠端桌面的 host 與 viewer。 |
718-
| `tools/_handlers_executor_bridge.py` | 1,448 | 252 個純委派(中位數 3 行,最長的 16 行全是參數簽章):每個都是 `from action_executor import _x` 再 `return _x(...)`,沒有分支邏輯。扁平表格,依 `CLAUDE.md` 的 flat data tables 條款不受 750 行限制。 |
718+
| `tools/_handlers_executor_bridge.py` | 1,448 | 252 個純委派(中位數 3 行,最長的 16 行全是參數簽章):每個都是 `from action_executor import _x` 再 `return _x(...)`,沒有分支邏輯。超過 750 行,理由記在 `Progress.md` 的豁免表(再切只能照 MCP 工廠領域分,會把同一種委派散進十幾個沒有語意邊界的檔)。 |
719719
| `tools/_handlers_locators.py` | 417 | 同一種 adapter,定位主題:無障礙樹、智慧等待、自我修復、螢幕觀察、座標空間、視覺與 OCR、影像去重、元件倉庫、A/B 定位。 |
720720
| `tools/_handlers_operations.py` | 644 | 同一種 adapter,營運主題:agent 與其記憶/追蹤、治理與合規、成本與遙測、失敗掛鉤、看門狗、速率限制、檢查點、核可、產物與資產、測試選擇與分片、佇列與 saga。 |
721721
| `server.py` | 717 | JSON-RPC 2.0 over stdio 的最小 MCP 伺服器:連線範圍狀態、行內/併發分派、工具與 resource/prompt 處理器。 |
@@ -787,7 +787,7 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
787787
| `permissions.py` / `clipboard_sync.py` / `wake_on_lan.py` / `session_actions.py` / `auth.py` | 64 / 72 / 56 / 40 / 28 | 逐 session 權限、剪貼簿同步、WOL、SAS 注入與螢幕遮蔽、HMAC 挑戰回應。 |
788788
| `ws_host.py` / `ws_viewer.py` / `jpeg_recorder.py` | 40 / 29 / 146 | WebSocket 傳輸變體與 TCP 路徑錄影。 |
789789

790-
#### `utils/usb/`(4,321 行)與 `utils/usbip/`(928 行)
790+
#### `utils/usb/`(4,335 行)與 `utils/usbip/`(928 行)
791791

792792
| 檔案 | 行數 | 職責 |
793793
| --- | ---: | --- |
@@ -804,7 +804,7 @@ socket server 有 8 MiB 讀取上限與 30 秒 handler timeout。
804804
| `usb/passthrough/key_provider.py` | 125 | ACL 的可插拔 HMAC 金鑰來源。 |
805805
| `usb/passthrough/commands.py` | 150 | 無頭直通指令(單一真實來源)。 |
806806
| `usb/usb_devices.py` | 296 | 跨平台 USB 裝置列舉。 |
807-
| `usb/usb_watcher.py` | 246 | 輪詢式 USB 熱插拔監看。 |
807+
| `usb/usb_watcher.py` | 260 | 輪詢式 USB 熱插拔監看。 |
808808
| `usbip/protocol.py` | 330 | USB/IP 線路格式封裝/解析。 |
809809
| `usbip/server.py` | 241 | USB/IP 主機端 TCP 伺服器。 |
810810
| `usbip/libusb_backend.py` | 210 | 以 PyUSB/libusb 執行 URB 的正式後端。 |
@@ -940,13 +940,14 @@ GUI 是**選用 extra**(`pip install je_auto_control[gui]`,PySide6 + qt-mate
940940
| diagnostics | `diagnostics_tab.py` | 91 | 執行子系統檢查並顯示結果。 |
941941
| report | `_report_tab.py` | 81 | 產生 HTML/JSON/XML 報表。 |
942942

943-
#### 遠端桌面 GUI(`gui/remote_desktop/`,18 檔/6,343 行)
943+
#### 遠端桌面 GUI(`gui/remote_desktop/`,19 檔/6,393 行)
944944

945945
| 模組 | 行數 | 職責 |
946946
| --- | ---: | --- |
947-
| `webrtc_panel.py` | 2,550 | WebRTC 子分頁主體。 |
947+
| `webrtc_panel.py` | 2,530 | WebRTC 子分頁主體。 |
948948
| `webrtc_dialogs.py` | 493 | WebRTC GUI 用的自訂對話框與清單元件(待審檢視者、信任清單、通訊錄、遠端檔案表、稽核記錄、LAN 瀏覽)。 |
949949
| `advanced_group.py` | 92 | 兩個 WebRTC 面板共用的 Advanced STUN/TURN(含選用硬體編碼器)群組,含它寫回面板的 Protocol。 |
950+
| `trusted_group.py` | 70 | WebRTC host 面板的信任 viewer 清單群組(移除/清空/匯入/匯出),含它寫回面板的 Protocol。 |
950951
| `connection_screen.py` | 672 | Quick Connect —— AnyDesk 風格單畫面入口。 |
951952
| `viewer_panel.py` | 542 | 「控制另一台機器」子分頁。 |
952953
| `webrtc_known_hosts.py` | 342 | TOFU 釘選庫瀏覽器:`KnownHostsDialog` 與帶外釘選用的小表單。由 `webrtc_dialogs` 再匯出。 |
@@ -1055,11 +1056,11 @@ socket 預設綁 `127.0.0.1`;資源一律用 `with`。
10551056

10561057
| 層/子系統 | 檔案數 | 行數 |
10571058
| --- | ---: | ---: |
1058-
| `gui/` | 90 | 26,722 |
1059+
| `gui/` | 91 | 26,772 |
10591060
| `utils/mcp_server/` | 31 | 17,473 |
10601061
| `utils/remote_desktop/` | 56 | 12,039 |
10611062
| `utils/executor/` | 6 | 9,081 |
1062-
| `utils/usb/` | 17 | 4,321 |
1063+
| `utils/usb/` | 17 | 4,335 |
10631064
| `je_auto_control/`(頂層 3 檔) | 3 | 2,367 |
10641065
| `utils/accessibility/` | 13 | 2,842 |
10651066
| `wrapper/` | 19 | 3,551 |
@@ -1075,6 +1076,6 @@ socket 預設綁 `127.0.0.1`;資源一律用 `with`。
10751076
| `osx/` | 17 | 919 |
10761077
| `autocontrol-lsp/` | 8 | 744 |
10771078
| `utils/hotkey/` | 7 | 738 |
1078-
| 其餘模組(約 286 個 `utils/` 子套件 + `android/`/`ios/`/周邊小工具) | 673 | 47,946 |
1079-
| **總計** | **1,036** | **141,863** |
1079+
| 其餘模組(約 286 個 `utils/` 子套件 + `android/`/`ios/`/周邊小工具) | 673 | 47,957 |
1080+
| **總計** | **1,037** | **141,938** |
10801081

0 commit comments

Comments
 (0)