v0.2.8-pre.004-fix.001

This commit is contained in:
2026-08-23 14:20:24 +02:00
parent f2a3ec62aa
commit 38fd62c256
8 changed files with 402 additions and 62 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml
# version: 221
# version: 222
[workspace]
resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
[workspace.package]
version = "0.2.8-pre.4"
version = "0.2.8-pre.4.fix.1"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -102,6 +102,47 @@
}
}
]
},
{
"profile_id": "devnet_helius",
"endpoints": [
{
"name": "devnet_public",
"enabled": true,
"provider": "solana-public",
"cluster": "devnet",
"url": "${KSP_PUBLIC_SOLANA_DEVNET_HTTP_URL:-https://api.devnet.solana.com}",
"connect_timeout_ms": 5000,
"request_timeout_ms": 15000,
"max_idle_connections_per_host": 8,
"roles": [
{
"role": "default",
"enabled": true,
"request_kinds": [
"*"
],
"priority": 100,
"limits": {
"requests_per_second": 5,
"burst_capacity": 10,
"max_concurrent_requests": 8,
"pause_after_rate_limit_ms": 1000
}
}
]
}
],
"ws_endpoints": [
{
"name": "devnet_helius_ws",
"enabled": true,
"provider": "helius",
"cluster": "devnet",
"kind": "helius_laserstream",
"url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}"
}
]
}
]
}

View File

@@ -1,5 +1,5 @@
<!-- file: crates/ksp-config-lib/USAGE.md -->
<!-- version: 9 -->
<!-- version: 11 -->
# Utilisation de ksp-config-lib
@@ -142,7 +142,7 @@ let _ = (http_settings, ws_settings);
`std.transport` V2 conserve `retry` et `profiles[].endpoints[]` pour HTTP, ajoute `ws_defaults` et `profiles[].ws_endpoints[]`, puis accepte les protocoles WebSocket `kind = "solana_standard"` et `kind = "helius_laserstream"`. Ce second discriminateur appartient exclusivement au namespace WebSocket et mappe vers `WsProtocolKind::HeliusLaserStream`; il ne préfigure aucun contrat LaserStream gRPC. Un `ws_endpoints[].session` optionnel surcharge seulement les paramètres génériques de `WsSessionSettings`.
Pour Helius LaserStream WebSocket, l'exemple versionné compose l'URL provider avec `${KSP_SECRET_HELIUS_API_KEY:-replace-me}`. Config reste l'unique propriétaire de cette variable : il résout la clé dans l'URL effective, transmet au Transport un `WsEndpointUrl` utilisable au runtime et redige la valeur dans la projection sûre et les représentations `Debug`. Transport ne lit jamais directement l'environnement.
Pour Helius LaserStream WebSocket, l'exemple versionné couvre explicitement les deux réseaux supportés par ce contrat : mainnet via `wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}` et devnet via `wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}`. Les deux réseaux vivent dans des profils Config distincts afin de ne pas mélanger des clusters dans un même profil logique. Config reste l'unique propriétaire de `KSP_SECRET_HELIUS_API_KEY` : il résout la clé dans l'URL effective et transmet au Transport un `WsEndpointUrl` utilisable au runtime. Dans `safe_value`, Config conserve les segments littéraux non sensibles d'une chaîne composée et remplace uniquement chaque segment secret par `********` ; les projections deviennent donc respectivement `wss://mainnet.helius-rpc.com/?api-key=********` et `wss://devnet.helius-rpc.com/?api-key=********`. Les représentations `Debug` restent sûres et n'exposent jamais la clé réelle. Transport ne lit jamais directement l'environnement.
Le même schema enregistré conserve la lecture stricte du V1 historique : dans ce cas `http_settings()` reste disponible et `ws_settings()` retourne `None`. Aucun `WsTransportSettings` vide n'est inventé pour simuler l'absence de WebSocket.

View File

