0.3.5-alpha.4

This commit is contained in:
2026-09-21 23:37:18 +02:00
parent fd6ffecdf5
commit ce3811f8ec
14 changed files with 1284 additions and 147 deletions

208
deltas/0.3.5/alpha.4.md Normal file
View File

@@ -0,0 +1,208 @@
<!-- file: deltas/0.3.5/alpha.4.md -->
<!-- version: 1 -->
# Delta 0.3.5-alpha.4
## Base requise
`0.3.5-alpha.3`, validée par l'utilisateur le 2026-09-21 avec fmt, audits, check workspace, Clippy strict, les sept tests du contrat realtime commun et les huit tests WebTransport entièrement verts.
La validation réellement fournie est conservée dans `history/0.3.5/alpha.3.md`.
## Objectif
Fermer la robustesse du chemin fiable WebTransport natif avant de créer le smoke runtime public. Cette tranche porte limites/deadlines, lifecycle, cancellation et cas négatifs de framing, sans introduire encore WASM, datagrams, fallback ou benchmark.
La version passe à :
```text
0.3.5-alpha.4
```
## Configuration et limites
Nouveau `WebTransportConfig` partagé par les configs client/server, avec defaults POC explicites :
```text
max_message_size = 1 MiB
connect_timeout = 10 s
primary_stream_timeout = 5 s
send_timeout = 5 s
```
La configuration est immutable par builders copiés et validée avant bind/connect. Sont refusés :
- `max_message_size == 0` ;
- une borne qui ne tient pas dans le champ de longueur `u32` sur les plateformes où cela peut arriver ;
- une deadline nulle.
La borne n'est plus une constante cachée : sender et receiver utilisent chacun la configuration transport associée à leur session. Le receiver contrôle toujours la longueur avant allocation.
## Deadlines et backpressure
Le client borne la tentative d'établissement complète par `connect_timeout`.
Le listener conserve une attente non bornée du prochain pair, comportement normal d'un serveur idle. Une fois la requête WebTransport CONNECT matérialisée, la réponse serveur est bornée par `connect_timeout`.
Ouverture et accept du stream bidirectionnel primaire sont bornés par `primary_stream_timeout`.
Un send complet — header puis payload — est borné par `send_timeout`. La backpressure reste celle du flow-control QUIC : aucune queue applicative artificielle n'est introduite. Si le flow-control empêche l'envoi de terminer dans la deadline, le résultat observable est `TransportErrorKind::Timeout`.
`receive()` n'impose volontairement aucun timeout d'idle. L'absence de message n'est pas une erreur transport ; la future peut être bornée/annulée par l'appelant.
## Cancellation sûre du receive
Le receiver n'utilise plus une lecture monolithique header/payload. Il garde un état incrémental :
```text
header bytes read
payload allocation after validated length
payload bytes read
```
La primitive de lecture amont utilisée est cancel-safe. Si une future `receive()` est abandonnée après une partie de la frame, l'état acquis reste dans `WebTransportReceiver` et l'appel suivant reprend au bon octet.
Cela permet de combiner un wait externe borné avec le contrat `RealtimeReceiver` sans perdre de bytes ni désynchroniser le framing.
## Close, reset, abort et drop
Le FIN propre reste `RealtimeSender::close()`.
Le backend concret expose en complément :
```text
WebTransportSender::abort(code)
WebTransportReceiver::abort(code)
```
Le premier reset la direction d'envoi ; le second stoppe la direction de réception.
Un sender ou receiver encore actif au moment de son drop est aborté explicitement au lieu de laisser le backend transformer implicitement le drop en FIN propre.
Un `send()` annulé en cours d'écriture est terminal : un guard reset le stream, car une frame dont seulement le header ou une partie du payload a été écrit ne peut pas être reprise sans ambiguïté. Une cancellation de `receive()` reste au contraire reprenable grâce au parseur incrémental.
## Framing négatif et mapping d'erreurs
Les nouvelles branches explicites sont :
- longueur entrante supérieure à `max_message_size` -> `MessageTooLarge`, avant allocation, puis stop de la direction ;
- EOF à frontière de frame -> `TransportReceive::Closed` ;
- EOF au milieu du header ou du payload -> `Protocol` ;
- reset/STOP distant -> `Aborted` ;
- stream/session fermé proprement -> `Closed` ;
- état de stream invalide rapporté par le backend -> `Protocol` ;
- deadline dépassée -> `Timeout` ;
- autre erreur de session -> `Io`.
Les types d'erreurs Quinn/WebTransport restent privés à la crate backend.
## Tests
Les tests unitaires ajoutent :
- validation des defaults et configurations invalides ;
- mapping reset/STOP, close et erreur protocolaire ;
- cancellation d'un `receive()` après deux octets de header puis reprise exacte ;
- header ou payload tronqué par FIN -> `Protocol`.
Le nouveau `tests/robustness.rs` prouve en loopback :
- rejet outbound d'un message supérieur à la borne avant écriture ;
- rejet inbound d'une longueur supérieure à la borne avant allocation ;
- reset explicite sender observé comme `Aborted` par le pair ;
- abort explicite receiver rendant immédiatement sa moitié locale terminale ;
- drop sender sans `close()` observé comme `Aborted`, pas comme FIN propre ;
- deadline d'accept du stream primaire lorsque le pair n'en ouvre aucun.
Aucun test de saturation artificielle n'est ajouté : provoquer de façon déterministe le flow-control QUIC sans s'appuyer sur des internals amont élargirait inutilement la tranche. Le mécanisme est borné par `send_timeout` et sera aussi exercé indirectement par les smokes/mesures ultérieurs.
## API et documentation
`src/lib.rs` réexporte `WebTransportConfig` conformément aux règles d'exports du workspace.
`README.md` et `USAGE.md` de la crate documentent les limites, le scope exact des deadlines, les différences FIN/abort/drop et les garanties de cancellation.
Le plan `005` est réconcilié avec les décisions réellement matérialisées. `ROADMAP.md` et `CHANGELOG.md` restent inchangés : la mission macro de `0.3.5` n'est pas modifiée par cette alpha.
## Dépendances
Aucune nouvelle crate n'est introduite.
`tokio`, déjà présent dans le workspace et déjà utilisé comme dev-dependency de la crate, devient aussi une dépendance runtime locale avec la feature `time`, car le backend porte désormais ses deadlines opérationnelles.
## Fichiers modifiés
```text
Cargo.toml
README.md
crates/common/game-realtime-webtransport-lib/Cargo.toml
crates/common/game-realtime-webtransport-lib/README.md
crates/common/game-realtime-webtransport-lib/USAGE.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/src/config.rs
crates/common/game-realtime-webtransport-lib/tests/robustness.rs
crates/common/game-realtime-webtransport-lib/unit_tests/config.rs
history/0.3.5/alpha.3.md
deltas/0.3.5/alpha.4.md
```
## 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), 275 file(s))
Distribution layout audit: clean (50 required path(s), 8 forbidden path(s) absent)
Targeted alpha.4 consistency audit: clean
```
Le compteur Markdown correspond à la reconstruction de travail issue du ZIP taggé et des deltas appliqués ; il n'est pas utilisé comme invariant contre le checkout utilisateur.
Le ZIP delta a ensuite été appliqué sur une copie propre de `0.3.5-alpha.3`. L'overlay reproduit exactement le candidat `alpha.4`, contient 14 fichiers utiles et repasse les mêmes audits Rust/workspace, Markdown et distribution, ainsi que le contrôle ciblé de version/cohérence. `unzip -t` ne signale aucune erreur.
## Validation utilisateur demandée
Cette tranche modifie le backend runtime et son graphe local de features Tokio. 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 -p game-realtime-webtransport-lib --edges normal
cargo tree -i game-realtime-webtransport-lib --workspace --edges normal
```
Le contrat commun est retesté pour garantir que les nouvelles catégories de lifecycle du backend restent compatibles avec son API transport-neutral.
Le tree direct vérifie le passage de Tokio en dépendance runtime locale ; le tree inverse conserve la preuve qu'aucune crate engine/gameplay n'a acquis le backend concret.
Aucun smoke executable n'est attendu dans cette tranche. Le smoke natif hors harness reste strictement réservé à `alpha.5` afin de respecter la taille d'un delta.
## Suite après validation
Si la gate est propre, ouvrir `0.3.5-alpha.5` pour créer/finaliser `game-realtime-webtransport-smoke`, effectuer un round-trip localhost hors `#[test]`, produire un `PASS` déterministe et contrôler le graphe runtime.
Un défaut fermé de cette tranche produit d'abord `0.3.5-alpha.4.fix.N` au lieu d'ouvrir `alpha.5`.