#128 landed multi-viewer, but several surfaces still described the model it replaced -- and the most prominent ones were the public site. goq.sh claimed "one-to-one" in its title, meta description, and hero, carried a feature card reading "One host, one client / A single active client, enforced", and listed "One to many viewers" under hardening-next with the line "Today a session admits exactly one client, enforced ... Not built yet." That last claim became false the moment #128 merged. The roadmap item now folds into the intro as landed, matching how issue 7 was handled, and the remaining cards are the three steps genuinely still ahead. docs/multi-viewer-relay-design.md called the whole attachment sequence "future" when its first two steps carry every direct attachment shipping today; only the relay hop is unbuilt. Step 1 now also records that the accepted hello states the authorization revision its capability was minted against. AGENTS.md listed the loopback-covered behaviours without the multi-viewer ones, and described verify-demo-build.sh without the focus-handoff proof it now runs. docs/public-alpha-uat.md documents the handoff proof as preflight, and says plainly that neutral_before_successor proves ordering, not latency, so it cannot be mistaken for the physical p95 gate. Verified: website_static_gate=ok, 29/29 shell tests.
- commit
- 5fc8b5fb4f2d15e998c2fac85e859bd09c8a1aea
- parent
- 4633e0357f88d47bfe498d983e098ee0776f1d7a
- author
- Dami <dami.etoile@gmail.com>
| M | AGENTS.md | 11 | ++++++++--- |
| M | docs/ | 5 | +++-- |
| M | docs/ | 25 | +++++++++++++++++++++++++ |
| M | website/ | 19 | +++++++------------ |
@@ -85,7 +85,11 @@ Sigil host.
8585 keyboard, and gamepad state when a session ends.8686 - Relative pointer movement, scroll, keyboard, virtual gamepad reports, Opus8787 audio, reconnects, and second-client rejection have focused and loopback88- coverage. Hardware acceptance that remains incomplete is listed below.88+ coverage. So does the multi-viewer path: bounded admission, one shared89+ generation, slot-0 focus handoff with the former holder neutralized before a90+ successor is granted, same-peer replacement, slow-viewer isolation, and91+ admission against a configured host at real enrollment revisions. Hardware92+ acceptance that remains incomplete is listed below.8993 - Portal preserves the user's native window geometry across sessions and9094 relaunches. The stream surface scales and letterboxes within those bounds so9195 larger or differently shaped client windows never stretch the host image.@@ -195,8 +199,9 @@ Sigil host.
195199 selected GstVA encoder plugin; never treat build headers as runtime payload.196200 - Run `./scripts/verify-demo-build.sh` for the complete repository gate. It197201 covers Rust format/tests/clippy, the Linux cross-build when available,198- frontend syntax/tests, ShellCheck, package tests, loopback transport, and199- release-profile containment of `--dev-connect`.202+ frontend syntax/tests, ShellCheck, package tests, loopback transport203+ including three-viewer admission and slot-0 focus handoff, legacy204+ second-client rejection, and release-profile containment of `--dev-connect`.200205 - Run `./scripts/verify-website.sh` for every website or public installer201206 change. Exercise interactive website changes in a real browser.202207 - Treat `docs/fresh-bazzite-host.md`, `docs/public-release-delivery.md`, and@@ -45,9 +45,10 @@ A shared-MAC contingency may be evaluated only if an exact Bazzite host or suppo
4545 4646 Sigil and every Portal retain normal Iroh endpoints. Iroh owns endpoint identity, encryption, direct-path discovery, NAT traversal, and relay fallback. A media relay is another authenticated Iroh delivery hop; it does not become Sigil and does not receive input or administration authority.4747 48-The future attachment sequence is:48+Steps 1 and 2 ship today and carry every direct multi-viewer attachment. Steps49+3 through 5 are the relay extension and are not built.4950 50-1. Sigil admits Portal B over control v2 and issues a short-lived subscription capability for B's exact Iroh endpoint, media generation, authorization revision, tracks, expiry, nonce, and one relay hop.51+1. Sigil admits Portal B over control v2 and issues a short-lived subscription capability for B's exact Iroh endpoint, media generation, authorization revision, tracks, expiry, nonce, and one relay hop. The accepted hello also states the authorization revision the capability was minted against, because a viewer cannot know its own enrollment revision; a hello whose capability disagrees with that advertisement is rejected before use.5152 2. Sigil's catalog certifies the generation key and media authentication format.5253 3. Sigil or a selected Portal A advertises an alternate publisher for a bounded group range. A production descriptor must identify the publisher endpoint, generation, track, group range, expiry, and host signature; raw peer identities must not enter the shared roster UI.5354 4. Portal B connects to Portal A through Iroh and presents the capability. Portal A verifies the host signature and compares the authenticated downstream `remote_id()` with the capability subscriber.@@ -342,6 +342,31 @@ bounded_queues=ok
342342 final_cleanup=ok343343 ```344344 345+Slot-0 handoff has its own proof. It is the only preflight that exercises the346+transfer itself, so run it alongside the record above when the physical gate347+will measure handoff latency:348+349+```bash350+./scripts/loopback-proof.sh --profile release --control-v2 --viewers 3 \351+ --focus-handoffs 3 --assert-neutral-before-successor \352+ --primary-frames 600 --reconnect-cycles 3 \353+ | sed '/^node_id=/d' \354+ >> /absolute/path/to/loopback-preflight.evidence355+```356+357+Its normalized record requires:358+359+```text360+loopback_proof=ok361+focus_handoffs=3362+slot_0_single_holder=ok363+neutral_before_successor=ok364+final_cleanup=ok365+```366+367+`neutral_before_successor=ok` proves ordering only, not latency. The p95368+handoff budget above is still a physical-gate measurement.369+345370 The harness ingests the output by value and never mutates the Bazzite host.346371 347372 ## 5. Verify and retain@@ -3,8 +3,8 @@
33 <head>44 <meta charset="utf-8" />55 <meta name="viewport" content="width=device-width, initial-scale=1" />6- <title>goq.sh: one-to-one SteamOS streaming over iroh</title>7- <meta name="description" content="goq.sh pairs Portal, a native client, with Sigil, a headless Gamescope host, for games over QUIC. One-to-one, low-latency SteamOS streaming over iroh. Your key is the address." />6+ <title>goq.sh: low-latency SteamOS streaming over iroh</title>7+ <meta name="description" content="goq.sh pairs Portal, a native client, with Sigil, a headless Gamescope host, for games over QUIC. Low-latency SteamOS streaming over iroh, a few viewers and one controller. Your key is the address." />88 <link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1024 1024' shape-rendering='crispEdges'%3E%3Crect x='100' y='100' width='824' height='824' rx='185' fill='%23ece3d2'/%3E%3Cg transform='translate(224,356) scale(44)' fill='%232b2119' fill-opacity='0.18'%3E%3Crect width='6' height='8'/%3E%3Crect x='6' y='3' width='8' height='2'/%3E%3Crect x='9' y='5' width='2' height='2'/%3E%3Crect x='12' y='5' width='2' height='3'/%3E%3C/g%3E%3Cg transform='translate(204,336) scale(44)'%3E%3Crect width='6' height='8' fill='%23b5623b'/%3E%3Crect x='2' y='3' width='2' height='2' fill='%23ece3d2'/%3E%3Crect x='6' y='3' width='8' height='2' fill='%23c98a3a'/%3E%3Crect x='9' y='5' width='2' height='2' fill='%236b7145'/%3E%3Crect x='12' y='5' width='2' height='3' fill='%236b7145'/%3E%3C/g%3E%3C/svg%3E" />99 <link rel="stylesheet" href="./styles.css" />1010 </head>@@ -91,7 +91,7 @@
9191 <p class="release-note">non-root Bazzite setup · signed release channel pending</p>9292 </div>9393 </div>94- <p class="hero-note">Games over QUIC: one-to-one SteamOS streaming over iroh <br> Work in progress. Not a finished product.</p>94+ <p class="hero-note">Games over QUIC: low-latency SteamOS streaming over iroh <br> Work in progress. Not a finished product.</p>9595 </div>9696 </section>9797 </div>@@ -123,8 +123,8 @@
123123 <p>Frame handoff capped at four, decode queue at two, every buffer bounded. Stale frames are dropped, not queued, so latency never drifts.</p>124124 </li>125125 <li class="feature reveal">126- <h3>One host, one client</h3>127- <p>A single active client, enforced, over an end-to-end encrypted iroh link, relay-assisted when a direct path isn't possible. No third-party streaming service.</p>126+ <h3>One host, a few viewers</h3>127+ <p>Three viewers by default, eight at most, sharing one encoded stream over end-to-end encrypted iroh links, relay-assisted when a direct path isn't possible. Exactly one holds the controller. No third-party streaming service.</p>128128 </li>129129 </ol>130130 </section>@@ -133,7 +133,7 @@
133133 <section class="roadmap" id="roadmap">134134 <div class="section-rule" aria-hidden="true"></div>135135 <h2 class="section-title"><span aria-hidden="true">##</span> hardening next</h2>136- <p class="roadmap-intro">The first target stays deliberately narrow: hardware H.264 at 1280×800/60. <a href="https://github.com/FelineStateMachine/goq/issues/7" rel="noopener">Bounded Iroh/MoQ media objects</a> have landed: video now rides prioritized, cancellable groups with explicit GOP boundaries and keyframe recovery, and the legacy media tiers and JPEG fallback are gone. These are the promoted steps still ahead.</p>136+ <p class="roadmap-intro">The first target stays deliberately narrow: hardware H.264 at 1280×800/60. <a href="https://github.com/FelineStateMachine/goq/issues/7" rel="noopener">Bounded Iroh/MoQ media objects</a> have landed: video now rides prioritized, cancellable groups with explicit GOP boundaries and keyframe recovery, and the legacy media tiers and JPEG fallback are gone. <a href="https://github.com/FelineStateMachine/goq/issues/74" rel="noopener">One to many viewers</a> has landed as well: one encoded generation now serves up to eight authenticated viewers with a single transferable slot-0 input focus and per-peer revocation, while legacy clients stay strictly exclusive. These are the promoted steps still ahead.</p>137137 <ol class="roadmap-grid">138138 <li class="roadmap-item reveal">139139 <span class="roadmap-status">promoted · control</span>@@ -150,11 +150,6 @@
150150 <h3><a href="https://github.com/FelineStateMachine/goq/issues/10" rel="noopener">Auto Codec</a></h3>151151 <p>Select from end-to-end hardware support and measured latency. H.264 remains the safe baseline; compression ratio alone never wins.</p>152152 </li>153- <li class="roadmap-item reveal">154- <span class="roadmap-status">planned · sessions</span>155- <h3><a href="https://github.com/FelineStateMachine/goq/issues/74" rel="noopener">One to many viewers</a></h3>156- <p>Today a session admits exactly one client, enforced. The planned pivot adds N viewers with a single transferable input focus, per-peer revocation, and media fan-out over MoQ groups. Not built yet.</p>157- </li>158153 </ol>159154 </section>160155 @@ -203,7 +198,7 @@
203198 204199 <ul class="dg-notes">205200 <li>Paired by your <strong>FIDO2 security key</strong>: same key, same address. No passwords, no accounts.</li>206- <li><strong>One host, one client</strong>. Media and input ride separate end-to-end encrypted iroh connections.</li>201+ <li><strong>One host, up to eight viewers</strong>. Media and input ride separate end-to-end encrypted iroh connections, and only the focus holder's input reaches the host.</li>207202 <li><strong>Every queue bounded</strong>. Stale frames are dropped, not queued, so it never drifts behind.</li>208203 </ul>209204 </section>