Files
Piik/docs/project-memory.md
T

16 KiB

Project Memory

Last updated: 2026-08-24

Current Product Truth

  • Build private, low-latency game screen sharing for one broadcaster and a small group of trusted friends. Public or large broadcasts belong on OBS/Twitch-class services.
  • A room supports one Host and up to 20 authenticated Viewers. Admission is independent of endpoint fanout and SFU capacity; the event-driven route controller must remain efficient at that bound without all-pairs probing.
  • Authenticated Hosts and shipped clients are trusted media participants in these private rooms; route authority, generation fencing, and server admission remain fail-closed.
  • Rooms use one bounded, process-memory model: a random free code from 1000..9999, default 24-hour configurable dormant lease, and no database or cross-restart recovery. Active sharing never expires; stop/disconnect starts the lease, the exact Host token may resume before expiry, Viewer activity does not renew it, and expiry releases the code. Process restart invalidates every room, token, invitation, password verifier, and participant.
  • Viewer grants and code entry are orthogonal. Every room has an expiring token-bearing invitation; code-only entry is open | password | disabled and defaults to open with no room password after site access. The Host browser locally retains its display name, code-entry policy, optional room password, and raw Host ownership token; the server keeps only current-process digests/verifiers and never uses IP, UA, device properties, or a fingerprint as identity. Recreating after restart reapplies local preferences but produces a new code, Host token, and grant.
  • Web is the current delivery target. The route release covers Browser Host, Viewer, and relay endpoints; packaged/native senders, capture helpers, shared-encode executables, and their acceptance runs are lowest-priority later work outside this milestone.
  • Keep routing automatic and media distributed. Direct/peer UDP is preferred; the dedicated LiveKit SFU/UDP path is the only application fallback and is not the default topology. Screener configures no TURN, ICE/TCP, media TCP, or TLS-relayed media path.
  • Every non-server endpoint uses one server-authoritative steady outbound media-copy capacity: default 2, statically configurable as 1, 2, or 3. A peer child or the Host publication consumes one slot; upstream receive is free, and SFU subscriber egress is accounted at the server. Browser role/UA/visibility does not create a separate tier, and clients cannot raise the deployment value.
  • The stable routing invariants are one authoritative upstream per Viewer, an acyclic source-reachable active graph, exact authenticated route attempts, endpoint and server admission, one room-serial child operation, and bounded success, wait, or failure.
  • One room controller reconciles allocation, child reparenting, and relay drain through the same operation. It finds one waiting Viewer or invalid edge and builds one deterministic tuple list. The operation owns its cursor, current candidate and reservations, fact version, plus one total deadline; only its current candidate may produce media. A screener-v9 prepare names that exact child, selected transport, and server-issued candidate connection ID. A usable old edge remains until the exact candidate child decodes its first new video frame. settleReady synchronously commits admission before graph promotion; success commits prepare revision P, while failure releases resources, broadcasts rollback R > P from one monotonic allocator, and advances the cursor without resetting the deadline. Exhaustion retires hard-invalid, departed-parent, or overflow edges into explicit waiting but retains a healthy bootstrap edge. Bounded-gap preflights server resources, replans the untried suffix after retirement, and appends one ordinary restore candidate when it cut healthy media. A relay with a bad ingress reparents itself as a child and retains its subtree. A disconnected endpoint, or one whose effective downstream capacity falls below its current child count, accepts no excess children; its direct or overflow children enter the same operation and a disconnected endpoint is removed when childless. Authoritative pause aborts the operation, suppresses decoded-progress stall decisions, and resumes from a fresh reconciliation.
  • One Host publication may serve all SFU subscriptions. Its exact generation owns one ingress handle and exact Viewer subscription handles own egress; later SFU children reuse the publication, while reserved, committed, and draining handles remain charged until the managed room is deleted and proven absent. Actual SFU usage release wakes only rooms that previously lost a candidate to global admission, and SFU-fed and peer-fed endpoints use the same provisional-child transaction. Parent choice hard-filters authority, reachability, cycles, effective capacity, and producer transition, then orders by shallowest result, remaining steady sender capacity, stable join order, and peer identity; server admission is checked at the current cursor. Acyclicity and room admission bound maximum depth; depth is observed but has no separate hard cap. Healthy committed edges remain sticky: the controller repairs waiting, invalid, departed-parent, and overflow children but does not periodically rebalance the graph. Raw IP, claimed NAT type, UA, geography, all-pairs probes, weighted scores, and periodic room rebalancing are not route inputs.
  • Ordinary peer ICE is STUN-only, and current LiveKit media is UDP-only. Credentials, room secrets, candidate details, and diagnostic data remain private and narrowly scoped. A future strict-firewall transport requires separate evidence and must remain inside LiveKit rather than becoming another Screener route candidate.
  • Browser peers use existing periodic WebRTC/LiveKit stats to maintain one exact-route decoded-progress timestamp. New frames or route/connection changes reset it; a non-paused deadline reports the edge once. Track availability, bitrate, FPS, resolution, freeze, RTT, jitter, loss, sender stats, and SFU layer describe only the current path: they remain framework or diagnostic inputs and cannot prove another parent would be better.
  • Browser capture requests available share audio by default on initial capture and source switch, with an explicit video-only warning when no audio track is returned. Its screen-audio control offers live-switchable 64/128/256 kbps sender ceilings and defaults to 128. The last-wins quality wire owns desired state; each endpoint serially applies and reads back current Host/relay/SFU audio senders, exposes local failures, and gives future senders the latest desired value. Opus remains fixed, and without an applied-ack wire the Host does not claim room-wide atomic convergence. These are configuration ceilings, not fidelity claims.
  • Video codec selection remains automatic | H.264 | VP8. Its first switching boundary is a generation-fenced renegotiation/republish transaction while sharing is explicitly paused. Preparation never resumes a user-paused share: it stops its deadline but retains the single room-serial codec owner as one bounded prepared record with no timer. The user's normal Resume atomically revalidates those exact bindings, allocates the next server-monotonic resume attempt, and starts one bounded resume/proof deadline. The server keeps authoritative pause until the Host enables its source and returns the exact attempt acknowledgement; only then does it broadcast Resume and issue proof requests. Authorization, source acknowledgement, proof request, and proof response echo that attempt, and Pause invalidates it before another Resume can allocate the next one. Proof failure first restores authoritative pause and immediately runs bounded rollback preparation; the resulting prepared rollback has no timer and waits for the user's next normal Resume before revalidation, a fresh resume attempt, proof, and source enable. Unpaused hot switching is later reuse of that transaction, not an independent mechanism.
  • Recommended quality remains exactly 1080p60, 1080p30, and 720p30, with the middle 1080p30 as the accepted default. 480p means only an advanced 854x480 resolution choice whose FPS and bitrate remain independently selected; it is not a fourth recommended profile.
  • Two distribution artifacts are accepted only after the current feature, NAT, and real-network ledger is complete. A public-server one-click deployment package installs the current application plus STUN/SFU and proxy components on a user-owned server. A Windows/macOS/Linux local package runs the Host, application server, and local state on the broadcaster's machine without source, Node, or any external Screener/network service; it keeps workable direct P2P but reports the reachability loss imposed by public ingress, TLS, gateway, NAT, or firewall limits rather than promising universal connectivity.
  • Current UI, presence, route labels, and diagnostics describe observed state only; they do not create route authority.
  • Before an explicit public-release decision, the private deployment and repository keep only the current product contract. Incompatible wire, configuration, parser, and API changes ship atomically; stale clients fail before authority, replaced compatibility surfaces are deleted, and Git history owns rollback.
  • Viewer presentation remains on the stage until current-generation frame presentation is proven, distinguishes access/Host/queue, peer, SFU, media, autoplay, recovery, and typed failure phases, and keeps Play specific to autoplay rejection. A failed Viewer can export its privacy-safe stage/revision/code even before connection metrics exist; an authenticated Host may request one current route/timing snapshot only when downloading diagnostics. Route decisions, queue timing, and current-path quality are diagnostic only. Browser ICE decides direct reachability; Screener does not predict ports, classify NATs, probe TCP, synthesize remote candidates, or reparent a healthy edge for speculative quality gain.

