# 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 : ```text 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 : ```text 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 : ```text 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-lib` sans Tokio, WebSocket, QUIC, HTTP ni TLS ; - `TransportMessage` binaire opaque et contrat message-oriented ; - split `RealtimeConnection -> Sender + Receiver` ; - fermeture distante propre distincte d'une erreur ; - erreurs transport-neutral ; - backend `game-realtime-websocket-lib` Tokio/tokio-tungstenite ; - tests loopback et robustesse ; - smoke runtime `game-realtime-websocket-smoke` hors harness `#[test]` ; - `beta.1` validée avec 53 tests workspace ; - `rc.1` validée avec 18 tests realtime ciblés, smoke `PASS` et 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 : - - 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 : 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é : ```text 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 : ```text 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 : - - - - 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 : ```text --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é : ```text 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 : ```text 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 `!Send` possible du contrat `0.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 : ```text WebTransport session -> one primary bidirectional reliable stream -> bounded backend framing -> TransportMessage ``` Le framing interne candidat est : ```text 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 : `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 : 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 : 1. compilation `wasm32-unknown-unknown` du chemin Rust choisi ; 2. 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 : ```text 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_apis` imposé 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`.