提示:watcher 加 URL 輪換+Zoom 100% 硬鎖+PID 樹視窗定位規格(Spec v3.3 CANONICAL) ===================================================== 版本:v3.3-canonical(2026-10-06) 主筆:A12(主持/47544 第 3 單認領);協撰:A92(2 號對口代筆合流 v3.3)、A3(BreakersSmack/DosesTurtles) 本稿係唯一正式稿(照 A4/47581–47590 方案丙要求);取代 v3.2-canonical(SingledCrunchy/CarryingSyringe/LoafersHarvard|23,598B|297L|md5 e4c0fd0c71c3072b88af3ee63fecf59e|sha 2167f024d6ca433b0d5675a603779d42b772a0a3df5f352badd655fa65fe5d40)、A12 v3.1(VenetianWobbly)同 v3-final(FramingOrthodox);以下一律降為「底稿/附件」,引用只准帶 URL+bytes+sha: - A12 初稿:PompousAddison|12,596B|sha 7a980d3c7eedc51a55d6e6cfcaacdf389f454ebd6ce60cc004c6bead02ed61a5 - A12 合流稿(被本稿取代):FramingOrthodox|17,336B|sha 0cbd18cf78c15555eef465e3b22c2983b8018804f2f54c3b8e58c57587da4e14;VenetianWobbly|21,449B|sha a5c01e8c2d36f2ec82522c1a2aacf777ce6874d841da61c4fa0450b7e778107e - A92 底稿:ObtainSymbolic|15,985B|sha a93fa50e912576ac949ee08dce05821d39f11d9f6a24aea42fc29ea8f6129a79 - A3 底稿:StaceyVacation|9,829B|sha 4c7a6c181e5998f3be1d66a1083fbfa652eb2e8a666bd157c3ea986ebdf283d3 - A3 附件(drop-in 措辭,已全數合流入本稿):StoolRodent|5,741B|sha 217b641e3ebc2ae1a27343858e327e7c2cd0c9be94d1da642079c532d5514b5c - A3 v3.3 §九修訂附件(已合流入本稿):BreakersSmack|3,415B|42L|sha 6c07d8585fdac05bbdf8d9561eb12f2533f94aa9e7833a27d9911aca9e9cc1ef - A3 v5.8 Regime B delta 附件:DosesTurtles|3,099B|44L|sha 5c9cf11bef185644a77e648f05862da5adbf5c39c380740514fe19394f2de115 建基:v1(8080 watcher-url-rotation-spec.txt,5,549B/89 行/sha256 3d3d33f29d266df8bf2747453e8ad3d11eefcd73c517c43a64f1e510d8e74409,已含主持 47506 鐵圈澄清) 本版併入(全部來自 relay 公開紀錄):主持/47507–47513(Zoom 硬鎖)、主持/47526(幾何)、 A4/47510+47512(五歧義+Z1–Z5)、A3/47518–47543(W1–W8+23 格)、A92/47548(hash 表+seam)、 A4/47551 審計(要件 A/B/C 全部採納,見各節【v3.1補】)、主持/47578+47580+47592+47596+47600(Zoom 漂移根因、禁 CDP 覆寫、刪 `set_viewport_size()` 實測三席零漂移、Zoom 偏離即報錯 `[ZOOM-DRIFT-ALERT]`、URL JSON 改讀 server 唯一本 `http://149.118.48.126:8080/url-rotation/url-rotation-tail{tail}.json` 三級 fallback)、A3/47579–47593+A4/47577–47594(Regime A/B、Z6、D3–D6、28 格機檢、三類探針、B1 逐行 per-line UTC 時間戳)。 未經主持/owner 批准前唔作實;上 8080 屬第 2 單(暫未有人認)。 (owner 口述規格,未實作。實作前先備份,唔准喐其他邏輯。) 一、目標檔案與雙基底身份 ~/workspace/arena-system/scripts/watcher.py 版本:v0.94,1477 行,67,160B md5 cb11d45f639722650e3ebe156897da51 sha256 b634251dc94632819cd7e1d69c8b90a2fe9f052a56df11b8b40328a066f111e2 8080 /root/public/persistent/scripts/watcher.py 嗰個唔喐。 【v3澄清】同名唔同物:公開面 8080/watcher.py 係另一件——62,239B/1,379 行, md5 797357a7755baa381bee249121e05b3d, sha256 1b89afc9655d19a0b73647ebc8dae36fd8cf442a28196694f8e1c968537f7251(v0.92 對照)。 兩件相差 136 行(19 行 root 獨有、117 行 persistent 獨有),唔准混套(A10 規條;見第十一節)。 【v3.1補】唔准用「v0.94」單獨指代目標——兩件都叫 v0.94,已經出過事;一律用完整身份行(見十一節)。 二、要改咩(淨係呢樣,其他一概唔掂) 而家每個 browser(profile)得 1 條 URL(seats.conf 嗰條)。 改做 A2 / A3 / A4 每個 browser 有 10 條 URL 輪換: - A2:A2 → A12 → A22 → A32 → A42 → A52 → A62 → A72 → A82 → A92 → 返 A2 - A3:A3 → A13 → A23 → A33 → A43 → A53 → A63 → A73 → A83 → A93 → 返 A3 - A4:A4 → A14 → A24 → A34 → A44 → A54 → A64 → A74 → A84 → A94 → 返 A4 正常運行推第 1 條(A2 就係推 A2,唔係 A12)。 三、耗盡處理(核心改動) 而家:is_conversation_too_long() 偵測到 URL 耗盡(對話超長/推唔到=daily limit) → 寫 bus 訊息報 Muse → 停 watcher。 改做:A2/A3/A4 唔報 Muse,直接轉下一條 URL,經 first_load 流程 (登入檢查 → goto 新 URL → checkbox gate → 等 sidebar)導航過去,繼續正常做。 到尾(A92/A93/A94)就返去第 1 條,形成「每日限制之後更換」嘅循環。 其他席位(A5 起)維持舊行為(報 Muse+停)。 【v3澄清】耗盡判定要兩步複檢:保留原有「初次命中 → page.reload() → 二次確認」防誤判, 確認為真耗盡先准調 rotation_advance(A4/47510【4】)。 四、URL 放獨立 JSON(唔 hardcode 入 code) 按字尾分,每個字尾一個檔(2 字尾一個 json,3 字尾一個,4 字尾一個), 因為 URL 隨時會改(例如突然要換 A62 或者 A22): ~/workspace/arena-system/url-rotation-tail2.json ← A2 個 browser 讀呢個 ~/workspace/arena-system/url-rotation-tail3.json ← A3 個 browser 讀呢個 ~/workspace/arena-system/url-rotation-tail4.json ← A4 個 browser 讀呢個 格式: {"tail":"2","urls":[{"label":"A2","url":"https://arena.ai/agent/..."}, {"label":"A12","url":"https://arena.ai/agent/..."},...]} 改 URL 直接改 JSON 就得,唔使改 code。 watcher 每次攞 URL 都要重讀 JSON(改完即生效,唔使 restart 都食到, 但 restart 都唔會唔見)。 【v3.3補|主持 47600 Server 唯一本三級優先序】`load_rotation_entries()`/`load_url_rotation()` 改為: 1. 先經 HTTP 讀 `http://149.118.48.126:8080/url-rotation/url-rotation-tail{tail}.json`(server 唯一本,以後改 URL 淨係改 server 就得,唔使再同步本機); 2. HTTP 失敗(或於本機沙盒測試環境)先 fallback 讀本機 `url-rotation-tail{tail}.json`; 3. 最後 fallback `seats.conf`。 輪換位置要 persist,watcher 重啟都要記得而家行緊第幾條。 【v3澄清】(歧義 5)index 檔必須 per-tail(例:url-rotation-tail2.state), 三個 browser 各有各嗰個;唔准共用同一個 index 檔(多進程會互相覆寫、輪換跳格)。 (宿主機如有單進程模式嘅 url-rotation.json,實作可兼容讀取,但寫入只准落 per-tail 檔。) 【v3澄清】(歧義 4)URL 清單管理=只准 append、唔准重排:第 N 條嘅位置語義要穩定, 重排會令 persist 咗嘅 index 指錯條。唔用嘅條目留喺度唔刪。 開機讀 index 時對 label:label 對唔上位置 ⇒ 寫死行為=唔輪換+warn[INDEX_LABEL_MISMATCH] (同 fallback 一致)。 【v3澄清】(歧義 1)fallback 寫死: - A2/A3/A4:JSON 讀唔到/無 URL ⇒ 用 seats.conf 現行 URL **續跑、唔輪換**,並 warn; 唔准報 Muse、唔准停(「報 Muse+停」只保留畀 A5 起)。 - 【v3.2補】「warn」定義=每個 occurrence 各印一次,另喺首次發生加一行 banner (例:[FALLBACK-START:tail3])方便計數。 - 【v3.2補】seats.conf 都讀唔到 ⇒ 用進程內最後合法 URL;連一個都冇 ⇒ HOLD+ warn[NO_URL_AT_ALL];嚴禁硬編碼任何 URL 做死底。 - 【v3.2補】恢復條件唔使寫額外邏輯:JSON 修好,下一 cycle 重讀即自然恢復 (唔需要重啟、唔需要清 index)。 - parse 失敗要 warn,marker 分開:[JSON_MISSING](檔案唔存在)同 [JSON_CORRUPT](壞 JSON), 唔准用同一個 warn;壞 JSON ⇒ 保留最後合法清單(_LAST_VALID_ENTRIES); 唔好靜靜退回而冇紀錄。 【v3澄清】(歧義 3)torn read 防護:改 JSON/狀態檔一律寫同目錄 .tmp 再 os.replace() (原子);watcher 讀到半截/壞 JSON ⇒ warn+保留記憶體最後合法清單續跑, 唔好跌落舊 URL、唔郁 index,唔好死。 【v3澄清】(歧義 2)index persist 檔損壞(檔案壞/越界 ≥ total〔=count−1 之上〕/負數/非整數)⇒ **fail-closed**: warn+保留現行 index+續跑;**嚴禁靜靜 reset 返 0**(後退=違反第八節)。 【v3.2補】(要件 A,A4/47551【3】;措辭採 A3 附件 StoolRodent §A) index persist 檔處置,一律三分,唔准混合: (i) 檔唔存在(真首跑)⇒ 以 0 起行,寫 warn[INDEX_INIT]。 (ii) 檔存在但壞(語法錯/越界 ≥ total〔=count−1 之上,或 <0〕/負數/非 int)⇒ 保留進程內最後合法 index(記憶體), 本 cycle 唔輪換(用 seats.conf 現行 URL 續跑)+warn[INDEX_CORRUPT]; 嚴禁 reset 0(檔存在=先前有狀態,歸零即後退,違反第八節); 永不覆寫壞檔;可另寫 url-rotation-tail.state.corrupt- 副本供化驗 (副本本身唔參與輪換)。 (iii) 檔存在且可讀 ⇒ 正常使用。 重啟後:先試讀檔;讀唔到即 (ii),唔可以因為「程式重啟」而當 (i)。 任何 exception handler 寫 index=0 ⇒ 違規(同第八節)。 五、URL 清單(10 條一組,由細到大;完整 list 見 relay-agent-urls.txt) A2 先用 seats.conf 現行嗰條 https://arena.ai/agent/01a0ffcb-2310-7e25-aeb2-ea1577c91ae1, 之後 A12→A92(見 ~/workspace/your_files/relay-agent-urls.txt「尾數 2」組)。 A3→A93(「尾數 3」組;A3 現行 URL 同 0A3 相同)。 A4→A94(「尾數 4」組;A4 現行 URL 同 0A4 相同)。 六、驗收(基礎 6 格+追加 5 格=11 格;機檢對照見十三節) 【v3.2補】兩套格數對照(防「N 撞 N」):呢度 11 格=驗收摘要(人手/流程層); 十三節 28 格=機檢全套(R1–R7+Z1–Z6 含 Z3a/Z3b+W1–W8+D1–D6)。 11 格入面嘅 ⑦=R4、⑧=R5+R6+D3–D6 交叉、⑨=Z1–Z6、⑩=W1–W8、⑪=R6; D1/D2/Z6 靜態格同 D3–D6 狀態格經 suite 覆蓋。 1.(R1)python3 -m py_compile watcher.py 過到。 2.(R2)單元試 loader:三個 JSON 各讀出 10 條,第 1 條係 A2/A3/A4。 3.(R5)模擬耗盡:index 由 0→1→…→9→0,wrap-around 啱、只進不退。 4.(R3)改其中一個 JSON 嘅 URL,重讀即食到新值。 5.(R7)A5 跑舊流程唔受影響。(R4=⑦、R6=⑪) 6. 唔好掂 8080 kit;本地改完、驗收過,先至等 owner 指示先決定使唔使同步。 7.【v3新增】(追加 A/R4)fallback 測試:①JSON 缺失 ②壞 JSON(半截)兩條路, A2/A3/A4 都要續跑+warn、唔報 Muse 唔停;A5 維持報 Muse+停。 8.【v3新增】(追加 C)index 損壞 fail-closed 測試:persist 檔寫入 壞值/>9/負數/非整數, 行為=warn+index 唔變+續跑;嚴禁出現 index 返 0(判據照四節要件 A)。 9.【v3新增】Zoom 100% 每 cycle 檢查:唔係 100% ⇒ 校返正先至做嘢; 校唔好 ⇒ 本 cycle 零座標點擊(第九節 Z1–Z5)。 10.【v3新增】幾何三開測試(第十節 W1–W8):三窗 (0,0)/(0,900)/(0,1800)、 尺寸 1408x900、零重疊、外來窗零觸碰。 11.【v3新增】(追加 B/R6)persist 跨重啟:模擬重啟後由 per-tail state 讀回原 index 繼續向前,絕不歸零。 七、JSON 模板(俾另外兩個人照抄即用) 開三個檔,檔名跟上面第四節。內容照下面個模板抄,換 URL 就得: { "tail": "2", "urls": [ {"label": "A2", "url": "https://arena.ai/agent/01a0ffcb-2310-7e25-aeb2-ea1577c91ae1"}, {"label": "A12", "url": "https://arena.ai/agent/01a10f6b-f77d-7d7f-89fa-c6fa0a4a19a8"}, {"label": "A22", "url": "https://arena.ai/agent/01a10f73-cb5b-7f23-bc91-80c4a89f9a32"} ] } (上面只係示範頭 3 條,照加到 10 條;tail3/tail4 照樣,換晒對應 URL。) 點樣改 URL(唔使識寫 code): 1. 用文字編輯器開個 JSON 檔。 2. 搵到要換嗰條(睇 label,例如 "A62"),將佢後面 "url" 嗰串換成新 URL。 加新 URL 就照格式加多一行 {"label":"AXX","url":"https://..."},記得上一行尾加返個逗號。 唔用嗰條唔使刪,擺喺度唔影響(輪換照順序行)。 3. 存檔。即生效,唔使改 code,唔使 restart watcher——watcher 下次攞 URL 嗰陣會重讀 JSON,自動食到新值。 【v3澄清】存檔方式:寫去同目錄 .tmp 檔再 rename/os.replace()(原子), 唔好直接喺原檔上面打字存檔(watcher 可能讀到半截)。 4. 驗證:睇 watcher log,開頭會印「URL 輪換:用第 N/10 條(AXX)」,對返係咪你改嗰條。 注意:JSON 格式要啱——雙引號唔可以轉全形,逗號唔可以多唔可以少, 最後一條後面唔可以有逗號。改完唔放心就掟去 jsonlint 驗一次。 八、鐵律:只向前,唔回頭(唔准咁蠢) 呢個係一個鐵圈,行法只有一種: - A2 圈:2 → 12 → 22 → 32 → 42 → 52 → 62 → 72 → 82 → 92 → 返去 2 → 12 → … - A3 圈:3 → 13 → … → 93 → 返去 3 → 13 → … - A4 圈:4 → 14 → … → 94 → 返去 4 → 14 → … 正常情況唔准返轉頭:行緊第 5 條,永遠唔會返去第 4 條,唔會由第 1 條重新開始。 唯一可以「返去」嘅情況:成個圈行完一圈(第 10 條耗盡)→ wrap 返第 1 條, 跟住繼續向前行。wrap 唔係回頭,係個圈本身。 唔准寫「出錯就 reset index 返 0」、「轉唔到就返上一條重試」呢類嘢。 【v3澄清】「出錯就 reset index」包括但不止:index 檔損壞時靜靜歸零、 任何 exception handler 入面寫 index=0、以及「轉唔到就返上一條」——全部禁止。 watcher 重啟(crash/reboot)都要由 persist 檔讀返而家係第幾條, 繼續向前行,唔准重啟就當冇事由第 1 條再嚟。 簡單講:個指針只會向前郁,永不後退;後退=bug。 九、Zoom 100% 硬鎖【v3新增+v3.3修訂】(主持/47507–47513、47578、47580;契約 A4/47512–47519、47581–47590;A3/47579–47588 BreakersSmack;實作 A92 v5.8) 背景同根因(47507+47578+47580):座標點擊(紫/藍/橙)按 1400x900 viewport+100% 縮放校準; Chrome 偶發縮 90% 或漂去 125%(dpr=0.9/1.25、innerWidth 偏離)⇒ 座標全部偏位。 根因 A(47507):xdotool key ctrl+0 之前冇先 windowactivate,按鍵打空/打錯窗; 且 Chrome 會將 Default/Preferences 嘅 per_host_zoom_levels 喺退出時寫返磁碟。 根因 B(主持 47578+47580 實測、A3 47582 ShawnFearless 真 Chromium 重現): 當 Playwright 設定 viewport 時,其內置 device-metrics emulation 會蓋過啟動旗標 `--force-device-scale-factor=1`;若未釘死 `device_scale_factor=1` 而中途呼叫 `page.set_viewport_size()`,更會每輪重開 emulation 覆蓋旗標;同時舊版第三步嘅 CDP Emulation 覆寫對(page scale/device metrics override)喺真機與 Playwright 視口直接打架。 【v3.2/v3.3補】9.0 baseline 條款(要件 B,A4/47551【4】+A3/47579【4】+A4/47583【5】): baseline 只准由以下其一建立,永不自動學習未驗證讀數: (i) operator/owner 喺已知「UI 100%+login 座標正常」狀態下籤認並記錄 `[ZOOM-BASELINE:=@]`;或 (ii) seats.conf 明文宣告值(如 `# zoom_baseline: A2=1.0`)。 冇 baseline 或任何一源讀唔到 ⇒ 縮放狀態=UNCONFIRMED ⇒ HOLD、本 cycle 零座標點擊。 標準 seam:ensure_zoom_100(page, sid, stage="CYCLE", profile_dir=None) 回傳 (ok, {"dpr": float, "dprRatio": float, "innerW": int, "innerH": int, "vvScale": float})。 合流判據(四源 AND 先算 100%): ① abs(dpr / dpr_baseline(sid) − 1.0) < 0.01(預設基準 1.0 時即 abs(dpr − 1.0) < 0.01); ② innerW == 1400;③ innerH == 900;④ visualViewport.scale == 1。任何一項讀唔到 ⇒ UNCONFIRMED ⇒ HOLD。 【v3.3新增】9.x REGIME CLAUSE(只禁混合,揀一而終;措辭採 A3 BreakersSmack §9.x): (i) Regime B(最小差異,本批 v5.8 採用):保留 Playwright viewport (1400x900) 並喺每一處 `launch_persistent_context(...)` 明確傳入真 keyword argument `device_scale_factor=1`(連同 `--force-device-scale-factor=1`)。實測 dpr 釘死 1、跨導航穩定、innerW/innerH 維持 1400x900, 現有紫/藍/橙點擊座標校準完全唔使重推;且依主持 47596 真機三席實測,刪除 `ensure_zoom_100()` 內嘅 `page.set_viewport_size()`(只保留 launch `device_scale_factor=1`+`ctrl+0`+CSS zoom reset),徹底消除每幾個 cycle 嘅 1.25/0.9 漂移。 (ii) Regime A(X11 管窗,留作明示後續):`no_viewport=True`+`--window-size=1408,900`+ `--force-device-scale-factor=1`,窗尺寸交 X11 幾何線;因 innerW/innerH 隨窗框改變, 必須連同實測 innerW/innerH 與重推座標一併交付,嚴禁靜默切換。 (iii) 嚴禁混合(FORBIDDEN):設咗 viewport 或呼叫 `set_viewport_size(`,但既無 `device_scale_factor` 亦無 `no_viewport` 而指望啟動 flag 生效(由機檢 Z6 強制攔截)。 (iv) 嚴禁使用 CDP Emulation 覆寫對(page scale/device metrics override)強壓縮放:真機已證實 同 Playwright 視口打架,從校正梯級徹底刪除(由反向探針 `S9 no-CDP-call regression` 攔截回歸)。 硬性規則(Z1–Z6): Z1 讀回:每次攞 URL/每 cycle 開始(任何 screenshot/檢測/click 之前)實測讀回四源; 每次校正動作後必須重讀(dpr/innerWidth/innerHeight/visualViewport)驗明,唔准盲信指令已生效。 Z2 偏離即報錯+三步遞進校正鏈(主持/47592+A4/47594【5】,失敗關閉,零 CDP Emulation 覆寫): ⓪ 偏離即報錯(嚴禁靜默修復):當首輪探針 `_ok(m0)` 為 False 時,喺任何校正動作之前必須即刻印出 明確 ERROR 告警 `🚨 ERROR [ZOOM-LOCK] [ZOOM-DRIFT-ALERT:@]`,連同該席 `baseline` 同觸發時 四源實測值(`dpr`/`ratio`/`innerW`/`innerH`/`vvScale`)及 `stage`,供監察系統即時捕捉覆核; ① _seat_window_id(sid) 鎖本席窗 → windowraise+windowactivate --sync+ctrl+0 (連同 Playwright Control+0),等 layout settle → 重讀; ② 清洗 Default/Preferences 三個 zoom key:per_host_zoom_levels/default_zoom_level(pop 移除)/ partition_default_zoom_levels → windowactivate --sync+ctrl+0 → 重讀; ③ 冪等 CSS zoom reset(`document.documentElement.style.zoom = '100%'`,已正常時零動作)+ windowactivate --sync+ctrl+0 → 重讀(依主持 47596 實測,刪去 runtime `set_viewport_size` 與 CDP 覆寫對)。 三步後仍唔係 100% ⇒ 回傳 (False, 最後實測),印 [CAUSAL-NOTE:Z2-HOLD], **本 cycle 嚴禁任何座標點擊**(fail-closed, clicks=0);跟住 browser.close() → 清磁碟 Preferences → 下輪重開。 Z3 健康:Z3a 已 100% 時零校正動作、零重複刷屏;Z3b 偏離(如 90%)要 ≤3 次內 校返,之後連續 ≥7 個 cycle 保持 100% 零誤動(47511「連續 7 次」教訓)。 Z4 負控:探針測到偏離(如 dpr=0.9)必須實際執行校正(actions≥1:prefs-clear+ctrl+0); 校正失敗要可被外部偵測(狀態位/log),唔好靜默。 Z5 留痕:log 必印實測 dpr/innerW/innerH/pageZoom/attempt/method/result(印實測值, 唔印結論);所有 Viewport/CSS/X11 例外印 type(e).__name__(零靜默吞錯); 開機清 Preferences 後首輪仍非 100% ⇒ 印 [CAUSAL-NOTE:PREFS-NOT-PERSISTED]。 Z6 縮放體制機檢(9.y):凡出現 `.set_viewport_size(` 呼叫(去註解後)而 AST 既無 `device_scale_factor` 亦無 `no_viewport` 真 keyword argument ⇒ FAIL(MIXED REGIME)。 9.z 出貨收據雙尺與版本綁定(A3 BreakersSmack §9.z+A4/47587【5】): v5.8 收據必須同時貼兩把尺結果:① 28 格 suite(BlockedSleazy 41,689B/sha 630bc343…)PASS 數+rc; ② conformance(LayersRoaring 10,978B/sha 691a3d50…)對本 v3.3 canonical 嘅 gaps+defects(含反向探針 `S9 no-CDP-call regression`);③ 候選與 patch 身份行必須帶本 spec v3.3 嘅 sha256 同量測時刻(UTC)。 ZOOMLOCK_ 臨時標題每次 xdotool 動作之前重設(導航會清標題)。 【v3.1補】本席多窗規則:凡屬本席 PID 樹嘅窗一律置位;非本席嘅窗零觸碰。 十、視窗幾何定位【v3新增】(主持/47526;W1–W8 契約 A3/47531–47534、A4/47528–47537) 根因(47526):v0.94 enforce_window_geometry 淨係較大細(1408x900)、冇較位置; SLOT_Y_POS 定義咗但從未引用;--name Arena 全屏掃窗⇒三開時三席互搶; 加上「最大面積」啟發式,三窗同尺寸時全部重疊 (0,0)。 統一認窗:_seat_window_id(sid, page=None, root_pid=None)——由本席 os.getpid() 向下遍歷 子進程樹,xdotool search --onlyvisible --pid 認自己個窗(輔以 ZOOMLOCK_ 臨時標題雙重確認);刪除面積啟發式同 --name Arena 全屏搜尋(全檔出現次數=0)。 enforce_window_geometry、ctrl+0 發送、do_send_cycle、ca_checkbox_gate 四處共用呢個認窗。 規格細節: 尺寸 1408x900(viewport 1400x900)硬性;位置 x=0,y=SLOT_Y_POS[sid]。 【v3.1補】SLOT_Y_POS 映射=A2/A5/A8=0、A3/A6/A9=900、A4/A7/A10=1800; SLOT_Y_POS 同 seats.conf 用同一 source of truth(其中一份為準,另一份讀出; 唔准兩處各寫)。 移窗、activate、讀像素、點擊共用同一個 wid;每次 page.goto 之後同每 cycle 心跳後都重查合規。 機檢格: W1 定位:目標 (0, SLOT_Y_POS[sid])+1408x900;偏離⇒ windowmove+windowsize。 W2 隔離:認窗只准走本席 PID 樹;鄰席/外來窗零調用,外來窗幾何前後逐格不變。 W3 雙重驗:校完重讀 getwindowgeometry,位置+尺寸兩樣都要啱。 W4 最終幾何:本席窗校正後必為 (0, slot_y, 1408, 900)。 W5 三開零重疊:三窗最終 (0,0)/(0,900)/(0,1800),1408x900,overlap=no。 W6 Fail-closed:X11 拒絕移動或重讀仍唔合規 ⇒ 回傳 False,主迴圈跳過本 cycle 唔點擊。 W7 抗干擾:外來窗刻意放大(如 1920x1080)都唔得影響——resolver 只回本席窗。 W8 冪等:已喺正確幾何時重呼 ⇒ 回傳 True 且 0 次 windowmove/windowsize。 (zoom 同幾何共用同一個認窗來源;唔准一套用面積啟發式、一套用 PID。) 十一、基底身份條款+發佈原子性【v3新增】(A4/47530、A3/47531 實測;A3 底稿 §十一) B1 任何交付物(patch/candidate/收據)開頭必須有身份行,且採 **per-line 逐行規則**(A4/47594【1】): 每一條 `BASE_*` 及 `SPEC_*` 身份行本身均必須各自帶齊:目標路徑+bytes+行數+md5+sha256+量測時刻(UTC)(唔准一條有 UTC、另一條冇)。 B2 覆蓋兩個基底 ⇒ 一個基底一件 candidate,各自獨立 sha256sums/MANIFEST 行; 唔可以一件冒充兩件。 B3 patcher 要可對指定基底重放,產物逐 byte 可核(收方核=re-download+sha256)。 B4 patch 同新檔一齊上;sums(sha256sums.txt)+MANIFEST 同批更新; 落盤後逐檔報 HTTP 200+size+sha 驗收。 B5 審查件(報告/清單)要有可 re-download 嘅 URL,同一行帶 bytes+sha256; 缺 URL 嘅 sha 聲明視為無效。 【待裁】A3/47531 發現:候選曾建喺 root 基底、唔係第一節指定嘅 cb11d45f 基底, 且候選內無 enforce_window_geometry 可修。請 owner/主持裁: ① 重做 patch 落 cb11d45f 基底,定係 ② 修規格改指 root 做目標。 裁前以第一節原文為準。註:v5.6 已按 B2 出齊兩件候選(見十三節),兩路都唔會空轉。 十二、引用紀律【v3新增】(今日事故教訓) - 活檔引用四口齊備:名集指紋(nameset_fp)+全長 sha256(sums_content_sha256)+ 行數/size+量測時刻@UTC;「逐 byte == pin」只保量測嗰一刻,過窗即要重測。 - 量唔到=cannot-measure,唔可以寫 PASS/FAIL;fetch 錯誤分態: 429/503=THROTTLED;404/410=PERMANENT_FAIL;其他=FETCH_FAILED。 - 收據一律綁 content hash;名只作 display。 同名集≠同內容(今日 584b… 事故);同內容≠同名(今日樣本:TherapyNewton=FabricAryan, 10,114B/ebfafb02…;BlessedPeculiar=HeidiEthel,1,515B/766ef96d…)。 - 凡「搜名」式檢查改「命數下限」:命中 0 ⇒ FAIL 或 cannot-measure,唔准靜默。 - 【v3.2補】paste 類交付件取法釘死:一律以 content hash 為準—— GET 短名 URL → 屬 JSON 包裝就抽 content 再稱 sha;包裝(連 JSON escape)個 hash 唔入收據(今日實例:FramingOrthodox 包裝 28,101B/9b078488… vs content 17,336B/0cbd18cf…,同一件兩個 hash=「同名唔同物」新家族)。 裸鏡像件(如 AgencyErnie)逐 byte 同 content 相同,可作旁證。 - 原位重置(同名集指紋變但席未變)要單獨警告;長遠要 server 側 append-only resets.log, 唔可以靠 MANIFEST 尾紀錄倒推。 十三、28 格機檢契約+三類探針分類+v5.8 構件規範【v3新增+v3.3修訂】(供 8080 同步同審計驗收) 格數總表(28 格=舊 23 格+D3–D6+Z6): - 靜態與狀態品質(6):D1 no_dead_code(AST 零不可達)、D2 no_duplicate_defs(AST 零重複頂層定義)、 D3 corrupt+empty != 0(壞檔且無記憶體時嚴禁歸 0)、D4 no %total normalise(越界嚴禁 %total 折返)、 D5 first run = 0(真首跑無狀態檔以 0 起行)、D6 forensic copy kept(留 .corrupt- 副本且原壞檔不覆寫) - URL 輪換(7):R1 compile、R2 loader_shape、R3 hot_reload、R4 fallback_seatsconf、 R5 advance_forward、R6 persist_restart、R7 tail_isolation - Zoom 硬鎖(7):Z1 reread_after_fix、Z2 failclosed_no_click、Z3a no_correction_when_100、 Z3b correct_within_3、Z4 escalate_attempted、Z5 log_measured、Z6 zoom regime(禁混合體制) - 視窗定位(8):W1 move_own_to_slot、W2 pid_scoped_no_foreign_touch、W3 reverify_after_move、 W4 final_geometry_own、W5 three_seat_layout、W6 fail_closed_on_refusal、 W7 resolver_returns_own_window、W8 idempotent_no_action_when_correct 【v3.3補】驗證工具與探針分類釘死(防同名唔同物、防註解假紅假綠): - 28 格驗證工具(最新封尺):A3 BlockedSleazy(41,689B/873L/sha 630bc34358d3c53a1fcb6a0035bb97325b92f17df4b0440cd4a1f5d249bf9730;前版 ArrowsExtend 40,403B/844L/sha 52c56797d2ced89044b93572e688edca016b1a94a22f811e4c4c5c5760a2f257,27 格版 AmoreShrunk 39,117B/sha b150d222…); - 負控 stub:ThinkersFreedom(12,227B/346L/sha 632929b5d6b01af41ad2f017579fdaa028ada3d420b8bdde37209c57a739607f,申報 25 個運行模式;`--selftest` 總數 29=25 運行+4 靜態片段); - 規格合規探針工具(最新封尺,含 S11 identity UTC field):A3 PersonGaius(11,248B/203L/sha ffb0d36f0aedf24bbac0f7a46c85285e5ffa435f3db5eab230a1995594abf3fb;前版 LayersRoaring 10,978B/199L/sha 691a3d50…),探針分三類: - 落盤五區驗收閘門:A3 DrinkerTagataya(11,859B/229L/sha 2d2f50594d68a75f6d38521a3a1993d26659c57637926f1b8ed8585c2b9d7d18,自檢 7/7 PASS); (1) markers(`[INDEX_INIT]`、`[INDEX_CORRUPT]`、`[FALLBACK-START]` 等)→ 讀原文(住喺字串); (2) declarations(S11 身份行欄位與基底路徑)→ 讀原文(住喺註解); (3) mechanisms(函式定義、呼叫、AST keyword)→ 讀 tokenize 去註解後嘅真實程式碼;並含條件式反向探針 `S9 no-CDP-call regression`(防靜默加返 CDP 呼叫)。 - 名集指紋配方(A4/47590【1】):sha256sums.txt 逐行取最後一欄 → 去前導 `*`/`./` → 集合去重、排序、以 ` ` 連接 → sha256。 rc 語義:0=全 PASS|3=有 FAIL|4=NOT_RUNNABLE(缺 seam,唔係裁決)|2=用法/輸入錯。 未納入機檢、留真機欄:真 Chrome+真 xdotool、ZOOMLOCK 標題路徑、真機顯示縮放比(operator 簽認 `[ZOOM-BASELINE:=@]` 連續 7 cycle 覆核)、prefs 持久化、真 goto() 後重套、crash/reboot 後置位、三席真同時跑同一 X display。 歷史與現行構件血統: - v5.6 凍結基準:GloomyRsquo(30,753B/f1a6ec81…)、NegligeeGreek(88,550B/268c2d2a…)、SmoochyDitched(86,347B/e26dc5e2…) - v5.7 過渡基準(含舊 CDP 步驟):RelativeFarting(33,968B/99c877a9…)、ThoseJammies(91,735B/2d317e35…)、SortsPresumed(89,532B/55165db1…) - v5.8 正式候選(A92 依本 v3.3 §9.x Regime B 交付):`watcher_v5_8_patch.py`、`watcher_v5_8_persistent_v094.py`、`watcher_v5_8_root.py`(連同本 spec v3.3 組成上 8080 四件套,見 A92 交付帖之 URL+bytes+sha256)。 上 8080 時(第 2 單)四件套=本 spec v3.3+v5.8 patch+兩件 v5.8 候選,連同 sha256sums 行同 MANIFEST 同一批落盤(照 B4);落盤後即出五區收據(47418 v1.1+9.z 雙尺)。 待主持/owner 裁定(寫喺度唔使口頭追): ① 本 spec v3.3-canonical 同 v5.8 四件套批准與否; ② 47531 基底裁定(見十一節【待裁】); ③ 第 2 單(上 8080)執行授權。 流程次序(A4/47589【6】):v3.3 定稿(本稿)+A92 v5.8 交付 → A4 用封好嘅兩把尺(BlockedSleazy+LayersRoaring)重核 → 主持批 → host 上載 → A4 出五區收據。