Files
games/deltas/0.3.5/alpha.8.md
2026-09-22 07:35:17 +02:00

213 lines
6.8 KiB
Markdown

<!-- file: deltas/0.3.5/alpha.8.md -->
<!-- version: 1 -->
# Delta 0.3.5-alpha.8
## Base requise
`0.3.5-alpha.7.fix.2`, validée par l'utilisateur le 2026-09-22.
La gate finale confirme fmt, audits, `cargo check --workspace`, Clippy strict, build WASM de l'adapter browser, génération `wasm-bindgen`, build TypeScript/Vite et smoke WebTransport navigateur réel terminé par :
```text
game-realtime-webtransport-browser-smoke: PASS
```
La preuve complète est enregistrée dans `history/0.3.5/alpha.7.fix.2.md`.
## Objectif
Prouver le fallback WebSocket au niveau composition sans modifier le contrat transport-neutral ni masquer les erreurs sensibles :
- essayer WebTransport en premier ;
- conserver WebTransport lorsqu'il est disponible ;
- basculer vers WebSocket uniquement pour des erreurs explicitement classifiées ;
- forcer une branche fallback déterministe ;
- garder une erreur non-fallback visible ;
- ne créer ni manager générique, ni registry, ni couplage gameplay.
## Version
La version workspace passe à :
```text
0.3.5-alpha.8
```
## Launcher de composition
Nouveau package technique :
```text
crates/apps/game-realtime-transport-fallback-smoke
```
Il dépend directement des deux backends candidats et du contrat commun, mais d'aucun engine ni gameplay.
Le sélecteur reste privé au launcher :
```text
WebTransport attempt
-> success -> WebTransport
-> classified Timeout/Io -> WebSocket attempt
-> any other error -> visible error
```
Aucune API n'est ajoutée à `game-realtime-transport-lib`, `game-realtime-websocket-lib` ou `game-realtime-webtransport-lib`.
## Classification conservative
Le backend WebTransport natif mappe actuellement les erreurs amont d'établissement sous une catégorie `Connect` trop large pour distinguer de manière sûre une indisponibilité réseau d'un problème TLS/pinning.
Pour éviter un downgrade silencieux, `alpha.8` autorise le fallback uniquement pour :
```text
Timeout
Io
```
et refuse explicitement le fallback pour :
```text
InvalidConfiguration
Connect
Bind
Accept
MessageTooLarge
Backpressure
Closed
Protocol
Aborted
```
Cette politique est volontairement plus restrictive qu'un fallback générique sur toute erreur de connexion. Une évolution future pourra élargir la matrice uniquement si le backend expose une classification suffisamment précise pour préserver les erreurs de sécurité/protocole.
## Smoke runtime
Le launcher exécute trois scénarios séquentiels sous une deadline globale de 10 s.
### 1. WebTransport disponible
- serveur WebTransport loopback réel sur port éphémère ;
- identité P-256 en mémoire et pin SHA-256 exact ;
- sélection WebTransport-first ;
- fallback WebSocket volontairement inutilisable si appelé ;
- round-trip binaire dans les deux sens ;
- fermeture propre dans les deux sens.
### 2. Fallback WebSocket forcé
- erreur WebTransport `Timeout` injectée explicitement au point de composition ;
- listener WebSocket loopback réel sur port éphémère ;
- sélection de la branche fallback ;
- round-trip binaire dans les deux sens ;
- fermeture propre dans les deux sens.
L'injection ne simule pas le backend WebSocket : elle force uniquement la cause WebTransport classifiée afin que la branche de sélection soit déterministe et rapide. La connexion fallback et son échange restent réels.
### 3. Erreur non-fallback visible
- vraie `WebTransportClientConfig` avec `connect_timeout = 0` ;
- `game-realtime-webtransport-lib::connect()` retourne `InvalidConfiguration` avant I/O ;
- la branche WebSocket ne doit pas être utilisée ;
- l'erreur exacte `connect_timeout must be greater than zero` doit rester visible.
Le verdict global attendu est :
```text
game-realtime-transport-fallback-smoke: PASS
```
## Tests unitaires
Le binary contient également des tests ciblés qui vérifient :
- la matrice `TransportErrorKind` complète ;
- `Connect` explicitement non éligible ;
- succès WebTransport prioritaire ;
- `Timeout` déclenchant la valeur WebSocket ;
- `InvalidConfiguration` restant inchangée et visible.
## Audit de distribution
`scripts/audit_distribution_layout.py` ajoute les chemins du launcher et vérifie :
- dépendance directe aux deux backends ;
- aucune dépendance engine/gameplay ;
- classification limitée à `Timeout`/`Io` ;
- exclusion explicite de `Connect` ;
- verdict `PASS` déterministe.
## Fichiers modifiés
```text
Cargo.toml
README.md
docs/plans/005-V0_3_5_WEBTRANSPORT_QUIC_POC_PLAN.md
scripts/audit_distribution_layout.py
```
Nouveaux fichiers :
```text
crates/apps/game-realtime-transport-fallback-smoke/Cargo.toml
crates/apps/game-realtime-transport-fallback-smoke/src/main.rs
crates/apps/game-realtime-transport-fallback-smoke/unit_tests/fallback.rs
deltas/0.3.5/alpha.8.md
history/0.3.5/alpha.7.fix.2.md
```
## Validation attendue
```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-websocket-lib --all-targets --all-features
cargo test -p game-realtime-webtransport-lib --all-targets --all-features
cargo test -p game-realtime-transport-fallback-smoke --all-targets --all-features
cargo run -p game-realtime-websocket-smoke
cargo run -p game-realtime-webtransport-smoke
cargo run -p game-realtime-transport-fallback-smoke
cargo tree -p game-realtime-transport-fallback-smoke --edges normal
cargo tree -i game-realtime-websocket-lib --workspace --edges normal
cargo tree -i game-realtime-webtransport-lib --workspace --edges normal
```
Le nouveau smoke doit terminer par :
```text
game-realtime-transport-fallback-smoke: PASS
```
Les graphes inverses peuvent contenir les launchers techniques, mais aucun engine ni crate gameplay ne doit dépendre des backends concrets.
## Contrôles statiques avant livraison
Le candidat a été vérifié côté générateur sans attribuer de résultat Cargo non exécuté :
```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), 286 file(s))
Distribution layout audit: clean (61 required path(s), 8 forbidden path(s) absent)
Cargo.toml parse: clean
```
La compilation, Clippy, les tests et les smokes restent à exécuter dans la gate utilisateur ci-dessus.
## Après validation
Créer `history/0.3.5/alpha.8.md` à partir des sorties réellement fournies, puis ouvrir `0.3.5-alpha.9` pour le POC datagram isolé si cette tranche reste justifiée par l'API/backend réellement disponibles.