# Delta 0.3.5-alpha.3 ## Base requise `0.3.5-alpha.2.fix.1`, validée par l'utilisateur le 2026-09-21 avec fmt, audits, check workspace, Clippy strict et les six tests de `game-realtime-webtransport-lib` entièrement verts. La validation réellement fournie est conservée dans `history/0.3.5/alpha.2.fix.1.md`. ## Objectif Fermer la première adaptation fiable WebTransport vers `game-realtime-transport-lib` sans introduire encore la robustesse/lifecycle avancés, le navigateur/WASM, les datagrams ou le smoke public. La version passe à : ```text 0.3.5-alpha.3 ``` ## Stream primaire Une `WebTransportSession` peut désormais être consommée de deux façons : ```text client -> open_primary_connection() server -> accept_primary_connection() ``` Chaque chemin sélectionne exactement un stream bidirectionnel fiable et retourne `WebTransportConnection`. Le backend `web-transport-quinn` écrit lui-même l'en-tête WebTransport nécessaire pendant `open_bi()`. Le serveur peut donc accepter le stream avant toute frame applicative. Aucun préambule games.sasedev supplémentaire n'est ajouté : après l'en-tête protocolaire géré par la dépendance, le premier octet applicatif appartient directement au framing prévu. ## Framing fiable privé Le framing du stream primaire est : ```text u32 big-endian payload length payload bytes ``` Il reste privé à `game-realtime-webtransport-lib` et n'est pas un wire codec gameplay. La borne POC actuelle est de 1 MiB par message. Elle est vérifiée : - avant écriture côté sender ; - immédiatement après décodage des quatre octets de longueur et avant toute allocation côté receiver. Une longueur hors limite produit `TransportErrorKind::MessageTooLarge`. La limite n'est pas encore exposée comme configuration produit. `alpha.4` possède cette décision avec les autres limites et deadlines. ## Contrat commun `WebTransportConnection` implémente `RealtimeConnection` et produit : ```text WebTransportSender WebTransportReceiver ``` Les deux moitiés conservent chacune une référence à la session WebTransport. Le `split()` ne ferme donc pas accidentellement la session au moment où l'objet connexion est consommé. `WebTransportSender::send(...)` écrit le header puis le payload sur le stream fiable et respecte la backpressure naturelle de QUIC pendant les écritures asynchrones. `WebTransportReceiver::receive(...)` reconstruit exactement un `TransportMessage`, y compris les payloads vides et binaires non UTF-8. `RealtimeSender::close()` termine proprement la direction locale du stream primaire. Lorsque le pair a consommé les messages précédents puis atteint le FIN, `RealtimeReceiver::receive()` retourne `TransportReceive::Closed`. La fermeture complète de session, reset, abort, cancellation, deadlines et mapping fin des erreurs restent hors de cette tranche. ## API et documentation `src/lib.rs` réexporte les nouveaux types publics conformément aux règles du workspace. Le README local est réconcilié avec le stream primaire et ses frontières. Un `USAGE.md` durable est ajouté car l'ordre session -> stream primaire -> `RealtimeConnection` et la contrainte d'accept serveur nécessitent désormais un guide d'utilisation distinct du delta. Le plan `005` enregistre les décisions réellement matérialisées sans modifier le forecast de `alpha.4+`. `ROADMAP.md` et `CHANGELOG.md` restent inchangés : cette alpha ne modifie ni la mission macro de `0.3.5` ni une livraison stable. ## Tests Le test unitaire du backend ajoute la preuve que : - la longueur est encodée en `u32` big-endian ; - la borne de frame refuse une taille supérieure à 1 MiB avec `MessageTooLarge`. Le nouveau test d'intégration `tests/realtime_connection.rs` prouve en loopback : - ouverture du stream primaire côté client ; - ouverture cliente puis accept du stream primaire côté serveur avant la première frame applicative ; - adaptation `RealtimeConnection` ; - payload vide ; - payload binaire non UTF-8 ; - ordre de plusieurs messages ; - echo bidirectionnel ; - FIN client observé comme `TransportReceive::Closed` côté serveur ; - FIN serveur observé comme `TransportReceive::Closed` côté client. Les sessions restent vivantes pendant toute la preuve afin que le test ne confonde pas FIN du stream logique et drop de session. ## Fichiers modifiés ```text Cargo.toml README.md crates/common/game-realtime-webtransport-lib/README.md crates/common/game-realtime-webtransport-lib/src/lib.rs crates/common/game-realtime-webtransport-lib/src/webtransport.rs crates/common/game-realtime-webtransport-lib/unit_tests/webtransport.rs docs/plans/005-V0_3_5_WEBTRANSPORT_QUIC_POC_PLAN.md ``` Nouveaux fichiers : ```text crates/common/game-realtime-webtransport-lib/USAGE.md crates/common/game-realtime-webtransport-lib/tests/realtime_connection.rs history/0.3.5/alpha.2.fix.1.md deltas/0.3.5/alpha.3.md ``` Aucune dépendance Cargo n'est ajoutée ou modifiée dans cette tranche. ## Validation exécutée dans l'environnement de génération L'environnement de génération ne possède pas de toolchain Rust. Aucun `cargo fmt`, `cargo check`, Clippy ou test n'est donc attribué à cette livraison. Les audits statiques disponibles ont été exécutés sur le candidat final : ```text General Rust rule audit: clean Rust export completeness audit: 0 candidate(s) games.sasedev workspace audit: clean Markdown table audit: clean (5 table(s), 273 file(s)) Distribution layout audit: clean (50 required path(s), 8 forbidden path(s) absent) ``` Le compteur de fichiers Markdown correspond à la reconstruction de travail issue de l'archive taggée et des deltas fournis. Il n'est pas utilisé comme invariant contre le checkout utilisateur, qui contient davantage de fichiers suivis localement. ## Validation utilisateur demandée Cette tranche modifie le backend Rust et ajoute un test d'intégration. La gate ciblée est : ```bash cargo fmt --all cargo fmt --all -- --check python3 scripts/audit_rust_workspace_rules.py python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates Android Web deltas history python3 scripts/audit_distribution_layout.py cargo check --workspace cargo clippy --workspace --all-targets --all-features -- -D warnings cargo test -p game-realtime-transport-lib --all-targets --all-features cargo test -p game-realtime-webtransport-lib --all-targets --all-features cargo tree -i game-realtime-webtransport-lib --workspace --edges normal ``` Le contrat commun est retesté parce que `alpha.3` en devient un nouvel implémenteur, même si sa crate n'est pas modifiée. Le `cargo tree` inverse vérifie qu'aucune crate moteur ou gameplay n'a acquis de dépendance vers le backend concret. Les arbres complets `web-transport-quinn` de `alpha.2` ne sont pas répétés puisque le graphe de dépendances n'a pas changé. Aucun smoke executable n'est encore attendu : le smoke natif public reste `alpha.5`, après la tranche de robustesse `alpha.4`. ## Suite après validation Si la gate est propre, ouvrir `0.3.5-alpha.4` pour : - limites configurables si justifiées ; - deadlines ; - backpressure/erreurs observables ; - close/reset/abort ; - cancellation/drop ; - cas négatifs de framing ; - mapping d'erreurs détaillé ; - tests de robustesse ciblés. Un défaut fermé de cette tranche produit d'abord `0.3.5-alpha.3.fix.N` au lieu d'ouvrir `alpha.4`.