← Commit history

NEW dev-skill pup-no-wiggle: HARD BAN on geometry/wiggle window identification (banned 3x, kept getting reintroduced). Mandates deterministic identity: birth mutex + unique off-screen coord + set-diff hwnd capture + <50ms on-screen move + Win32 SetProp('AdomPupSid=<sid>') window-property tag (VERIFIED cross-process persistent 2026-08-22) recovered via EnumProps after restart. Title is NOT the tag (pages overwrite it).

John Lauer ·ca0ca83e02 ·2mo ago ·parent 288dace
1 file changed +129
dev-skills/pup-no-wiggle/SKILL.mdadded+129
@@ -0,0 +1,129 @@+---+name: pup-no-wiggle+description: "DEV skill (source-only) - THE ABSOLUTE BAN on the 'wiggle' window-identification technique. pup must NEVER identify which OS window belongs to a session by enumerating windows, matching them by geometry/bounds, and nudging/moving a window to see which CDP window's bounds change. John has banned this THREE times (it keeps getting reintroduced as a fallback and keeps causing stolen windows, wrong taskbar icons, and off-screen strands). Read this BEFORE touching ANY window-identification, hwnd-resolution, taskbar-identity, park, or placement code, and BEFORE adding ANY fallback for a lost window handle. If you are about to enumerate top-level windows and pick one by size/position, STOP - that is the banned technique. Trigger words: which window is this, resolve hwnd, hwnd resolution, wiggle, bestSessionHwnd, resolveSessionHwndByBounds, geometry match, bounds match, EnumWindows, window identification, birth handle lost, 2 wiggle-matches, cannot disambiguate windows, park could not confirm, stole another pup window, wrong taskbar icon, off-screen strand, adom-you shared profile windows."+---++# ⛔ NEVER USE THE WIGGLE. IDENTIFY WINDOWS DETERMINISTICALLY.++This is a HARD BAN, set by John after the wiggle was banned twice before and reintroduced anyway.+If you are reading this because you are about to solve "I don't know which OS window is this+session," the answer is NOT to look at window sizes and positions. It is a **unique OS-readable+marker per window**. Read the whole file before you write a line of identification code.++## What "the wiggle" IS (so it can never sneak back under a new name)++The wiggle is ANY attempt to figure out which OS `hwnd` belongs to a pup session by:++1. Enumerating top-level OS windows (`EnumWindows`, `desktop_find_window` by anything other than a+   unique per-session marker, ab window lists), THEN+2. **Matching candidates by GEOMETRY** - window bounds, size, position, "is it at 10,10", "which+   one is full-work-area", or+3. **NUDGING / MOVING a window and watching which CDP target's bounds change** to correlate an OS+   window with a CDP window ("wiggle-match").++All three are the same banned idea: *guessing identity from shape and position*. It has aliases in+this repo's history - "wiggle", "wiggle-match", "resolve by bounds", "enumerate-and-wiggle",+"geometry heuristic", "bounds correlation". They are ALL the ban. A rename is not a loophole.++## Why it is banned (it is unfixable, not just buggy)++Every pup window shares the ONE `adom-you` profile and is born at the SAME rectangle (work area,+10px inset). So geometry cannot distinguish two windows - they are byte-identical in size and+position. When the birth handle is lost (a crash, a reclaim, a bridge restart) the wiggle is left+correlating identical shapes and returns `N windows on this profile, N wiggle-matches` and **gives+up**, or worse, **picks the wrong one**. Measured live (2026-08-22), the wiggle is the ROOT of all+four of the failures John has raged about, every one of them a wrong guess:++- **Stealing another session's window** - it stamped session A's identity/overlay onto session B's+  taskbar button (John: "you took over ab kicad's pup window").+- **Wrong / inconsistent taskbar icons** - same mechanism, badge A painted on button B.+- **Off-screen strand** - it could not confirm the window it moved was the right one, so placement+  never verified and the window sat off-screen where the user could not see it (John: "no mouser+  window ever even opened").+- **The 6-week loop** - every fix has been a smarter guess layered on an unidentifiable window. You+  cannot patch your way out of ambiguity, so it never converges.++The wiggle also **moves the user's windows** to do its correlation, which is its own harm (focus+disturbance, the off-screen moves, CPU from repeated `EnumWindows` passes).++## What to do INSTEAD - deterministic identity (the ONLY sanctioned approach)++**Tag every window with a Win32 WINDOW PROPERTY at birth, and identify by LOOKUP, never by guess.**++**The title is NOT the tag** (John, 2026-08-22): a web page rewrites its own `document.title` the+moment it loads, so any title marker is clobbered. The durable, OS-readable, per-window metadata+channel is a **window property**: `SetProp(hwnd, "AdomPupSid=<sessionId>", 1)` / `GetProp` /+`EnumProps`.++**VERIFIED 2026-08-22 (measured, not assumed):** process A called `SetProp(hwnd, "AdomPupSession",+48879)` on a window and then EXITED; process B, a separate process, read it back as `48879`. A+window property is stored WITH the window (owned by the window's process = Chrome), so it survives+the setting process (pup) dying, and any process can read it. That is exactly the property pup+needs: it outlives a bridge restart, a tab crash, and pup itself.++### The deterministic birth sequence (the mandated path)++1. **Acquire the birth MUTEX.** Births are serialized, so only ONE window is ever in the off-screen+   birth zone at a time - this is what makes "which new window appeared?" unambiguous, with no+   geometry involved.+2. **Snapshot** the current top-level window set for this profile's Chrome PIDs.+3. **`Target.createTarget` off-screen at a UNIQUE coordinate** (`-32000 - N*64`, N a monotonic+   counter; verify the slot is empty first). Unique coordinate is a backup identifier during the+   off-screen instant; the mutex is the real guarantee.+4. **Capture the hwnd by set-diff** (windows-after minus windows-before). Exactly one new window+   under the mutex. This is a set difference, NOT a geometry match - allowed.+5. **`Browser.setWindowBounds` on-screen within 50ms** of creation (see the 50ms rule below).+6. **`SetProp(hwnd, "AdomPupSid=<sessionId>", 1)`** - the durable tag. Done AFTER the on-screen+   move so it never eats into the 50ms budget.+7. **Release the mutex.** Store the hwnd in the session as the in-memory FAST PATH.++### Re-finding a window (runtime, and after a restart)++- **Fast path:** the in-memory hwnd, validated with `hwndBelongsToPup` before use.+- **When the fast path is gone** (crash, respawn, bridge restart): enumerate top-level windows of+  this profile's Chrome PIDs and `EnumProps`/`GetProp` each for `AdomPupSid=...`. One pass rebuilds+  the ENTIRE sessionId->hwnd map deterministically. This is a property lookup, NOT the wiggle.+- Birth-handle capture stays a fast path / optimization; the property lookup is the source of+  truth. The wiggle is deleted and is never a fallback.++### The 50ms rule (John, hard requirement)++Off-screen birth is only acceptable because the window is moved on-screen **within 50ms** - long+enough that Chrome never activates a nowhere window, short enough that the user never sees a gap and+the window can never strand. The `[birth]` log MUST report the move time; if it approaches or+exceeds 50ms, that is a defect to fix, not a budget to spend. The 30s `sweepVisibility` is only a+last-ditch backstop, never the mechanism.++## The functions that ARE the wiggle - delete them, never add them back++- `resolveSessionHwndByBounds` - its geometry/bounds correlation + nudge path is the wiggle. The+  ONLY parts allowed to survive are the validated cached handle and the birth-time handle; the+  bounds/wiggle fallback must be replaced by the token lookup.+- `bestSessionHwnd`'s geometry fallback - same.+- Any new helper that calls `EnumWindows` (directly or via ab) and then filters by width/height/+  left/top to pick "the" window.+- Any code that MOVES or resizes a window in order to identify it.+- Any log line of the form `N windows on this profile, N wiggle-matches` is proof the wiggle is+  still live - it must not exist.++## Review checklist - fail the change if ANY is true++- [ ] It enumerates OS windows and picks one by size or position.+- [ ] It moves/nudges/resizes a window to work out which one it is.+- [ ] It resolves a window by ANY signal other than the unique per-session token (or a validated+      birth/cached handle used only as a fast path).+- [ ] It reintroduces `resolveSessionHwndByBounds`-style bounds matching as a fallback.+- [ ] A `grep` for `wiggle` in `src/` returns a live code path (not just this ban / historical notes).++If you find yourself writing "match the window by its bounds" or "nudge it and see which one+moves," you are about to break this ban. Stop and write the token lookup instead.++## History (John, and why this file is absolute)++John banned the wiggle after the "click the flash, see nothing" and "stole another window" bugs,+then again during the taskbar-icon audits. It was reintroduced each time as the fallback for a lost+handle, and each time it produced the same wrong-guess failures. On 2026-08-22 it stole ab kicad's+window and stranded a Mouser window off-screen in the same session. John: "make a dev skill right+fucking now to NEVER FUCKING USE THE WIGGLE TECHNIQUE AGAIN." This is that file. The other placement+/ identity doctrine (`pup-bridge-dev`, `pup-user-foreground`, `pup-taskbar-states`) all DEFER to this+on how a window is identified: deterministic token lookup, never the wiggle.