2 Commits
Author SHA1 Message Date
ducoterra 24cb10ee5c ci: publish the image, but only past the test suite
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
2026-11-01 17:46:58 -05:00
ducoterra 555fc1c3b4 feat: browser-only screen mirroring prototype
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
2026-11-01 16:54:03 -05:00