phase: 02_sharp_capture
Build and Push Containers / test (push) Successful in 46s
Build and Push Containers / build-and-push-app (push) Successful in 8s

**Phase 02 final verification pass — complete, 100% green.**

**Verified (all 4 tasks in `complete/02_sharp_capture/`):**
- Task 1: `pickSurface()` requests `screen × devicePixelRatio` (capped 3840×2160) instead of window size
- Task 2: `degradationPreference: "maintain-resolution"` + per-leg `maxBitrate`, re-applied after `setLocalDescription` *and* on `connected` (both call sites asserted in `test_app.py`)
- Task 3: default cap raised to 25 Mbit/s — `config.py` constant, `net.js` offline fallback, `.env.example`, README, and the drift-guard test all agree
- Task 4: realdisplay sharpness floor (viewer decoded width ≥ 1152px = 90% of Xvfb 1280px) in `test_sharp_picture_reaches_the_wall`

**Gates (all green):**
- `uv run ruff check . && uv run ruff format --check .` → clean
- `uv run pyright` → 0 errors
- `uv run pytest` → 231 passed, 3 skipped (realdisplay), coverage 95%
- `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → 3 passed on a real Xvfb + headed Chromium

**Completion criteria:** (1) 90% width floor asserted on viewer's decoded pixels — PASS · (2) `/api/config` `maxBitrateBps: 25000000` default, net.js fallback agrees — PASS · (3) `#stat-resolution` matches viewer-decoded size incl. documented window downscale (1100×620, 1280×720 fake-device tests) — PASS · (4) both suites green, aspect-ratio guard (`1280/800` ± 0.06 + `≠ 1280×720`) still distinguishes real from fake capture — PASS · (5) README Configuration documents `25000000` — PASS; `PLAN.md` §6 "default 12 Mbit/s" left untouched as instructed — **flag for the user to amend**.

**Docs:** README — fixed suite timing `~20s → ~50s` (measured 49s); all other claims verified (CLI flags, dev extra, config table, kiosk key table vs. `watch.js`/`share.js` routers, kiosk commands vs. `docs/kiosk-silverblue.md`). AGENTS.md — same stale timing fixed, nothing else stale (all referenced test names/files exist).

**Notable:** `docs/kiosk-silverblue.md` + its scripts use `mirror.reeselink.com` while README/SECURITY.md/Containerfile use `mirror.reeseapps.com` — a pre-existing cross-file mismatch I could not resolve from the repo (both in same-day commits; live-infra fact). Left untouched; user should confirm the live kiosk URL. No live changes made.

