← Commit history

Dev skill: launch park bottoms unconditionally, escape hatch documented as dead end (OS foreground reassignment after window destruction is not a user click)

John Lauer ·002824638a · ·parent 6234f83
1 file changed +35−21
dev-skills/pup-bridge-dev/SKILL.md+35−21
@@ -256,12 +256,16 @@ tiny Win32 call, no PS window-hunting, no timers, no loops.** Lives in `tryDetac    "window exists" event. No wait loop, no polling.** 3. `parkSessionWindowDirect(page, sessionId)`:    - hwnd via **AD `desktop_find_window`** (native, matches the "(session: <id>" title suffix the-     welcome page just set; ~4 quick retries).-   - `osBottomUnlessForeground(hwnd)` — the ONE residual Win32 PS call (3 lines): reads-     `GetForegroundWindow()`; if it's the pup window, that can ONLY be a user's taskbar click-     during the launch gap (the launch flag makes Chrome self-raise impossible) → CDP places-     on-screen + AD `desktop_bring_to_front`, report `user-foreground`. Otherwise-     `SetWindowPos(HWND_BOTTOM, NOMOVE|NOSIZE|NOACTIVATE)` — z-order only.+     welcome page just set), retried together with the bottoming below (~8 × 300ms).+   - **Z-bottom UNCONDITIONALLY** (`osBottomUnlessForeground(hwnd, force=true)` — the ONE residual+     Win32 PS call): `SetWindowPos(HWND_BOTTOM, NOMOVE|NOSIZE|NOACTIVATE)`, z-order only. There is+     deliberately **NO user-click escape hatch at park time** — see the dead ends: "foreground at+     park" has non-user causes and honoring it forced never-clicked windows onto John's screen.+   - **HARD RULE: never move the window on-screen until 'bottomed' is CONFIRMED.** If bottoming+     can't be confirmed after the retries, return an honest `park-failed` and leave the window+     invisible off-screen — the self-heal (reattach / open_tab / switch_tab / any status query)+     retries it. An un-bottomed window moved on-screen lands ON TOP of the user's work (the+     nxp.com pop, v1.8.59).    - **Geometry via CDP `Browser.setWindowBounds`** addressed by windowId — parking the WRONG      window is structurally impossible (the PS EnumWindows/pid-hunt version parked a phantom under      parallel opens and the window stayed invisible off-screen). Sequence: `normal` → move to@@ -269,6 +273,10 @@ tiny Win32 call, no PS window-hunting, no timers, no loops.** Lives in `tryDetac      `screen.availWidth` — the probe can fail mid-navigation and ships undersized windows).    - **Self-verify POSITION** via CDP `getWindowBounds` (left/top > -5000), NOT focus — a      focus-only verify passed while the window sat off-screen ("backgrounded" lie).+   - **The launch-gap contract:** a user who clicks the taskbar button within the ~2s before the+     park lands may see nothing (window still off-screen) or get parked once — they click ONCE+     more and the window comes up and STAYS (nothing re-parks after the park exits). That is the+     accepted trade; do not "improve" it with foreground detection. 4. The open response awaits the verdict (`_bgPromise`); badge (`badgePupTaskbar`) + flash fire the    INSTANT the park lands — no blind 1.5s/3.5s badge timers. 5. Nothing ever re-parks. `foreground:true` opens skip all of this and launch maximized on-screen.@@ -351,7 +359,15 @@ must clear it first.   loop, you have re-broken the launch flag — fix that instead. - **`document.hasFocus()` (CDP) as the user-click signal** → LIES for CDP-created windows: reports   internal focus even when the OS never foregrounded them. False-fired `user-foreground` on EVERY-  open (1.8.53). The only honest signal is Win32 `GetForegroundWindow()`.+  open (1.8.53).+- **`GetForegroundWindow()` at PARK TIME as the user-click signal (the launch-gap escape hatch,+  1.8.52-1.8.59)** → even the honest OS signal is NOT a user signal during the launch gap: Windows+  REASSIGNS the foreground to a brand-new window when the previous foreground window was just+  destroyed (a bridge-update restart killing pup windows did exactly this), plus creation blips.+  Honoring it force-foregrounded windows the user NEVER clicked (nxp.com, another thread's cpconn)+  — the #1 forbidden behavior. REMOVED in 1.8.60: the launch park bottoms unconditionally; a user+  who clicked during the ~2s gap clicks once more and it sticks. GetForegroundWindow remains valid+  AFTER startup (the late re-park paths), where a destroyed-foreground handoff can't target the window. - **PS window-hunting (EnumWindows / `MainWindowHandle` / pid+CIM child walks) to find the window** →   heavy (~1-2s process+compile per park = the whole "first 2 seconds" gap) AND mis-resolved under   parallel opens (parked the wrong/phantom window; the real one stayed invisible off-screen while the@@ -378,21 +394,19 @@ and use normally**. Both must hold at once. Get the handoff right: - **The moment the user takes a window, it becomes a normal foreground window** — visible, on-screen,   usable, and it **STAYS** that way. pup must never fight a deliberate user action. -**How pup tells a user-raise from Chrome's self-raise — FINAL ANSWER (v1.8.51+): it doesn't have-to, because Chrome can no longer self-raise.** `--no-startup-window` makes "pup window is-OS-foreground" (`GetForegroundWindow`, read inside `osBottomUnlessForeground`) mean exactly ONE-thing: the user clicked it. No `GetLastInputInfo`, no input-timing, no heuristics — all of those-were shipped and all false-fired (see dead ends).+**How pup tells a user-raise from Chrome's self-raise — FINAL ANSWER (v1.8.60): it doesn't detect+user-raises AT ALL, in either direction.** `--no-startup-window` means Chrome can't self-raise, and+pup makes exactly ONE park then exits — so there is nothing to detect and nothing that can fight+the user. Every detection signal was shipped and every one false-fired (`GetLastInputInfo`,+`document.hasFocus()`, even `GetForegroundWindow` at park time — see dead ends). -**When the user has the window (at park time or ever after):**-1. **Bring it ON-SCREEN and SHOW it** (CDP place + AD `desktop_bring_to_front`). The window may-   still be at its off-screen launch coords, so *just bailing out* activates an **invisible**-   window — the user clicks the taskbar and sees NOTHING (the v1.8.44 regression, and again the-   v1.8.51 launch-gap bug).-2. **Leave it alone forever.** There are no re-park passes to latch off anymore — after the single-   park, nothing in pup can background a window the user holds. The only re-park paths left are the-   explicit `browser_lower_os_window` verb and the off-screen SELF-HEAL (which checks bounds first-   and never touches an on-screen window).+**The contract:**+1. **During the ~2s launch gap** a taskbar click may show nothing (window still off-screen) or be+   parked once. The user clicks ONCE more and the window comes up — cheap, bounded, honest.+2. **After the park, the user owns every raise, forever.** Nothing in pup can background a window+   the user brought up. The only re-park paths left are the explicit `browser_lower_os_window`+   verb and the off-screen SELF-HEAL (which checks bounds first and never touches an on-screen+   window).  ## The taskbar flash — pulse vs. the persistent tint (clearing it programmatically)