Current Source And Production

  • Production runs Browser runtime 39fcf93bae057fcbb1002702c3be6b90bac9027f, release 39fcf93, on screener-v9. Canonical root main contains that runtime plus the docs-only postflight truth; auxiliary branches and older worktrees do not supersede it.
  • Integrated source and production admit up to 20 Viewers and implement the uniform 1/2/3 endpoint cap, exact prepare candidate, first-decoded-frame commit, strict rollback revision, decoded-progress stall, a two-stage direct/SFU operation deadline, and one event-driven room controller. A short-lived exact-generation decoded-frame observer proves only the pending candidate inside the existing total deadline; the periodic stats sampler remains responsible for active-path diagnostics and stalls. Ordinary peer ICE is STUN-only and the sole application fallback is SFU/UDP; stale TURN environment keys fail startup. SFU admission uses exact publication and Viewer-subscription handles with explicit no-default ingress/egress capacities and a listener-fenced dedicated LiveKit owner.
  • Integrated source and production use the memory-resident room model: random free four-digit codes, the configurable dormant lease, exact-Host resume, restart loss, local creation-preference replay, orthogonal Viewer grants and open | password | disabled code entry, and direct invitation/policy controls. SQLite room persistence, ROOM_DATABASE_PATH, ROOM_TTL_SECONDS, and a writable room StateDirectory are absent from the current runtime.
  • Production runs from /opt/screener/releases/39fcf93. Its immutable runtime ZIP SHA-256 is 28190c3a69ec937d39ab5d49fdbc8db6a07e6013c2ddd5f5590bf8249bf6bce6; /opt/screener/backups/39fcf93-pre-v9-20260824T004257Z is the verified rollback boundary and its SHA256SUMS hash is 1f741f29022f5eb1eb311a24f87f5f48598dca7b1879b88f9033c331fa06bd37.
  • Production implements live 64/128/256 kbps audio-ceiling mutation; generation-fenced paused codec prepare, Resume source acknowledgement, decoded-progress proof, and rollback; typed first-frame Viewer presentation and privacy-safe on-demand route diagnostics; neutral room-code denial and responsive entry controls; exactly three recommended profiles with 1080p30 as default and advanced-only 854x480; and no parent-edge quality-proof wire.
  • Browser SFU subscribers reconcile eligible Host screen publications across connect/activate event ordering, participant/track arrival, and reconnect. Production LiveKit logs only warn/error, and the application service has a bounded same-host LiveKit readiness preflight.
  • Exact runtime source d543f38aacad3df5ef65fde1055cc8e733972afe, integrated without runtime changes by main 39fcf93bae057fcbb1002702c3be6b90bac9027f, passed 670 Web tests in 48 files, TypeScript typecheck, client/server production builds, the access/privacy gate, production-dependency audit, and repository hygiene. Its one-Host/20-Viewer Chrome loopback decoded every Viewer and kept endpoint fanout within cap 2, but used direct local peer routes and observed no SFU publication; it is not public-network, SFU, mobile, audio-quality, codec-switch, H.264 performance, or background-lifecycle evidence.
  • Postflight found screener, LiveKit, coturn, and nginx active with NRestarts=0; local and public / and /healthz return 200, every served client file matches the immutable release, the public Browser bundle contains screener-v9 and no screener-v8, the release shares no regular-file inode with its rollback predecessor, and the accepted socket/firewall boundary is intact. No current v9 media room was created, so deployment evidence is not route or physical-media acceptance. Detail is owned by deployment and verification status.
  • Chrome loopback, cap2/cap3, short resource, recovery, MBB, and A/V fixtures are bounded evidence only. They do not establish quality, resource limits, or product policy.

Current Priority

  1. Close the current evidence ledger with physical codec and live-audio validation, controlled H.264 and Host-background diagnosis, and representative direct/peer-relay/SFU network runs. Browser loopback, state-machine gates, and deployment health do not substitute for those paths.
  2. Run the mobile lifecycle matrix and later mechanism-simplification audit only at their stated boundaries; Native/executable and distribution work remain later product phases.

Working Rules

  • Discussion and evidence are inputs, not executable TODOs. Accepted semantics are written to their owners before implementation.
  • Prefer standards and mature framework behavior, then one general reconciliation mechanism. Repair an invariant before adding a case branch; a specialized gate, probe, timer, state container, or test requires evidence that the general mechanism cannot cover the failure.
  • Current documents state the current model directly. Rejected alternatives and removal narratives are deleted; Git history owns them.
  • Old branches may contribute scoped code or evidence only after reconciliation. Their memory, requirements, ADRs, status, and deployment snapshots never overwrite newer mainline truth.
  • Preserve dirty, unique, open-stack, and evidence worktrees until their disposition is explicitly decided. Workspace counts are sampled on demand rather than stored here.

Source Map