**Next pending phase:** `03_audio_share`.
This commit is contained in:
2026-11-01 21:41:28 -05:00
parent 1e816da5a8
commit 1da466a412
36 changed files with 938 additions and 26 deletions
@@ -0,0 +1,21 @@
**Phase 02 final verification pass — complete, 100% green.**
**Verified (all 4 tasks in `complete/02_sharp_capture/`):**
- Task 1: `pickSurface()` requests `screen × devicePixelRatio` (capped 3840×2160) instead of window size
- Task 2: `degradationPreference: "maintain-resolution"` + per-leg `maxBitrate`, re-applied after `setLocalDescription` *and* on `connected` (both call sites asserted in `test_app.py`)
- Task 3: default cap raised to 25 Mbit/s — `config.py` constant, `net.js` offline fallback, `.env.example`, README, and the drift-guard test all agree
- Task 4: realdisplay sharpness floor (viewer decoded width ≥ 1152px = 90% of Xvfb 1280px) in `test_sharp_picture_reaches_the_wall`
**Gates (all green):**
- `uv run ruff check . && uv run ruff format --check .` → clean
- `uv run pyright` → 0 errors
- `uv run pytest` → 231 passed, 3 skipped (realdisplay), coverage 95%
- `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → 3 passed on a real Xvfb + headed Chromium
**Completion criteria:** (1) 90% width floor asserted on viewer's decoded pixels — PASS · (2) `/api/config` `maxBitrateBps: 25000000` default, net.js fallback agrees — PASS · (3) `#stat-resolution` matches viewer-decoded size incl. documented window downscale (1100×620, 1280×720 fake-device tests) — PASS · (4) both suites green, aspect-ratio guard (`1280/800` ± 0.06 + `≠ 1280×720`) still distinguishes real from fake capture — PASS · (5) README Configuration documents `25000000` — PASS; `PLAN.md` §6 "default 12 Mbit/s" left untouched as instructed — **flag for the user to amend**.
**Docs:** README — fixed suite timing `~20s → ~50s` (measured 49s); all other claims verified (CLI flags, dev extra, config table, kiosk key table vs. `watch.js`/`share.js` routers, kiosk commands vs. `docs/kiosk-silverblue.md`). AGENTS.md — same stale timing fixed, nothing else stale (all referenced test names/files exist).
**Notable:** `docs/kiosk-silverblue.md` + its scripts use `mirror.reeselink.com` while README/SECURITY.md/Containerfile use `mirror.reeseapps.com` — a pre-existing cross-file mismatch I could not resolve from the repo (both in same-day commits; live-infra fact). Left untouched; user should confirm the live kiosk URL. No live changes made.
**Next pending phase:** `03_audio_share`.
@@ -0,0 +1,33 @@
........................................................sss............. [ 30%]
........................................................................ [ 61%]
........................................................................ [ 92%]
.................. [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/home/ducoterra/Projects/Personal/mirror/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.8-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------
src/mirror/__init__.py 3 0 100%
src/mirror/__main__.py 72 3 96% 129, 145, 156
src/mirror/access.py 60 0 100%
src/mirror/app.py 185 12 94% 108, 113, 116-117, 182-183, 212-216, 245
src/mirror/config.py 68 5 93% 110-111, 118-120
src/mirror/debug.py 15 10 33% 19-28
src/mirror/protocol.py 59 0 100%
src/mirror/registry.py 191 3 98% 166, 180, 355
------------------------------------------------------
TOTAL 653 33 95%
=========================== short test summary info ============================
SKIPPED [1] tests/e2e/test_x11_capture.py:249: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:289: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:332: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
231 passed, 3 skipped, 1 warning in 48.27s
All checks passed!
27 files already formatted
0 errors, 0 warnings, 0 informations
@@ -0,0 +1,17 @@
All four gates green. Final report:
**Implemented (task 01 — capture the screen's pixels, not the window's)**
- `share.js` `pickSurface()`: explicit `ideal` width/height = `screen × devicePixelRatio`, capped 3840×2160, one shared `video` object for both the audio and silent `getDisplayMedia` attempts (catch semantics unchanged); `contentHint = "detail"` untouched; kiosk-rule comment added
- Diagnostic toast once per share when delivered width < 75% of requested, with the PLAN §5 reason commented
- Tests: `test_share_never_asks_for_an_exact_capture_size` (regex guard in `TestClientScripts`), new E2E `test_the_screen_sized_request_does_not_break_the_fake_device`, `test_x11_capture.py` stale "no matter what" comment fixed
**Results**
- `node --check share.js` OK; `uv run ruff check . && uv run ruff format --check .` clean; `uv run pyright` 0 errors
- `uv run pytest` → 225 passed, 2 skipped (realdisplay-gated); `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` → 2 passed
- Measured (Xvfb 1280×800, window 1200×760): **requested 1200×760 → delivered 1200×750**, `displaySurface: monitor`. **Chromium still clamps the capture to the window** — please amend PLAN.md §5 accordingly (not edited, per task rules)
**Docs** — README "Development" and AGENTS.md §5 updated: fake-device stream is 1280×720 *by default*, clamped to the window when a size is requested (the E2E context now yields 1100×620, asserted as such)
**Deviations** — the task's "viewer still decodes 1280×720" premise holds only when no size is requested; the fake UI clamps named `ideal` sizes to the fake window, so the E2E asserts the viewer decodes exactly the sharer's delivered settings (window-clamped), moving, with `publish()` reporting delivered, not requested
**Next pending task** — `02_sharp_capture/02_sender_fidelity.md`
@@ -0,0 +1,32 @@
....................................................ss.................. [ 31%]
........................................................................ [ 63%]
........................................................................ [ 95%]
........... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/home/ducoterra/Projects/Personal/mirror/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.8-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------
src/mirror/__init__.py 3 0 100%
src/mirror/__main__.py 72 3 96% 129, 145, 156
src/mirror/access.py 60 0 100%
src/mirror/app.py 185 11 94% 108, 113, 117, 182-183, 212-216, 245
src/mirror/config.py 68 5 93% 110-111, 118-120
src/mirror/debug.py 15 10 33% 19-28
src/mirror/protocol.py 59 0 100%
src/mirror/registry.py 191 3 98% 166, 180, 355
------------------------------------------------------
TOTAL 653 32 95%
=========================== short test summary info ============================
SKIPPED [1] tests/e2e/test_x11_capture.py:221: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:258: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
225 passed, 2 skipped, 1 warning in 36.96s
All checks passed!
26 files already formatted
0 errors, 0 warnings, 0 informations
@@ -0,0 +1,22 @@
All gates green. Final verification of the complete gate sequence was done above. Done — here's the report:
**Task 02 — Tell the encoder to keep the pixels — complete**
**Implemented**
- `share.js`: `applySenderQuality(peer)` — finds the video sender, sets `degradationPreference: "maintain-resolution"`, `maxBitrate` from `config.maxBitrateBps` on first encoding only (skipped when 0, which means "uncapped" in the WebRTC API); named `NotAllowedError` catch (Firefox rejects `degradationPreference`), `typeof setParameters` guard
- Both `addTransceiver`/`addTrack` paths capture the returned sender into `peer.senders`; initial `sendEncodings` cap **kept** alongside the re-apply with a comment (it covers the pre-negotiation window the re-apply can't)
- Re-applied after `setLocalDescription` in `negotiate()` (never blocks the offer) and on `connectionState === "connected"`
- `window.__probe` test handle (the sanctioned global) exposing `peers` + `renegotiate()` for driving a real in-place renegotiation
- New `tests/e2e/test_sender_fidelity.py`: 2-viewer baseline (params read back per leg) + renegotiation survival test; new guard in `test_app.py::TestClientScripts` (single `"maintain-resolution"`, both call sites via regex)
**Gates**
- `uv run ruff check . && uv run ruff format --check .` — clean; `uv run pyright` — 0 errors
- `uv run pytest -m e2e` — 54 passed (incl. both new tests, real Chromium, config value read from `/api/config`); `uv run pytest -m "not e2e…"` — 174 passed, 95% coverage
- `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` — 2 passed
- Full `uv run pytest` — 228 passed, 2 skipped (realdisplay without env) — 100% green
**Docs** — no doc impact: no config/command/API change (default cap stays 12 Mbit/s; task 03 raises it); `AGENTS.md` states nothing now stale.
**Notable decisions** — `maxBitrate` only set when truthy (0 = uncapped, matches `addPeer`); immediate post-renegotiation read asserted because `renegotiate()` awaits the re-apply, so it proves the parameters return with the re-offer regardless of connection-state timing.
**Next pending task** — `02_sharp_capture/03_bitrate_default_and_surface.md` (raise default cap to 25 Mbit/s; server, `net.js` fallback, `.env.example`, README).
@@ -0,0 +1,32 @@
......................................................ss................ [ 31%]
........................................................................ [ 62%]
........................................................................ [ 93%]
.............. [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/home/ducoterra/Projects/Personal/mirror/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.8-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------
src/mirror/__init__.py 3 0 100%
src/mirror/__main__.py 72 3 96% 129, 145, 156
src/mirror/access.py 60 0 100%
src/mirror/app.py 185 12 94% 108, 113, 116-117, 182-183, 212-216, 245
src/mirror/config.py 68 5 93% 110-111, 118-120
src/mirror/debug.py 15 10 33% 19-28
src/mirror/protocol.py 59 0 100%
src/mirror/registry.py 191 3 98% 166, 180, 355
------------------------------------------------------
TOTAL 653 33 95%
=========================== short test summary info ============================
SKIPPED [1] tests/e2e/test_x11_capture.py:221: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:258: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
228 passed, 2 skipped, 1 warning in 40.94s
All checks passed!
27 files already formatted
0 errors, 0 warnings, 0 informations
@@ -0,0 +1,26 @@
**Task 03 complete — 100% green.**
**Implemented**
- `config.py`: `DEFAULT_MAX_BITRATE_BPS` 12_000_000 → 25_000_000 (flows to `client_config()` unchanged, no new field)
- `net.js`: `loadConfig()` offline fallback `maxBitrateBps` → 25000000
- `test_config.py::test_defaults` now pins `max_bitrate_bps == DEFAULT_MAX_BITRATE_BPS` (constant imported); `test_environment_wins` (override `250000`) left as-is
- New cross-file guard `TestClientScripts::test_server_and_client_agree_on_the_bitrate_default` — regex-extracts the `config.py` constant and the `net.js` literal, asserts they are equal (one number, two places, one test that notices)
- `test_config_advertises_the_media_defaults` untouched (fixture `2_000_000` — still passes, proving the value is honoured end-to-end)
**Gates**
- `uv run ruff check . && uv run ruff format --check .` — clean
- `uv run pyright` — 0 errors
- `uv run pytest` — 229 passed, 2 skipped (the realdisplay-gated pair), ~41s; coverage 95% overall, config.py 93% (only pre-existing `pragma: no cover` lines)
- `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` — 2 passed
- `uv run python -c "...Settings.from_env().max_bitrate_bps"` → `25000000`; live `curl /api/config` on bare serve → `maxBitrateBps: 25000000`; `grep "12000000\|12_000_000"` over `src/`, `.env.example`, `tests/` → nothing
**Docs**
- README.md: `MIRROR_MAX_BITRATE` row → `25000000` + one-sentence trade-off (Wi-Fi sharer with many viewers may need less, not more)
- `.env.example`: `25000000` + one-line comment (wired-LAN 1440p; lower for Wi-Fi)
- AGENTS.md: no change (it never stated the 12 Mbit figure — only PLAN.md §6 does)
**Decisions / notes**
- The stale `PLAN.md` §6 line ("default 12 Mbit/s") is **not** edited per protocol; the phase commit message should name it for the user to amend.
- Value is pinned via the constant + cross-file equality (as the task spec dictates), not as a magic number in a test.
**Next pending task:** `.agents/phases/todo/02_sharp_capture/04_sharpness_assertion_e2e.md`
@@ -0,0 +1,32 @@
......................................................ss................ [ 31%]
........................................................................ [ 62%]
........................................................................ [ 93%]
............... [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/home/ducoterra/Projects/Personal/mirror/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.8-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------
src/mirror/__init__.py 3 0 100%
src/mirror/__main__.py 72 3 96% 129, 145, 156
src/mirror/access.py 60 0 100%
src/mirror/app.py 185 11 94% 108, 113, 117, 182-183, 212-216, 245
src/mirror/config.py 68 5 93% 110-111, 118-120
src/mirror/debug.py 15 10 33% 19-28
src/mirror/protocol.py 59 0 100%
src/mirror/registry.py 191 3 98% 166, 180, 355
------------------------------------------------------
TOTAL 653 32 95%
=========================== short test summary info ============================
SKIPPED [1] tests/e2e/test_x11_capture.py:221: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:258: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
229 passed, 2 skipped, 1 warning in 40.85s
All checks passed!
27 files already formatted
0 errors, 0 warnings, 0 informations
@@ -0,0 +1,18 @@
All gates green. Final verification complete.
## Report
**Implemented**
- `tests/e2e/test_x11_capture.py`: `SHARP_FLOOR_PX = 1152` (90% of the 1280 Xvfb width); size floor added to the existing viewer probe (`test_a_real_desktop_reaches_a_second_machine_and_moves`); new `test_sharp_picture_reaches_the_wall` (matches `-k sharp`) asserting viewer-decoded width ≥ 1152, aspect guard + moving frames in the same probe, and `/api/streams` metadata within 1 px of both the sharer's `track.getSettings()` and the viewer's decoded size; module docstring now records the measured requested-vs-delivered table (1200×760 → 1200×750; 1024×700 → 1024×640 = 80%; 800×600 → 800×500 = 62.5%).
- `tests/e2e/test_live_mirror.py`: `test_the_fake_device_keeps_exactly_1280x720` (1280×820 sharer window → fake device delivers exactly 1280×720, viewer decodes exactly 1280×720, moving); `test_the_staged_tile_bytes_keep_growing` (inbound-rtp.bytesReceived on a staged tile, via a `window.__probe`-only init-script scaffold; observed ~126 KB / ~0.5 Mbit/s over ~2 s, recorded in the docstring, growth-only assertion).
**Gates** — `uv run ruff check . && uv run ruff format --check .` clean; `uv run pyright` 0 errors; `uv run pytest` 231 passed, 3 skipped (opt-in), coverage 95% (unchanged); `MIRROR_REALDISPLAY=1 uv run pytest -m realdisplay` 3 passed; `-m realdisplay -k sharp` 1 passed.
**Docs** — no doc impact (README's 25 Mbit/s default already done by task 03; AGENTS.md statements all still accurate).
**Notable findings (for the commit message / user)**
- Measured: Chromium **still clamps the monitor capture to the capturing window even with the explicit `ideal` size named** — agrees with PLAN §5. Under Playwright `screen` emulates the viewport, so the request can never outgrow the window here.
- Negative verification: with the size constraints removed, a 1200×760 window delivers the identical 1200×750 (93.75% of the desktop), so the 1152 floor passes on this host for both old and new code — it discriminates by *window* size here (a 1024 window lands at 80% and fails). On real hardware, where `screen` is the true display resolution, a small window on a large display is the discriminating case the floor and the share page's 75% toast guard.
- `PLAN.md` §6's "default 12 Mbit/s" is stale (since task 03) — flagged for the user; not edited per protocol.
**Next pending task** — none; this was the last task of phase 02.
@@ -0,0 +1,33 @@
........................................................sss............. [ 30%]
........................................................................ [ 61%]
........................................................................ [ 92%]
.................. [100%]
=============================== warnings summary ===============================
.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1
/home/ducoterra/Projects/Personal/mirror/.venv/lib64/python3.14/site-packages/fastapi/testclient.py:1: StarletteDeprecationWarning: Using `httpx` with `starlette.testclient` is deprecated; install `httpx2` instead.
from starlette.testclient import TestClient as TestClient # noqa
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================ tests coverage ================================
_______________ coverage: platform linux, python 3.14.8-final-0 ________________
Name Stmts Miss Cover Missing
------------------------------------------------------
src/mirror/__init__.py 3 0 100%
src/mirror/__main__.py 72 3 96% 129, 145, 156
src/mirror/access.py 60 0 100%
src/mirror/app.py 185 12 94% 108, 113, 116-117, 182-183, 212-216, 245
src/mirror/config.py 68 5 93% 110-111, 118-120
src/mirror/debug.py 15 10 33% 19-28
src/mirror/protocol.py 59 0 100%
src/mirror/registry.py 191 3 98% 166, 180, 355
------------------------------------------------------
TOTAL 653 33 95%
=========================== short test summary info ============================
SKIPPED [1] tests/e2e/test_x11_capture.py:249: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:289: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
SKIPPED [1] tests/e2e/test_x11_capture.py:332: set MIRROR_REALDISPLAY=1 to exercise the real X11 capture backend
231 passed, 3 skipped, 1 warning in 49.94s
All checks passed!
27 files already formatted
0 errors, 0 warnings, 0 informations