Skip to content

Integrate host-owned Media into JamPeerTransport-on-Seity - #1217

Draft
replghost wants to merge 52 commits into
feat/jam-peer-transport-on-seityfrom
feat/media-on-jam-seity
Draft

replghost wants to merge 52 commits into
feat/jam-peer-transport-on-seityfrom
feat/media-on-jam-seity

Conversation

@replghost

@replghost replghost commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Integration layer that adds the host-owned Media service (#838, RFC #839) to the JamPeerTransport-on-Seity line (#1011), so the dotli layer that deploys paseo.fyi can vendor one host with Seity, JamPeerTransport and Media.

The integration began with a --no-ff merge:

It now also integrates the Tommy platform fixes from #1216 and subsequent Media updates. Source feature layers remain separate; this PR assembles them above #1011.

Media in one paragraph

Products get calling without touching WebRTC. The host owns capture, signaling (sealed packets over the Statement Store), relay-only ICE through TURN, and picture compositing. Products see opaque session, participant and operation handles, authoritative snapshots, peer product-account keys, and submit picture rectangles. No SDP, ICE candidates, IP addresses, device ids or media bytes reach product memory. Calling consent is a separate permission scoped to product, network and account; camera and microphone keep their own device consent.

Wire

  • Media is prototype wire trait 218, methods 0–10. Sequential trait 20 is Contacts upstream; 218 keeps this unreviewed service clear of the range assigned in merge order. Only the trait byte moves when it is allocated for real.
  • RemotePermission order: …, StatementSubmit, JamPeers, Calling (JamPeers keeps 5, already deployed on paseo.fyi).
  • PermissionAuthorizationRequest order: …, ProfileDisclosure (6), Calling (7).

Initial Media qualification (historical)

  • cargo test -p truapi --lib: 1615 passed (media 28, permission 103, jam 10, profile 31, calling 7)
  • bun test: truapi-host 371, truapi 921, js/container 126
  • Playground media specs (real Chromium + loopback coturn): 6/6, including "peers connect through TURN and signal only relay candidates" and "host and reflexive candidates never leave the backend"
  • CI clippy: three lints already present on 795a40820 (unnecessary_lazy_evaluations in capabilities/platform.rs, two too_many_arguments in the receiving code); none in Media code
  • Live: two Epoca desktop instances on Paseo Next V2 completed calls in both directions over the default light client with the same Media code (Epoca vendors the fc86c56 variant of this layer)

Draft: not for merge; it exists so the paseo.fyi integration layer has a pushed host revision and review surface.

Current integration qualification

  • Browser SDK provenance: host JavaScript rebuilt from 8e735637702df560eb3af7853301d06cf1c942fb; client and production/testing signing-host WASM retain the verified 44b87fea6fbe430589bb53c31a3e38b620ad5374 build. The intervening changes do not change Rust/WASM. All 110 host archive files and 143 client archive files match the browser vendor, allowing only its declared local client dependency override.
  • Host JavaScript: 370 tests passed; real Chromium/coturn Media backend: 8 tests passed, including picture stability and late viewport replay.
  • Rust qualification for the retained build: 1,647 core and 39 wire/integration tests passed; Android products: 317 tests across 60 suites passed.
  • iOS CI at ba1f865ac: core, simulator app build and tests passed; xcresult reports 2,452 passed, zero failed/skipped (2,640 parameterized device executions). The later Media change is browser TypeScript only.
  • Signed iOS archive remains blocked by the missing readonly-match MediaBroadcastExtension development profile. Signing and distribution remain CI-owned; this is not a claim that all repository CI is green.
  • Integrated platform behavior includes request-correlated SSO decoding, bounded/revocable automatic Bulletin uploads with cross-runtime CAS, canonical trusted-product notification policy, and selected iOS theme propagation.

Known qualification limits: the exact legacy TrUAPI 0.7 storage probe still times out; no claim is made that historical #263 is fixed. Physical-device theme appearance, fully-quit native notification activation, and Tommy’s historical paired-device identity case are not covered by the simulator/local-browser evidence.

Adds the generic host-owned Media service: v01 Media wire types and
methods 0-10 at prototype wire trait 218, RemotePermission::Calling,
host-core media sessions, groups, signaling and backend boundaries,
platform media capabilities, browser media backend for the JS host,
native Android/iOS media backends, and playground media specs.

Squashes:
- wip(media): preserve implementation before approved upstream integration
- fix(media): keep receive-only sessions on device revocation; wait for
  backend session before placing pictures
- refactor(media): move Media to prototype wire trait 218
Media session_subscribe waited for MediaSignaling to start, so a cold
light client ended the stream with NotConnected before any snapshot.

Subscribing now only probes the backend and starts observation. One
background connector owns signaling: it starts it, drives its events,
and after a failure or loss restarts it with backoff (500 ms doubling
to 10 s) until the runtime closes. Each binding is still fenced by the
current authority and a new epoch. Mutations that need signaling wait
for the binding within their operation deadline and skip the pending
backoff.
…er starts

The core admits a participant, and the product sees it, before the call
handshake asks the backend to create its peer. The browser backend
re-checked remote surfaces against its own peer table and rejected those
rectangles with InvalidHandle, so Vox showed "Pictures not placed" while
a call was negotiating. The core already validates participant handles;
the backend now queues the rectangle and renders it once the peer media
is live, like the Android and iOS backends. Unknown handles still fail
in the core.
Always construct RTCPeerConnection with iceTransportPolicy relay and drop
the optional override. Never signal a non-relay candidate, neither as an
IceCandidate event nor embedded in a description. The playground media
specs now run against a loopback coturn relay.
Lock navigator.mediaDevices.enumerateDevices on the instance and every
prototype with the same NotAllowedError as capture.
Size the event queue for a full 256-statement page plus control headroom,
and admit only messages a lagging consumer has room for. Unadmitted
packets are not replay-recorded, so a later delivery still succeeds and
the endpoint no longer ends every call with ConnectivityLost.
A waiter parked while a signaling attempt runs found no backoff to wake,
so the attempt's failure still waited a full backoff. The retry request
is now sticky and consumed by the next backoff wait.
…layer

Merge feat/media-sessions (Media service, prototype wire trait 218, on #709
a78944c) into the integration revision 795a408 that #291 vendors.

- RemotePermission keeps JamPeers at positional index 5 and appends
  Calling at 6 (TS codegen encodes variants positionally).
- PermissionAuthorizationRequest keeps the deployed ProfileDisclosure at
  codec index 6 and moves Calling to index 7.
- Platform super-trait, runtime adapters and wasm wiring carry both the
  Profile and Media platforms; JamPeerSession is retained.
- Codegen keeps the receiving layer's Option<codec>/Option<bytes> argument
  form ahead of Media's generic Option fallback, and its receiving test
  passes Media's private_media flag.
- The mock-permission arm count covers both JamPeers and Calling (16).
@github-actions github-actions Bot added javascript Pull requests that update javascript code rust Pull requests that update rust code host-ios Touches the iOS host tree host-android Touches the Android host tree labels Oct 6, 2026
Preserve Media's generalized optional callback codecs and exports. Drop a timing-dependent wording assertion; structured cancellation and SSO cleanup coverage remain.
attachmentIsolated() probed the product frame with a discarded
`frame.contentWindow.document` read inside try/catch. dotli's production
build tells rolldown/oxc that property reads have no side effects, which
deletes the read and leaves the check always "not isolated", so attach()
failed with SurfaceUnavailable on paseo.fyi. Use contentDocument === null,
whose value is used and which is null exactly for cross-origin and opaque
sandboxed documents.

The new media spec runs the decision in Chromium against tsc, esbuild
--minify and dotli-configured rolldown builds.
@github-actions

github-actions Bot commented Oct 6, 2026

Copy link
Copy Markdown
Contributor

This pull request touches an app, which is not built by default. Add a label for each build you want:

  • iOS simulator build, ios-simulator-build: builds the iOS app, runs its tests and attaches a build for the iOS Simulator on a Mac.
  • iOS device build, ios-device-build: attaches a signed build that installs on a registered iPhone or iPad.
  • Android build, android-device-build: attaches an APK that installs on an Android phone or an emulator.

Each starts as soon as it is added and follows the branch from then on.

@socket-security

socket-security Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​hpke@​0.12.0100100100100100

View full report

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Bundle size report

Compared with main at c75de1b.

Raw Gzip Brotli
truapi-host 8.82 MiB (+979.1 KiB, +12.2%) 6.05 MiB (+407.6 KiB, +7.0%) 5.68 MiB (+302.2 KiB, +5.5%)
truapi-provider 4.03 MiB (-7 B) 1.27 MiB (-5 B) 959.6 KiB (-180 B)
truapi 6.51 MiB (+502.9 KiB, +8.2%) 943.0 KiB (+92.1 KiB, +10.8%) 770.0 KiB (+72.9 KiB, +10.5%)
Total 19.36 MiB (+1.45 MiB, +8.1%) 8.24 MiB (+499.7 KiB, +6.3%) 7.36 MiB (+374.9 KiB, +5.2%)

WebAssembly modules

Raw Gzip Brotli
truapi-host/wasm/web/truapi_server_bg.wasm 3.46 MiB (+717.1 KiB, +25.4%) 1.30 MiB (+353.0 KiB, +35.9%) 995.8 KiB (+254.9 KiB, +34.4%)
truapi-host/wasm/web/truapi_verifiable_bg.wasm 4.89 MiB 4.64 MiB (-11 B) 4.61 MiB (+537 B)
truapi-provider/truapi_provider_bg.wasm 3.99 MiB (-7 B) 1.26 MiB (-5 B) 951.9 KiB (-180 B)
Changed files (37)
Raw Gzip Brotli
truapi-host/wasm/web/truapi_server_bg.wasm 3.46 MiB (+717.1 KiB, +25.4%) 1.30 MiB (+353.0 KiB, +35.9%) 995.8 KiB (+254.9 KiB, +34.4%)
truapi/explorer/codegen/types.js 385.3 KiB (+168.2 KiB, +77.4%) 56.2 KiB (+26.0 KiB, +86.2%) 43.9 KiB (+19.8 KiB, +82.1%)
truapi/playground/codegen/truapi-dts.js 436.0 KiB (+148.2 KiB, +51.5%) 79.0 KiB (+29.2 KiB, +58.6%) 62.3 KiB (+22.1 KiB, +55.1%)
truapi-host/web/browser-media-backend.js (new) 81.7 KiB 17.2 KiB 14.6 KiB
truapi/playground/codegen/services.js 141.8 KiB (+42.1 KiB, +42.2%) 23.3 KiB (+8.1 KiB, +53.3%) 19.5 KiB (+6.6 KiB, +51.8%)
truapi/generated/types.js 100.1 KiB (+36.7 KiB, +58.0%) 12.6 KiB (+5.0 KiB, +64.4%) 10.6 KiB (+4.1 KiB, +62.1%)
truapi/generated/client.js 105.8 KiB (+34.3 KiB, +48.0%) 17.3 KiB (+6.6 KiB, +60.8%) 14.3 KiB (+5.3 KiB, +59.2%)
truapi-host/browser-receiving-worker.js (new) 33.8 KiB 6.6 KiB 5.8 KiB
truapi/jam-peer-transport.js (new) 29.7 KiB 6.6 KiB 5.7 KiB
truapi-host/wasm/web/truapi_server.js 80.3 KiB (+22.3 KiB, +38.5%) 12.6 KiB (+2.1 KiB, +19.5%) 10.8 KiB (+1.7 KiB, +18.7%)
truapi-host/web/native-chat-files.js (new) 20.5 KiB 4.6 KiB 4.0 KiB
truapi-host/web/create-worker-host-runtime.js 74.0 KiB (+20.0 KiB, +37.0%) 15.0 KiB (+3.2 KiB, +27.0%) 13.0 KiB (+2.7 KiB, +26.2%)
truapi-host/generated/host-callbacks.js 24.3 KiB (+13.8 KiB, +131.4%) 6.7 KiB (+3.4 KiB, +101.1%) 5.7 KiB (+2.9 KiB, +102.5%)
truapi-host/web/native-chat-media.js (new) 12.0 KiB 3.3 KiB 2.9 KiB
truapi/generated/wire-decode.js 40.0 KiB (+11.3 KiB, +39.5%) 4.1 KiB (+1.0 KiB, +33.0%) 3.4 KiB (+856 B, +32.4%)
truapi-host/worker-runtime.js 48.8 KiB (+11.2 KiB, +29.9%) 11.5 KiB (+1.8 KiB, +19.0%) 10.0 KiB (+1.6 KiB, +18.9%)
truapi/notification-envelope.js (new) 10.7 KiB 3.2 KiB 2.8 KiB
truapi/jam-peer-transport-cert.js (new) 9.0 KiB 3.4 KiB 3.0 KiB
truapi/notification-container.js (new) 7.9 KiB 2.3 KiB 2.0 KiB
truapi-host/adapter-support.js 10.1 KiB (+6.7 KiB, +195.2%) 2.9 KiB (+1.6 KiB, +117.6%) 2.5 KiB (+1.3 KiB, +110.7%)
truapi-host/browser-receiving.js (new) 6.6 KiB 1.9 KiB 1.7 KiB
truapi-host/wallet-allowances.js (new) 6.5 KiB 1.7 KiB 1.5 KiB
truapi-host/browser-receiving-transport.js (new) 6.1 KiB 2.2 KiB 1.9 KiB
truapi-host/worker-local-identity.js (new) 5.7 KiB 1.8 KiB 1.5 KiB
truapi-host/generated/host-callbacks-adapter.js 12.4 KiB (+5.3 KiB, +74.9%) 2.6 KiB (+1.0 KiB, +65.0%) 2.3 KiB (+909 B, +64.5%)
truapi-host/generated/worker-callbacks.js 12.0 KiB (+4.7 KiB, +64.7%) 2.2 KiB (+765 B, +50.2%) 1.8 KiB (+633 B, +50.6%)
truapi/generated/wire-table.js 12.3 KiB (+3.4 KiB, +37.8%) 2.0 KiB (+406 B, +24.9%) 1.5 KiB (+303 B, +23.6%)
truapi-host/locale.js (new) 1.9 KiB 689 B 622 B
truapi-host/runtime.js 2.3 KiB (+1.6 KiB, +215.6%) 855 B (+419 B, +96.1%) 692 B (+361 B, +109.1%)
truapi/client.js 34.4 KiB (+1.3 KiB, +3.8%) 8.3 KiB (+305 B, +3.7%) 7.1 KiB (+262 B, +3.7%)
truapi-host/worker-permission-authorization.js 3.2 KiB (+674 B, +26.1%) 432 B (+55 B, +14.6%) 387 B (+81 B, +26.5%)
truapi-host/worker-dispatch.js 1.8 KiB (+467 B, +33.1%) 525 B (+125 B, +31.3%) 446 B (+100 B, +28.9%)
truapi-host/worker-protocol.js 3.7 KiB (+282 B, +8.1%) 1.4 KiB (+157 B, +12.2%) 1.1 KiB (+114 B, +10.7%)
truapi-host/web/index.js 328 B (+183 B, +126.2%) 177 B (+63 B, +55.3%) 152 B (+34 B, +28.8%)
truapi/sandbox.js 13.5 KiB (+153 B, +1.1%) 4.2 KiB (+68 B, +1.6%) 3.6 KiB (+54 B, +1.5%)
truapi-host/index.js 80 B (+50 B, +166.7%) 80 B (+30 B, +60.0%) 67 B (+33 B, +97.1%)
truapi-provider/truapi_provider_bg.wasm 3.99 MiB (-7 B) 1.26 MiB (-5 B) 951.9 KiB (-180 B)

Commit: ca5a6bc

@github-actions

github-actions Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

CI Status: 24 required jobs green, 22 passed and 2 skipped by path filter.

All job results
job result
android-bindings success
bundle-size success
changes success
changeset-guard success
cli-package success
codegen success
e2e skipped
explorer success
headless-install success
host-android-bindings success
host-android-detekt success
host-wasm success
ios-bindings success
ios-swift success
licenses success
playground success
provider-android-bindings success
release-guard success
rust success
ts-client success
ts-debugger success
ts-host success
wasm-provider success
workflow-lint skipped

Signing credentials: failure as of 2026-10-09, a release may fail

Commit ca5a6bcd · run log

A Statement Store submit that outlives its budget (e.g. while the light
client stalls) or loses its transport may still have been accepted. The
caller then failed its outgoing link with ConnectivityLost while the
callee rang, accepted, and waited for a Commit that never came
(Unanswered). Invite, Accept and Commit are idempotent at the receiver,
so retry them (up to four attempts, one second apart, fenced again after
the wait) while the link would still send them; other messages keep the
existing failure path.
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Oct 6, 2026
Keep upload consent separate from remote capability and signing grants; scope it to product, root account and Bulletin genesis. Reserve persistent rolling usage before backend work, fence pending consent on revocation and session changes, and expose native settings plus explicit CLI revocation. Correct explicit self capture in the theme regression fixture.
A browser runtime attached before its event stream opens buffered the
attach-time detach (None) and the measured viewport. Opening the stream
pushed the current viewport first and then replayed both, so the core
took the revisionless None and dropped the repeated revision as stale:
pictures never rendered until the viewport changed again.

The stream already opens with the current viewport, so viewport changes
are no longer buffered while no stream is open.
Merge cf424c9 into e1808d8 with explicit approval. Preserve scoped Media permissions and live-resource revocation alongside upload consent, notification trust, correlated SSO decoding and ordered native theme updates.

Use the integration storage CAS for shared upload quota and stale consent answers. Rust and Android product suites pass; real isolated CLI revocation advances consent generation without erasing usage. Browser artifacts and iOS qualification follow from this merge.
@github-actions github-actions Bot added the rfc label Oct 7, 2026
Every accepted layout rebuilt the compositor planes from scratch, so a
product that re-submits its rectangles on each scroll frame replaced the
<video> on every frame. A fresh element shows nothing until its first
decoded frame: traced in Chromium, 60 scroll-frame layouts created 61
elements and left the picture blank for the whole scroll, with the
product's dark placeholder showing through.

render() now keys planes by placement, session and surface id and keeps
the element while its track is unchanged, updating only the geometry in
place; removed or retracked pictures still release their element. The
playground regression drives 20 scroll-frame layouts over a live relay
pair and checks the element survives, lands at the last accepted
rectangle, and that a stale layout leaves it alone.
# Conflicts:
#	rust/crates/truapi/tests/wire_result_shape.rs
@replghost replghost added android-instrumented-tests Run the Android instrumented tests on this pull request ios-simulator-build Build the iOS app, run its tests and attach a simulator build to this pull request labels Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

iOS simulator preview

Built from ca5a6bcd2, stamped with it in TrUAPICommit.

gh run download 37994765007 --name simulator-preview-ca5a6bcd2
unzip polkadot-app-*.app.zip
xcrun simctl install booted polkadot-app.app
xcrun simctl launch booted io.parity.polkadotapp.develop

Or download it in a browser, which arrives as a zip wrapping
the .app.zip, so it needs unzipping twice.

An arm64 simulator slice, so it needs an Apple Silicon Mac and does not
install on a device. Kept for 14 days, after which the link stops
resolving and a new push rebuilds it while ios-simulator-build is
set.

Remove the obsolete mock installation assertion while checking camera and microphone denial without permission requests. Remove redundant awaits on immutable peer IDs and the nonisolated presentation initializer.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

android-instrumented-tests Run the Android instrumented tests on this pull request documentation Improvements or additions to documentation host-android Touches the Android host tree host-ios Touches the iOS host tree ios-simulator-build Build the iOS app, run its tests and attach a simulator build to this pull request javascript Pull requests that update javascript code rfc rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant