0.3.5-alpha.4
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
<!-- file: docs/plans/005-V0_3_5_WEBTRANSPORT_QUIC_POC_PLAN.md -->
|
||||
<!-- version: 4 -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Plan 0.3.5 — POC WebTransport/QUIC et fallback WebSocket
|
||||
|
||||
## Statut
|
||||
|
||||
Plan actif créé pendant `0.3.5-alpha.1` à partir de l'archive taggée `v0.3.4`, puis réconcilié pour l'implémentation native de `0.3.5-alpha.2`, son correctif de validation `0.3.5-alpha.2.fix.1` et le chemin fiable candidat de `0.3.5-alpha.3`.
|
||||
Plan actif créé pendant `0.3.5-alpha.1` à partir de l'archive taggée `v0.3.4`, puis réconcilié pour l'implémentation native de `0.3.5-alpha.2`, son correctif de validation `0.3.5-alpha.2.fix.1`, le chemin fiable validé de `0.3.5-alpha.3` et la robustesse candidate de `0.3.5-alpha.4`.
|
||||
|
||||
Le cadrage détaillé et la comparaison des stacks actuelles sont conservés dans `docs/studies/026-V0_3_5_WEBTRANSPORT_QUIC_STACK_AUDIT.md`. Le présent document porte les décisions opérationnelles, le scope, les gates et le forecast vivant de la version.
|
||||
|
||||
@@ -92,6 +92,35 @@ Le FIN du stream primaire constitue la fermeture logique de base de `alpha.3` et
|
||||
|
||||
`web-transport-quinn` écrit l'en-tête WebTransport du stream durant `open_bi()` avant de rendre le stream au code appelant. L'accept serveur peut donc terminer avant la première frame applicative ; le framing games.sasedev commence directement au premier octet applicatif et n'ajoute aucun préambule de visibilité.
|
||||
|
||||
La gate utilisateur de `alpha.3` a ensuite confirmé fmt, audits, check workspace, Clippy strict, les sept tests du contrat commun, les sept tests unitaires/établissement WebTransport déjà présents et le round-trip primaire dédié. Le graphe inverse confirme aussi que `game-realtime-webtransport-lib` reste un backend feuille et ne remonte pas dans engine/gameplay.
|
||||
|
||||
### Fermeture robustesse et lifecycle en alpha.4
|
||||
|
||||
`alpha.4` remplace la borne interne figée par `WebTransportConfig`, partagé par les configs client/server. Les valeurs par défaut restent volontairement conservatrices pour le POC : 1 MiB par message, 10 s pour la connexion/fin de réponse CONNECT, 5 s pour l'ouverture ou l'accept du stream primaire et 5 s pour un envoi complet. Les valeurs nulles ou une taille incompatible avec le champ de longueur `u32` sont rejetées avant démarrage.
|
||||
|
||||
La notion de deadline est volontairement opérationnelle et non un timeout d'inactivité global :
|
||||
|
||||
- le client borne l'établissement de session ;
|
||||
- côté serveur, l'attente du prochain pair reste non bornée comme un listener normal, puis la réponse WebTransport après matérialisation de la requête CONNECT est bornée ;
|
||||
- ouverture/accept du stream primaire sont bornés ;
|
||||
- un envoi header + payload est borné, de sorte qu'un blocage durable sous flow-control/backpressure devient un `TransportErrorKind::Timeout` visible ;
|
||||
- `receive()` n'a pas de timeout d'idle implicite : l'absence de message n'est pas une panne de transport et l'appelant peut annuler sa future sans perdre l'état du framing.
|
||||
|
||||
Le receiver utilise donc un parseur incrémental persistant fondé sur la lecture cancel-safe du backend. Une future `receive()` abandonnée après une partie du header ou du payload peut être relancée et reprend au bon octet. EOF au milieu d'une frame devient `Protocol`, tandis qu'un EOF à frontière de frame reste `TransportReceive::Closed`. Une longueur supérieure à la borne est refusée avant allocation puis la direction de réception est stoppée.
|
||||
|
||||
Le lifecycle distingue désormais explicitement FIN propre et abandon :
|
||||
|
||||
- `RealtimeSender::close()` émet le FIN propre ;
|
||||
- `WebTransportSender::abort(code)` reset la direction d'envoi ;
|
||||
- `WebTransportReceiver::abort(code)` stoppe la direction de réception ;
|
||||
- drop d'un sender/receiver encore actif provoque reset/stop au lieu de synthétiser une fermeture propre ;
|
||||
- cancellation d'un `send()` en cours arme un guard terminal qui reset le stream, car une frame partiellement écrite ne peut pas être reprise sans ambiguïté ;
|
||||
- cancellation d'un `receive()` reste non terminale grâce au parseur incrémental.
|
||||
|
||||
Les erreurs amont restent confinées au backend : reset/STOP observables -> `Aborted`, FIN/stream/session fermé proprement -> `Closed`, framing/état de stream invalide -> `Protocol`, dépassement -> `MessageTooLarge`, deadline -> `Timeout`, et autres erreurs de session -> `Io`. Aucun type Quinn/WebTransport n'entre dans `game-realtime-transport-lib`.
|
||||
|
||||
Aucune file applicative n'est ajoutée pour fabriquer artificiellement `Backpressure` : la pression est celle du flow-control QUIC. Lorsqu'elle empêche un envoi de terminer dans sa deadline, l'erreur observable est `Timeout`. Un test synthétique de saturation n'est pas imposé tant qu'il ne peut pas être rendu déterministe sans dépendre d'internals amont.
|
||||
|
||||
### Ownership physique
|
||||
|
||||
Nouveau backend durable candidat :
|
||||
@@ -397,7 +426,7 @@ Pas encore d'implémentation complète `RealtimeConnection` si cela rend la tran
|
||||
|
||||
### `0.3.5-alpha.3` — stream fiable et contrat commun
|
||||
|
||||
Tranche candidate matérialisée avec :
|
||||
Tranche validée avec :
|
||||
|
||||
- stream bidirectionnel principal ;
|
||||
- framing `u32 + payload` borné avant allocation ;
|
||||
@@ -408,18 +437,25 @@ Tranche candidate matérialisée avec :
|
||||
- tests loopback ciblés ;
|
||||
- `USAGE.md` pour la séquence session -> stream primaire -> contrat commun.
|
||||
|
||||
La gate utilisateur reste requise avant d'ouvrir `alpha.4`.
|
||||
La gate utilisateur du 2026-09-21 est conservée dans `history/0.3.5/alpha.3.md`.
|
||||
|
||||
### `0.3.5-alpha.4` — robustesse et lifecycle
|
||||
|
||||
- limites ;
|
||||
- deadlines ;
|
||||
- backpressure/erreurs observables ;
|
||||
- close/reset/abort ;
|
||||
- cancellation/drop ;
|
||||
- cas négatifs de framing ;
|
||||
- mapping d'erreurs ;
|
||||
- tests de robustesse ciblés.
|
||||
Tranche candidate matérialisée avec :
|
||||
|
||||
- `WebTransportConfig` et borne de message configurable, validée avant démarrage ;
|
||||
- deadlines de connexion/réponse CONNECT, stream primaire et send ;
|
||||
- flow-control QUIC conservé comme backpressure naturelle, avec timeout observable si un send reste bloqué ;
|
||||
- FIN propre distinct des reset/stop explicites ;
|
||||
- drop actif -> abort au lieu de FIN synthétique ;
|
||||
- cancellation d'un send partiel -> reset terminal ;
|
||||
- receive incrémental cancel-safe et reprenable ;
|
||||
- EOF au milieu d'une frame et framing invalide -> `Protocol` ;
|
||||
- dépassement entrant refusé avant allocation ;
|
||||
- mapping backend -> `Timeout`, `MessageTooLarge`, `Closed`, `Protocol`, `Aborted` ou `Io` ;
|
||||
- tests ciblés sur limites, reset/drop, deadline du stream, cancellation de receive et frame tronquée.
|
||||
|
||||
Un timeout d'idle de `receive()` n'est volontairement pas imposé au contrat : l'appelant peut borner/annuler l'attente sans corrompre l'état du frame parser. Un test artificiel de saturation/backpressure n'est pas ajouté tant qu'il n'est pas déterministe. La gate utilisateur reste requise avant d'ouvrir `alpha.5`.
|
||||
|
||||
### `0.3.5-alpha.5` — smoke natif hors harness
|
||||
|
||||
|
||||
Reference in New Issue
Block a user