← Commit history

dev skill: seat dialog owned-popup detection + screenshot-verify + readiness self-heal (v1.6.47 learnings)

John Lauer ·6454cf70cf ·3mo ago ·parent c0dba63
1 file changed +24−7
skills/fusion-bridge-dev/SKILL.md+24−7
@@ -65,8 +65,18 @@ opening path you add MUST follow it: - **Seat conflict ("Active Sessions Exceeded") = AUTO-RESOLVE via UIA, in the background, never ask   (SOLVED live 2026-07-06 after a very long day).** The definitive facts, hard-won:   - It is a **Qt** dialog (`automationId` = `QTApplication.QTSessionBlockedStartup...`), NOT CEF.-  - Its window **TITLE is literally "Fusion360"** — the "Active Sessions Exceeded" text is body-    content — so detect it by **owning process + dialog size** (`find_licensing_dialog()`), never title.+  - Its window **TITLE is literally "Fusion360"** — the seat text is body content — so NEVER detect by+    title. There are **multiple variants of different SIZES**: "Active Sessions Exceeded" (~1235x527,+    with radios) and the **"Suspend Remote Session" confirm (only 823x262)**.+  - **DETECT by the OWNED-POPUP signal, not a size window (fixed 2026-07-06 v1.6.46/1.6.47 after a+    fragile 320px height floor silently MISSED the 262px confirm and readiness lied that it was gone).**+    A seat/sign-in modal is ALWAYS an **owned popup** of the main Fusion window (`GetWindow(hwnd,+    GW_OWNER)` != 0; confirmed by `desktop_screenshot_window`'s `ownedPopupCount` on the main window).+    The splash and the maximized main app are NEVER owned popups. `find_licensing_dialog()` returns the+    owned family window that is **dialog-SHAPED: width ≥ 480** (excludes Fusion's own ~300px-wide side+    panels — the Data Panel/browser rail are owned popups too, and matching them false-blocked `ready`+    the moment a doc was open) **and height ≥ 180** (excludes toolbar strips), smaller than the maxed+    main app. ctypes `GetWindow` MUST have `restype/argtypes=HWND` set or the owner handle truncates.   - Its native **"Continue"** button IS exposed to **UIA** (`desktop_ui_click {hwnd, name:"Continue"}`),     and UIA **Invoke runs in the BACKGROUND — no foreground, no focus steal, no cursor move**. Suspend     is the pre-selected radio, so Continue grabs the license. (The radios themselves are web content@@ -76,11 +86,18 @@ opening path you add MUST follow it:     dead code, kept only as a comment-marker — do not resurrect it.   - **DO NOT** coordinate-click it (`desktop_click`/SendInput): that needs foreground (disturbs the     user) AND the focus-guard fights you by minimizing the dialog.-  - **RETRY + VERIFY.** The FIRST UIA Invoke on a mid-render dialog silently NO-OPs. So the launch loop-    re-invokes "Continue" EVERY tick until `find_licensing_dialog()` no longer sees it — never click-    once and trust it. And a STALE add-in port (port 8774 from a just-killed instance) answers while-    the CURRENT Fusion is blocked behind the dialog, so the seat check must take PRIORITY over the-    add-in probe in both the launch loop and `fusion_readiness` (else you falsely read `ready`).+  - **RESOLVE + SCREENSHOT-VERIFY.** The FIRST UIA Invoke on a mid-render dialog silently NO-OPs, so+    `_resolve_seat_dialog()` re-invokes "Continue" and confirms it TRULY cleared by re-reading the+    parent window's `ownedPopupCount` via `desktop_screenshot_window` (parent/child screenshotting) —+    NOT by re-running the size heuristic that once false-'resolved' it. Do the screenshot check;+    "I clicked it" is not "it's gone."+  - **AUTO-RESOLVE ANYWHERE, in CODE, not just the launch loop.** The seat dialog also appears LATER —+    minutes after sign-in, when the license server notices too many sessions — long after the launch+    loop exits. So `fusion_readiness` SELF-HEALS: whenever it detects the dialog it auto-resolves it in+    the background and re-probes. The seat is handled deterministically in code no matter when it shows+    up; the AI never has to notice or act (John: "do all this tracking from your code ... the ai never+    follows skills"). A STALE add-in port (8774 from a just-killed instance) answers while the CURRENT+    Fusion is blocked, so the seat check takes PRIORITY over the add-in probe in both paths. - **The add-in still loads while minimized** — background operation (open/model/export) needs no   visible window. So minimized costs you nothing. - **Foreground is opt-in, only to SHOW the user something.** The ONLY time you may foreground/restore