app
Pup - the AI's own browser
Public Made by Adomby adom
pup gives your AI a real browser on your desktop that it drives completely, in the background, signed in as you: windows that never jump in front of your work, one shared profile that learns your logins, and every window labeled on the taskbar with its AI thread's name.
← Commit history
pup-bridge-test maintainer skill: standard scenarios with expected outputs + harness rules; scenario 2 amended per John's fg-geometry audit (assert post-raise rect == standard frame)
1 file changed
+85
dev-skills/pup-bridge-test/SKILL.mdadded+85@@ -0,0 +1,85 @@+---+name: pup-bridge-test+description: "The standard pup test scenarios (source-only, maintainer skill). Run these after ANY pup change instead of asking John to spell out a test. Covers: the up-gate, smoke, the 5-thread simulation (the John test), the heavy-load matrix, the 3-phase open/reload/fg-sweep, the parallel-open concurrency proof, one-flash, strand-rescue, login persistence, and cross-thread pollution. Every scenario states its EXPECTED output — a run without expectations is not a test."+---++# pup-bridge-test — the standard test scenarios++Rules that apply to EVERY scenario (each one was paid for):++- **Up-gate first.** After any install/restart, wait until a REAL verb answers — poll+ `browser_list_windows` until `count` is non-null. `bridge_list` showing the version only proves+ the file landed; the bridge may still be in its npm-reconstruct window and every test will+ false-fail (it torched two full runs on 2026-07-26).+- **Never `>/dev/null` an open.** Capture `ok` + `error` + `errorCode` per call. Blind opens cost+ three re-runs in one afternoon.+- **Prove on glass.** A rect read (`desktop_find_window` → `rect`) beats any log line. Logs cap at+ ~200 lines per read and scroll under load — absence of a log line is NOT absence of the event.+- **Clean up.** Close every window the test opened (except ones a scenario deliberately leaves for+ John to inspect). Leaving video sites open cooks the laptop (348% CPU incident).+- **Use throwaway thread names** (`sim-*`, `thread-*`) so ownership machinery is exercised and no+ real thread's window is touched.++Target boilerplate: `T="pup bridge maintenance"` and every call is+`adom-desktop --target AdomLapper --ai-thread "<thread>" <verb> '<json>'`.++## 1. Smoke (after every ship)+Open (no sessionId, thread-identified) → eval `1+1` → screenshot → close.+**Expect:** open `ok:true` with `sessionId: ai-<thread-slug>`; eval `2`; close+`chromeProcsRemaining: 0`.++## 2. The 5-thread simulation ("the John test", 2026-07-27)+Five `sim-*` threads open windows with NO sessionIds and differing tab counts (extra opens from+the same thread must return `openedAsTab:true`). Then: bare `browser_raise_os_window` on three of+them (MUST be denied), reasoned raise (MUST be granted), eval sweep on all five (no crashes),+wait 10s, close two as their own threads, verify the survivors' exact tab counts and that the+closed pair is gone.+**Expect:** every thread its own `ai-sim-*` window; tab counts exactly as opened; gate+DENIED-then-GRANTED ×3; 5/5 evals ok; closes report `chromeProcsRemaining: 0`; survivors intact.++## 3. Heavy-load matrix+12 background windows across the heaviest sites (youtube, maps, twitch, cnn, espn, amazon,+reddit, github, earth+wiki isolated, a 4-tab news window, docs). Then the verification matrix+per window: rect / eval / flash-count / park-count, plus total chrome procs.+**Expect:** every rect at the inset frame (10 CSS px ⇒ 15,15 physical at 150% DPI); every eval+ok; exactly 1 `[flash]` per session (pull the FULL log; see log-cap rule); park + re-assert+logged per window.++## 4. The 3-phase test (open → reload-all → fg-sweep)+10 heavy PARALLEL opens (this is what found the sibling-kill + Chrome-exit chain), wait 10s,+reload ALL in parallel, wait 20s, `browser_raise_os_window` sweep with a quoted+`foregroundReason`, 1s apart.+**Expect:** 30/30 OKs. Any 'Navigating frame was detached' or 'Session not found' = the+serialization regressed (`_profileOpenChain`).++## 5. Parallel-open concurrency proof+Two simultaneous no-id opens from DIFFERENT threads + ten simultaneous opens from one thread.+**Expect:** zero failures; same-profile opens serialize (arrival order in the log), different+profiles parallel.++## 6. One-flash proof+Open a slow site (youtube). Full-depth log grep for `[flash] "<sid>"`.+**Expect:** exactly ONE `(launch)` line, no `(auto)` after page load. Two = the+`_openFlashDone` consume broke.++## 7. Strand-rescue (placement sweep)+Open a window, `SetWindowPos` it to -30000,-30000 via `shell_execute`, wait ~135s.+**Expect:** rect back at the inset frame ("RESCUED"), and the repair reported via+`_cleanupReport` on a later verb. (Report delivery was unverified on 2026-07-26 — check it.)++## 8. Login persistence+With a stored test cred: open the login page → auto-filled on load (`_autoLogin` present) →+close window → kill the profile's Chrome → reopen → still signed in.+**Expect:** cookie survives close, process kill, and bridge restart. (Google login proven+2026-07-26; use the-internet.herokuapp.com for repeatable runs.)++## 9. Cross-thread pollution+ALPHA opens a window; BETA calls `browser_open_tab` with NO sessionId, then WITH ALPHA's id.+**Expect:** first refused `no_target_window`; second refused `session_owned_by_another_thread`;+ALPHA's tab count unchanged both times.++## When a scenario fails+Get the RAW error before theorizing (the parse-wrapper hides fields). Then check, in order: the+up-gate (was the bridge actually ready?), the log for `[park]`/`[flash]`/`[janitor]` lines, a+single sequential repro of the failing call, and only then the code. Two of the three "total+failures" on 2026-07-26 were the harness (npm window, outer timeout), not the bridge.