open-standards/wai/wai-web/peer/README.md
Transaction Science 95ca152263
Some checks failed
WAI Studio / does this change touch it (push) Successful in 22s
wai-quantum for JavaScript / does this change touch it (push) Successful in 23s
wai peer delivery in browsers / peer delivery in Chromium, Firefox and WebKit · macos (push) Successful in 2m10s
WAI Studio / Studio in Chromium and Firefox · macos (push) Successful in 12m10s
WAI breaking changes and the conformance runner / WAI breaking · does this change touch WAI (push) Successful in 40s
WAI examples / WAI examples · does this change touch them (push) Successful in 1m4s
WAI Studio / the catalogue's actions, the unit tests and the core · linux (push) Successful in 1m40s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (push) Successful in 21m32s
wai-quantum studio and desktop / does this change touch it (push) Has been cancelled
wai-quantum studio and desktop / desktop app · macos (push) Has been skipped
wai-quantum for JavaScript / javascript · linux (push) Successful in 21m38s
WAI examples / WAI examples · the archive, the readiness check, the browser and Apple · macos (push) Successful in 20m57s
WAI breaking changes and the conformance runner / WAI breaking and conform · their tests, and the independent verifiers through wai conform · linux (push) Failing after 18s
WAI breaking changes and the conformance runner / WAI breaking · wire, record and API against main · linux (push) Successful in 1m14s
WAI Studio / Studio in WebKit · linux (push) Successful in 33m40s
wai-quantum studio and desktop / studio · browser (push) Has been skipped
wai-quantum studio and desktop / desktop app · linux (push) Has been skipped
WAI examples / WAI examples · android-app · linux-arm64 (push) Successful in 17m22s
WAI examples / WAI examples · portable · linux (push) Successful in 27m53s
wai-quantum studio and desktop / desktop app · windows (push) Has been skipped
wai-peer-browser: peer delivery runs in Firefox with every check the other engines get, and the skip is gone
The 13 November nightly (run 34710) failed at its Firefox step by the run's own guard: the step
skipped peer delivery in Firefox (WAI_E2E_KNOWN_LACKS=firefox=rtc-pair) for want of a data
channel between two of its pages on the CI host, and a pair of Firefox 150.0.2's pages now opens
one there (the host's application firewall lists Playwright's Firefox build as allowed incoming
connections). The Firefox step now makes the run and is held to the same PASS line as Chromium
and WebKit.

"The run wrote no session to recompute" was the throw's consequence, not a second fault: the
throw came before the first page, and run.mjs writes the session once its asker is done. run.mjs
now reports the guard's finding as a FAIL line and closes the browser, and run.sh says that a
run stopped before its session was written.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-13 04:00:15 -05:00

79 lines
4.8 KiB
Markdown

# Peer delivery in a page
A page fetches objects from the neighbours that hold them before it asks the origin, holds every
byte a peer sent to the object's receipt before it uses it, and signs for what it verified
([peer-delivery](../../extensions/peer-delivery.md)). Asking and serving are each off until the
person using the page turns them on, and the operator's policy must allow each as well.
| file | what it is |
|---|---|
| `peer.js` | the links (a data channel, HTTP) and the client and holder over them |
| `index.html`, `page.js` | the reference page: an asker or a holder, by its query |
| `harness.mjs` | what the two runs share: the bundle in node, the corpus's world, an HTTP holder |
| `verify_peer.mjs` | the run with no browser: links in memory and a local HTTP link, faults planted |
| `run.mjs` | the run in a browser: pages over data channels and a local HTTP link, faults planted |
| `run.sh` | builds the bundle, makes `run.mjs`'s run and recomputes its session with the second implementation |
Everything that decides is the `peer` bundle, `src/peer.rs` over `wai::peer_delivery`: the Rust a
native sink runs. `peer.js` carries frames and makes requests; it never hands on a byte the
bundle has not answered `taken` for.
## Build
```
# from wai/wai-web
cargo build --locked --release --target wasm32-unknown-unknown --features peer
wasm-bindgen --target web --out-dir peer/pkg --out-name wai_peer \
"${CARGO_TARGET_DIR:-target}/wasm32-unknown-unknown/release/wai_web.wasm"
```
## The runs
Both use the world of the conformance corpus
([`live-conformance/peer-delivery/`](../../live-conformance/peer-delivery/)): group A of six
objects and group B of three, the second of B past one `data` frame. Every service they start
binds port 0 and prints its port, and is closed before the run exits.
```
node peer/verify_peer.mjs .. peer/pkg [session.json]
PLAYWRIGHT_HOST=<dir with node_modules/playwright>/ node peer/run.mjs .. [session.json]
python3 -I ../live-conformance/peer_delivery_verify.py --session session.json
```
`verify_peer.mjs` (33 checks) needs node alone. `run.mjs` (23 checks) opens seven pages in the
installed browser, each a profile of its own: a holder and an asker whose settings are left
off, four holders that serve over data channels, and an asker with asking on, which also
reaches a holder over HTTP on another origin. The faults are planted on the holders' side, and
the checks are on what the asker did:
| planted | held to |
|---|---|
| a peer serves an object with a byte changed | the bytes are refused at their receipt, the next holder serves, the peer is asked nothing more, and no acknowledgement names it |
| a record states a group one object larger than its receipt | the record is refused whole and its holder is never asked |
| a peer lists an object it does not hold | its `miss` sets the record aside, the origin serves, and the next object it listed is not asked of it |
| a setting left off | the page constructs no peer connection, sends no request to a holder and signs nothing |
Each run can write the session's acknowledgements to a file, and
`peer_delivery_verify.py --session` recomputes from those signed records alone what each holder
was acknowledged, with no code of the client's.
A browser gives a page its local addresses as names that resolve on the local network. Where
they do not resolve between two profiles of one machine (a session started over SSH, with no
multicast), no data channel opens and `run.mjs` fails at "four data channels and the HTTP link
are up", naming the kinds of candidate each connection offered. There,
`WAI_PEER_BROWSER_ARGS="--disable-features=WebRtcHideLocalIpsWithMdns"` has the browser offer
the addresses themselves, and the run is otherwise the same.
`run.sh` builds the bundle, runs `run.mjs` with each page offering its addresses themselves
(`WAI_PEER_HOST_ADDRESSES=1`, which is the argument above for Chromium and the preference
`media.peerconnection.ice.obfuscate_host_addresses` off for Firefox), and recomputes the session
with `peer_delivery_verify.py`. CI runs it on each push to main that touches the page, the bundle's
source or the corpus, and nightly, in Chromium (the installed Chrome), Firefox and WebKit on the
host that has them (`.github/workflows/wai-peer-browser.yml`), each held to the same checks.
Before its first page `run.mjs` tests a pair of the browser's own pages for a data channel: where a
host's firewall stops one (an application firewall that lets in signed software only stops
Playwright's Firefox, an unsigned build, unless a rule of its own lets that build in), the run
fails there, saying so, and a host that is known to stop it is named by
`WAI_E2E_KNOWN_LACKS=<engine>=rtc-pair`, which skips the run with that reason and fails it once
the pair connects. `WAI_E2E_ENGINE=chromium|firefox|webkit` names the engine by hand.
`verify_peer.mjs` and the session recomputation also run in `wai-web-wasm.yml`.