open-standards/.github/workflows/joule-moq-web.yml
Transaction Science 1739817397 Merge B1 #413 (the browser sink and contentBinding) into train/live-room
By meaning:
- Page: app.js keeps the age parameters and paragraph and adds debug=binding;
  imports, state and roomTest hooks of age, co and binding side by side.
  index.html carries the co section and the binding table, each with its CSS.
- room.e2e.mjs carries scenarioBinding whole beside scenarioAge and
  scenarioCo; default list `...,age,co` with a room, `binding` always;
  run.sh's node unit tests are every page module's (capsule, media,
  presentation, privacy-pass, binding).
- wai-live-web: the wai dependency takes co_performance and browser_sink;
  the crate doc lists both.
- joule-moq-web README: one node-test bullet for capsule, media and binding,
  then privacy-pass and ad-presentation; scenarios age, co and binding.
- REGISTRY prose names exploration and browser-sink together; the shared
  lists keep both sides; export regenerated.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-22 03:45:27 -04:00

179 lines
9.7 KiB
YAML

name: joule-moq-web browser client
# The browser MoQ client (joule-code/joule-code-rs/crates/joule-moq-web) against
# joule-moq-relay on loopback, in the host's installed browser, driven by the automation
# package of e2e/package.json, with a fake camera and microphone
# (crates/joule-moq-web/e2e/run.sh):
#
# compose live-conformance/compose in the page: every layout, mix, descriptor and
# composition case through wai-live-web's wasm build, and wai-rs's own
# corpus check run in the browser;
# webtransport two participants and the room's clock over WebTransport: media both ways,
# every object verified against its receipt (the relay's door checks each
# too), the composed canvas's tiles equal to the host's layout for the same
# descriptor and set, the mix in an AudioWorklet, captions with their origin
# label, and a late joiner served earlier groups by FETCH;
# websocket the same over the WebSocket binding, forced;
# goaway the relay shut down with GOAWAY naming a second: every page moves and
# closes its old session before the timeout;
# service a room service (joule-moq-room) keeps the room, as in production: pages
# make their own keys and enter from their buttons, the service grants and
# its clock authors the lifecycle, the relay (WebSocket only, behind a
# same-origin proxy) honours the grants by the service's authority key;
# age a room that admits by age (WAI age-assurance §5.6): pages answer the room
# service's Privacy Pass challenges with tokens they obtain by blind issuance
# from a test issuer over the corpus's published keys; a viewer at 16 is served
# the audio and refused the video its performer rates 18 (below_threshold), a
# viewer at 18 is served both, a token of 13 is refused by the service, a token
# spent twice is refused, and the admission receipt verifies and suppresses;
# e2ee an end-to-end encrypted room (WAI confidentiality) kept by a room service:
# pages key through the service's log, seal every frame and open every object
# before it is decoded; a viewer outside the group opens nothing, every change
# a relay could make is refused with its reason, a late joiner opens nothing
# sealed before its join, a member that stops publishing is removed and opens
# no later epoch, and the relay's DVR store keeps nothing of the room;
# co a room with co-performance (WAI co-performance) kept by a room service behind a
# relay that holds the floor and the audience's inputs: a lead starts turns from
# its page, a performer out of turn is marked by the clock and, under a schedule
# that refuses, held back by the relay; an AI participant's lines show ahead of
# when they play, one kept and one not; a late object is marked; the audience
# votes and sends prompts from the page, the relay withholding each input the
# rules refuse; the clock commits and selects, credited; and the room with the
# clock's log of objects verifies the same in the page and on the host.
# binding the browser sink (WAI browser-sink): live-conformance/browser in the page,
# a wasm-route decode verified against its receipts with every frame bound,
# the binding through clone, transfer, copyTo and re-encode, the user agent's
# decoder's frames bound through the side table, no codec string outside the
# WebCodecs Codec Registry put to the user agent, a measured figure per decode
# beside powerEfficient, and a room whose tiles show verified, bound frames.
#
# Before the browser, wai-live-web's own tests: the room's records a page reads, co-performance's
# among them, each statement read and the corpus verified through the crate.
#
# The macos runner is the host with the browser installed; the tests drive that browser
# (its executable named by BROWSER_BIN), not a bundled one. The automation package comes
# from e2e/package-lock.json with install scripts off. Each browser runs under the host's
# memguard where it exists. Nothing listens beyond loopback.
#
# Push filters match the push's delta, so every path the job reads is listed.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
paths:
- 'joule-code/joule-code-rs/crates/joule-moq-web/**'
- 'joule-code/joule-code-rs/crates/joule-moq/**'
- 'joule-code/joule-code-rs/crates/joule-moq-mls/**'
- 'joule-code/joule-code-rs/crates/joule-moq-relay/**'
- 'joule-code/joule-code-rs/crates/joule-moq-room/**'
- 'joule-code/joule-code-rs/crates/jwp/**'
- 'joule-code/joule-code-rs/Cargo.toml'
- 'joule-code/joule-code-rs/Cargo.lock'
- 'joule-code/joule-code-rs/vendor/**'
- 'wai/wai-live-web/**'
- 'wai/wai-rs/**'
- 'wai/wai-ops/**'
- 'wai/live-conformance/compose/**'
- 'wai/live-conformance/presentation/**'
# The page's Privacy Pass client test reads RFC 9578 A.2's vector from the age corpus, and
# the age scenario's issuer its published test keys.
- 'wai/live-conformance/age/**'
- 'wai/live-conformance/coperformance/**'
- 'wai/live-conformance/browser/**'
- 'wai/wai-rs/tests/vectors/int_video/**'
- '.github/workflows/joule-moq-web.yml'
pull_request:
paths:
- 'joule-code/joule-code-rs/crates/joule-moq-web/**'
- 'joule-code/joule-code-rs/crates/joule-moq/**'
- 'joule-code/joule-code-rs/crates/joule-moq-mls/**'
- 'joule-code/joule-code-rs/crates/joule-moq-relay/**'
- 'joule-code/joule-code-rs/crates/joule-moq-room/**'
- 'joule-code/joule-code-rs/crates/jwp/**'
- 'joule-code/joule-code-rs/Cargo.toml'
- 'joule-code/joule-code-rs/Cargo.lock'
- 'joule-code/joule-code-rs/vendor/**'
- 'wai/wai-live-web/**'
- 'wai/wai-rs/**'
- 'wai/wai-ops/**'
- 'wai/live-conformance/compose/**'
- 'wai/live-conformance/presentation/**'
# The page's Privacy Pass client test reads RFC 9578 A.2's vector from the age corpus, and
# the age scenario's issuer its published test keys.
- 'wai/live-conformance/age/**'
- 'wai/live-conformance/coperformance/**'
- 'wai/live-conformance/browser/**'
- 'wai/wai-rs/tests/vectors/int_video/**'
- '.github/workflows/joule-moq-web.yml'
jobs:
# Forgejo matches `paths:` against the push delta, so a rebase fires this workflow
# whatever the pull request changes. This job reads the pull request's own diff against
# the paths above (scripts/pr-touches-paths.py, which fails open).
relevant:
name: joule-moq-web · does this change touch it
runs-on: linux
outputs:
run: ${{ steps.gate.outputs.run }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- id: gate
run: |
set -euo pipefail
r=$(python3 scripts/pr-touches-paths.py .github/workflows/joule-moq-web.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches the browser client: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
e2e:
name: joule-moq-web · browser end-to-end (macos)
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: macos
timeout-minutes: 90
steps:
- uses: actions/checkout@v5
# launchd's PATH omits cargo on the macOS host runner.
- name: Put cargo on PATH
shell: bash
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
# Pinned to the wasm-bindgen both crates pin: the CLI and the crate must match.
- name: wasm32 target and wasm-bindgen CLI 0.2.127
shell: bash
run: |
set -euo pipefail
rustup target add wasm32-unknown-unknown
cargo install --locked wasm-bindgen-cli --version 0.2.127
# The page's codec is joule-moq built without its runtime; this is the build that
# holds the feature split.
- name: joule-moq without its runtime
shell: bash
working-directory: joule-code/joule-code-rs
run: nice -n 10 cargo check --locked -p joule-moq --no-default-features
# The page's records library, natively: its co-performance reading checked against the
# corpus live-conformance/coperformance (src/co.rs) beside its own cases.
- name: wai-live-web, its own tests
shell: bash
working-directory: wai/wai-live-web
run: nice -n 10 cargo test --locked --lib
- name: The browser end-to-end tests
shell: bash
env:
BROWSER_BIN: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
MOQ_WEB_OUT: ${{ runner.temp }}/moq-web
run: |
set -euo pipefail
test -x "$BROWSER_BIN" || { echo "::error::this runner has no browser at $BROWSER_BIN"; exit 1; }
mg=/Volumes/macos_4TB_external_1/wai-build/bin/memguard
if [ -x "$mg" ]; then export MEMGUARD="$mg"; fi
nice -n 10 bash joule-code/joule-code-rs/crates/joule-moq-web/e2e/run.sh 2>&1 | tee "$RUNNER_TEMP/moq-web-e2e.log"
grep -qE '^room e2e: 1 of 1 runs passed; ' "$RUNNER_TEMP/moq-web-e2e.log" \
|| { echo "::error::the browser end-to-end run did not pass"; exit 1; }
if grep -q '^FAIL' "$RUNNER_TEMP/moq-web-e2e.log"; then echo "::error::a check failed"; exit 1; fi