@@ -81,6 +81,47 @@
"url": "wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}"
}
]
},
{
"profile_id": "helius_devnet",
"endpoints": [
{
"name": "fixture_devnet_http",
"enabled": true,
"provider": "solana-public",
"cluster": "devnet",
"url": "https://api.devnet.solana.com",
"connect_timeout_ms": 750,
"request_timeout_ms": 2500,
"max_idle_connections_per_host": 3,
"roles": [
{
"role": "default",
"enabled": true,
"request_kinds": [
"*"
],
"priority": 7,
"limits": {
"requests_per_second": 9,
"burst_capacity": 12,
"max_concurrent_requests": 4,
"pause_after_rate_limit_ms": 650
}
}
]
}
],
"ws_endpoints": [
{
"name": "fixture_helius_devnet_ws",
"enabled": true,
"provider": "helius",
"cluster": "devnet",
"kind": "helius_laserstream",
"url": "wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-fixture-helius-key}"
}
]
}
]
}

View File

@@ -267,7 +267,7 @@ fn secret_websocket_url_is_runtime_available_but_safe_projection_is_redacted() {
}
#[test]
fn helius_laserstream_secret_api_key_maps_to_provider_protocol_and_safe_redaction() {
fn helius_laserstream_mainnet_and_devnet_api_key_map_to_protocol_and_safe_redaction() {
let engine = fixture_engine();
let engine = match engine {
std::result::Result::Ok(value) => value,
@@ -277,33 +277,63 @@ fn helius_laserstream_secret_api_key_maps_to_provider_protocol_and_safe_redactio
let mut process = std::collections::BTreeMap::<String, String>::new();
process.insert("KSP_SECRET_HELIUS_API_KEY".to_owned(), canary.to_owned());
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
let resolved = engine.load_resolved_transport_config(std::option::Option::None, &environment);
assert!(resolved.is_ok(), "Helius LaserStream WebSocket endpoint should map without exposing its API key: {resolved:?}");
let resolved = match resolved {
let mainnet = engine.load_resolved_transport_config(std::option::Option::None, &environment);
assert!(mainnet.is_ok(), "Helius mainnet WebSocket endpoint should map without exposing its API key: {mainnet:?}");
let mainnet = match mainnet {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let ws = resolved.ws_settings();
assert!(ws.is_some(), "V2 fixture should expose WebSocket settings");
if let std::option::Option::Some(ws) = ws {
let mainnet_ws = mainnet.ws_settings();
assert!(mainnet_ws.is_some(), "V2 fixture should expose mainnet WebSocket settings");
if let std::option::Option::Some(ws) = mainnet_ws {
assert_eq!(ws.endpoints().len(), 2);
let endpoint = &ws.endpoints()[1];
assert_eq!(endpoint.provider().as_str(), "helius");
assert_eq!(endpoint.cluster().as_str(), "mainnet-beta");
assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream);
assert_eq!(endpoint.url().as_str(), "wss://mainnet.helius-rpc.com/?api-key=helius-api-key-canary");
}
let safe_url = resolved.effective().safe_value().pointer("/ws_endpoints/1/url").and_then(serde_json::Value::as_str);
assert_eq!(safe_url, std::option::Option::Some(crate::REDACTED_CONFIG_VALUE));
let provenance = resolved.effective().provenance_at("/ws_endpoints/1/url");
assert!(provenance.is_some(), "Helius endpoint URL should retain secret environment provenance");
if let std::option::Option::Some(provenance) = provenance {
let mainnet_safe_url = mainnet.effective().safe_value().pointer("/ws_endpoints/1/url").and_then(serde_json::Value::as_str);
assert_eq!(mainnet_safe_url, std::option::Option::Some("wss://mainnet.helius-rpc.com/?api-key=********"));
let mainnet_provenance = mainnet.effective().provenance_at("/ws_endpoints/1/url");
assert!(mainnet_provenance.is_some(), "Helius mainnet endpoint URL should retain secret environment provenance");
if let std::option::Option::Some(provenance) = mainnet_provenance {
assert_eq!(provenance.len(), 1);
assert_eq!(provenance[0].environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process));
assert_eq!(provenance[0].variable_name(), std::option::Option::Some("KSP_SECRET_HELIUS_API_KEY"));
}
let debug = format!("{resolved:?}");
assert!(!debug.contains(canary));
assert!(debug.contains(crate::REDACTED_CONFIG_VALUE));
let devnet = engine.load_resolved_transport_config(std::option::Option::Some("helius_devnet"), &environment);
assert!(devnet.is_ok(), "Helius devnet WebSocket endpoint should map without exposing its API key: {devnet:?}");
let devnet = match devnet {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let devnet_ws = devnet.ws_settings();
assert!(devnet_ws.is_some(), "V2 fixture should expose devnet WebSocket settings");
if let std::option::Option::Some(ws) = devnet_ws {
assert_eq!(ws.endpoints().len(), 1);
let endpoint = &ws.endpoints()[0];
assert_eq!(endpoint.provider().as_str(), "helius");
assert_eq!(endpoint.cluster().as_str(), "devnet");
assert_eq!(endpoint.protocol(), ksp_onchain_transport_lib::WsProtocolKind::HeliusLaserStream);
assert_eq!(endpoint.url().as_str(), "wss://devnet.helius-rpc.com/?api-key=helius-api-key-canary");
let _connect_future = ksp_onchain_transport_lib::HeliusLaserStreamWsSession::connect(endpoint.clone());
}
let devnet_safe_url = devnet.effective().safe_value().pointer("/ws_endpoints/0/url").and_then(serde_json::Value::as_str);
assert_eq!(devnet_safe_url, std::option::Option::Some("wss://devnet.helius-rpc.com/?api-key=********"));
let devnet_provenance = devnet.effective().provenance_at("/ws_endpoints/0/url");
assert!(devnet_provenance.is_some(), "Helius devnet endpoint URL should retain secret environment provenance");
if let std::option::Option::Some(provenance) = devnet_provenance {
assert_eq!(provenance.len(), 1);
assert_eq!(provenance[0].environment_source(), std::option::Option::Some(crate::ConfigEnvironmentSource::Process));
assert_eq!(provenance[0].variable_name(), std::option::Option::Some("KSP_SECRET_HELIUS_API_KEY"));
}
let mainnet_debug = format!("{mainnet:?}");
let devnet_debug = format!("{devnet:?}");
assert!(!mainnet_debug.contains(canary));
assert!(!devnet_debug.contains(canary));
assert!(mainnet_debug.contains(crate::REDACTED_CONFIG_VALUE));
assert!(devnet_debug.contains(crate::REDACTED_CONFIG_VALUE));
}
#[test]

View File

@@ -0,0 +1,182 @@
<!-- file: deltas/0.2.8/pre.004-fix.001.md -->
<!-- version: 2 -->
# Delta `0.2.8-pre.004-fix.001` — redaction Helius Config + couverture Devnet
## 1. Objet
Ce fix corrige deux défauts circonscrits de `0.2.8-pre.004` :
```text
1. faux négatif du nouveau canari de redaction `safe_value` Helius ;
2. représentation déterministe incomplète : mainnet était matérialisé, Devnet ne l'était pas encore.
```
Le résolveur Config, le mapping Config -> Transport et le moteur WebSocket restent inchangés.
Version workspace :
```text
0.2.8-pre.4.fix.1
```
Livraison / commit attendu :
```text
0.2.8-pre.004-fix.001
v0.2.8-pre.004-fix.001
```
Aucun tag prerelease.
## 2. Preuve opérateur ayant déclenché le fix
Le checkpoint `pre.004` reçu le 2026-08-23 donne :
```text
cargo fmt --all OK
python3 scripts/audit_rust_workspace_rules.py clean
cargo check --workspace OK
cargo clippy --workspace --all-targets OK
cargo test -p ksp-config-lib FAIL 109/110
cargo test -p ksp-onchain-transport-lib OK
cargo test --workspace FAIL sur le même test Config
```
L'échec exact est :
```text
observé = wss://mainnet.helius-rpc.com/?api-key=********
attendu = ********
```
Le test avait déjà prouvé avant cette assertion que le schema accepte `helius_laserstream`, que l'adapter produit `WsProtocolKind::HeliusLaserStream` et que l'URL runtime contient la clé Helius résolue.
## 3. Redaction Config confirmée
Le contrat historique Config est segmentaire pour une chaîne composée :
```text
source composée safe_value
https://rpc.example/?token=${SECRET} -> https://rpc.example/?token=********
token=${SECRET} -> token=********
```
La projection sûre conserve donc les littéraux non sensibles et masque uniquement le segment secret.
Pour Helius :
```text
mainnet runtime = wss://mainnet.helius-rpc.com/?api-key=<clé réelle>
mainnet safe_value = wss://mainnet.helius-rpc.com/?api-key=********
devnet runtime = wss://devnet.helius-rpc.com/?api-key=<clé réelle>
devnet safe_value = wss://devnet.helius-rpc.com/?api-key=********
```
La clé réelle doit rester absente de `safe_value` et de toutes les représentations `Debug`.
## 4. Couverture Helius Devnet ajoutée
La documentation Helius WebSocket actuelle expose un endpoint unifié par réseau :
```text
mainnet wss://mainnet.helius-rpc.com/?api-key=<api-key>
devnet wss://devnet.helius-rpc.com/?api-key=<api-key>
```
`pre.004` avait documenté les deux réseaux dans le plan mais n'avait matérialisé que mainnet dans l'exemple et la fixture Config. Le fix complète ce manque.
Décision de structure :
```text
mainnet et devnet vivent dans des profils Config distincts ;
un même profil logique ne mélange pas les deux clusters ;
la même variable KSP_SECRET_HELIUS_API_KEY peut alimenter les deux URLs ;
config/std.transport.json reste standard-only.
```
L'exemple versionné ajoute un profil `devnet_helius`. La fixture Config ajoute un profil `helius_devnet` et le test charge explicitement ce profil en plus du profil mainnet par défaut.
## 5. Correction du test
Le canari devient :
```text
helius_laserstream_mainnet_and_devnet_api_key_map_to_protocol_and_safe_redaction
```
Il vérifie pour **mainnet et devnet** :
```text
provider = helius
cluster exact
protocol = WsProtocolKind::HeliusLaserStream
URL runtime exacte avec la clé résolue
safe_value exact avec segment ********
provenance = KSP_SECRET_HELIUS_API_KEY / Process
Debug sans la clé réelle
composition avec HeliusLaserStreamWsSession au moins sur le profil Devnet dédié
```
## 6. Invariants non modifiés
Aucune modification n'est apportée à :
```text
ConfigEnvironment / moteur de résolution
sensitivity / provenance semantics
JSON Schema Transport V2
mapping helius_laserstream -> HeliusLaserStream
WsEndpointUrl
WsSession / façades / actor
config/std.transport.json canonique
transactionSubscribe
heartbeat
new dependency
```
`.env.example` conserve une seule variable `KSP_SECRET_HELIUS_API_KEY`, suffisante pour les deux endpoints Helius.
## 7. Fichiers de la livraison
Nouveau :
```text
deltas/0.2.8/pre.004-fix.001.md
```
Modifiés :
```text
Cargo.toml
config/examples/std.transport.example.json
crates/ksp-config-lib/unit_tests/fixtures/std.transport.json
crates/ksp-config-lib/unit_tests/transport.rs
crates/ksp-config-lib/USAGE.md
docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md
docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md
```
Inchangés volontairement :
```text
config/std.transport.json
config/schemas/std.transport.schema.json
.env.example
Transport WebSocket runtime
```
## 8. Validation à rejouer
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-config-lib
cargo test -p ksp-onchain-transport-lib
cargo test --workspace
```
`pre.004` + `fix.001` restent non fermés jusqu'à réception de ce checkpoint intégralement vert.

View File

@@ -1,9 +1,9 @@
<!-- file: docs/plans/015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md -->
<!-- version: 9 -->
<!-- version: 11 -->
# Plan `0.2.8` — Helius LaserStream WebSocket
> **Statut : `0.2.8-pre.003` est validé ; `0.2.8-pre.004` est préparé.** La façade `HeliusLaserStreamWsSession` possède désormais sa surface standard 6/6 validée. `pre.004` étend uniquement Config V2 au discriminateur WebSocket `helius_laserstream`, ajoute la fixture/exemple Helius et verrouille la résolution/redaction de `KSP_SECRET_HELIUS_API_KEY`, sans ouvrir `transactionSubscribe`.
> **Statut : `0.2.8-pre.003` est validé ; le checkpoint `0.2.8-pre.004` a révélé un faux négatif de test, puis la revue du fix a identifié l'omission d'une représentation Devnet Helius déterministe. `pre.004-fix.001` corrige les deux points et reste préparé.** Le runtime Config/Transport est inchangé : pour une chaîne composée, `safe_value` conserve les segments littéraux non sensibles et remplace uniquement le segment secret par `********`. Le fix couvre désormais mainnet et devnet sans ouvrir `transactionSubscribe`.
## 1. Objet, base et état courant
@@ -27,10 +27,11 @@ pre.001-fix.002 forecast compact + namespace LaserStream WS/gRPC
pre.002 socle protocolaire validé
pre.002-fix.001 correction Clippy + normalisation structure documentaire validées
pre.003 six familles standard Helius validées
pre.004 Config V2 Helius + secret/redaction préparés
pre.004 Config V2 Helius implémenté ; checkpoint bloqué par un faux négatif de test
pre.004-fix.001 correction safe_value + couverture Devnet Helius préparées
workspace.package.version courant = 0.2.8-pre.4
commit attendu = v0.2.8-pre.004
workspace.package.version courant = 0.2.8-pre.4.fix.1
commit attendu = v0.2.8-pre.004-fix.001
aucun tag prerelease
```
@@ -50,8 +51,10 @@ pre.002 DONE — socle protocolaire : WsProtocolKind::HeliusLaserStream + faça
fix.001 DONE — correction Clippy `implicit_return` + audit/normalisation structure docs
pre.003 DONE — surface Helius standard supportée : account/logs/program/root/signature/slot
+ absence typée de block/slotsUpdates/vote sur Helius + non-régression standard 9/9
pre.004 PREPARED — Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport
+ stratégie de secret Helius et redaction URL
pre.004 CHECKPOINT — Config V2 helius_laserstream + schema/fixtures + mapping Config -> Transport
+ stratégie de secret Helius et redaction URL ; runtime/check/clippy/Transport verts
fix.001 PREPARED — corrige le faux négatif `safe_value` + complète la représentation Devnet Helius
+ mainnet/devnet dans des profils distincts, même secret, sans changement runtime
pre.005 transactionSubscribe request typed + filters/options/tokenAccounts + transactionUnsubscribe
+ bounds 50k + maxSupportedTransactionVersion conditionnel
pre.006 transactionNotification + actor integration + reconnect/resubscribe/unsubscribe races
@@ -709,17 +712,18 @@ profiles[].ws_endpoints[].kind:
helius_laserstream -> WsProtocolKind::HeliusLaserStream
```
La fixture Config contient un endpoint Helius typé et l'exemple versionné montre la composition de l'URL mainnet. `config/std.transport.json` reste standard-only pour ne pas imposer de provider/credential dans la configuration par défaut. Les paramètres de `transactionSubscribe` restent runtime et n'appartiennent pas au profil endpoint Config.
La fixture Config contient un endpoint Helius mainnet typé ainsi qu'un profil Helius devnet distinct. L'exemple versionné matérialise lui aussi un profil mainnet et un profil devnet séparés ; aucun profil logique ne mélange les deux clusters. `config/std.transport.json` reste standard-only pour ne pas imposer de provider/credential dans la configuration par défaut. Les paramètres de `transactionSubscribe` restent runtime et n'appartiennent pas au profil endpoint Config.
### 7.13 Credentials
L'api-key reste uniquement dans l'URL résolue :
```text
wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}
mainnet = wss://mainnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}
devnet = wss://devnet.helius-rpc.com/?api-key=${KSP_SECRET_HELIUS_API_KEY:-replace-me}
```
`KSP_SECRET_HELIUS_API_KEY` est inventorié dans `.env.example` sous forme commentée/placeholder. Config résout la clé au sein de l'URL effective, marque la valeur comme `Secret`, conserve l'URL réelle uniquement pour le runtime légitime et redige la projection sûre ainsi que `Debug`. Transport ne lit jamais `std::env` et reçoit uniquement un `WsEndpointUrl`.
`KSP_SECRET_HELIUS_API_KEY` est inventorié dans `.env.example` sous forme commentée/placeholder et est réutilisé pour les deux réseaux Helius. Config résout la clé au sein de chaque URL effective, marque le segment résolu comme `Secret` et conserve l'URL réelle uniquement pour le runtime légitime. Le contrat Config existant de redaction **segmentaire** s'applique aux chaînes composées : les littéraux sûrs sont conservés et le segment secret devient `********`, soit `wss://mainnet.helius-rpc.com/?api-key=********` ou `wss://devnet.helius-rpc.com/?api-key=********`. `Debug` n'expose jamais la clé réelle. Transport ne lit jamais `std::env` et reçoit uniquement un `WsEndpointUrl`.
## 8. Threat model provider
@@ -890,7 +894,7 @@ validation finale fermée
prompt 0.2.9 prêt
```
## 13. Checkpoint `pre.004`
## 13. Checkpoint `pre.004` et `fix.001`
Le checkpoint `pre.003` est fermé par preuve opérateur :
@@ -910,8 +914,8 @@ Les preuves spécifiques `pre.003` sont acquises : fixture Helius 6/6, 38 tests
```text
WsProtocolKind Config mapping helius_laserstream -> HeliusLaserStream
JSON Schema V2 kind accepte solana_standard + helius_laserstream
fixture Config endpoint Helius avec interpolation d'api-key
example Config endpoint Helius mainnet explicite
fixture Config Helius mainnet + profil Helius devnet séparé, interpolation d'api-key
example Config profils Helius mainnet/devnet explicites et séparés
secret KSP_SECRET_HELIUS_API_KEY
safe projection / Debug credential Helius redacted
Config -> Transport endpoint typé HeliusLaserStream
@@ -921,7 +925,21 @@ heartbeat toujours absent
new dependency aucune
```
Le checkpoint opérateur requis avant de déclarer `pre.004` `DONE` est :
Le premier checkpoint opérateur `pre.004` reçu le 2026-08-23 donne :
```text
cargo fmt --all OK
python3 scripts/audit_rust_workspace_rules.py clean
cargo check --workspace OK
cargo clippy --workspace --all-targets OK
cargo test -p ksp-config-lib FAIL 109/110
cargo test -p ksp-onchain-transport-lib OK 314 unit + 38 public + 26 completeness + 4 doctests
cargo test --workspace FAIL sur le même test Config
```
L'unique échec opérateur compare `safe_value` à `********` alors que le résolveur produit correctement `wss://mainnet.helius-rpc.com/?api-key=********`. Les canaris historiques Config prouvent déjà ce contrat de redaction segmentaire pour les chaînes composées. La revue du fix a aussi identifié que `pre.004` ne matérialisait déterministiquement que mainnet alors que le contrat Helius WebSocket couvre mainnet et devnet. `pre.004-fix.001` corrige donc l'attente du test **et** ajoute un profil/fixture Devnet Helius séparé, sans modifier le résolveur, le schema, le mapping protocol ou le runtime Transport.
Le checkpoint à rejouer avant de déclarer `pre.004` + `fix.001` `DONE` est :
```bash
cargo fmt --all

View File

@@ -1,9 +1,9 @@
<!-- file: docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md -->
<!-- version: 9 -->
<!-- version: 11 -->
# Validation `0.2.8` — Helius LaserStream WebSocket
> **Statut : `pre.003` validé ; `pre.004` préparé.** Les six wrappers standard Helius, leurs exact-wire fixtures, canaries publiques/release-completeness et compile-fail sont verts. La tranche courante ajoute uniquement le mapping Config V2 `helius_laserstream`, une fixture/exemple Helius et les preuves de résolution/redaction du secret provider.
> **Statut : `pre.003` validé ; `pre.004` a atteint son checkpoint avec un faux négatif Config et la revue a ensuite relevé l'absence d'un cas Devnet Helius déterministe. `pre.004-fix.001` couvre les deux corrections.** `fmt`, audit, `check`, `clippy` et Transport sont verts. Le fix aligne le test Helius sur la redaction segmentaire existante et exige désormais mainnet + devnet dans des profils distincts.
## 1. Références
@@ -17,6 +17,8 @@ fix forecast/nomenclature deltas/0.2.8/pre.001-fix.002.md
pre.002 deltas/0.2.8/pre.002.md
pre.002 Clippy/docs fix deltas/0.2.8/pre.002-fix.001.md
pre.003 deltas/0.2.8/pre.003.md
pre.004 deltas/0.2.8/pre.004.md
pre.004 redaction test fix deltas/0.2.8/pre.004-fix.001.md
validation standard WS docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
HTTP compliance docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md
KSP-TRANSPORT-007 docs/validation/005-V0_2_3_KSP_TRANSPORT_007_RETRO_AUDIT.md
@@ -130,22 +132,22 @@ Verdict : **gate `0.2.8-pre.001` positif ; `pre.002` + `fix.001` et `pre.003` so
### 4.2 Invariants architecture
| Critère | Décision | Preuve cible | État |
|-------------------------------------|------------------------------------------------------------------|---------------------------------|--------|
| Critère | Décision | Preuve cible | État |
|-------------------------------------|------------------------------------------------------------------|---------------------------------|--------------------|
| actor physique | un seul `WsSession` actor partagé | source/runtime canary | pre.002 implémenté |
| façade standard | `SolanaStandardWsSession` | public API canary | pre.002 implémenté |
| façade Helius | `HeliusLaserStreamWsSession` | public API canary | pre.002 implémenté |
| namespace LaserStream WS | `WsProtocolKind` + `ws_endpoints` possèdent `helius_laserstream` | API/Config/docs canary | pre.004 préparé |
| LaserStream gRPC | backend/type/Config distincts, hors `0.2.8` | absence de réutilisation WS | décidé |
| namespace LaserStream WS | `WsProtocolKind` + `ws_endpoints` possèdent `helius_laserstream` | API/Config/docs canary | pre.004 préparé |
| LaserStream gRPC | backend/type/Config distincts, hors `0.2.8` | absence de réutilisation WS | décidé |
| escape hatch Helius | aucun `inner()`/`into_inner()` public | compile-fail/source canary | pre.002 implémenté |
| generic Helius `WsSession::connect` | ne doit pas permettre de contourner la façade | invalid protocol pre-I/O canary | pre.002 implémenté |
| Helius unsupported | absent de la façade | compile-fail/API absence canary | pre.003 validé |
| standard Helius commun | délégation vers le même wire/actor | exact fixture | pre.003 validé |
| DTO duplication | seulement si wire/sémantique divergent | public/source audit | décidé |
| Config direction | Config -> Transport uniquement | ownership tests | pre.004 préparé |
| heartbeat | Helius-only, actor commun | deterministic timers | décidé |
| secret | query URL derrière `WsEndpointUrl` | redaction canaries | pre.004 préparé |
| new Rust dependency | aucune | manifest/tree audit | décidé |
| Helius unsupported | absent de la façade | compile-fail/API absence canary | pre.003 validé |
| standard Helius commun | délégation vers le même wire/actor | exact fixture | pre.003 validé |
| DTO duplication | seulement si wire/sémantique divergent | public/source audit | décidé |
| Config direction | Config -> Transport uniquement | ownership tests | pre.004 préparé |
| heartbeat | Helius-only, actor commun | deterministic timers | décidé |
| secret | query URL derrière `WsEndpointUrl` | redaction canaries | pre.004 préparé |
| new Rust dependency | aucune | manifest/tree audit | décidé |
## 5. Contrat `transactionSubscribe` à valider
@@ -232,8 +234,8 @@ aucun payload brut dans logs/snapshots
[x] KSP-TRANSPORT-007 inchangé — tests Transport/workspace verts
[x] Config V1 HTTP-only backward readable — tests Config workspace verts
[x] Config V2 solana_standard backward readable — tests Config workspace verts
[ ] Config V2 helius_laserstream mappe vers WsProtocolKind::HeliusLaserStream — pre.004 test ajouté, pending
[ ] schema V2 accepte helius_laserstream sans relâcher les autres contraintes — pre.004 fixture pending
[x] Config V2 helius_laserstream mappe vers WsProtocolKind::HeliusLaserStream — test pre.004 atteint cette assertion avant l'échec safe_value
[x] schema V2 accepte helius_laserstream sans relâcher les autres contraintes — fixture chargée par le test pre.004
[x] no Transport -> Config/Wallet/Store/Program/tracing direct — audits/tests ownership verts
```
@@ -241,8 +243,8 @@ aucun payload brut dans logs/snapshots
```text
[x] api-key absente de Debug WsEndpointUrl — canaries héritées + pre.002 vert
[ ] KSP_SECRET_HELIUS_API_KEY redacted dans safe_value Config — pre.004 test ajouté, pending
[ ] KSP_SECRET_HELIUS_API_KEY absente de ResolvedTransportConfig Debug — pre.004 test ajouté, pending
[ ] KSP_SECRET_HELIUS_API_KEY redacted dans safe_value Config — comportement correct observé, attente du test corrigée par fix.001, checkpoint à rejouer
[ ] KSP_SECRET_HELIUS_API_KEY absente de ResolvedTransportConfig Debug — assertion située après le faux négatif, checkpoint fix.001 à rejouer
[ ] api-key absente de Debug settings/session/subscription
[ ] api-key absente des KspError safe contexts
[ ] URL complète absente des snapshots
@@ -293,16 +295,18 @@ La fixture Transport rapporte 314 tests unitaires verts, 38 tests public API ver
Surface `pre.004` préparée :
```text
[ ] schema `ws_endpoints[].kind` accepte `helius_laserstream`
[ ] adapter Config mappe `helius_laserstream` vers `WsProtocolKind::HeliusLaserStream`
[ ] fixture Config matérialise un endpoint Helius typé
[ ] exemple Transport matérialise Helius mainnet sans credential réel
[ ] `.env.example` inventorie `KSP_SECRET_HELIUS_API_KEY`
[ ] interpolation du secret produit l'URL runtime Helius attendue
[ ] safe_value redige l'URL contenant l'api-key
[ ] Debug de `ResolvedTransportConfig` n'expose pas la clé
[ ] Config produit un endpoint composable avec `HeliusLaserStreamWsSession`
[ ] `config/std.transport.json` canonique reste standard-only
[x] schema `ws_endpoints[].kind` accepte `helius_laserstream`
[x] adapter Config mappe `helius_laserstream` vers `WsProtocolKind::HeliusLaserStream`
[x] fixture Config matérialise un endpoint Helius mainnet typé
[ ] fixture Config matérialise un profil Helius devnet distinct — ajouté par fix.001, checkpoint à rejouer
[x] exemple Transport matérialise Helius mainnet sans credential réel
[ ] exemple Transport matérialise Helius devnet dans un profil distinct — ajouté par fix.001, checkpoint à rejouer
[x] `.env.example` inventorie `KSP_SECRET_HELIUS_API_KEY`
[x] interpolation du secret produit l'URL runtime Helius attendue
[ ] safe_value conserve les littéraux Helius mainnet/devnet et redige uniquement l'api-key (`...api-key=********`) — fix.001 à rejouer
[ ] Debug de `ResolvedTransportConfig` n'expose pas la clé — assertion à rejouer après fix.001
[x] Config produit un endpoint composable avec `HeliusLaserStreamWsSession`
[x] `config/std.transport.json` canonique reste standard-only
```
Aucun `transactionSubscribe`, heartbeat, changement du moteur WebSocket ou nouvelle dépendance n'est introduit dans cette tranche.
@@ -333,7 +337,31 @@ Constats `pre.002-fix.001` :
Aucun split en fichiers supplémentaires n'est retenu : les plans historiques `0.2.5``0.2.7` sont de taille comparable ou supérieure, et le contenu du plan `015` reste entièrement centré sur une seule release. Le problème identifié était **l'ordre interne et la duplication de responsabilités**, pas la nécessité d'un nouveau type de document.
## 12. Gate opérateur `pre.004`
## 12. Gate opérateur `pre.004` / `fix.001`
Premier passage `pre.004` reçu le 2026-08-23 :
```text
[x] cargo fmt --all
[x] python3 scripts/audit_rust_workspace_rules.py = clean
[x] cargo check --workspace
[x] cargo clippy --workspace --all-targets
[ ] cargo test -p ksp-config-lib — 109/110 ; faux négatif safe_value Helius
[x] cargo test -p ksp-onchain-transport-lib — vert
[ ] cargo test --workspace — échoue uniquement sur le même test Config
```
Observation exacte :
```text
observé = wss://mainnet.helius-rpc.com/?api-key=********
attendu = ********
```
L'observé est conforme au contrat historique du résolveur Config : dans une chaîne composée, les littéraux non sensibles restent visibles dans la projection sûre tandis que chaque placeholder secret est remplacé par `********`. Le fix ne modifie donc pas le runtime ; il corrige le canari pour attendre l'URL sûre segmentaire exacte. La revue du même checkpoint complète également la couverture Config avec un profil Helius Devnet distinct utilisant `wss://devnet.helius-rpc.com/?api-key=...`, afin que mainnet et devnet soient tous deux prouvés sans mélange de clusters.
À rejouer après `pre.004-fix.001` :
```text
[ ] cargo fmt --all
@@ -345,4 +373,4 @@ Aucun split en fichiers supplémentaires n'est retenu : les plans historiques `0
[ ] cargo test --workspace
```
Verdict courant : **`pre.003` DONE ; `pre.004` préparé, non déclaré `DONE` avant ce checkpoint.**
Verdict courant : **`pre.003` DONE ; `pre.004` fonctionnellement implémenté mais non fermé ; `pre.004-fix.001` PREPARED.**