# P1 — exact human ↔ agent handoff continuity (Phase-0 proof harness)

**These are Phase-0 PROOF HARNESSES, not shipped code.** Nothing here is imported by
`matrx_scraper`, wired into any host, or intended to run in production. They exist to settle
one question with an experiment instead of an assumption, and to be re-runnable by the next
agent who doubts the answer.

Program: `common-docs/projects/persistent-cloud-browser/` (WS-0, proof P1).
Findings and verdicts: `common-docs/projects/persistent-cloud-browser/reports/WS-0-proofs.md`.

## The claim under test

From `PLAN.md` §"Persistent context", §"Headed and automated modes", §"Exact human ↔ agent
handoff":

> An agent drives a **headed** Chromium persistent context on a virtual display. A human then
> interacts with that **same running browser** through input injected into the display. Afterwards
> Playwright **continues in the same process, same context, same page objects**, sees the human's
> changes — including a tab the human opened — and no relaunch happens.

Plus the negative the plan relies on: **a second Chromium cannot open the same `user_data_dir`.**

## What is real here and what is a stand-in

| Production | Here | Same thing? |
|---|---|---|
| Headed Chromium persistent context on Xvfb | identical | yes |
| Human input reaching the browser via Selkies → XTEST | `xdotool` → XTEST | **yes, same injection mechanism** |
| WebRTC transport, encoder, TURN, auth gateway | not exercised | **no — out of scope, see limits** |
| A real provider's login/CAPTCHA | local synthetic provider | no, deliberately (never probe real providers) |

The synthetic provider's login is gated on **input provenance** (keystroke count, inter-key delay
variety, pointer-move count, distinct pointer positions). This exists only so that "the human did
this, not the agent" is an *observable fact*: `page.fill()` + `page.click()` produce 0 keydowns and
a single pointer jump and are refused, while display-injected input clears the floors easily. It is
**not** a bot detector and must never be cited as one — Playwright could clear it with
`keyboard.type(delay=…)` and stepped `mouse.move()`.

The harness reads element bounding boxes with Playwright before injecting clicks. That is the rig
standing in for a human's eyes; it produces no input events. All input in the human phase comes
from `xdotool`.

## Layout

```
testapp/server.py      synthetic provider (stdlib http.server, 127.0.0.1 only, no external network)
harness/run_p1.py      the experiment: 8 phases, writes artifacts/p1_results.json
harness/second_launch.py  negative control: second Chromium on a live user_data_dir
artifacts/             results JSON, run logs, screenshots (committed as evidence)
```

## Re-running it

Requirements: `Xvfb`, `xdotool`, Python `playwright` whose bundled Chromium is present.

```bash
# one-time, if missing
apt-get install -y --no-install-recommends xdotool xvfb
pip3 install 'playwright==1.56.0'          # 1.56.x pairs with chromium build 1194
export PLAYWRIGHT_BROWSERS_PATH=/opt/pw-browsers   # or run: python3 -m playwright install chromium

cd packages/matrx-scraper/proofs/cloud_browser/p1_handoff_continuity
python3 -u harness/run_p1.py               # ~20s; prints a verdict table
python3 -u harness/run_p1.py --keep        # leave Xvfb + app running to poke at
```

Env overrides: `P1_DISPLAY` (default `:91`). The profile is recreated at
`/tmp/p1_handoff_continuity/profile` on every run — the harness deletes it first, so a run never
inherits the previous run's cookies.

Exit code is 0 whether sub-claims pass or fail; **read the verdict table and
`artifacts/p1_results.json`**, not the exit code. A failed sub-claim is a successful outcome of
this work.

## Phases

1. launch headed persistent context, capture the browser PID **and its kernel start-time**
2. agent attempts login the automated way → expect refusal (the control)
3. human phase: `xdotool` focus → calibrate screen↔viewport offset from a real injected
   mousemove → pointer path → click → type → submit
4. continuity: same process? human's cookie/localStorage visible? original `page` still usable?
5. human opens a tab (`target=_blank` clicked via XTEST) → does it appear in `context.pages` and
   can Playwright read *and mutate* it?
6. page-pointer behaviour when the human switches (`ctrl+Tab`) and closes (`ctrl+w`) a tab
7. agent resumes: new page in the same context, still authenticated, still the same process
8. negative control: second Chromium on the same `user_data_dir`

## What this proof does NOT establish

Do not cite it for any of these; they belong to P2/P4/P5/P6:

- WebRTC/Selkies encoding, transport, TURN, latency, or bandwidth
- the streaming gateway's authentication and per-viewer authorization
- multi-host locking (a second machine reaching the same profile) — only single-host
  `SingletonLock` is exercised here
- stale-lock recovery after an unclean kill
- profile encryption, checkpoint/restore, or storage durability (that is P3)
- anything about real providers, real accounts, or real anti-bot systems
