14 KiB
Audit WebTransport/QUIC pour 0.3.5
Statut et objet
Cette étude cadre 0.3.5-alpha.1 à partir de l'archive taggée v0.3.4. Elle reste non normative : les décisions opérationnelles retenues pour la version sont portées par docs/plans/005-V0_3_5_WEBTRANSPORT_QUIC_POC_PLAN.md.
L'objectif est de déterminer, sur l'état réel de l'écosystème au 2026-09-21, quelle pile WebTransport/QUIC mérite un POC, comment elle se confronte au contrat game-realtime-transport-lib livré en 0.3.4, quelles preuves navigateur/TLS sont réalistes et où doit vivre le fallback WebSocket.
Base auditée
L'archive fournie est annoncée comme le téléchargement ZIP du tag Gitea v0.3.4 et déclare :
workspace.package.version = 0.3.4
17 membres workspace
Avant modification, les contrôles statiques exécutables dans l'environnement de génération donnent :
unzip -t : no errors
General Rust rule audit: clean
Rust export completeness audit: 0 candidate(s)
games.sasedev workspace audit: clean
Markdown table audit: clean (5 table(s), 263 file(s))
Distribution layout audit: clean (50 required path(s), 8 forbidden path(s) absent)
L'inventaire indépendant confirme :
437 fichiers dans le ZIP
267 fichiers Markdown extraits
68 fichiers Rust
18 Cargo.toml, dont le manifest racine
17 membres workspace
0 symlink
0 chemin absolu ou traversal détecté
0 target/, node_modules/, build/ ou gen/android/ généré
La sortie utilisateur fournie à l'ouverture de session confirme également cargo fmt --all -- --check, les trois audits et cargo check --workspace propres sur son checkout 0.3.4. Son audit Markdown annonce 279 fichiers contre 263 dans le périmètre scanné du ZIP fourni. La baseline taggée reçue reste l'autorité de génération conformément à CMD-GIT-003 et CMD-GIT-004; l'écart est enregistré sans inventer les fichiers locaux absents de l'archive.
État hérité de 0.3.4
Les preuves de history/0.3.4/ et deltas/0.3.4/rel.001.md confirment :
game-realtime-transport-libsans Tokio, WebSocket, QUIC, HTTP ni TLS ;TransportMessagebinaire opaque et contrat message-oriented ;- split
RealtimeConnection -> Sender + Receiver; - fermeture distante propre distincte d'une erreur ;
- erreurs transport-neutral ;
- backend
game-realtime-websocket-libTokio/tokio-tungstenite ; - tests loopback et robustesse ;
- smoke runtime
game-realtime-websocket-smokehors harness#[test]; beta.1validée avec 53 tests workspace ;rc.1validée avec 18 tests realtime ciblés, smokePASSet arbre inverse où seul le launcher de smoke consomme le backend WebSocket.
Cette frontière constitue la baseline de comparaison. 0.3.5 n'a pas besoin de la redessiner avant d'avoir une preuve WebTransport concrète.
État du protocole au 2026-09-21
WebTransport côté navigateur est désormais classé « Baseline 2026 » par MDN : l'API fonctionne sur les versions récentes des principaux navigateurs depuis mars 2026, avec la réserve habituelle sur les versions anciennes et certaines sous-capacités. L'API exige un contexte sécurisé et expose streams bidirectionnels/unidirectionnels fiables ainsi que datagrams non fiables.
Sources :
- https://developer.mozilla.org/en-US/docs/Web/API/WebTransport_API
- https://developer.mozilla.org/en-US/docs/Web/API/WebTransport
Le binding WebTransport over HTTP/3 n'est cependant pas encore un RFC final. draft-ietf-webtrans-http3-16, daté du 2026-07-06, est toujours un Internet-Draft en WG Last Call avec statut visé Proposed Standard.
Source : https://datatracker.ietf.org/doc/draft-ietf-webtrans-http3/
Conséquence pour le POC : l'interopérabilité navigateur est suffisamment réelle pour être testée, mais la version ne doit pas présenter le protocole ni une crate comme une dépendance produit définitivement stabilisée.
Candidats Rust actuels
Famille web-transport
État observé :
web-transport 0.12.0 (2026-08-20)
web-transport-quinn 0.12.1 (2026-08-20)
web-transport-wasm 0.6.0 (2026-08)
web-transport fournit une API générique qui sélectionne :
native -> web-transport-quinn
wasm32 -> web-transport-wasm
La crate native s'appuie sur Quinn, Rustls, Tokio et expose streams + datagrams. La crate WASM enveloppe l'API WebTransport du navigateur. Le projet amont est sous licence MIT OR Apache-2.0.
Sources :
- https://docs.rs/crate/web-transport/latest
- https://docs.rs/crate/web-transport-quinn/latest
- https://docs.rs/crate/web-transport-wasm/latest
- https://github.com/moq-dev/web-transport
Point particulièrement pertinent pour games.sasedev : la documentation web-transport explique explicitement le problème Send entre natif et WASM et contourne ce problème par sélection de l'implémentation selon la cible. Cela rejoint la décision prise en 0.3.4 de ne pas imposer Send aux futures du contrat transport-neutral.
La voie WASM impose actuellement :
--cfg=web_sys_unstable_apis
car les bindings WebTransport de web-sys restent derrière ce cfg. Ce flag doit être fourni par le build final et ne peut pas être activé par une dépendance. Une éventuelle modification .cargo/config.toml devra donc être ciblée sur wasm32-unknown-unknown, pas appliquée globalement au workspace.
wtransport
État observé :
wtransport 0.7.2 (2026-08-11)
La crate fournit une implémentation WebTransport/HTTP3 pure Rust, client et serveur natifs, fondée notamment sur Quinn, Rustls et Tokio. Sa documentation est plus riche et elle fournit des helpers explicites pour certificat self-signed, hash SHA-256 et contraintes W3C. La branche 0.7.x annonce un MSRV au moins Rust 1.88 dans la metadata consultée de 0.7.1; la compilation exacte de 0.7.2 reste à prouver sur le toolchain du projet.
Sources :
Sa limite pour ce projet est l'absence d'une façade Rust WASM équivalente : l'intégration navigateur documentée utilise directement l'API JavaScript WebTransport. Cela reste viable pour un serveur Rust, mais apporte moins de valeur au POC si l'objectif est aussi de challenger le contrat Rust commun sur wasm32.
Quinn / H3 de plus bas niveau
Quinn est la base QUIC commune à plusieurs stacks, mais l'utiliser directement imposerait de réimplémenter le binding WebTransport/HTTP3, la négociation et les détails de session déjà possédés par les crates spécialisées.
Cette voie reste un recours si les wrappers retenus bloquent une exigence essentielle ; elle n'est pas retenue comme premier POC, conformément au principe d'éviter une infrastructure disproportionnée.
Choix de POC retenu
La famille web-transport est retenue en premier pour 0.3.5, avec :
game-realtime-webtransport-lib
-> web-transport
-> native: web-transport-quinn
-> wasm32: web-transport-wasm
Raisons :
- façade native + WASM déjà pensée par l'amont ;
- alignement direct avec la contrainte
!Sendpossible du contrat0.3.4; - serveur natif et client natif/WASM disponibles dans la même famille ;
- streams et datagrams disponibles pour le POC ;
- Quinn/Rustls/Tokio restent contenus dans le backend concret ;
- licence compatible avec le dépôt ;
- activité amont récente en août 2026.
wtransport reste le candidat de repli technique prioritaire si web-transport échoue sur une exigence concrète de alpha.2 à alpha.4, notamment configuration TLS, lifecycle ou interop navigateur. Un échec d'implémentation ne justifie pas de basculer silencieusement : le plan et le delta doivent enregistrer la raison.
Compatibilité avec le contrat 0.3.4
Chemin fiable
Le contrat commun est message-oriented alors qu'un stream QUIC/WebTransport est un flux d'octets fiable, ordonné et flow-controlled. La différence de sémantique est réelle mais ne nécessite pas de modifier RealtimeConnection.
Le POC retiendra un stream bidirectionnel principal par connexion logique :
WebTransport session
-> one primary bidirectional reliable stream
-> bounded backend framing
-> TransportMessage
Le framing interne candidat est :
u32 big-endian payload length
payload bytes
avec une limite produit vérifiée avant allocation/écriture. Ce framing sert uniquement à reconstruire les frontières TransportMessage sur un byte stream ; il n'est pas le futur wire codec métier, ne porte aucune version de protocole joueur/room et reste privé au backend.
Le client ouvre le stream principal ; le serveur l'accepte avant de considérer la RealtimeConnection établie. Ce choix conserve l'ordre des messages et permet au split commun de mapper naturellement le côté write/read du même stream.
Datagrams
Les datagrams WebTransport sont non fiables, non ordonnés et non flow-controlled. Ils ne satisfont donc pas le contrat fiable/ordonné livré en 0.3.4.
Ils seront exercés séparément dans le POC, sans élargir RealtimeConnection et sans créer une capability commune tant qu'un second consommateur réel et un besoin sémantique durable ne sont pas démontrés.
Une mesure backend-spécifique peut utiliser la session amont directement ou une surface expérimentale locale au launcher de mesure. Elle ne doit pas devenir une API durable uniquement pour permettre le benchmark.
TLS et certificats de développement
Le navigateur impose une URL https:// vers le serveur WebTransport. L'option serverCertificateHashes permet de faire confiance à un certificat connu sans PKI publique lorsque la connexion est dédiée.
La documentation MDN impose notamment pour ce mode :
- hash SHA-256 ;
- certificat X.509v3 ;
- validité totale inférieure à deux semaines ;
- date courante dans la période de validité ;
- ECDSA P-256 comme choix interopérable minimal.
Source : https://developer.mozilla.org/en-US/docs/Web/API/WebTransport/WebTransport
web-transport-quinn fournit ClientBuilder::with_server_certificate_hashes, ce qui permet de reprendre la même stratégie de pinning côté client natif sans désactiver la validation TLS.
Source : https://docs.rs/web-transport-quinn/latest/web_transport_quinn/struct.ClientBuilder.html
Le POC doit donc privilégier une identité self-signed courte générée pour localhost et un pin de hash explicite. Une API « dangerous/no certificate verification » ne devient pas le chemin normal du smoke.
Aucun certificat privé, clé privée durable ou secret ne doit être commité.
Plateformes
Linux natif
Cible de référence pour :
- serveur local UDP/QUIC ;
- client natif ;
- tests loopback déterministes ;
- smoke runtime hors harness ;
- benchmark local borné.
Navigateur / WASM
Cible obligatoire du POC parce que WebTransport apporte une valeur spécifique au navigateur. Deux preuves distinctes sont nécessaires :
- compilation
wasm32-unknown-unknowndu chemin Rust choisi ; - interop runtime d'un navigateur récent avec le serveur Rust local.
Le smoke navigateur ne doit pas être confondu avec un simple cargo check WASM.
Android
La pile native Quinn/Rustls rend Android plausible, mais 0.3.5-alpha.1 ne le déclare pas validé. Le plan réserve au minimum un contrôle de compilation ciblé si la dépendance choisie ne force pas une réouverture disproportionnée du pipeline Android.
Aucun changement Java/Gradle/JNI n'est prévu pour le POC ; la matrice quatre ABI 0.3.3 n'est donc pas rejouée par cérémonie.
macOS / iOS
La trajectoire est documentée mais non validée en l'absence d'environnement Apple. Une compatibilité supposée depuis Quinn/Rustls ne doit pas être présentée comme un smoke réel.
Fallback WebSocket
Le fallback est retenu au niveau composition/application du POC, pas dans le gameplay et pas dans game-realtime-transport-lib.
La preuve visée est :
attempt WebTransport
success -> use WebTransport path
classified establishment failure / unsupported path -> WebSocket baseline
Le POC doit également permettre de forcer chaque branche afin de vérifier le fallback de façon déterministe. Il ne doit pas créer de registry dynamique, TransportManager générique ni système de plugins.
Aucune règle n'impose encore que cette logique devienne une crate réutilisable : un launcher technique suffit tant qu'un second consommateur réel ne justifie pas l'extraction.
Mesures retenues
Les mesures minimales sont :
- temps d'établissement ;
- RTT de petits payloads ;
- débit sur payloads bornés ;
- plusieurs messages en vol ;
- comparaison WebSocket vs stream WebTransport fiable ;
- comparaison datagram uniquement si la preuve datagram est effectivement réalisée ;
- coût opérationnel observé : certificat, UDP, port, debug et build WASM.
Les résultats loopback sont décrits comme des mesures locales contrôlées. Ils ne seront jamais extrapolés en gains Internet/mobile sans test réseau correspondant.
CPU/mémoire peuvent être relevés si la méthode est stable, mais ne sont pas une gate de release.
Risques principaux
- protocole HTTP/3 WebTransport encore en Internet-Draft ;
- APIs amont actives mais encore susceptibles de casser ;
web_sys_unstable_apisimposé au build WASM ;- contraintes de certificats plus lourdes que la baseline
ws://; - UDP parfois bloqué par réseau, firewall ou infrastructure ;
- browser smoke nécessitant plusieurs processus/outils locaux ;
- framing message interne nécessaire sur le stream fiable ;
- différences de close/reset entre session WebTransport et stream principal ;
- dépendances crypto natives pouvant compliquer certains targets ;
- Android plausible mais non prouvé ;
- benchmark loopback trop bruité pour porter seul une décision produit.
Conclusion de cadrage
Le POC est viable et justifie 0.3.5, mais le forecast initial du prompt est trop grossier pour la règle de 15 à 30 minutes par delta. En particulier, backend natif, robustesse, smoke runtime, WASM, interop navigateur/TLS, fallback et mesures ne doivent pas être agrégés en deux grosses alpha.
Le plan actif découpe ces preuves en tranches verticales indépendantes et ajoute une consolidation explicite avant RC, conformément à SESSION-009 et VER-PHASE-010.