One image (gitea.reeseapps.com/experimental/mirror), tagged :main on main and
a version tag on release, exactly like brain-of-reese — plus a `test` job the
publish job `needs`. A red pipeline therefore leaves :main on the last good
build, which is what podman auto-update keeps serving: red means nothing
shipped, not that production broke.
The test job runs unit + API only and --ignores tests/e2e rather than
deselecting it: -m filtering happens after collection, and tests/e2e/conftest.py
imports playwright, so a marker alone would not keep the browser suite out of a
container that has no browser. The e2e and realdisplay rungs stay local gates
(AGENTS.md), and pyright is not in CI either, since the python container has no
node to run it with — that asymmetry is written down rather than pretended
away.
The image sheds curl and its HEALTHCHECK: health belongs to the deployment
(HealthCmd in the quadlet, which probes with the python already in the image),
so the runtime image no longer ships a package that exists only to answer
/healthz — and no longer contains a way to make outbound requests, which is
consistent with a server that dials nothing. 171 MB to 157 MB. The image
source label points at the real repo now instead of example.invalid.
Verified locally with podman 5.8: the image builds, `mirror --help` exits 0,
and it serves on 8080 when MIRROR_PORT says 8080.
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
130 tests, ~20s, 94% coverage. Four rungs, each proving something the one
below it cannot:
registry admission, fan-out, signal authorization and teardown, no I/O
wire camelCase round-trip, malformed frames, WebSocket lifecycle
e2e real capture -> encode -> SRTP -> decode -> painted frames
realdisplay the actual X11 capture backend on a private Xvfb display
The e2e rung drives Chromium's fake media device, which produces a genuine
moving 1280x720 monitor stream, so the assertion is that a watcher's <video>
has a size and that its pixels change over time -- a frozen or never-started
peer connection fails the suite, which a "signal arrived" assertion would
not have caught.
Findings encoded as flags and comments, because each cost a debugging cycle:
the headless shell has no media stack at all (use channel="chromium");
mediaDevices is undefined off a secure context (serve over 127.0.0.1); and
--use-fake-ui-for-media-stream breaks real X11 capture by approving the
request without ever selecting a source, so the realdisplay suite selects
the source explicitly instead.
The realdisplay fixture strips WAYLAND_DISPLAY and DBUS_SESSION_BUS_ADDRESS
from the browser environment. Without that, a headed Chromium reaches
xdg-desktop-portal, mirrors the developer's actual desktop and raises a
permission dialog on their real screen -- which is exactly what happened
before this was isolated. Skipped unless MIRROR_REALDISPLAY=1.
Also guards the frontend's structure: scripts must parse as ES modules,
every id a script looks up must exist in its page, ids must not collide
across pages that share one stylesheet, and nothing may load from a CDN.
LLM-Generated: true
A FastAPI server with two pages and one WebSocket. /mirror captures a
window, screen or tab through the OS-native getDisplayMedia picker; /watch
shows every live mirror as a wall and takes one fullscreen on click. Any
number of sharers and watchers, at the same time.
Media never touches the server: each watcher gets its own RTCPeerConnection
to the sharer, and the Python process only relays JSON. The roster lives in
registry.py, which is transport-free by design -- every operation returns
the envelopes to deliver, so admission, fan-out and teardown policy are all
unit-testable without a socket.
Registry rules worth stating: a signal frame is relayed only along an
existing subscription in either direction; viewer-to-peer traffic is
refused; and teardown is broadcast to every viewer rather than only the
subscribers, because a tile is drawn on stream_added and a viewer that has
not yet subscribed still has a stale tile to clear.
Frontend is hand-written ES modules with no build step and no external
asset. Chromium scales a monitor capture to the capturing window and
requires a secure context, so /mirror detects an insecure origin and prints
the three ways out rather than failing on a button click.
LLM-Generated: true