← Commit history

doctrine: proven background (2.0.634), foreground-proof ship gate, birth token, launcher branches

John Lauer ·715d59fe39 ·1mo ago ·parent 3fcc8b8
5 files changed +135
CLAUDE.md+6
@@ -96,6 +96,12 @@ Reuse one window (`sessionId: cft` or `pup-wiki`) instead of spawning new ones; ## Ship gates (run before `--insiders-from-candidate`)  - `tools/parity.py --via-ab` and `tools/ab-smoke.sh <box>` on the candidate.+- `tools/foreground-proof.sh <box> [pinHwnd]` (added 2026-09-18, 2.0.634): pins a non-pup window in front, force-kills+  pup's Chrome for a COLD lane, then samples the top-of-screen window twice a second through ab while it does a cold+  open, two navigates, two warm opens and a navigate. PASS only when ZERO samples have a pup Chrome window on top,+  counted by PROCESS (a 40-char title can lose the "Chrome for Testing" suffix and hide a window that sat on top for+  28 s). INVALID (exit 2) if any step fails or fewer than 3 windows exist at the end. This is the gate for John's+  goal ("stop shoving windows in front of me"); the first PASS ever was 2.0.634 on ConfRoomROG. - `tools/jumplist-ralph.py --target <box>`: every jump-list task fired THROUGH ab's taskrun shim with the   link's exact target and arguments, effect asserted in the window. Added 2026-09-06 after the Rust port   shipped 17 versions with every window-targeting task refused (`not_your_window`) while a by-hand exe
dev-skills/pup-bridge-dev/SKILL.md+11
@@ -348,6 +348,11 @@ R1 never visually pop / cover the user's work · R2 the window is reachable (tas were set after a pup window opened off-screen behind a live taskbar button for the second time in one day: *"you need to allow a user to open a pup window immediately if they want to."* +**R1 on the EXTENSION lane (2.0.630+): the extension API refuses off-screen bounds and refuses `state:"minimized"`+combined with bounds, so the ext-lane birth is `chrome.windows.create({url: birth.html?token, focused:false,+state:"minimized"})`, bound by the `PUPBIRTH-<token>` title, then shown at the bottom with `SWP_NOOWNERZORDER` and+fitted. The 50 ms move budget is recorded as 0 on this lane. The CDP-lane text below still holds for lane:"cdp".**+ **R1 BIRTH IT OFF-SCREEN, PARK IT ON-SCREEN WITHIN 50ms — UNCONDITIONALLY (revised 2026-08-22, v2.0.276).** `Target.createTarget` is created at `-32000,-32000`, then IMMEDIATELY moved by `Browser.setWindowBounds` to its final geometry (the PRIMARY MONITOR's work area inset **10px on all four sides**) in the same@@ -369,6 +374,12 @@ the window is never left off-screen, so it can never strand — the 2.0.258-and- was built to kill came from off-screen as a RESTING/STAGING/FALLBACK state gated on a self-defeating `zConfirmedBelow` proof, NOT from a guaranteed-transient birth. Do not conflate the two. +**R2 (2026-09-18 addendum) `launch_extdrive_opts` has TWO argument lists, stock and default. The 2.0.617 startup+flags lived in the stock branch only for 17 versions while the default lane, the one every user runs, opened+Chrome's real startup window on top at every cold start. A launch flag goes in BOTH branches or it is not shipped.+And no URL argument at cold launch: it overrides `--no-startup-window` (an empty string opens Chrome's cwd as a file+listing). Proven by `tools/foreground-proof.sh`, see `pup-user-foreground` "PROVEN BACKGROUND".**+ **R2 BACKGROUND IS THE PREFERENCE, NOT A PRECONDITION.** `--no-startup-window` is what actually keeps the foreground (the browser process holds no foreground rights by the time CDP creates the window), and it works with an on-screen rect exactly as well as an off-screen one. If it fails anyway and the window
dev-skills/pup-user-foreground/SKILL.md+34
@@ -309,3 +309,37 @@ result must still short-circuit callers and stamp `_userActiveAt`. If ab ever gr    `SKIP-FG` proves nothing, and an audit that reports no findings does not nudge at all, so a    "it stayed minimized" claim off that is worthless — and the window must still be minimized    afterwards. Verified on ConfRoomROG across two NUDGED events, 2026-08-20.+++## PROVEN BACKGROUND, at last (2.0.634, 2026-09-18): what actually made it work, and what did not++`tools/foreground-proof.sh ConfRoomROG` passed twice in a row on 2.0.634 (92 and 53 samples, a pup window never on+top through a cold open, navigates and warm opens). Every earlier "it works" claim in this session was invalid: John+alt-tabs back the instant a window appears, so "his window came back" proved nothing (John: "my orig window comes back+cuz i alt_tab immediately you idiot"). Only the sampler counts. The four things that were actually wrong:++1. **`SetWindowPos(HWND_BOTTOM, NOMOVE|NOSIZE|NOACTIVATE)` on a Chrome window RAISES it** (measured 2.0.626: returns+   true and the window goes to z1). Adding `SWP_NOOWNERZORDER` makes it go to the bottom and stay there. Every park+   in `host-win` (`show_at_bottom_no_activate`, `send_to_bottom_no_activate`) now carries it. Months of "the park did+   not hold" were this one flag.+2. **The default extension lane never had `--no-startup-window`.** 2.0.617 added `--no-startup-window` ++   `--keep-alive-for-test` to the `laneStockFlags` branch of `launch_extdrive_opts` only; stock is off by default, so+   every cold start still got Chrome's real startup window (a New Tab page, activated by Chrome) on top of the user for+   the whole session. Both launcher branches carry both flags now. When you add a launch flag, add it to BOTH branches.+3. **No URL argument at cold launch, ever.** A URL argument overrides `--no-startup-window`; `"about:blank"` made an+   unowned window on top for 18 s (2.0.631), and an EMPTY string made Chrome open its working directory as a file+   listing on top for 28 s (2.0.632). The launcher pushes the url only when it is non-empty, and the cold path passes "".+4. **The birth window is bound by a title token, never by set-diff.** The worker creates the first window minimized+   on `birth.html?token=…`, whose `birth.js` sets the title to `PUPBIRTH-<token>` (inline script is blocked by the+   extension CSP; it must be a file). pup resolves the hwnd by that title. The set-diff fallback bound Chrome's+   placeholder window instead of ours (2.0.631: "the set-diff caught 6492112, the birth token names 10032046").++Also measured and now doctrine: ab's `desktop_clear_window_attention` RAISES the window (z11 to z1, adom-bridge#199),+so no park path calls it; ab's `desktop_set_window_state bottom` does nothing; Chrome ACTIVATES the first window of a+fresh browser after pup's park, so a cold birth gets a re-assert schedule (40 ms to 2.5 s) that bottoms the window+unless the user has foregrounded it themselves.++**Superseded by this section:** the 2.0.614 consent gate for cold starts (removed in 2.0.617, John: "being asked even+that once is too much") and the "warn first" toasts as a substitute for a background open (John: "i hate all these ab+toasts... if you can truly figure out opening background pup windows, it generally solves the problem"). A toast is+for the moment pup NEEDS the user (a password), not an apology for a window it should never have raised.
dev-skills/pup-window-targeting/SKILL.md+11
@@ -132,3 +132,14 @@ the answer. If you think you need the wiggle, you need birth-time capture instea ## One-line summary Target windows by handle through `windowTarget()`, resolve the handle read-only (birth-time + persist, never resize), leave bare when unsure, and never, ever look a window up by its title again.+++## The birth token (2.0.630-2.0.634): how the ext lane gets the hwnd without geometry or set-diff++The worker creates every new window on `chrome-extension://…/birth.html?token=<random>`; `birth.js` sets+`document.title = "PUPBIRTH-" + token` (a FILE, because the extension CSP blocks inline scripts, which is why 2.0.630+and 2.0.631 bound the wrong window: the title never carried the token and the 3 s lookup timed out into the set-diff).+`extdrive::hwnd_by_birth_token` polls the lane's top-level windows every 25 ms for that title prefix, skips handles+already taken, and has no width filter. The set-diff stays as a fallback only; when both disagree the token wins and+the log says so ("the set-diff caught X, the birth token names Y; bound by token"). Never identify a window by its+size, position or a generic title.
tools/foreground-proof.shadded+73
@@ -0,0 +1,73 @@+#!/usr/bin/env bash+# The ship gate for "a pup window never lands in front of the user" (John, 2026-09-18: "if you can truly+# figure out opening background pup windows, it generally solves the problem").+#+#   tools/foreground-proof.sh <box> [pinHwnd]+#+# Pins a NON-pup window in front (the given hwnd, else the topmost non-Chrome normal window), forces a cold+# lane, then does what a sign-in does: cold open, navigate, navigate, warm open, warm open, navigate; the+# whole time it samples the top-of-screen window twice a second through ab (no console, no focus change).+# PASS = zero samples with a Chrome-for-Testing window on top. Any pup window on top, even one sample, FAILS.+# Never run it on the user's own desktop: it opens windows. winvm or the conference-room box.+set -u+BOX="${1:?usage: tools/foreground-proof.sh <box> [pinHwnd]}"; PIN="${2:-}"+AB="adom-bridge --target $BOX --ai-thread pup-foreground-proof"+S="${TMPDIR:-/tmp}/fgproof-$$"; mkdir -p "$S"+lw() { timeout 25 $AB desktop_list_windows '{}' 2>/dev/null; }+top() { lw | python3 -c "+import sys,json+d=json.load(sys.stdin); o=d.get('output',d)+if isinstance(o,str): o=json.loads(o)+w=(o.get('data') or o).get('windows') or []+t=[x for x in w if not x.get('minimized') and x.get('kind')=='normal']; t.sort(key=lambda x: x.get('z',999))+print(((t[0].get('image') or '?')+'|'+(t[0].get('title') or '')[:40]) if t else 'none')"; }+if [ -z "$PIN" ]; then PIN=$(lw | python3 -c "+import sys,json+d=json.load(sys.stdin); o=d.get('output',d)+if isinstance(o,str): o=json.loads(o)+w=(o.get('data') or o).get('windows') or []+t=[x for x in w if not x.get('minimized') and x.get('kind')=='normal' and x.get('image')!='chrome.exe']; t.sort(key=lambda x: x.get('z',999))+print(t[0].get('hwnd') if t else '')"); fi+[ -n "$PIN" ] || { echo "no non-pup window to pin on $BOX"; exit 2; }+echo "== pin window $PIN in front, force a cold lane =="+# every thread's windows, by name: the "everyone" close only clears the caller's own (measured), and a+# leftover window with the harness's name owned by another thread makes the open fail with not_your_window+for W in $(timeout 60 $AB pup_status '{}' 2>/dev/null | python3 -c "+import sys,json+try: print(' '.join(s.get('sessionId') for s in json.load(sys.stdin).get('sessions') or []))+except Exception: pass"); do timeout 60 $AB pup_close_window "{\"window\":\"$W\",\"takeover\":true,\"reason\":\"foreground proof: clear every pup window first\"}" >/dev/null 2>&1; done+cat > "$S/cold.ps1" <<'PS'+Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" | Where-Object { $_.CommandLine -match 'pup-profiles' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force -ErrorAction SilentlyContinue }+Start-Sleep -Seconds 2; "cold"+PS+ENC=$(iconv -f utf-8 -t utf-16le "$S/cold.ps1" | base64 -w0)+timeout 120 $AB shell_execute "{\"command\":\"powershell -NoProfile -EncodedCommand $ENC\",\"timeoutMs\":60000,\"reason\":\"foreground proof: force a cold pup browser\"}" >/dev/null 2>&1+timeout 60 $AB desktop_bring_to_front "{\"hwnd\":$PIN,\"reason\":\"foreground proof: pin a non-pup window in front\"}" >/dev/null 2>&1; sleep 2+echo "top before: $(top)"+(for i in $(seq 1 240); do echo "$(date +%H:%M:%S) $(top)"; sleep 0.5; done > "$S/samples" 2>&1) & SP=$!+mark() { echo "$(date +%H:%M:%S) ===== $*" >> "$S/marks"; }+FAILS=0+# a step must SUCCEED: a window that never opens trivially never surfaces, and that must not read as a pass+step() { local name="$1"; shift; mark "$name"; local r; r=$(timeout 250 $AB "$@" 2>&1); local ok; ok=$(echo "$r" | python3 -c "+import sys,json+try: d=json.load(sys.stdin); print('ok' if d.get('ok') is True else 'FAIL '+str(d.get('errorCode') or d.get('error') or '?')[:90])+except Exception: print('FAIL unparsable')"); case "$ok" in ok) ;; *) FAILS=$((FAILS+1)); mark "$name FAILED: $ok";; esac; }+sleep 1+step "cold open A"      pup_open_window '{"window":"fgp-a","url":"https://example.com/"}'+step "navigate A"       pup_navigate    '{"window":"fgp-a","url":"https://example.org/"}'+step "navigate A again" pup_navigate    '{"window":"fgp-a","url":"https://example.com/"}'+step "warm open B"      pup_open_window '{"window":"fgp-b","url":"https://example.org/"}'+step "warm open C"      pup_open_window '{"window":"fgp-c","url":"https://example.com/"}'+step "navigate C"       pup_navigate    '{"window":"fgp-c","url":"https://example.org/"}'+mark "done"; sleep 3; kill $SP 2>/dev/null; wait 2>/dev/null+BAD=$(grep -cE "^[0-9:]+ chrome\.exe\|" "$S/samples"); TOTAL=$(grep -c . "$S/samples")   # by PROCESS: a 40-char title can lose the "Chrome for Testing" suffix (2.0.632 missed a listing window on top for 28 s)+OPEN=$(timeout 60 $AB pup_my_windows '{}' 2>/dev/null | python3 -c "+import sys,json+try: print(json.load(sys.stdin).get('count') or 0)+except Exception: print(0)")+echo; echo "== top of screen, start to finish =="; sort -m "$S/samples" "$S/marks" | uniq -f1 -c+echo+echo "steps failed: $FAILS | pup windows open at the end: $OPEN (want 3)"+if [ "$FAILS" -ne 0 ] || [ "$OPEN" -lt 3 ]; then echo "FOREGROUND PROOF: INVALID ($FAILS step(s) failed, $OPEN of 3 windows open): nothing to measure"; timeout 90 $AB pup_close '{"all":true,"takeover":true}' >/dev/null 2>&1; exit 2; fi+timeout 90 $AB pup_close '{"all":true,"takeover":true}' >/dev/null 2>&1+if [ "$BAD" -eq 0 ]; then echo "FOREGROUND PROOF: PASS ($TOTAL samples, 3 windows opened and navigated, a pup window was never on top)"; exit 0; else echo "FOREGROUND PROOF: FAIL ($BAD of $TOTAL samples had a pup window on top)"; exit 1; fi