v0.2.7-pre.006
This commit is contained in:
287
deltas/0.2.7/pre.006.md
Normal file
287
deltas/0.2.7/pre.006.md
Normal file
@@ -0,0 +1,287 @@
|
||||
<!-- file: deltas/0.2.7/pre.006.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.7-pre.006` — registry subscriptions + IDs locaux + moteur typed générique
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
```text
|
||||
0.2.7-pre.005 appliqué
|
||||
workspace.package.version = 0.2.7-pre.5
|
||||
```
|
||||
|
||||
Le checkpoint opérateur reçu avant cette tranche est vert : `cargo fmt --all`, audit Python, `cargo check --workspace`, `cargo clippy --workspace --all-targets`, `cargo test -p ksp-onchain-transport-lib` et `cargo test --workspace`. Les 269 tests unitaires Transport de `pre.005` passent.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Cette tranche ajoute le registry de subscriptions au même actor que le socket et la pending map JSON-RPC, sans avancer sur reconnect/resubscribe.
|
||||
|
||||
Objectifs matérialisés :
|
||||
|
||||
```text
|
||||
1 session physique
|
||||
-> 0..N subscriptions logiques
|
||||
-> WsSubscriptionId local stable
|
||||
-> remote subscription id interne/transient
|
||||
-> channel de notifications typed et bounded
|
||||
```
|
||||
|
||||
La création générique de subscription reste crate-private jusqu'aux wrappers standard publics des lots `pre.009+`.
|
||||
|
||||
## 3. Signal technique
|
||||
|
||||
Cette prerelease modifie le runtime Rust, les tests et la documentation. Conformément aux règles KSP :
|
||||
|
||||
```text
|
||||
livraison = 0.2.7-pre.006
|
||||
workspace.package.version = 0.2.7-pre.6
|
||||
commit = v0.2.7-pre.006
|
||||
```
|
||||
|
||||
Aucun tag prerelease.
|
||||
|
||||
## 4. Registry actor-owned
|
||||
|
||||
Le même actor possède maintenant :
|
||||
|
||||
```text
|
||||
socket physique
|
||||
request counter
|
||||
pending JSON-RPC map
|
||||
subscription local counter
|
||||
subscription registry local
|
||||
remote_subscription_id -> WsSubscriptionId
|
||||
safe snapshots
|
||||
```
|
||||
|
||||
Le registry local est ordonné par local ID. Les IDs locaux sont assignés par l'actor et ne dépendent jamais du remote ID retourné par Solana.
|
||||
|
||||
Le remote ID reste absent de l'API publique, de `Debug`, des snapshots et des logs. Seul `remote_bound: bool` reste projeté par `WsSubscriptionSnapshot`.
|
||||
|
||||
## 5. Binding subscribe atomique
|
||||
|
||||
Le subscribe n'est pas implémenté comme :
|
||||
|
||||
```text
|
||||
execute_json_rpc
|
||||
puis register local
|
||||
```
|
||||
|
||||
car une notification pourrait alors arriver entre les deux opérations.
|
||||
|
||||
`pre.006` ajoute une command actor `Subscribe`. Le pending request conserve le local ID et le dispatcher typed. Lorsque la réponse `*Subscribe` est reçue :
|
||||
|
||||
1. la réponse JSON-RPC est validée ;
|
||||
2. le remote ID numérique est validé ;
|
||||
3. l'unicité du remote ID actif est vérifiée ;
|
||||
4. le remote ID est lié au local ID ;
|
||||
5. la subscription passe `Requested -> Active` ;
|
||||
6. seulement ensuite le handle typed est rendu au caller.
|
||||
|
||||
Le prochain message socket ne peut donc pas être dispatché avant la mise à jour du mapping actor-owned.
|
||||
|
||||
## 6. `WsSubscription<T>`
|
||||
|
||||
Nouvelle surface publique commune :
|
||||
|
||||
```text
|
||||
WsSubscription<T>
|
||||
id() -> WsSubscriptionId
|
||||
kind() -> WsSubscriptionKind
|
||||
state() -> WsSubscriptionState
|
||||
recv().await -> Option<Result<T>>
|
||||
unsubscribe().await -> Result<bool>
|
||||
```
|
||||
|
||||
Le receiver de notifications est borné par `notification_queue_capacity`.
|
||||
|
||||
La création `WsSession::subscribe_typed(...)` reste `pub(crate)` : elle sera consommée par les wrappers typed standard et ne crée pas de surface raw provider-extension publique.
|
||||
|
||||
## 7. Dispatch notifications
|
||||
|
||||
Pour une notification Solana standard :
|
||||
|
||||
```text
|
||||
JSON-RPC notification
|
||||
-> params.subscription remote u64
|
||||
-> remote_to_local
|
||||
-> WsSubscriptionRuntime
|
||||
-> validation notification method
|
||||
-> decoder typed
|
||||
-> bounded typed channel
|
||||
```
|
||||
|
||||
Le mapping exact famille/méthodes est centralisé sur `WsSubscriptionKind` pour les neuf familles :
|
||||
|
||||
```text
|
||||
account
|
||||
block
|
||||
logs
|
||||
program
|
||||
root
|
||||
signature
|
||||
slot
|
||||
slotsUpdates
|
||||
vote
|
||||
```
|
||||
|
||||
Chaque famille possède son triplet exact `*Subscribe`, `*Unsubscribe`, `*Notification`.
|
||||
|
||||
## 8. Anomalies isolées
|
||||
|
||||
Politique matérialisée dans cette tranche :
|
||||
|
||||
- remote ID inconnu/stale : safe drop + diagnostic sûr, session inchangée ;
|
||||
- notification method incompatible avec la famille enregistrée : subscription `Failed`, session reste `Active` ;
|
||||
- typed decoder failure : erreur livrée au channel lorsque possible, subscription `Failed`, session reste `Active` ;
|
||||
- queue typed déjà pleine : aucune perte silencieuse considérée normale, subscription terminale ; le compteur/cleanup adversarial complet est finalisé en `pre.008` ;
|
||||
- malformed JSON / structure JSON-RPC invalide : reste une anomalie de session selon le contrat acquis.
|
||||
|
||||
Aucun reconnect n'est déclenché par une erreur RPC applicative ou une erreur typed locale.
|
||||
|
||||
## 9. Unsubscribe
|
||||
|
||||
`WsSubscription<T>::unsubscribe()` ne reçoit jamais le remote ID du caller.
|
||||
|
||||
L'actor :
|
||||
|
||||
1. marque la subscription `Cancelling` ;
|
||||
2. retire immédiatement le remote ID du mapping de dispatch local ;
|
||||
3. construit le `*Unsubscribe` exact avec le remote ID interne ;
|
||||
4. valide la réponse booléenne ;
|
||||
5. publie `Closed` et ferme le channel local.
|
||||
|
||||
Le booléen standard Solana est préservé au caller afin de ne pas perdre une variante de réponse pertinente.
|
||||
|
||||
Les races unsubscribe/reconnect et le principe « local cancellation wins » sous reconnexion restent le scope explicite de `pre.007`.
|
||||
|
||||
## 10. Tests déterministes
|
||||
|
||||
Ajouts principaux :
|
||||
|
||||
```text
|
||||
subscribe slot -> remote binding -> notification typed -> unsubscribe exact
|
||||
2 familles -> 2 IDs locaux ordonnés + remote IDs indépendants
|
||||
unknown remote ID -> notification suivante valide toujours dispatchée
|
||||
notification method mismatch -> seule la subscription échoue
|
||||
typed decode error -> erreur receiver + seule la subscription échoue
|
||||
triplets exacts des 9 familles standard
|
||||
public API canary WsSubscription<T>
|
||||
```
|
||||
|
||||
Le serveur reste exclusivement local et déterministe. Aucun réseau Solana réel n'est requis.
|
||||
|
||||
## 11. Logging et sécurité
|
||||
|
||||
Toutes les émissions passent exclusivement par `ksp-logging-lib` avec :
|
||||
|
||||
```text
|
||||
TRACING_TARGET = "ksp-onchain-transport-lib"
|
||||
```
|
||||
|
||||
Les diagnostics n'exposent que :
|
||||
|
||||
```text
|
||||
session_id
|
||||
subscription_id local
|
||||
subscription_kind
|
||||
endpoint logique
|
||||
counts/états sûrs
|
||||
```
|
||||
|
||||
Aucun remote subscription ID n'est journalisé comme identité métier, et aucune URL, credential ou notification brute n'est loggée.
|
||||
|
||||
## 12. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-onchain-transport-lib/src/ws_subscription.rs
|
||||
deltas/0.2.7/pre.006.md
|
||||
```
|
||||
|
||||
## 13. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/USAGE.md
|
||||
crates/ksp-onchain-transport-lib/src/lib.rs
|
||||
crates/ksp-onchain-transport-lib/src/ws_lifecycle.rs
|
||||
crates/ksp-onchain-transport-lib/src/ws_session.rs
|
||||
crates/ksp-onchain-transport-lib/tests/public_api.rs
|
||||
crates/ksp-onchain-transport-lib/unit_tests/ws_lifecycle.rs
|
||||
crates/ksp-onchain-transport-lib/unit_tests/ws_session.rs
|
||||
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
|
||||
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
|
||||
```
|
||||
|
||||
## 14. Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
`ROADMAP.md` et `CHANGELOG.md` restent inchangés pendant la série prerelease.
|
||||
|
||||
## 15. Validation exécutée dans le sandbox
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
```
|
||||
|
||||
Contrôles statiques supplémentaires :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.7-pre.6
|
||||
tracing direct = absent
|
||||
question-mark runtime = absent
|
||||
remote ID public = absent
|
||||
lignes Rust > 160 ajoutées = absentes
|
||||
```
|
||||
|
||||
## 16. Validation non exécutée dans le sandbox
|
||||
|
||||
Cargo/rustfmt ne sont pas disponibles dans le sandbox de génération. Aucun résultat local n'est revendiqué pour :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-onchain-transport-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
## 17. Gates opérateur avant commit
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-onchain-transport-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Si le checkpoint est vert :
|
||||
|
||||
```text
|
||||
commit = v0.2.7-pre.006
|
||||
```
|
||||
|
||||
La tranche suivante est `0.2.7-pre.007` : reconnect borné, resubscribe déterministe, continuity gap et races unsubscribe/reconnect.
|
||||
|
||||
## 18. Décisions / questions ouvertes
|
||||
|
||||
Décisions :
|
||||
|
||||
- le registry et le mapping remote/local appartiennent exclusivement à l'actor ;
|
||||
- le local ID est stable et le remote ID est transient/interne ;
|
||||
- la création générique typed reste crate-private ;
|
||||
- le handle typed public possède le receiver et l'unsubscribe ;
|
||||
- une anomalie typed connue ne doit pas faire tomber la session physique ;
|
||||
- aucune promesse lossless n'est introduite.
|
||||
|
||||
Questions laissées aux tranches suivantes :
|
||||
|
||||
- `pre.007` finalise la restauration déterministe après reconnexion et les races cancellation/ACK ;
|
||||
- `pre.008` finalise overflow counters, cleanup best-effort et leak/lifecycle adversarial sous slow consumer.
|
||||
Reference in New Issue
Block a user