The Share button on /mirror is unclickable below ~700px and below the
fold in short windows. Measured with elementFromPoint on Chromium:
320x568 stage 288x180 button 187px past the stage bottom hit=H2
390x844 stage 358x224 button 113px past hit=LABEL
480x800 stage 448x280 button 36px past hit=#share-link
900x480 stage 868x543 inside the stage, below the viewport hit=null
Root cause: .stage is display:grid with place-items:center, so <video>,
.placeholder and .livetag occupy three stacked rows rather than one
overlay cell. An idle <video> is intrinsically 300x150, so the
placeholder always starts at stage.top + 151 and runs out of the
overflow:hidden box; aspect-ratio 16/10 with no min/max height then
clips it when narrow and overshoots the viewport when short.
#stop measures clickable everywhere (the placeholder is hidden when
live), so the fix is scoped to the idle stage.
Phase: one-cell stage, floor + ceiling + scroll escape, a 12-viewport
clickability sweep (idle and live), and stylesheet guards.
LLM-Generated: true
Convert the three open TODO items into .agents/phases/todo/ directories
(Protocol B append — PLAN.md, AGENTS.md and existing phases untouched, so
PLAN.md's roadmap table does not list these phases):
- 01_keyboard_kiosk_control (TODO.md:3) — mouse-free /watch and /mirror:
key router, j/k/Enter/f/g/n/p/1-9/m/?, focus-visible controls, help overlay.
- 02_sharp_capture (TODO.md:4) — capture screen pixels instead of window
pixels, maintain-resolution per leg, 12 -> 25 Mbit/s default cap,
real-desktop size assertion on the viewer.
- 03_audio_share (TODO.md:5) — one accumulating MediaStream per tile (the
ontrack overwrite dropped the first track), staged-only unmute policy,
honest audio states on /mirror, viewer-side inbound-audio assertion.
Every task cites its TODO source line. Locked with the user: 25 Mbit/s
default, only the staged mirror can be audible, full key map.
Note for the user: PLAN.md section 6 still says the per-leg cap defaults to
12 Mbit/s; phase 02 task 03 changes that and this commit does not edit PLAN.md.
LLM-Generated: true
The internal deployment exists (deployments repo, `mirror/`: quadlet, nginx
edge, certbot, route53, VM SOP), so the docs that said "the real fix is HTTPS"
were describing a future that has arrived from a different direction — TLS
terminates in nginx on the service VM, not in this process, and there is no
`--https` flag here.
SECURITY.md's trust model said "trusted: anyone who can open a TCP connection".
With an allow list in production that sentence was simply no longer true, so the
table now names the address space, and a new section says what the list is and
what it is not: one wall (network/nginx) and one belt (the app, for the path
that bypasses nginx at 127.0.0.1:8080), plus the thing neither can do — once two
browsers are in the room their media never asks the server again, and it can
never tell you *who*, only *where from*. Saying "defence in depth" about that
would have been the dishonest version.
PLAN.md gains A19 (TLS + admission in production, LOCKED) and A18 becomes
deprioritised rather than deleted — standalone `mirror serve --https` is still
worth having for offline/ad-hoc use, it just stopped being the thing blocking
cross-device sharing, and candidate phase 1 is now share-page resilience.
AGENTS.md gains the two rules most likely to be broken by a well-meaning edit:
trust XFF only from a trusted proxy, and change the nginx and app lists in the
same commit.
LLM-Generated: true
PLAN.md locks the architectural decisions (WebRTC mesh with the sharer as
sole offerer, JSON-only signaling, in-memory roster with no database, no
auth, no CDN, Linux as the reference platform) and records the roster rules,
the verification ladder, and the constraints that are accepted rather than
hidden: the secure-context requirement, mesh upload scaling with watcher
count, and the Wayland portal's per-share prompt.
Phases are deliberately not written yet -- the prototype and its tests came
first, so .agents/phases/todo/ holds only a README pointing at the candidate
phase list in PLAN.md section 7.
SECURITY.md answers the question a no-auth tool has to answer: not "who is
allowed in" but "where is this allowed to run". It separates what an
unauthenticated LAN visitor can do from the guarantees that are enforced and
named to a test, and tells users the two things they will actually hit --
that http://<lan-ip> hides getDisplayMedia, and that on Wayland the
compositor asks every time and mirror must not work around it.
LLM-Generated: true