v0.2.9-pre.012
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 252
|
# version: 253
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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"]
|
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]
|
[workspace.package]
|
||||||
version = "0.2.9-pre.11"
|
version = "0.2.9-pre.12"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
||||||
<!-- version: 20 -->
|
<!-- version: 21 -->
|
||||||
|
|
||||||
# `ksp-onchain-transport-lib`
|
# `ksp-onchain-transport-lib`
|
||||||
|
|
||||||
`ksp-onchain-transport-lib` est la bibliothèque KSP propriétaire du transport on-chain Solana. Elle fournit le transport HTTP JSON-RPC complet et le moteur WebSocket Solana standard ; les extensions provider-specific et gRPC sont ajoutées séparément lorsqu’une release les cible.
|
`ksp-onchain-transport-lib` est la bibliothèque KSP propriétaire du transport on-chain Solana. Elle fournit le transport HTTP JSON-RPC complet, le moteur WebSocket Solana standard et la foundation Yellowstone gRPC standard/provider-neutral. Les extensions provider-specific restent ajoutées séparément lorsqu’une release les cible.
|
||||||
|
|
||||||
## Responsabilités
|
## Responsabilités
|
||||||
|
|
||||||
@@ -21,6 +21,8 @@ La crate possède :
|
|||||||
- l'exécution générique des méthodes standard supportées ;
|
- l'exécution générique des méthodes standard supportées ;
|
||||||
- les wrappers typés HTTP et WebSocket explicitement livrés par KSP ;
|
- les wrappers typés HTTP et WebSocket explicitement livrés par KSP ;
|
||||||
- les sessions physiques WebSocket, subscriptions logiques, reconnect/resubscribe et backpressure bornés ;
|
- les sessions physiques WebSocket, subscriptions logiques, reconnect/resubscribe et backpressure bornés ;
|
||||||
|
- les settings, channels, unary et sessions `Subscribe` Yellowstone gRPC standard ;
|
||||||
|
- le reconnect/replay Yellowstone prudent avec observabilité de gaps/duplicates sans promesse lossless ;
|
||||||
- les snapshots runtime sûrs ;
|
- les snapshots runtime sûrs ;
|
||||||
- l'observabilité Transport via `ksp-logging-lib`.
|
- l'observabilité Transport via `ksp-logging-lib`.
|
||||||
|
|
||||||
@@ -37,6 +39,7 @@ ksp-config-lib
|
|||||||
-> ksp-logging-lib
|
-> ksp-logging-lib
|
||||||
-> reqwest / tokio / serde
|
-> reqwest / tokio / serde
|
||||||
-> tokio-tungstenite / futures-util
|
-> tokio-tungstenite / futures-util
|
||||||
|
-> tonic / tonic-prost / yellowstone-grpc-proto
|
||||||
```
|
```
|
||||||
|
|
||||||
La direction inverse est interdite :
|
La direction inverse est interdite :
|
||||||
@@ -217,6 +220,32 @@ Pour Helius, l’actor envoie automatiquement un control frame WebSocket `Ping`
|
|||||||
|
|
||||||
LaserStream **gRPC** reste un backend distinct, hors de cette façade, de `WsProtocolKind` et de la Config WebSocket `helius_laserstream`.
|
LaserStream **gRPC** reste un backend distinct, hors de cette façade, de `WsProtocolKind` et de la Config WebSocket `helius_laserstream`.
|
||||||
|
|
||||||
|
|
||||||
|
## Yellowstone gRPC standard
|
||||||
|
|
||||||
|
La foundation `0.2.9` ajoute un troisième backend réseau distinct de HTTP et WebSocket. Le moteur est KSP-owned : `yellowstone-grpc-proto` fournit le wire publié, tandis que Tonic reste encapsulé derrière les types crate-root KSP. Aucun client Tonic brut ni type protobuf upstream n’est réexporté.
|
||||||
|
|
||||||
|
La surface publique principale comprend :
|
||||||
|
|
||||||
|
```text
|
||||||
|
YellowstoneGrpcEndpointUrl / YellowstoneGrpcEndpointSettings
|
||||||
|
YellowstoneGrpcSessionSettings / YellowstoneGrpcReconnectSettings
|
||||||
|
YellowstoneGrpcTransportSettings
|
||||||
|
YellowstoneGrpcChannel
|
||||||
|
SolanaYellowstoneGrpcUnaryClient
|
||||||
|
YellowstoneSubscribeRequest
|
||||||
|
SolanaYellowstoneGrpcSubscribeSession
|
||||||
|
YellowstoneGrpcSubscribeSnapshot
|
||||||
|
```
|
||||||
|
|
||||||
|
Les sept unary standards retenus sont `SubscribeReplayInfo`, `Ping`, `GetLatestBlockhash`, `GetBlockHeight`, `GetSlot`, `IsBlockhashValid` et `GetVersion`. `Subscribe` couvre accounts, slots, transactions, transaction status, blocks, block metadata et entries, avec `commitment`, `accounts_data_slice`, `ping` et `from_slot`. `SubscribeDeshred` reste hors scope de la foundation standard.
|
||||||
|
|
||||||
|
Le stream bidirectionnel est borné : request/update queues, tailles inbound/outbound, half-close, close timeout et reconnect budget sont explicites. Après reconnect, KSP rejoue la dernière requête complète acceptée et avance prudemment `from_slot` selon le dernier slot observé et `SubscribeReplayInfo.first_available`. Les compteurs de gap et duplicate sont de l’observabilité ; ils ne constituent jamais une garantie exactly-once ou lossless.
|
||||||
|
|
||||||
|
Config Transport V3 peut mapper des `grpc_endpoints` vers ces settings sans inverser la dépendance. `protocol = solana_yellowstone` décrit le wire standard, tandis que `provider` reste un descripteur distinct. Le profil committé `publicnode_mainnet` utilise le standard sans credential ni façade PublicNode spécifique.
|
||||||
|
|
||||||
|
Un smoke live opt-in vérifie directement PublicNode Mainnet via `GetVersion` puis `GetSlot`. Le hostname PublicNode Testnet Yellowstone n’est pas versionné tant qu’une source officielle exploitable ne l’a pas confirmé ; KSP ne déduit pas un endpoint à partir d’une convention de nommage.
|
||||||
|
|
||||||
## Résilience
|
## Résilience
|
||||||
|
|
||||||
L'admission est calculée par couple endpoint/rôle. Le pool applique :
|
L'admission est calculée par couple endpoint/rôle. Le pool applique :
|
||||||
@@ -253,7 +282,7 @@ La configuration Logging de référence conserve un fichier dédié Transport à
|
|||||||
|
|
||||||
Les tests par défaut sont déterministes et n'exigent pas Internet : fixtures JSON et serveur HTTP local couvrent requêtes, réponses, retry, 429, timeout, redaction et routing.
|
Les tests par défaut sont déterministes et n'exigent pas Internet : fixtures JSON et serveur HTTP local couvrent requêtes, réponses, retry, 429, timeout, redaction et routing.
|
||||||
|
|
||||||
Trois smokes Devnet opt-in sont séparés par responsabilité :
|
Quatre smokes réseau opt-in sont séparés par responsabilité :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Transport HTTP pur : settings programmatiques -> HttpTransportPool
|
Transport HTTP pur : settings programmatiques -> HttpTransportPool
|
||||||
@@ -270,13 +299,16 @@ Transport WebSocket pur : settings programmatiques -> WsSession
|
|||||||
|
|
||||||
Composition historique : Config -> std.transport/devnet_public -> HttpTransportPool
|
Composition historique : Config -> std.transport/devnet_public -> HttpTransportPool
|
||||||
-> getHealth/getGenesisHash/getVersion/getBalance
|
-> getHealth/getGenesisHash/getVersion/getBalance
|
||||||
|
|
||||||
|
Transport Yellowstone gRPC : settings programmatiques -> PublicNode Mainnet
|
||||||
|
-> TLS -> GetVersion -> GetSlot confirmed
|
||||||
```
|
```
|
||||||
|
|
||||||
Le smoke HTTP Transport utilise pour sa branche Token la forme Devnet documentée `getTokenAccountsByOwner(owner, { programId }, { commitment: finalized, encoding: jsonParsed })`. L'owner est une Pubkey ordinaire de l'exemple officiel ; aucune présence de token account n'est exigée, donc une liste vide reste valide.
|
Le smoke HTTP Transport utilise pour sa branche Token la forme Devnet documentée `getTokenAccountsByOwner(owner, { programId }, { commitment: finalized, encoding: jsonParsed })`. L'owner est une Pubkey ordinaire de l'exemple officiel ; aucune présence de token account n'est exigée, donc une liste vide reste valide.
|
||||||
|
|
||||||
Le smoke WebSocket Transport cible uniquement la famille stable `slotSubscribe` sur l'endpoint public Devnet `wss://api.devnet.solana.com`. Il borne connexion, attente de notification, unsubscribe et fermeture ; il ne transforme aucune famille unstable en gate live.
|
Le smoke WebSocket Transport cible uniquement la famille stable `slotSubscribe` sur l'endpoint public Devnet `wss://api.devnet.solana.com`. Il borne connexion, attente de notification, unsubscribe et fermeture ; il ne transforme aucune famille unstable en gate live.
|
||||||
|
|
||||||
Les trois tests sont `ignored` par défaut. Les deux smokes Transport appartiennent durablement à cette crate ; le smoke cross-crates hébergé dans Config reste transitoire jusqu'à l'existence d'une surface KSP d'intégration/orchestration appropriée. Un rate-limit, refus externe ou incident Devnet n'est pas assimilé automatiquement à une régression locale.
|
Les quatre tests sont `ignored` par défaut. Les trois smokes Transport appartiennent durablement à cette crate ; le smoke cross-crates hébergé dans Config reste transitoire jusqu'à l'existence d'une surface KSP d'intégration/orchestration appropriée. Un rate-limit, refus externe ou incident Devnet n'est pas assimilé automatiquement à une régression locale.
|
||||||
|
|
||||||
Aucun smoke Helius live supplémentaire n’est committé en `0.2.8-pre.010`. Un tel test devrait à la fois obtenir `KSP_SECRET_HELIUS_API_KEY` via Config et exercer Transport ; l’ajouter dans Transport violerait l’ownership environnement/secret, tandis que l’ajouter dans Config étendrait l’exception cross-crates que le projet veut au contraire résorber. La première surface KSP d’intégration/orchestration dédiée devra héberger ce smoke. Le scénario live recommandé est alors `helius_devnet -> HeliusLaserStreamWsSession -> slotSubscribe -> notification -> unsubscribe -> close`; `transactionSubscribe` reste un smoke optionnel dépendant des droits provider et ne devient pas un gate stable de release.
|
Aucun smoke Helius live supplémentaire n’est committé en `0.2.8-pre.010`. Un tel test devrait à la fois obtenir `KSP_SECRET_HELIUS_API_KEY` via Config et exercer Transport ; l’ajouter dans Transport violerait l’ownership environnement/secret, tandis que l’ajouter dans Config étendrait l’exception cross-crates que le projet veut au contraire résorber. La première surface KSP d’intégration/orchestration dédiée devra héberger ce smoke. Le scénario live recommandé est alors `helius_devnet -> HeliusLaserStreamWsSession -> slotSubscribe -> notification -> unsubscribe -> close`; `transactionSubscribe` reste un smoke optionnel dépendant des droits provider et ne devient pas un gate stable de release.
|
||||||
|
|
||||||
@@ -290,4 +322,6 @@ Aucun smoke Helius live supplémentaire n’est committé en `0.2.8-pre.010`. Un
|
|||||||
- [`../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée Transactions ;
|
- [`../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md`](../../docs/validation/006-V0_2_3_HTTP_TRANSACTIONS.md) — matrice finale validée Transactions ;
|
||||||
- [`../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) — plan Blocks/Economics et compliance HTTP finale ;
|
- [`../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md`](../../docs/plans/011-V0_2_4_HTTP_BLOCKS_ECONOMICS_PLAN.md) — plan Blocks/Economics et compliance HTTP finale ;
|
||||||
- [`../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) — matrice finale validée `52/52 + 14/14` et audit `KSP-TRANSPORT-007` global ;
|
- [`../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md`](../../docs/validation/007-V0_2_4_HTTP_FINAL_COMPLIANCE.md) — matrice finale validée `52/52 + 14/14` et audit `KSP-TRANSPORT-007` global ;
|
||||||
- [`../../config/std.transport.json`](../../config/std.transport.json) — configuration standard HTTP + WebSocket V2, avec lecture backward V1 HTTP-only.
|
- [`../../docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md`](../../docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md) — plan Yellowstone gRPC standard/provider-neutral et PublicNode ;
|
||||||
|
- [`../../docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md`](../../docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md) — matrice de compliance Yellowstone ;
|
||||||
|
- [`../../config/std.transport.json`](../../config/std.transport.json) — configuration standard Transport V3 HTTP + WebSocket + gRPC, avec lecture backward V1/V2.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: crates/ksp-onchain-transport-lib/USAGE.md -->
|
<!-- file: crates/ksp-onchain-transport-lib/USAGE.md -->
|
||||||
<!-- version: 20 -->
|
<!-- version: 21 -->
|
||||||
|
|
||||||
# Utilisation de `ksp-onchain-transport-lib`
|
# Utilisation de `ksp-onchain-transport-lib`
|
||||||
|
|
||||||
@@ -257,7 +257,99 @@ Les limites de taille et de capacité sont des policies KSP configurables par `W
|
|||||||
|
|
||||||
Le snapshot expose seulement l'identité locale, les metadata logiques de l'endpoint, l'état, les compteurs sûrs et les projections locales de subscriptions. L'URL et les remote subscription IDs ne sont jamais projetés. La disparition de tous les handles de session déclenche le cleanup actor best-effort ; `close().await` reste la voie normale de shutdown.
|
Le snapshot expose seulement l'identité locale, les metadata logiques de l'endpoint, l'état, les compteurs sûrs et les projections locales de subscriptions. L'URL et les remote subscription IDs ne sont jamais projetés. La disparition de tous les handles de session déclenche le cleanup actor best-effort ; `close().await` reste la voie normale de shutdown.
|
||||||
|
|
||||||
## 4. Appels typés
|
## 4. Yellowstone gRPC standard
|
||||||
|
|
||||||
|
### Construction programmatique et unary
|
||||||
|
|
||||||
|
Transport peut ouvrir directement un endpoint Yellowstone sans Config :
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let grpc_url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse(
|
||||||
|
"https://solana-yellowstone-grpc.publicnode.com:443",
|
||||||
|
) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let grpc_endpoint = ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new(
|
||||||
|
"publicnode_mainnet_yellowstone",
|
||||||
|
true,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new("publicnode"),
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new("mainnet-beta"),
|
||||||
|
grpc_url,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::default(),
|
||||||
|
);
|
||||||
|
let grpc_channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(&grpc_endpoint).await {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let grpc = grpc_channel.standard_unary_client();
|
||||||
|
let version = grpc.get_version().await;
|
||||||
|
let slot = grpc
|
||||||
|
.get_slot(Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed))
|
||||||
|
.await;
|
||||||
|
```
|
||||||
|
|
||||||
|
L’URL reste sensible : `Debug`, erreurs KSP et snapshots n’en exposent pas la valeur. Les metadata publiques/secrètes se construisent avec `YellowstoneGrpcMetadataEntry`; Transport ne lit jamais l’environnement.
|
||||||
|
|
||||||
|
### Config Transport V3
|
||||||
|
|
||||||
|
Avec `ksp-config-lib`, un profil V3 peut exposer les trois transports sans casser l’accesseur historique HTTP + WS :
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let resolved = match engine.load_resolved_transport_config(Some("publicnode_mainnet"), &environment) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let grpc_settings = match resolved.grpc_settings() {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err(ksp_core_lib::Error::new(
|
||||||
|
ksp_onchain_transport_lib::ERROR_CODE_INVALID_SETTINGS,
|
||||||
|
"selected profile has no Yellowstone gRPC endpoint",
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
let endpoint = match grpc_settings.endpoints().iter().find(|candidate| candidate.enabled()) {
|
||||||
|
Some(value) => value,
|
||||||
|
None => return Err(ksp_core_lib::Error::new(
|
||||||
|
ksp_onchain_transport_lib::ERROR_CODE_INVALID_SETTINGS,
|
||||||
|
"selected profile has no enabled Yellowstone gRPC endpoint",
|
||||||
|
)),
|
||||||
|
};
|
||||||
|
let channel = ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(endpoint).await;
|
||||||
|
```
|
||||||
|
|
||||||
|
`protocol = solana_yellowstone` est validé par Config et reste distinct du descripteur `provider`. Une valeur provider n’autorise pas Transport à introduire une API provider-specific sans divergence réelle.
|
||||||
|
|
||||||
|
### Subscribe bidirectionnel
|
||||||
|
|
||||||
|
Une session standard part d’une requête typed complète :
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new();
|
||||||
|
let name = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new("slots") {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
if let Err(error) = request.insert_slot_filter(
|
||||||
|
name,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneSubscribeSlotFilter::new(),
|
||||||
|
) {
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
request.set_commitment(Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed));
|
||||||
|
let mut stream = match grpc_channel.open_standard_subscribe(request).await {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
};
|
||||||
|
let update = stream.next_update().await;
|
||||||
|
let snapshot = stream.snapshot();
|
||||||
|
let closed = stream.close().await;
|
||||||
|
```
|
||||||
|
|
||||||
|
`try_update()` remplace dynamiquement la requête complète tant que la session est `Active`. Une mutation pendant `Reconnecting` est refusée pour éviter une application ambiguë. Le snapshot expose reconnects, replay attempts, gaps, duplicates, dernier `from_slot` demandé et dernier slot observé, sans endpoint ni payload arbitraire.
|
||||||
|
|
||||||
|
Le reconnect réutilise la dernière requête acceptée et peut avancer `from_slot`, mais le consumer doit traiter cette reprise comme best-effort. KSP ne promet ni exactly-once, ni replay historique complet, ni absence de fork/equivocation entre nœuds.
|
||||||
|
|
||||||
|
## 5. Appels typés
|
||||||
|
|
||||||
Les wrappers typés se trouvent directement sur `HttpTransportPool`.
|
Les wrappers typés se trouvent directement sur `HttpTransportPool`.
|
||||||
|
|
||||||
@@ -317,7 +409,7 @@ let stake_minimum = pool.get_stake_minimum_delegation(&role, Some(&context)).awa
|
|||||||
|
|
||||||
`getBlock` possède également une forme bare-encoding legacy séparée et deprecated. Les valeurs Economics restent celles du runtime : le consumer ne doit pas supposer localement un taux d'inflation ou un minimum de délégation constant.
|
`getBlock` possède également une forme bare-encoding legacy séparée et deprecated. Les valeurs Economics restent celles du runtime : le consumer ne doit pas supposer localement un taux d'inflation ou un minimum de délégation constant.
|
||||||
|
|
||||||
## 5. Exécution JSON-RPC standard générique
|
## 6. Exécution JSON-RPC standard générique
|
||||||
|
|
||||||
Une méthode courante auditée peut être appelée via son descriptor :
|
Une méthode courante auditée peut être appelée via son descriptor :
|
||||||
|
|
||||||
@@ -331,7 +423,7 @@ Cette API retourne un `serde_json::Value`. Elle reste utile pour les extensions
|
|||||||
|
|
||||||
Avant exécution, `ensure_runtime_supported()` est appliqué. Une méthode historique `Removed` retourne `ERROR_CODE_METHOD_REMOVED` au lieu d'émettre un appel réseau fictif.
|
Avant exécution, `ensure_runtime_supported()` est appliqué. Une méthode historique `Removed` retourne `ERROR_CODE_METHOD_REMOVED` au lieu d'émettre un appel réseau fictif.
|
||||||
|
|
||||||
## 6. Sélection et admission sans exécuter la requête
|
## 7. Sélection et admission sans exécuter la requête
|
||||||
|
|
||||||
Pour inspecter le routing :
|
Pour inspecter le routing :
|
||||||
|
|
||||||
@@ -346,13 +438,13 @@ Dans le même bloc, `acquire_for_method()` réserve réellement la capacité RPS
|
|||||||
|
|
||||||
`HttpRequestPermit` détient la capacité de concurrence jusqu'à sa destruction. Aucun verrou synchrone n'est conservé pendant l'attente réseau.
|
`HttpRequestPermit` détient la capacité de concurrence jusqu'à sa destruction. Aucun verrou synchrone n'est conservé pendant l'attente réseau.
|
||||||
|
|
||||||
## 7. Snapshots runtime
|
## 8. Snapshots runtime
|
||||||
|
|
||||||
`HttpTransportPool::snapshot()` fournit une vue sûre des endpoints/rôles : disponibilité, limites, requêtes en vol, cooldown restant et compteurs runtime.
|
`HttpTransportPool::snapshot()` fournit une vue sûre des endpoints/rôles : disponibilité, limites, requêtes en vol, cooldown restant et compteurs runtime.
|
||||||
|
|
||||||
Les URLs d'endpoint n'y apparaissent jamais.
|
Les URLs d'endpoint n'y apparaissent jamais.
|
||||||
|
|
||||||
## 8. Retry et write submissions
|
## 9. Retry et write submissions
|
||||||
|
|
||||||
La policy de retry est portée par la metadata des méthodes et `evaluate_transport_retry()`.
|
La policy de retry est portée par la metadata des méthodes et `evaluate_transport_retry()`.
|
||||||
|
|
||||||
@@ -360,7 +452,7 @@ Les reads/simulations classés `RetrySafe` peuvent être réessayés dans le bud
|
|||||||
|
|
||||||
Pour une opération `WriteSubmission / NeverAfterDispatch`, un timeout ou autre résultat ambigu après dispatch arrête la resoumission automatique. Le consumer métier ne doit pas contourner cette protection avec une boucle de retry externe aveugle.
|
Pour une opération `WriteSubmission / NeverAfterDispatch`, un timeout ou autre résultat ambigu après dispatch arrête la resoumission automatique. Le consumer métier ne doit pas contourner cette protection avec une boucle de retry externe aveugle.
|
||||||
|
|
||||||
## 9. Logging
|
## 10. Logging
|
||||||
|
|
||||||
Les événements Transport utilisent le target :
|
Les événements Transport utilisent le target :
|
||||||
|
|
||||||
@@ -372,7 +464,7 @@ Ne jamais journaliser l'URL complète, un token provider, un body massif, une tr
|
|||||||
|
|
||||||
La configuration standard route les événements `info` de Transport vers un fichier dédié. Pour une investigation temporaire, élever uniquement ce target/sink à `debug` ou `trace`, puis revenir à `info` avant clôture du développement.
|
La configuration standard route les événements `info` de Transport vers un fichier dédié. Pour une investigation temporaire, élever uniquement ce target/sink à `debug` ou `trace`, puis revenir à `info` avant clôture du développement.
|
||||||
|
|
||||||
## 10. Smokes Devnet opt-in
|
## 11. Smokes réseau opt-in
|
||||||
|
|
||||||
Le smoke **Transport HTTP pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif d'Accounts/Tokens/Cluster, trois reads Transactions, puis des reads Blocks/Economics :
|
Le smoke **Transport HTTP pur** construit ses settings programmatiquement et exerce un sous-ensemble représentatif d'Accounts/Tokens/Cluster, trois reads Transactions, puis des reads Blocks/Economics :
|
||||||
|
|
||||||
@@ -390,6 +482,14 @@ cargo test -p ksp-onchain-transport-lib --test websocket_devnet_smoke -- --ignor
|
|||||||
|
|
||||||
Il n'utilise ni `blockSubscribe`, ni `slotsUpdatesSubscribe`, ni `voteSubscribe` : ces familles restent unstable et leur disponibilité dépend des capabilities du validator. Le smoke live n'est donc pas un gate de disponibilité de ces extensions.
|
Il n'utilise ni `blockSubscribe`, ni `slotsUpdatesSubscribe`, ni `voteSubscribe` : ces familles restent unstable et leur disponibilité dépend des capabilities du validator. Le smoke live n'est donc pas un gate de disponibilité de ces extensions.
|
||||||
|
|
||||||
|
Le smoke **Transport Yellowstone gRPC PublicNode** ne dépend d’aucun secret ni de Config. Il construit l’endpoint Mainnet programmatiquement, ouvre TLS puis exerce deux unary standards peu coûteux : `GetVersion` et `GetSlot` avec commitment `confirmed` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Le hostname Mainnet provient directement de la page PublicNode. Le hostname Testnet n’est pas versionné dans le smoke tant qu’une source PublicNode suffisamment autoritative et exploitable ne l’a pas confirmé ; une convention de nommage ou une source tierce ne suffit pas.
|
||||||
|
|
||||||
Le smoke de **composition Config -> Transport** reste également disponible :
|
Le smoke de **composition Config -> Transport** reste également disponible :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -400,7 +500,7 @@ Il valide le profil committé `devnet_public` et les quatre canaris foundation.
|
|||||||
|
|
||||||
### Smoke Helius live
|
### Smoke Helius live
|
||||||
|
|
||||||
Aucun nouveau test Helius live n’est committé en `0.2.8-pre.010`. La raison est architecturale : Transport ne peut pas lire `KSP_SECRET_HELIUS_API_KEY` ni dépendre de Config, et Config ne doit pas devenir la destination générale des futurs smokes `Config + autre crate`. Créer un quatrième smoke dans l’une de ces deux crates contournerait donc une frontière déjà documentée.
|
Aucun nouveau test Helius live n’est committé en `0.2.8-pre.010`. La raison est architecturale : Transport ne peut pas lire `KSP_SECRET_HELIUS_API_KEY` ni dépendre de Config, et Config ne doit pas devenir la destination générale des futurs smokes `Config + autre crate`. Créer un smoke Helius supplémentaire dans l’une de ces deux crates contournerait donc une frontière déjà documentée.
|
||||||
|
|
||||||
Lorsque la surface KSP d’intégration/orchestration dédiée existera, le smoke live minimal recommandé sera :
|
Lorsque la surface KSP d’intégration/orchestration dédiée existera, le smoke live minimal recommandé sera :
|
||||||
|
|
||||||
@@ -416,7 +516,7 @@ Config helius_devnet
|
|||||||
|
|
||||||
Ce scénario utilise une méthode standard stable sur l’endpoint Helius et teste donc auth + façade provider + actor + unsubscribe sans dépendre d’une entitlement particulière de `transactionSubscribe`. Un smoke `transactionSubscribe` pourra être ajouté séparément comme opt-in provider-specific si l’environnement opérateur possède les droits nécessaires ; il ne doit pas devenir un gate réseau obligatoire de la release.
|
Ce scénario utilise une méthode standard stable sur l’endpoint Helius et teste donc auth + façade provider + actor + unsubscribe sans dépendre d’une entitlement particulière de `transactionSubscribe`. Un smoke `transactionSubscribe` pourra être ajouté séparément comme opt-in provider-specific si l’environnement opérateur possède les droits nécessaires ; il ne doit pas devenir un gate réseau obligatoire de la release.
|
||||||
|
|
||||||
Les endpoints publics/provider sont des dépendances externes. Un rate-limit, refus d’auth, entitlement absente ou incident réseau n’est pas assimilé automatiquement à une régression locale ; les fixtures HTTP/WebSocket locales et les gates déterministes restent autoritaires.
|
Les endpoints publics/provider sont des dépendances externes. Un rate-limit, refus d’auth, entitlement absente ou incident réseau n’est pas assimilé automatiquement à une régression locale ; les fixtures HTTP/WebSocket/gRPC locales et les gates déterministes restent autoritaires.
|
||||||
|
|
||||||
Pour auditer les dépendances, inspecter également le graphe effectif après résolution Cargo :
|
Pour auditer les dépendances, inspecter également le graphe effectif après résolution Cargo :
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
// file: crates/ksp-onchain-transport-lib/tests/yellowstone_publicnode_smoke.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Opt-in live PublicNode Mainnet smoke for the provider-neutral Yellowstone gRPC facade.
|
||||||
|
|
||||||
|
fn publicnode_mainnet_endpoint() -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings> {
|
||||||
|
let url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse("https://solana-yellowstone-grpc.publicnode.com:443") {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
|
};
|
||||||
|
let session = ksp_onchain_transport_lib::YellowstoneGrpcSessionSettings::new(
|
||||||
|
std::time::Duration::from_secs(10),
|
||||||
|
std::time::Duration::from_secs(10),
|
||||||
|
std::time::Duration::from_secs(5),
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcReconnectSettings::new(0, std::time::Duration::from_millis(250), std::time::Duration::from_secs(2)),
|
||||||
|
8,
|
||||||
|
8,
|
||||||
|
16 * 1024 * 1024,
|
||||||
|
4 * 1024 * 1024,
|
||||||
|
);
|
||||||
|
return std::result::Result::Ok(ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new(
|
||||||
|
"publicnode_mainnet_yellowstone",
|
||||||
|
true,
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new("publicnode"),
|
||||||
|
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new("mainnet-beta"),
|
||||||
|
url,
|
||||||
|
session,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "current_thread")]
|
||||||
|
#[ignore = "opt-in live PublicNode Mainnet Yellowstone gRPC smoke; performs external TLS and unary gRPC requests"]
|
||||||
|
async fn publicnode_mainnet_yellowstone_reaches_standard_version_and_slot_without_credentials() {
|
||||||
|
let endpoint = publicnode_mainnet_endpoint().expect("programmatic PublicNode Yellowstone settings must construct an endpoint");
|
||||||
|
let channel = ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(&endpoint).await.expect("PublicNode Yellowstone TLS connection must succeed");
|
||||||
|
assert_eq!(channel.endpoint_name(), "publicnode_mainnet_yellowstone");
|
||||||
|
assert_eq!(channel.provider().as_str(), "publicnode");
|
||||||
|
assert_eq!(channel.cluster().as_str(), "mainnet-beta");
|
||||||
|
let client = channel.standard_unary_client();
|
||||||
|
let version = client.get_version().await.expect("PublicNode Yellowstone GetVersion must succeed");
|
||||||
|
assert!(!version.version().is_empty());
|
||||||
|
let slot = client
|
||||||
|
.get_slot(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed))
|
||||||
|
.await
|
||||||
|
.expect("PublicNode Yellowstone GetSlot must succeed");
|
||||||
|
assert!(slot.slot() > 0);
|
||||||
|
}
|
||||||
257
deltas/0.2.9/pre.012.md
Normal file
257
deltas/0.2.9/pre.012.md
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
<!-- file: deltas/0.2.9/pre.012.md -->
|
||||||
|
<!-- version: 1 -->
|
||||||
|
|
||||||
|
# Delta `0.2.9-pre.012` — fermeture technique Yellowstone + PublicNode + documentation
|
||||||
|
|
||||||
|
## Statut
|
||||||
|
|
||||||
|
Candidate de fermeture technique `0.2.9` construite sur `0.2.9-pre.011`, dont le gate opérateur est entièrement vert.
|
||||||
|
|
||||||
|
Cette tranche ne change pas la sémantique runtime Yellowstone fermée en `pre.010`. Elle ajoute le smoke live PublicNode Mainnet opt-in, ferme le réaudit documentaire final, synchronise README/USAGE, prépare le prompt `0.2.10 — OrbitFlare Yellowstone gRPC` et rend la mise en forme des tableaux Markdown normative et mécaniquement vérifiable.
|
||||||
|
|
||||||
|
## Version technique
|
||||||
|
|
||||||
|
```text
|
||||||
|
workspace.package.version = 0.2.9-pre.12
|
||||||
|
```
|
||||||
|
|
||||||
|
## Base opérateur confirmée
|
||||||
|
|
||||||
|
`pre.011` a été validée avec :
|
||||||
|
|
||||||
|
```text
|
||||||
|
cargo fmt --all PASS
|
||||||
|
scripts/audit_rust_workspace_rules.py PASS, 0 export candidate
|
||||||
|
cargo check --workspace PASS
|
||||||
|
cargo clippy --workspace --all-targets PASS sans warning
|
||||||
|
Config unit 113/113
|
||||||
|
Config public API 15/15
|
||||||
|
Config ownership 5/5
|
||||||
|
Transport unit 383/383
|
||||||
|
Transport public API 49/49
|
||||||
|
Transport release completeness 43/43
|
||||||
|
Transport doctests 4/4
|
||||||
|
workspace dependencies 3/3
|
||||||
|
cargo test --workspace PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
## Réaudit Yellowstone final
|
||||||
|
|
||||||
|
Le réaudit du 2026-08-24 distingue désormais explicitement les numéros de `master` et les releases GitHub publiées :
|
||||||
|
|
||||||
|
```text
|
||||||
|
latest release GitHub indexée v14.2.2+solana.4.1.0
|
||||||
|
master yellowstone-grpc-geyser 15.1.2
|
||||||
|
master yellowstone-grpc-client 13.3.0
|
||||||
|
master yellowstone-grpc-proto 12.6.0
|
||||||
|
master Agave Geyser / storage 4.2.0
|
||||||
|
master Tonic / Prost 0.14.x
|
||||||
|
```
|
||||||
|
|
||||||
|
La surface N2 utilisée par KSP reste matériellement compatible : service `Geyser`, `Subscribe`, sept unary retenus, `SubscribeRequest` courant et neuf variantes `SubscribeUpdate`. `SubscribeDeshred` reste hors scope.
|
||||||
|
|
||||||
|
La licence du subtree `yellowstone-grpc-proto` reste déclarée Apache-2.0 dans `LICENSING.md` upstream.
|
||||||
|
|
||||||
|
## PublicNode Mainnet
|
||||||
|
|
||||||
|
Ajout d'un smoke Transport pur :
|
||||||
|
|
||||||
|
```text
|
||||||
|
crates/ksp-onchain-transport-lib/tests/yellowstone_publicnode_smoke.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
Le smoke :
|
||||||
|
|
||||||
|
```text
|
||||||
|
est ignored par défaut
|
||||||
|
construit ses settings programmatiquement
|
||||||
|
n'utilise ni Config ni variable d'environnement
|
||||||
|
n'utilise aucun credential
|
||||||
|
cible https://solana-yellowstone-grpc.publicnode.com:443
|
||||||
|
ouvre le channel TLS Yellowstone standard
|
||||||
|
appelle GetVersion
|
||||||
|
appelle GetSlot avec commitment confirmed
|
||||||
|
```
|
||||||
|
|
||||||
|
Il ne crée aucune façade `PublicNodeGrpc*` et réutilise le contrat provider-neutral de `0.2.9`.
|
||||||
|
|
||||||
|
## PublicNode Testnet
|
||||||
|
|
||||||
|
Le service Testnet gRPC est annoncé par PublicNode, mais l'hostname exact n'est toujours pas disponible dans une source PublicNode suffisamment autoritative et exploitable.
|
||||||
|
|
||||||
|
Décision :
|
||||||
|
|
||||||
|
```text
|
||||||
|
aucun hostname déduit
|
||||||
|
aucun profil Testnet
|
||||||
|
aucun smoke Testnet
|
||||||
|
statut documentaire = EXTERNAL BLOCK / NOT GUESSED
|
||||||
|
```
|
||||||
|
|
||||||
|
Cette limite externe ne bloque pas la fondation Mainnet et ne doit pas être transformée en endpoint supposé.
|
||||||
|
|
||||||
|
## Règles des tableaux Markdown
|
||||||
|
|
||||||
|
`docs/rules/RULES_DOCUMENTATION.md` formalise désormais :
|
||||||
|
|
||||||
|
```text
|
||||||
|
pipe littéral ou échappé interdit dans le contenu d'une cellule
|
||||||
|
pipe réservé aux séparateurs structurels
|
||||||
|
largeur de colonne déterminée par le contenu le plus large
|
||||||
|
tous les séparateurs verticaux alignés
|
||||||
|
exactement un espace de marge autour du contenu le plus large
|
||||||
|
cellules plus courtes complétées uniquement pour conserver l'alignement
|
||||||
|
ligne séparatrice dimensionnée exactement à la colonne
|
||||||
|
tableau entier réaligné lorsqu'une ligne est touchée
|
||||||
|
```
|
||||||
|
|
||||||
|
Ajout du canari :
|
||||||
|
|
||||||
|
```text
|
||||||
|
scripts/audit_markdown_tables.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Il audite les fichiers ou répertoires Markdown explicitement fournis, ignore les blocs de code fenced et rejette les tables qui ne respectent pas le contrat KSP.
|
||||||
|
|
||||||
|
La version de `docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md` corrigée manuellement par l'opérateur avant le commit `pre.011` a été conservée comme base ; `pre.012` ne réintroduit pas l'ancien format.
|
||||||
|
|
||||||
|
## Normalisation documentaire rétroactive modifiable
|
||||||
|
|
||||||
|
Le premier audit étendu de la nouvelle règle a révélé 26 écarts historiques dans neuf documents **modifiables** : principalement du padding antérieur au contrat actuel et un tableau HTTP utilisant des pipes échappés dans ses cellules.
|
||||||
|
|
||||||
|
Ces documents ont été normalisés sans changer leurs décisions :
|
||||||
|
|
||||||
|
```text
|
||||||
|
docs/formats/KSPWALLET_V1.md
|
||||||
|
docs/formats/KSPWALLET_V2.md
|
||||||
|
docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md
|
||||||
|
docs/plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md
|
||||||
|
docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md
|
||||||
|
docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md
|
||||||
|
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
|
||||||
|
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
|
||||||
|
docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Dans le plan HTTP `008`, les anciens `\|` utilisés pour exprimer une alternative ont été reformulés avec `/`, conformément à la nouvelle interdiction des pipes internes.
|
||||||
|
|
||||||
|
Un scan du repository a encore signalé uniquement onze écarts de padding dans d'anciens deltas `0.1.4`. Ils ne sont **pas** modifiés : les deltas déjà publiés sont immuables. `DOC-TABLE-006` formalise cette priorité ; tous les nouveaux deltas restent soumis au format courant.
|
||||||
|
|
||||||
|
## Documentation Transport
|
||||||
|
|
||||||
|
`README.md` et `USAGE.md` documentent maintenant la foundation Yellowstone complète :
|
||||||
|
|
||||||
|
```text
|
||||||
|
settings/channel/unary/Subscribe
|
||||||
|
reconnect/replay prudent
|
||||||
|
Config V3
|
||||||
|
PublicNode Mainnet
|
||||||
|
smoke live opt-in
|
||||||
|
limite Testnet non inventée
|
||||||
|
```
|
||||||
|
|
||||||
|
## Plan et validation
|
||||||
|
|
||||||
|
Le plan `016` et la validation `012` restent structurés par état courant plutôt que par appendices successifs.
|
||||||
|
|
||||||
|
Mises à jour principales :
|
||||||
|
|
||||||
|
```text
|
||||||
|
pre.011 fermé par gate opérateur
|
||||||
|
pre.012 active candidate
|
||||||
|
récconciliation master vs release GitHub
|
||||||
|
PublicNode Testnet fermé comme limite externe documentée
|
||||||
|
smoke Mainnet ajouté mais non déclaré exécuté
|
||||||
|
cargo tree final explicitement pending operator
|
||||||
|
workspace final explicitement pending operator
|
||||||
|
```
|
||||||
|
|
||||||
|
## Prompt suivant
|
||||||
|
|
||||||
|
Ajout :
|
||||||
|
|
||||||
|
```text
|
||||||
|
prompts/015-V0_2_10_START_PROMPT.md
|
||||||
|
```
|
||||||
|
|
||||||
|
La release suivante active est `0.2.10 — OrbitFlare Yellowstone gRPC`.
|
||||||
|
|
||||||
|
Le prompt impose un `pre.001` audit/sizing avant code provider et cible notamment les questions ouvertes suivantes :
|
||||||
|
|
||||||
|
```text
|
||||||
|
IP whitelist vs X_TOKEN vs control-plane X-ORBIT-KEY
|
||||||
|
endpoints régionaux / Devnet / transport security
|
||||||
|
support réel des unary/replay/from_slot
|
||||||
|
heartbeat proactif recommandé par OrbitFlare
|
||||||
|
réutilisation N1/N2 sans second actor/client
|
||||||
|
Config V3 et secret ownership
|
||||||
|
smoke architecture-safe
|
||||||
|
```
|
||||||
|
|
||||||
|
`0.2.11` reste Helius LaserStream gRPC.
|
||||||
|
|
||||||
|
## Fichiers ajoutés ou modifiés
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cargo.toml
|
||||||
|
docs/rules/RULES_DOCUMENTATION.md
|
||||||
|
scripts/audit_markdown_tables.py
|
||||||
|
crates/ksp-onchain-transport-lib/tests/yellowstone_publicnode_smoke.rs
|
||||||
|
crates/ksp-onchain-transport-lib/README.md
|
||||||
|
crates/ksp-onchain-transport-lib/USAGE.md
|
||||||
|
docs/formats/KSPWALLET_V1.md
|
||||||
|
docs/formats/KSPWALLET_V2.md
|
||||||
|
docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md
|
||||||
|
docs/plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md
|
||||||
|
docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md
|
||||||
|
docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md
|
||||||
|
docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md
|
||||||
|
docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md
|
||||||
|
docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md
|
||||||
|
docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md
|
||||||
|
docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md
|
||||||
|
prompts/000-README.md
|
||||||
|
prompts/015-V0_2_10_START_PROMPT.md
|
||||||
|
deltas/0.2.9/pre.012.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Gate local disponible dans l'environnement de préparation
|
||||||
|
|
||||||
|
Exécuté avant livraison de l'archive :
|
||||||
|
|
||||||
|
```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
|
||||||
|
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.9
|
||||||
|
Markdown table audit: clean (87 table(s), 116 file(s))
|
||||||
|
```
|
||||||
|
|
||||||
|
Cargo et Rustfmt ne sont pas disponibles dans l'environnement de préparation ; aucune commande Cargo n'est donc déclarée réussie pour la candidate `pre.012`.
|
||||||
|
|
||||||
|
## Gate opérateur requis
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo fmt --all
|
||||||
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.9
|
||||||
|
cargo check --workspace
|
||||||
|
cargo clippy --workspace --all-targets
|
||||||
|
cargo test -p ksp-config-lib
|
||||||
|
cargo test -p ksp-onchain-transport-lib
|
||||||
|
cargo test -p ksp-core-lib --test workspace_dependencies
|
||||||
|
cargo test --workspace
|
||||||
|
cargo tree -p ksp-onchain-transport-lib
|
||||||
|
cargo tree -p ksp-onchain-transport-lib --duplicates
|
||||||
|
cargo tree --duplicates
|
||||||
|
```
|
||||||
|
|
||||||
|
Smoke live séparé :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Si tous les gates locaux sont verts et que le smoke Mainnet est consigné, `0.2.9` peut passer à sa tranche de publication stable. Un défaut découvert dans cette candidate crée `pre.012-fix.001` ; l'historique précédent reste immuable.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/formats/KSPWALLET_V1.md -->
|
<!-- file: docs/formats/KSPWALLET_V1.md -->
|
||||||
<!-- version: 14 -->
|
<!-- version: 15 -->
|
||||||
|
|
||||||
# `.kspwallet` V1 — spécification du format natif Wallet KSP
|
# `.kspwallet` V1 — spécification du format natif Wallet KSP
|
||||||
|
|
||||||
@@ -399,29 +399,29 @@ Les champs binaires sont les **octets décodés** du Base64url, jamais le texte
|
|||||||
|
|
||||||
| Tag hex | Champ |
|
| Tag hex | Champ |
|
||||||
|--------:|----------------------------------------------------|
|
|--------:|----------------------------------------------------|
|
||||||
| `0001` | magic |
|
| `0001` | magic |
|
||||||
| `0002` | format_version |
|
| `0002` | format_version |
|
||||||
| `0003` | owner_auth_public_key |
|
| `0003` | owner_auth_public_key |
|
||||||
| `0010` | view enabled |
|
| `0010` | view enabled |
|
||||||
| `0011` | rôle VIEW littéral `view` |
|
| `0011` | rôle VIEW littéral `view` |
|
||||||
| `0012` | view slot_id ; longueur zéro lorsque VIEW disabled |
|
| `0012` | view slot_id ; longueur zéro lorsque VIEW disabled |
|
||||||
| `0100` | slot_id |
|
| `0100` | slot_id |
|
||||||
| `0101` | slot role |
|
| `0101` | slot role |
|
||||||
| `0102` | KDF algorithm |
|
| `0102` | KDF algorithm |
|
||||||
| `0103` | KDF version |
|
| `0103` | KDF version |
|
||||||
| `0104` | KDF memory_kib |
|
| `0104` | KDF memory_kib |
|
||||||
| `0105` | KDF iterations |
|
| `0105` | KDF iterations |
|
||||||
| `0106` | KDF parallelism |
|
| `0106` | KDF parallelism |
|
||||||
| `0107` | KDF salt |
|
| `0107` | KDF salt |
|
||||||
| `0108` | wrap algorithm |
|
| `0108` | wrap algorithm |
|
||||||
| `0109` | wrap nonce |
|
| `0109` | wrap nonce |
|
||||||
| `010A` | wrap ciphertext |
|
| `010A` | wrap ciphertext |
|
||||||
| `0200` | compartment kind |
|
| `0200` | compartment kind |
|
||||||
| `0201` | compartment payload version |
|
| `0201` | compartment payload version |
|
||||||
| `0202` | compartment algorithm |
|
| `0202` | compartment algorithm |
|
||||||
| `0203` | compartment nonce |
|
| `0203` | compartment nonce |
|
||||||
| `0204` | compartment ciphertext |
|
| `0204` | compartment ciphertext |
|
||||||
| `0500` | state-signature algorithm |
|
| `0500` | state-signature algorithm |
|
||||||
|
|
||||||
Les tags ne remplacent pas l'ordre normatif ; **l'ordre ci-dessous est obligatoire**.
|
Les tags ne remplacent pas l'ordre normatif ; **l'ordre ci-dessous est obligatoire**.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/formats/KSPWALLET_V2.md -->
|
<!-- file: docs/formats/KSPWALLET_V2.md -->
|
||||||
<!-- version: 3 -->
|
<!-- version: 4 -->
|
||||||
|
|
||||||
# `.kspwallet` V2 — spécification du wire binaire natif KSP
|
# `.kspwallet` V2 — spécification du wire binaire natif KSP
|
||||||
|
|
||||||
@@ -104,14 +104,14 @@ Une implémentation conforme doit vérifier les bornes **avant** toute allocatio
|
|||||||
|
|
||||||
Le début de fichier est strictement :
|
Le début de fichier est strictement :
|
||||||
|
|
||||||
| Ordre | Champ | Taille | Valeur / règle |
|
| Ordre | Champ | Taille | Valeur / règle |
|
||||||
|------:|---------------------------|-----------------:|------------------------------------------------|
|
|------:|---------------------------|-----------------:|------------------------------------------------|
|
||||||
| 1 | `magic` | 9 | ASCII exact `KSPWALLET` |
|
| 1 | `magic` | 9 | ASCII exact `KSPWALLET` |
|
||||||
| 2 | `format_version` | 2 | `0x0002` |
|
| 2 | `format_version` | 2 | `0x0002` |
|
||||||
| 3 | `document_length` | 4 | longueur totale exacte du fichier |
|
| 3 | `document_length` | 4 | longueur totale exacte du fichier |
|
||||||
| 4 | `flags` | 2 | bit 0 = VIEW activé ; tous les autres bits = 0 |
|
| 4 | `flags` | 2 | bit 0 = VIEW activé ; tous les autres bits = 0 |
|
||||||
| 5 | `owner_auth_public_key` | 32 | clé publique Ed25519 OWNER |
|
| 5 | `owner_auth_public_key` | 32 | clé publique Ed25519 OWNER |
|
||||||
| 6 | `view_descriptor.slot_id` | 16 conditionnels | présent uniquement si `flags & 0x0001 != 0` |
|
| 6 | `view_descriptor.slot_id` | 16 conditionnels | présent uniquement si `flags & 0x0001 != 0` |
|
||||||
|
|
||||||
Offsets fixes avant le descripteur conditionnel :
|
Offsets fixes avant le descripteur conditionnel :
|
||||||
|
|
||||||
@@ -154,20 +154,20 @@ Aucun compteur de slots ou de compartiments n'est nécessaire : leur cardinalit
|
|||||||
|
|
||||||
Chaque key slot est encodé ainsi :
|
Chaque key slot est encodé ainsi :
|
||||||
|
|
||||||
| Champ | Taille | Valeur / règle |
|
| Champ | Taille | Valeur / règle |
|
||||||
|--------------------------|---------:|-----------------------------------------|
|
|--------------------------|---------:|-----------------------------------------|
|
||||||
| `role` | 1 | `0x01` OWNER, `0x02` VIEW |
|
| `role` | 1 | `0x01` OWNER, `0x02` VIEW |
|
||||||
| `slot_id` | 16 | identifiant binaire exact |
|
| `slot_id` | 16 | identifiant binaire exact |
|
||||||
| `kdf_algorithm` | 1 | `0x01` Argon2id |
|
| `kdf_algorithm` | 1 | `0x01` Argon2id |
|
||||||
| `kdf_version` | 4 | `19` |
|
| `kdf_version` | 4 | `19` |
|
||||||
| `memory_kib` | 4 | `1..1 048 576`, et `>= parallelism * 8` |
|
| `memory_kib` | 4 | `1..1 048 576`, et `>= parallelism * 8` |
|
||||||
| `iterations` | 4 | `1..64` |
|
| `iterations` | 4 | `1..64` |
|
||||||
| `parallelism` | 4 | `1..64` |
|
| `parallelism` | 4 | `1..64` |
|
||||||
| `salt_length` | 1 | `16..64` |
|
| `salt_length` | 1 | `16..64` |
|
||||||
| `salt` | variable | exactement `salt_length` octets |
|
| `salt` | variable | exactement `salt_length` octets |
|
||||||
| `wrap_algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
| `wrap_algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
||||||
| `wrap_nonce` | 24 | nonce exact |
|
| `wrap_nonce` | 24 | nonce exact |
|
||||||
| `wrap_ciphertext_length` | 2 | `16..4096` |
|
| `wrap_ciphertext_length` | 2 | `16..4096` |
|
||||||
| `wrap_ciphertext` | variable | exactement la longueur déclarée |
|
| `wrap_ciphertext` | variable | exactement la longueur déclarée |
|
||||||
|
|
||||||
Ordre obligatoire :
|
Ordre obligatoire :
|
||||||
@@ -189,13 +189,13 @@ Toute divergence est invalide avant KDF/déchiffrement.
|
|||||||
|
|
||||||
Chaque compartiment est encodé :
|
Chaque compartiment est encodé :
|
||||||
|
|
||||||
| Champ | Taille | Valeur / règle |
|
| Champ | Taille | Valeur / règle |
|
||||||
|---------------------|---------:|------------------------------------------------------|
|
|---------------------|---------:|------------------------------------------------------|
|
||||||
| `kind` | 1 | `0x01` OWNER-CONTROL, `0x02` METADATA, `0x03` SECRET |
|
| `kind` | 1 | `0x01` OWNER-CONTROL, `0x02` METADATA, `0x03` SECRET |
|
||||||
| `payload_version` | 4 | `1` pour le profil initial V2 |
|
| `payload_version` | 4 | `1` pour le profil initial V2 |
|
||||||
| `algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
| `algorithm` | 1 | `0x01` XChaCha20-Poly1305 |
|
||||||
| `nonce` | 24 | nonce exact |
|
| `nonce` | 24 | nonce exact |
|
||||||
| `ciphertext_length` | 4 | longueur exacte |
|
| `ciphertext_length` | 4 | longueur exacte |
|
||||||
| `ciphertext` | variable | ciphertext + tag Poly1305 |
|
| `ciphertext` | variable | ciphertext + tag Poly1305 |
|
||||||
|
|
||||||
Bornes initiales :
|
Bornes initiales :
|
||||||
@@ -216,8 +216,8 @@ La fin du document est :
|
|||||||
|
|
||||||
| Champ | Taille | Valeur / règle |
|
| Champ | Taille | Valeur / règle |
|
||||||
|-----------------------------|-------:|---------------------------|
|
|-----------------------------|-------:|---------------------------|
|
||||||
| `state_signature.algorithm` | 1 | `0x01` Ed25519 |
|
| `state_signature.algorithm` | 1 | `0x01` Ed25519 |
|
||||||
| `state_signature.signature` | 64 | signature detached exacte |
|
| `state_signature.signature` | 64 | signature detached exacte |
|
||||||
|
|
||||||
Aucun octet ne peut suivre ces 65 octets.
|
Aucun octet ne peut suivre ces 65 octets.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md -->
|
<!-- file: docs/plans/005-V0_1_3_CONFIG_FOUNDATION_PLAN.md -->
|
||||||
<!-- version: 19 -->
|
<!-- version: 20 -->
|
||||||
|
|
||||||
# Plan `0.1.3` — Configuration foundation
|
# Plan `0.1.3` — Configuration foundation
|
||||||
|
|
||||||
@@ -605,23 +605,23 @@ Décisions :
|
|||||||
|
|
||||||
### 8.1 Écart `ksp-logging-lib 0.1.2` à fermer
|
### 8.1 Écart `ksp-logging-lib 0.1.2` à fermer
|
||||||
|
|
||||||
| Capacité | `0.1.2` | Requise par `std.logging.json` |
|
| Capacité | `0.1.2` | Requise par `std.logging.json` |
|
||||||
|-----------------------------------|----------------:|-------------------------------------:|
|
|-----------------------------------|----------------:|-------------------------------------:|
|
||||||
| filtre global | oui | oui |
|
| filtre global | oui | oui |
|
||||||
| overrides par target | oui | oui |
|
| overrides par target | oui | oui |
|
||||||
| lifecycle spans | oui | oui |
|
| lifecycle spans | oui | oui |
|
||||||
| console stdout/stderr | oui | oui |
|
| console stdout/stderr | oui | oui |
|
||||||
| console enabled | via `Option` | oui explicite |
|
| console enabled | via `Option` | oui explicite |
|
||||||
| console ANSI configurable | non | oui |
|
| console ANSI configurable | non | oui |
|
||||||
| format console configurable | non | oui |
|
| format console configurable | non | oui |
|
||||||
| plusieurs fichiers | non | oui |
|
| plusieurs fichiers | non | oui |
|
||||||
| rotation par fichier | un seul fichier | oui par sink |
|
| rotation par fichier | un seul fichier | oui par sink |
|
||||||
| format par fichier | non | oui |
|
| format par fichier | non | oui |
|
||||||
| filtre par sink/target | non | oui |
|
| filtre par sink/target | non | oui |
|
||||||
| filtre par sink/domain | non | oui |
|
| filtre par sink/domain | non | oui |
|
||||||
| filtre par sink/niveau | non indépendant | oui |
|
| filtre par sink/niveau | non indépendant | oui |
|
||||||
| hot reload transactionnel | oui | à conserver |
|
| hot reload transactionnel | oui | à conserver |
|
||||||
| non-blocking/guards/drop counters | oui | à conserver et généraliser par sinks |
|
| non-blocking/guards/drop counters | oui | à conserver et généraliser par sinks |
|
||||||
|
|
||||||
Ce tableau est un **gap identifié**, pas une invitation à déplacer Logging dans Config. La tranche qui le ferme modifie `ksp-logging-lib` uniquement dans son domaine propriétaire.
|
Ce tableau est un **gap identifié**, pas une invitation à déplacer Logging dans Config. La tranche qui le ferme modifie `ksp-logging-lib` uniquement dans son domaine propriétaire.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md -->
|
<!-- file: docs/plans/006-V0_1_4_CONFIG_DESKTOP_PLAN.md -->
|
||||||
<!-- version: 28 -->
|
<!-- version: 29 -->
|
||||||
|
|
||||||
# Plan `0.1.4` — `ksp-app-config-desk`
|
# Plan `0.1.4` — `ksp-app-config-desk`
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ Chaque application Tauri desk KSP reçoit un couple de ports Vite/HMR propre. La
|
|||||||
|
|
||||||
| Application | Port Vite HTTP | Port HMR |
|
| Application | Port Vite HTTP | Port HMR |
|
||||||
|-----------------------|---------------:|---------:|
|
|-----------------------|---------------:|---------:|
|
||||||
| `ksp-app-config-desk` | `1430` | `1431` |
|
| `ksp-app-config-desk` | `1430` | `1431` |
|
||||||
|
|
||||||
Les applications suivantes incrémentent le couple de deux ports (`1432/1433`, puis `1434/1435`, etc.). Vite doit utiliser un port strict afin qu'une collision soit signalée au lieu de provoquer un basculement silencieux vers un autre port. Cette allocation permet de faire fonctionner simultanément plusieurs applications desk en mode développement.
|
Les applications suivantes incrémentent le couple de deux ports (`1432/1433`, puis `1434/1435`, etc.). Vite doit utiliser un port strict afin qu'une collision soit signalée au lieu de provoquer un basculement silencieux vers un autre port. Cette allocation permet de faire fonctionner simultanément plusieurs applications desk en mode développement.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md -->
|
<!-- file: docs/plans/008-V0_2_1_ONCHAIN_HTTP_PLAN.md -->
|
||||||
<!-- version: 12 -->
|
<!-- version: 13 -->
|
||||||
|
|
||||||
# `0.2.1-pre.001` — plan `ksp-onchain-transport-lib` HTTP Solana foundation
|
# `0.2.1-pre.001` — plan `ksp-onchain-transport-lib` HTTP Solana foundation
|
||||||
|
|
||||||
@@ -230,30 +230,30 @@ Colonnes : nom, catégorie, paramètres/config à préserver, forme de résultat
|
|||||||
|
|
||||||
| Méthode | Catégorie | Params / config | Résultat | Statut | Runtime | Bot3 | Release | Tests minimaux | Source |
|
| Méthode | Catégorie | Params / config | Résultat | Statut | Runtime | Bot3 | Release | Tests minimaux | Source |
|
||||||
|-------------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------|----------|---------------|---------|--------------------------------------------------------------|------------------------------------------------------------------------------|
|
|-------------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------|---------------------------------|----------|---------------|---------|--------------------------------------------------------------|------------------------------------------------------------------------------|
|
||||||
| `getAccountInfo` | Accounts | pubkey ; config? {commitment, encoding, dataSlice, minContextSlot} | RpcResponse<Account\|null> | Stable | Supporté | typed_adapter | `0.2.2` | params/encoding/dataSlice ; account/null ; RPC error | [Solana](https://solana.com/docs/rpc/http/getaccountinfo) |
|
| `getAccountInfo` | Accounts | pubkey ; config? {commitment, encoding, dataSlice, minContextSlot} | RpcResponse<Account / null> | Stable | Supporté | typed_adapter | `0.2.2` | params/encoding/dataSlice ; account/null ; RPC error | [Solana](https://solana.com/docs/rpc/http/getaccountinfo) |
|
||||||
| `getBalance` | Accounts | pubkey ; config? {commitment, minContextSlot} | RpcResponse<u64> | Stable | Supporté | typed_adapter | `0.2.1` | params/config ; value u64 ; context/error | [Solana](https://solana.com/docs/rpc/http/getbalance) |
|
| `getBalance` | Accounts | pubkey ; config? {commitment, minContextSlot} | RpcResponse<u64> | Stable | Supporté | typed_adapter | `0.2.1` | params/config ; value u64 ; context/error | [Solana](https://solana.com/docs/rpc/http/getbalance) |
|
||||||
| `getLargestAccounts` | Accounts | config? {commitment, filter, sortResults} | RpcResponse<[LargestAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | config/filter/sort ; array | [Solana](https://solana.com/docs/rpc/http/getlargestaccounts) |
|
| `getLargestAccounts` | Accounts | config? {commitment, filter, sortResults} | RpcResponse<[LargestAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | config/filter/sort ; array | [Solana](https://solana.com/docs/rpc/http/getlargestaccounts) |
|
||||||
| `getMinimumBalanceForRentExemption` | Accounts | data_len ; config? {commitment} | u64 | Stable | Supporté | typed_adapter | `0.2.2` | data length/config ; u64 | [Solana](https://solana.com/docs/rpc/http/getminimumbalanceforrentexemption) |
|
| `getMinimumBalanceForRentExemption` | Accounts | data_len ; config? {commitment} | u64 | Stable | Supporté | typed_adapter | `0.2.2` | data length/config ; u64 | [Solana](https://solana.com/docs/rpc/http/getminimumbalanceforrentexemption) |
|
||||||
| `getMultipleAccounts` | Accounts | pubkeys <= 100 ; config? {commitment, minContextSlot, dataSlice, encoding} | RpcResponse<[Account\|null]> | Stable | Supporté | typed_adapter | `0.2.2` | max/params ; mixed account/null ; encoding | [Solana](https://solana.com/docs/rpc/http/getmultipleaccounts) |
|
| `getMultipleAccounts` | Accounts | pubkeys <= 100 ; config? {commitment, minContextSlot, dataSlice, encoding} | RpcResponse<[Account / null]> | Stable | Supporté | typed_adapter | `0.2.2` | max/params ; mixed account/null ; encoding | [Solana](https://solana.com/docs/rpc/http/getmultipleaccounts) |
|
||||||
| `getProgramAccounts` | Accounts | program pubkey ; config? {commitment, minContextSlot, withContext, encoding, dataSlice, filters, sortResults} | [KeyedAccount] ou RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | filters/dataSlice ; withContext false/true ; errors | [Solana](https://solana.com/docs/rpc/http/getprogramaccounts) |
|
| `getProgramAccounts` | Accounts | program pubkey ; config? {commitment, minContextSlot, withContext, encoding, dataSlice, filters, sortResults} | [KeyedAccount] ou RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | filters/dataSlice ; withContext false/true ; errors | [Solana](https://solana.com/docs/rpc/http/getprogramaccounts) |
|
||||||
| `getTokenAccountBalance` | Tokens | token account ; config? {commitment} | RpcResponse<TokenAmount> | Stable | Supporté | typed_adapter | `0.2.2` | config ; token amount | [Solana](https://solana.com/docs/rpc/http/gettokenaccountbalance) |
|
| `getTokenAccountBalance` | Tokens | token account ; config? {commitment} | RpcResponse<TokenAmount> | Stable | Supporté | typed_adapter | `0.2.2` | config ; token amount | [Solana](https://solana.com/docs/rpc/http/gettokenaccountbalance) |
|
||||||
| `getTokenAccountsByDelegate` | Tokens | delegate ; filter {mint\|programId} ; config? {commitment,minContextSlot,dataSlice,encoding} | RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | mint/programId exclusifs ; config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenaccountsbydelegate) |
|
| `getTokenAccountsByDelegate` | Tokens | delegate ; filter {mint / programId} ; config? {commitment,minContextSlot,dataSlice,encoding} | RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | mint/programId exclusifs ; config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenaccountsbydelegate) |
|
||||||
| `getTokenAccountsByOwner` | Tokens | owner ; filter {mint\|programId} ; config? {commitment,minContextSlot,dataSlice,encoding} | RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | mint/programId exclusifs ; config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenaccountsbyowner) |
|
| `getTokenAccountsByOwner` | Tokens | owner ; filter {mint / programId} ; config? {commitment,minContextSlot,dataSlice,encoding} | RpcResponse<[KeyedAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | mint/programId exclusifs ; config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenaccountsbyowner) |
|
||||||
| `getTokenLargestAccounts` | Tokens | mint ; config? {commitment} | RpcResponse<[TokenLargestAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenlargestaccounts) |
|
| `getTokenLargestAccounts` | Tokens | mint ; config? {commitment} | RpcResponse<[TokenLargestAccount]> | Stable | Supporté | typed_adapter | `0.2.2` | config ; array | [Solana](https://solana.com/docs/rpc/http/gettokenlargestaccounts) |
|
||||||
| `getTokenSupply` | Tokens | mint ; config? {commitment} | RpcResponse<TokenAmount> | Stable | Supporté | typed_adapter | `0.2.2` | config ; TokenAmount | [Solana](https://solana.com/docs/rpc/http/gettokensupply) |
|
| `getTokenSupply` | Tokens | mint ; config? {commitment} | RpcResponse<TokenAmount> | Stable | Supporté | typed_adapter | `0.2.2` | config ; TokenAmount | [Solana](https://solana.com/docs/rpc/http/gettokensupply) |
|
||||||
| `getFeeForMessage` | Transactions | message base64 ; config? {commitment,minContextSlot} | RpcResponse<u64\|null> | Stable | Supporté | typed_adapter | `0.2.3` | message/config ; fee/null ; error | [Solana](https://solana.com/docs/rpc/http/getfeeformessage) |
|
| `getFeeForMessage` | Transactions | message base64 ; config? {commitment,minContextSlot} | RpcResponse<u64 / null> | Stable | Supporté | typed_adapter | `0.2.3` | message/config ; fee/null ; error | [Solana](https://solana.com/docs/rpc/http/getfeeformessage) |
|
||||||
| `getLatestBlockhash` | Transactions | config? {commitment,minContextSlot} | RpcResponse<{blockhash,lastValidBlockHeight}> | Stable | Supporté | typed_adapter | `0.2.3` | config ; object | [Solana](https://solana.com/docs/rpc/http/getlatestblockhash) |
|
| `getLatestBlockhash` | Transactions | config? {commitment,minContextSlot} | RpcResponse<{blockhash,lastValidBlockHeight}> | Stable | Supporté | typed_adapter | `0.2.3` | config ; object | [Solana](https://solana.com/docs/rpc/http/getlatestblockhash) |
|
||||||
| `getRecentPrioritizationFees` | Transactions | pubkeys? <= 128 | [{slot,prioritizationFee}] | Stable | Supporté | typed_adapter | `0.2.3` | no params / addresses ; max ; array | [Solana](https://solana.com/docs/rpc/http/getrecentprioritizationfees) |
|
| `getRecentPrioritizationFees` | Transactions | pubkeys? <= 128 | [{slot,prioritizationFee}] | Stable | Supporté | typed_adapter | `0.2.3` | no params / addresses ; max ; array | [Solana](https://solana.com/docs/rpc/http/getrecentprioritizationfees) |
|
||||||
| `getSignaturesForAddress` | Transactions | address ; config? {commitment,minContextSlot,limit,before,until} | [SignatureInfo] | Stable | Supporté | typed_adapter | `0.2.3` | pagination/config ; nullable memo/blockTime/status | [Solana](https://solana.com/docs/rpc/http/getsignaturesforaddress) |
|
| `getSignaturesForAddress` | Transactions | address ; config? {commitment,minContextSlot,limit,before,until} | [SignatureInfo] | Stable | Supporté | typed_adapter | `0.2.3` | pagination/config ; nullable memo/blockTime/status | [Solana](https://solana.com/docs/rpc/http/getsignaturesforaddress) |
|
||||||
| `getSignatureStatuses` | Transactions | signatures <= 256 ; config? {searchTransactionHistory} | RpcResponse<[SignatureStatus\|null]> | Stable | Supporté | typed_adapter | `0.2.3` | max ; cache/history ; object/null | [Solana](https://solana.com/docs/rpc/http/getsignaturestatuses) |
|
| `getSignatureStatuses` | Transactions | signatures <= 256 ; config? {searchTransactionHistory} | RpcResponse<[SignatureStatus / null]> | Stable | Supporté | typed_adapter | `0.2.3` | max ; cache/history ; object/null | [Solana](https://solana.com/docs/rpc/http/getsignaturestatuses) |
|
||||||
| `getTransaction` | Transactions | signature ; config? {commitment,maxSupportedTransactionVersion,encoding} ; legacy bare encoding deprecated | TransactionResponse\|null | Stable; forme legacy deprecated | Supporté | typed_adapter | `0.2.3` | config + legacy warning ; all encodings ; null ; error | [Solana](https://solana.com/docs/rpc/http/gettransaction) |
|
| `getTransaction` | Transactions | signature ; config? {commitment,maxSupportedTransactionVersion,encoding} ; legacy bare encoding deprecated | TransactionResponse / null | Stable; forme legacy deprecated | Supporté | typed_adapter | `0.2.3` | config + legacy warning ; all encodings ; null ; error | [Solana](https://solana.com/docs/rpc/http/gettransaction) |
|
||||||
| `getTransactionCount` | Transactions | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.3` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/gettransactioncount) |
|
| `getTransactionCount` | Transactions | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.3` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/gettransactioncount) |
|
||||||
| `isBlockhashValid` | Transactions | blockhash ; config? {commitment,minContextSlot} | RpcResponse<bool> | Stable | Supporté | typed_adapter | `0.2.3` | hash/config ; bool | [Solana](https://solana.com/docs/rpc/http/isblockhashvalid) |
|
| `isBlockhashValid` | Transactions | blockhash ; config? {commitment,minContextSlot} | RpcResponse<bool> | Stable | Supporté | typed_adapter | `0.2.3` | hash/config ; bool | [Solana](https://solana.com/docs/rpc/http/isblockhashvalid) |
|
||||||
| `requestAirdrop` | Transactions | pubkey ; lamports ; config? {commitment,recentBlockhash} | signature | Stable | Supporté | typed_adapter | `0.2.3` | serialization ; signature/error ; no-resend policy | [Solana](https://solana.com/docs/rpc/http/requestairdrop) |
|
| `requestAirdrop` | Transactions | pubkey ; lamports ; config? {commitment,recentBlockhash} | signature | Stable | Supporté | typed_adapter | `0.2.3` | serialization ; signature/error ; no-resend policy | [Solana](https://solana.com/docs/rpc/http/requestairdrop) |
|
||||||
| `sendTransaction` | Transactions | signed transaction ; config? {encoding,skipPreflight,preflightCommitment,maxRetries,minContextSlot} | signature | Stable | Supporté | typed_adapter | `0.2.3` | all configs ; RPC error ; timeout/no-resend | [Solana](https://solana.com/docs/rpc/http/sendtransaction) |
|
| `sendTransaction` | Transactions | signed transaction ; config? {encoding,skipPreflight,preflightCommitment,maxRetries,minContextSlot} | signature | Stable | Supporté | typed_adapter | `0.2.3` | all configs ; RPC error ; timeout/no-resend | [Solana](https://solana.com/docs/rpc/http/sendtransaction) |
|
||||||
| `simulateTransaction` | Transactions | transaction ; config? {commitment,encoding,replaceRecentBlockhash,sigVerify,minContextSlot,innerInstructions,accounts} | RpcResponse<SimulationResult> | Stable | Supporté | typed_adapter | `0.2.3` | configs compatibles/incompatibles ; logs/accounts/null/error | [Solana](https://solana.com/docs/rpc/http/simulatetransaction) |
|
| `simulateTransaction` | Transactions | transaction ; config? {commitment,encoding,replaceRecentBlockhash,sigVerify,minContextSlot,innerInstructions,accounts} | RpcResponse<SimulationResult> | Stable | Supporté | typed_adapter | `0.2.3` | configs compatibles/incompatibles ; logs/accounts/null/error | [Solana](https://solana.com/docs/rpc/http/simulatetransaction) |
|
||||||
| `getBlock` | Blocks | slot ; config? {commitment,encoding,transactionDetails,maxSupportedTransactionVersion,rewards} ; legacy bare encoding deprecated | BlockResponse\|null | Stable; forme legacy deprecated | Supporté | typed_adapter | `0.2.4` | config + legacy warning ; transactionDetails variants ; null | [Solana](https://solana.com/docs/rpc/http/getblock) |
|
| `getBlock` | Blocks | slot ; config? {commitment,encoding,transactionDetails,maxSupportedTransactionVersion,rewards} ; legacy bare encoding deprecated | BlockResponse / null | Stable; forme legacy deprecated | Supporté | typed_adapter | `0.2.4` | config + legacy warning ; transactionDetails variants ; null | [Solana](https://solana.com/docs/rpc/http/getblock) |
|
||||||
| `getBlockCommitment` | Blocks | slot | {commitment:[u64]\|null,totalStake:u64} | Stable | Supporté | typed_adapter | `0.2.4` | slot ; commitment null/array | [Solana](https://solana.com/docs/rpc/http/getblockcommitment) |
|
| `getBlockCommitment` | Blocks | slot | {commitment:[u64] / null,totalStake:u64} | Stable | Supporté | typed_adapter | `0.2.4` | slot ; commitment null/array | [Solana](https://solana.com/docs/rpc/http/getblockcommitment) |
|
||||||
| `getBlockHeight` | Blocks | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.4` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/getblockheight) |
|
| `getBlockHeight` | Blocks | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.4` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/getblockheight) |
|
||||||
| `getBlockProduction` | Blocks | config? {commitment,identity,range} | RpcResponse<BlockProduction> | Stable | Supporté | typed_adapter | `0.2.4` | identity/range/config ; map | [Solana](https://solana.com/docs/rpc/http/getblockproduction) |
|
| `getBlockProduction` | Blocks | config? {commitment,identity,range} | RpcResponse<BlockProduction> | Stable | Supporté | typed_adapter | `0.2.4` | identity/range/config ; map | [Solana](https://solana.com/docs/rpc/http/getblockproduction) |
|
||||||
| `getBlocks` | Blocks | startSlot ; endSlot? ou config? ; config? {commitment,minContextSlot} | [u64] | Stable | Supporté | typed_adapter | `0.2.4` | overload 1/2/3 params ; max range 500k ; empty | [Solana](https://solana.com/docs/rpc/http/getblocks) |
|
| `getBlocks` | Blocks | startSlot ; endSlot? ou config? ; config? {commitment,minContextSlot} | [u64] | Stable | Supporté | typed_adapter | `0.2.4` | overload 1/2/3 params ; max range 500k ; empty | [Solana](https://solana.com/docs/rpc/http/getblocks) |
|
||||||
@@ -267,19 +267,19 @@ Colonnes : nom, catégorie, paramètres/config à préserver, forme de résultat
|
|||||||
| `getEpochSchedule` | Cluster | aucun | EpochSchedule | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; object | [Solana](https://solana.com/docs/rpc/http/getepochschedule) |
|
| `getEpochSchedule` | Cluster | aucun | EpochSchedule | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; object | [Solana](https://solana.com/docs/rpc/http/getepochschedule) |
|
||||||
| `getGenesisHash` | Cluster | aucun | string base58 | Stable | Supporté | typed_adapter | `0.2.1` | empty params ; hash string ; error | [Solana](https://solana.com/docs/rpc/http/getgenesishash) |
|
| `getGenesisHash` | Cluster | aucun | string base58 | Stable | Supporté | typed_adapter | `0.2.1` | empty params ; hash string ; error | [Solana](https://solana.com/docs/rpc/http/getgenesishash) |
|
||||||
| `getHealth` | Cluster | aucun | "ok" ou RPC unhealthy error | Stable | Supporté | typed_adapter | `0.2.1` | healthy ; unhealthy RPC error | [Solana](https://solana.com/docs/rpc/http/gethealth) |
|
| `getHealth` | Cluster | aucun | "ok" ou RPC unhealthy error | Stable | Supporté | typed_adapter | `0.2.1` | healthy ; unhealthy RPC error | [Solana](https://solana.com/docs/rpc/http/gethealth) |
|
||||||
| `getHighestSnapshotSlot` | Cluster | aucun | {full:u64,incremental:u64\|null} | Stable | Supporté | typed_adapter | `0.2.2` | incremental null ; no snapshot/error | [Solana](https://solana.com/docs/rpc/http/gethighestsnapshotslot) |
|
| `getHighestSnapshotSlot` | Cluster | aucun | {full:u64,incremental:u64 / null} | Stable | Supporté | typed_adapter | `0.2.2` | incremental null ; no snapshot/error | [Solana](https://solana.com/docs/rpc/http/gethighestsnapshotslot) |
|
||||||
| `getIdentity` | Cluster | aucun | {identity:string} | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; identity | [Solana](https://solana.com/docs/rpc/http/getidentity) |
|
| `getIdentity` | Cluster | aucun | {identity:string} | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; identity | [Solana](https://solana.com/docs/rpc/http/getidentity) |
|
||||||
| `getLeaderSchedule` | Cluster | slot? \| config? \| null ; config? {commitment,identity} | map identity->[slot_index] \| null | Stable | Supporté | typed_adapter | `0.2.2` | all overloads ; filter ; null | [Solana](https://solana.com/docs/rpc/http/getleaderschedule) |
|
| `getLeaderSchedule` | Cluster | slot? / config? / null ; config? {commitment,identity} | map identity->[slot_index] / null | Stable | Supporté | typed_adapter | `0.2.2` | all overloads ; filter ; null | [Solana](https://solana.com/docs/rpc/http/getleaderschedule) |
|
||||||
| `getMaxRetransmitSlot` | Cluster | aucun | u64 | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; u64 | [Solana](https://solana.com/docs/rpc/http/getmaxretransmitslot) |
|
| `getMaxRetransmitSlot` | Cluster | aucun | u64 | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; u64 | [Solana](https://solana.com/docs/rpc/http/getmaxretransmitslot) |
|
||||||
| `getMaxShredInsertSlot` | Cluster | aucun | u64 | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; u64 | [Solana](https://solana.com/docs/rpc/http/getmaxshredinsertslot) |
|
| `getMaxShredInsertSlot` | Cluster | aucun | u64 | Stable | Supporté | typed_adapter | `0.2.2` | empty params ; u64 | [Solana](https://solana.com/docs/rpc/http/getmaxshredinsertslot) |
|
||||||
| `getSlot` | Cluster | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.2` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/getslot) |
|
| `getSlot` | Cluster | config? {commitment,minContextSlot} | u64 | Stable | Supporté | typed_adapter | `0.2.2` | config ; u64 | [Solana](https://solana.com/docs/rpc/http/getslot) |
|
||||||
| `getSlotLeader` | Cluster | config? {commitment,minContextSlot} | string pubkey | Stable | Supporté | typed_adapter | `0.2.2` | config ; pubkey | [Solana](https://solana.com/docs/rpc/http/getslotleader) |
|
| `getSlotLeader` | Cluster | config? {commitment,minContextSlot} | string pubkey | Stable | Supporté | typed_adapter | `0.2.2` | config ; pubkey | [Solana](https://solana.com/docs/rpc/http/getslotleader) |
|
||||||
| `getSlotLeaders` | Cluster | startSlot ; limit 1..5000 | [string pubkey] | Stable | Supporté | typed_adapter | `0.2.2` | limit boundaries ; array | [Solana](https://solana.com/docs/rpc/http/getslotleaders) |
|
| `getSlotLeaders` | Cluster | startSlot ; limit 1..5000 | [string pubkey] | Stable | Supporté | typed_adapter | `0.2.2` | limit boundaries ; array | [Solana](https://solana.com/docs/rpc/http/getslotleaders) |
|
||||||
| `getVersion` | Cluster | aucun | {solana-core:string,feature-set:u32\|null} | Stable | Supporté | typed_adapter | `0.2.1` | empty params ; feature-set present/null | [Solana](https://solana.com/docs/rpc/http/getversion) |
|
| `getVersion` | Cluster | aucun | {solana-core:string,feature-set:u32 / null} | Stable | Supporté | typed_adapter | `0.2.1` | empty params ; feature-set present/null | [Solana](https://solana.com/docs/rpc/http/getversion) |
|
||||||
| `getVoteAccounts` | Cluster | config? {commitment,votePubkey,keepUnstakedDelinquents,delinquentSlotDistance} | {current:[VoteAccount],delinquent:[VoteAccount]} | Stable | Supporté | typed_adapter | `0.2.2` | filters/config ; both sets | [Solana](https://solana.com/docs/rpc/http/getvoteaccounts) |
|
| `getVoteAccounts` | Cluster | config? {commitment,votePubkey,keepUnstakedDelinquents,delinquentSlotDistance} | {current:[VoteAccount],delinquent:[VoteAccount]} | Stable | Supporté | typed_adapter | `0.2.2` | filters/config ; both sets | [Solana](https://solana.com/docs/rpc/http/getvoteaccounts) |
|
||||||
| `getInflationGovernor` | Economics | config? {commitment} | InflationGovernor | Stable | Supporté | typed_adapter | `0.2.4` | config ; f64 fields | [Solana](https://solana.com/docs/rpc/http/getinflationgovernor) |
|
| `getInflationGovernor` | Economics | config? {commitment} | InflationGovernor | Stable | Supporté | typed_adapter | `0.2.4` | config ; f64 fields | [Solana](https://solana.com/docs/rpc/http/getinflationgovernor) |
|
||||||
| `getInflationRate` | Economics | aucun | {total,validator,foundation:f64,epoch:u64} | Stable | Supporté | typed_adapter | `0.2.4` | empty params ; object | [Solana](https://solana.com/docs/rpc/http/getinflationrate) |
|
| `getInflationRate` | Economics | aucun | {total,validator,foundation:f64,epoch:u64} | Stable | Supporté | typed_adapter | `0.2.4` | empty params ; object | [Solana](https://solana.com/docs/rpc/http/getinflationrate) |
|
||||||
| `getInflationReward` | Economics | addresses ; config? {commitment,epoch,minContextSlot} | [InflationReward\|null] | Stable | Supporté | typed_adapter | `0.2.4` | addresses/config ; reward/null ; commission null | [Solana](https://solana.com/docs/rpc/http/getinflationreward) |
|
| `getInflationReward` | Economics | addresses ; config? {commitment,epoch,minContextSlot} | [InflationReward / null] | Stable | Supporté | typed_adapter | `0.2.4` | addresses/config ; reward/null ; commission null | [Solana](https://solana.com/docs/rpc/http/getinflationreward) |
|
||||||
| `getStakeMinimumDelegation` | Economics | config? {commitment,minContextSlot} | RpcResponse<u64> | Stable | Supporté | typed_adapter | `0.2.4` | config ; value | [Solana](https://solana.com/docs/rpc/http/getstakeminimumdelegation) |
|
| `getStakeMinimumDelegation` | Economics | config? {commitment,minContextSlot} | RpcResponse<u64> | Stable | Supporté | typed_adapter | `0.2.4` | config ; value | [Solana](https://solana.com/docs/rpc/http/getstakeminimumdelegation) |
|
||||||
| `getSupply` | Economics | config? {commitment,excludeNonCirculatingAccountsList} | RpcResponse<Supply> | Stable | Supporté | typed_adapter | `0.2.4` | config true/false ; list semantics | [Solana](https://solana.com/docs/rpc/http/getsupply) |
|
| `getSupply` | Economics | config? {commitment,excludeNonCirculatingAccountsList} | RpcResponse<Supply> | Stable | Supporté | typed_adapter | `0.2.4` | config true/false ; list semantics | [Solana](https://solana.com/docs/rpc/http/getsupply) |
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md -->
|
<!-- file: docs/plans/012-V0_2_5_WALLET_FOUNDATION_PLAN.md -->
|
||||||
<!-- version: 15 -->
|
<!-- version: 16 -->
|
||||||
|
|
||||||
# Plan `0.2.5` — Wallet foundation
|
# Plan `0.2.5` — Wallet foundation
|
||||||
|
|
||||||
@@ -205,23 +205,23 @@ Les permissions/ACL et le contrôle de qui peut écrire le chemin relèvent du s
|
|||||||
|
|
||||||
### 5.7 Matrice des garanties
|
### 5.7 Matrice des garanties
|
||||||
|
|
||||||
| Garantie | Cryptographie du format | Types/capabilities KSP |
|
| Garantie | Cryptographie du format | Types/capabilities KSP |
|
||||||
|------------------------------------------------------------------------|-------------------------------------------------------:|-------------------------:|
|
|------------------------------------------------------------------------|-------------------------------------------------------:|-------------------------:|
|
||||||
| confidentialité metadata verrouillées | oui | oui |
|
| confidentialité metadata verrouillées | oui | oui |
|
||||||
| confidentialité secret Solana face à VIEW | oui | oui |
|
| confidentialité secret Solana face à VIEW | oui | oui |
|
||||||
| indépendance VIEW/OWNER | oui | oui |
|
| indépendance VIEW/OWNER | oui | oui |
|
||||||
| VIEW ne signe pas | séparation de clés | oui |
|
| VIEW ne signe pas | séparation de clés | oui |
|
||||||
| VIEW ne modifie pas Pubkey/alias/notes via API | authentification OWNER des metadata | oui |
|
| VIEW ne modifie pas Pubkey/alias/notes via API | authentification OWNER des metadata | oui |
|
||||||
| VIEW change son propre password | slot VIEW rewrappable sous la même capability metadata | oui, opération dédiée |
|
| VIEW change son propre password | slot VIEW rewrappable sous la même capability metadata | oui, opération dédiée |
|
||||||
| VIEW ne change pas password OWNER / activation VIEW / autres key slots | authentification OWNER de l'état de contrôle | oui |
|
| VIEW ne change pas password OWNER / activation VIEW / autres key slots | authentification OWNER de l'état de contrôle | oui |
|
||||||
| metadata modifiées par VIEW détectées sous la même autorité OWNER | oui, `state_signature` | oui |
|
| metadata modifiées par VIEW détectées sous la même autorité OWNER | oui, `state_signature` | oui |
|
||||||
| détection corruption/tampering partiel | oui | parsing strict |
|
| détection corruption/tampering partiel | oui | parsing strict |
|
||||||
| signature Solana sans OWNER | impossible sous les primitives retenues | API absente hors OWNER |
|
| signature Solana sans OWNER | impossible sous les primitives retenues | API absente hors OWNER |
|
||||||
| export secret sans OWNER | secret non déverrouillable | API absente hors OWNER |
|
| export secret sans OWNER | secret non déverrouillable | API absente hors OWNER |
|
||||||
| mutation Pubkey/alias/notes/OWNER-state sans OWNER | état non authentifiable | API absente hors OWNER |
|
| mutation Pubkey/alias/notes/OWNER-state sans OWNER | état non authentifiable | API absente hors OWNER |
|
||||||
| no-clobber / atomic replace | non | propriété de persistence |
|
| no-clobber / atomic replace | non | propriété de persistence |
|
||||||
| détection remplacement total par un autre wallet valide | hors garantie V1 | hors garantie V1 |
|
| détection remplacement total par un autre wallet valide | hors garantie V1 | hors garantie V1 |
|
||||||
| détection rollback total vers une copie valide | hors garantie V1 | hors garantie V1 |
|
| détection rollback total vers une copie valide | hors garantie V1 | hors garantie V1 |
|
||||||
|
|
||||||
Les ACL/permissions OS ne figurent volontairement pas dans cette matrice : elles ne participent pas au modèle de sécurité de `.kspwallet` V1.
|
Les ACL/permissions OS ne figurent volontairement pas dans cette matrice : elles ne participent pas au modèle de sécurité de `.kspwallet` V1.
|
||||||
|
|
||||||
@@ -388,9 +388,9 @@ Audit source notable : `solana-keypair 3.1.2` contient un bloc `unsafe` interne
|
|||||||
|
|
||||||
| Primitive | Version publiée auditée | Décision V1 |
|
| Primitive | Version publiée auditée | Décision V1 |
|
||||||
|-----------|------------------------:|--------------------------------------------|
|
|-----------|------------------------:|--------------------------------------------|
|
||||||
| Argon2 | `0.5.3` | **retenu : Argon2id v19** |
|
| Argon2 | `0.5.3` | **retenu : Argon2id v19** |
|
||||||
| scrypt | `0.12.0` | alternative maintenue, non ajoutée |
|
| scrypt | `0.12.0` | alternative maintenue, non ajoutée |
|
||||||
| PBKDF2 | `0.13.0` | compatibilité/legacy seulement, non ajouté |
|
| PBKDF2 | `0.13.0` | compatibilité/legacy seulement, non ajouté |
|
||||||
|
|
||||||
Les paramètres Argon2 de création ont été mesurés avec le benchmark opérateur de `pre.004` : `64 MiB / 3 / 1 = 1742 ms`, `128 MiB / 3 / 1 = 3459 ms`, `256 MiB / 3 / 1 = 6925 ms` sur la machine/profil testés le 2026-08-19. `pre.005` retient donc **64 MiB / 3 passes / 1 lane** comme profil initial de création KSP, avec un salt CSPRNG indépendant de 32 octets par slot. Ce choix n'est copié ni de bot3, ni d'un RFC, ni d'un default de crate. Le fichier sérialise tous les paramètres nécessaires afin qu'un ancien wallet conserve son profil historique même lorsque les defaults KSP seront durcis.
|
Les paramètres Argon2 de création ont été mesurés avec le benchmark opérateur de `pre.004` : `64 MiB / 3 / 1 = 1742 ms`, `128 MiB / 3 / 1 = 3459 ms`, `256 MiB / 3 / 1 = 6925 ms` sur la machine/profil testés le 2026-08-19. `pre.005` retient donc **64 MiB / 3 passes / 1 lane** comme profil initial de création KSP, avec un salt CSPRNG indépendant de 32 octets par slot. Ce choix n'est copié ni de bot3, ni d'un RFC, ni d'un default de crate. Le fichier sérialise tous les paramètres nécessaires afin qu'un ancien wallet conserve son profil historique même lorsque les defaults KSP seront durcis.
|
||||||
|
|
||||||
@@ -398,10 +398,10 @@ Le parseur impose des **bornes maximales** avant de lancer le KDF, afin qu'un fi
|
|||||||
|
|
||||||
### 8.3 AEAD
|
### 8.3 AEAD
|
||||||
|
|
||||||
| Primitive | Version publiée auditée | Décision V1 |
|
| Primitive | Version publiée auditée | Décision V1 |
|
||||||
|--------------------|--------------------------:|------------------|
|
|--------------------|--------------------------:|------------------|
|
||||||
| XChaCha20-Poly1305 | `chacha20poly1305 0.11.0` | **retenu** |
|
| XChaCha20-Poly1305 | `chacha20poly1305 0.11.0` | **retenu** |
|
||||||
| AES-256-GCM-SIV | `aes-gcm-siv 0.12.0` | non retenu en V1 |
|
| AES-256-GCM-SIV | `aes-gcm-siv 0.12.0` | non retenu en V1 |
|
||||||
|
|
||||||
XChaCha20-Poly1305 fournit une clé 256 bits et un nonce étendu 192 bits. Un nonce neuf est généré pour chaque wrapping/chiffrement. La crate RustCrypto documente un audit NCC Group sans constat significatif.
|
XChaCha20-Poly1305 fournit une clé 256 bits et un nonce étendu 192 bits. Un nonce neuf est généré pour chaque wrapping/chiffrement. La crate RustCrypto documente un audit NCC Group sans constat significatif.
|
||||||
|
|
||||||
@@ -1107,20 +1107,20 @@ liens Markdown locaux audités
|
|||||||
|
|
||||||
| Domaine | Taille | Risque principal |
|
| Domaine | Taille | Risque principal |
|
||||||
|-------------------------------|-------:|----------------------------------------------|
|
|-------------------------------|-------:|----------------------------------------------|
|
||||||
| crate/API foundation | M | capability surface durable |
|
| crate/API foundation | M | capability surface durable |
|
||||||
| threat model | M | faux niveau de garantie |
|
| threat model | M | faux niveau de garantie |
|
||||||
| format wire | L | strict parsing/versioning |
|
| format wire | L | strict parsing/versioning |
|
||||||
| interop/test vectors | L | transcript exact multi-langages |
|
| interop/test vectors | L | transcript exact multi-langages |
|
||||||
| KDF/AEAD/key wrapping | L | paramètres + nonce/AAD |
|
| KDF/AEAD/key wrapping | L | paramètres + nonce/AAD |
|
||||||
| VIEW/OWNER key slots | XL | indépendance et rotations |
|
| VIEW/OWNER key slots | XL | indépendance et rotations |
|
||||||
| auth crypto metadata niveau B | L/XL | clé admin + transcript + substitution limits |
|
| auth crypto metadata niveau B | L/XL | clé admin + transcript + substitution limits |
|
||||||
| persistence | L | no-clobber + crash semantics multi-OS |
|
| persistence | L | no-clobber + crash semantics multi-OS |
|
||||||
| signing | M | aucun secret getter |
|
| signing | M | aucun secret getter |
|
||||||
| password/key-slot rotation | L | rotation vs vraie révocation |
|
| password/key-slot rotation | L | rotation vs vraie révocation |
|
||||||
| alias/notes | M | bornes + persistence |
|
| alias/notes | M | bornes + persistence |
|
||||||
| import/export | M/L | extension sans secret API générale |
|
| import/export | M/L | extension sans secret API générale |
|
||||||
| security/adversarial tests | XL | tamper/fault/diagnostics |
|
| security/adversarial tests | XL | tamper/fault/diagnostics |
|
||||||
| spec/README/USAGE | L | contrat externe autonome |
|
| spec/README/USAGE | L | contrat externe autonome |
|
||||||
|
|
||||||
Conclusion : **pas de rescoping fonctionnel**, mais split supplémentaire avant crypto lourde.
|
Conclusion : **pas de rescoping fonctionnel**, mais split supplémentaire avant crypto lourde.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md -->
|
<!-- file: docs/plans/014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md -->
|
||||||
<!-- version: 17 -->
|
<!-- version: 18 -->
|
||||||
|
|
||||||
# Plan `0.2.7` — WebSocket Solana standard
|
# Plan `0.2.7` — WebSocket Solana standard
|
||||||
|
|
||||||
@@ -361,10 +361,10 @@ Audit au 2026-08-22 :
|
|||||||
|
|
||||||
| Candidate | Version auditée | Verdict | Motif |
|
| Candidate | Version auditée | Verdict | Motif |
|
||||||
|---------------------|----------------:|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------|----------------:|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `tokio-tungstenite` | `0.30.0` | **retenue** | mature, Tokio-native, TLS rustls, continuité avec bot3 mais réauditée, contrôle de `WebSocketConfig`, client + serveur local de test |
|
| `tokio-tungstenite` | `0.30.0` | **retenue** | mature, Tokio-native, TLS rustls, continuité avec bot3 mais réauditée, contrôle de `WebSocketConfig`, client + serveur local de test |
|
||||||
| `futures-util` | `0.3.34` | **retenue comme utilitaire** | `StreamExt`/`SinkExt`; features minimales `std,sink` |
|
| `futures-util` | `0.3.34` | **retenue comme utilitaire** | `StreamExt`/`SinkExt`; features minimales `std,sink` |
|
||||||
| `tokio-websockets` | `0.13.3` | alternative viable, non retenue | strict/minimal et performant, mais exige davantage d'assemblage/features et n'apporte pas de besoin fonctionnel supérieur démontré pour cette foundation |
|
| `tokio-websockets` | `0.13.3` | alternative viable, non retenue | strict/minimal et performant, mais exige davantage d'assemblage/features et n'apporte pas de besoin fonctionnel supérieur démontré pour cette foundation |
|
||||||
| `fastwebsockets` | `0.10.0` | non retenue | plus bas niveau ; peut déléguer davantage de compliance au caller, inutile pour la première foundation KSP |
|
| `fastwebsockets` | `0.10.0` | non retenue | plus bas niveau ; peut déléguer davantage de compliance au caller, inutile pour la première foundation KSP |
|
||||||
|
|
||||||
Landing matérialisé par **`pre.004`** :
|
Landing matérialisé par **`pre.004`** :
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<!-- file: docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md -->
|
<!-- file: docs/plans/016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md -->
|
||||||
<!-- version: 22 -->
|
<!-- version: 23 -->
|
||||||
|
|
||||||
# Plan `0.2.9` — moteur Yellowstone gRPC + standard Solana + PublicNode
|
# Plan `0.2.9` — moteur Yellowstone gRPC + standard Solana + PublicNode
|
||||||
|
|
||||||
> **Statut courant : `0.2.9-pre.010-fix.001` est fermée par gate opérateur sans warning. `0.2.9-pre.011` est la tranche active : Config Transport V3, séparation explicite protocol/provider, mapping Config -> Yellowstone gRPC et premier profil PublicNode Mainnet. Le présent document a été réorganisé pendant `pre.011` : les décisions actives restent ici ; les journaux historiques détaillés restent dans `deltas/0.2.9/`.**
|
**Statut courant : `0.2.9-pre.011` est fermée par gate opérateur complet sans warning. `0.2.9-pre.012` est la tranche active de fermeture technique : réaudit upstream final, smoke PublicNode Mainnet opt-in, compliance finale, graphes Cargo, README/USAGE, règles de tableaux Markdown et prompt autonome `0.2.10 — OrbitFlare Yellowstone gRPC`. Les journaux détaillés restent dans `deltas/0.2.9/`; ce plan conserve l’état courant et les décisions.**
|
||||||
|
|
||||||
## 1. Objet et autorité de la release
|
## 1. Objet et autorité de la release
|
||||||
|
|
||||||
@@ -88,18 +88,24 @@ Les intégrations provider futures ne dupliquent jamais le moteur N1. Une façad
|
|||||||
|
|
||||||
## 4. Audit upstream et dépendances retenues
|
## 4. Audit upstream et dépendances retenues
|
||||||
|
|
||||||
### 4.1 Snapshot normatif du gate
|
### 4.1 Snapshot normatif et réaudit final
|
||||||
|
|
||||||
Le gate d'ouverture a réaudité Yellowstone courant et a constaté des versions indépendantes entre plugin, client et proto :
|
Le gate d'ouverture puis le réaudit final du 2026-08-24 confirment que les numéros du plugin, du client, du proto et des releases GitHub évoluent indépendamment. Il ne faut donc pas transformer un numéro de `master` en numéro de release publié.
|
||||||
|
|
||||||
|
État observé au réaudit final :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
release GitHub observée v15.1.2+solana.4.2.0 — 2026-08-18
|
latest release GitHub indexée v14.2.2+solana.4.1.0 — 2026-07-27
|
||||||
yellowstone-grpc-client 13.3.0
|
master yellowstone-grpc-geyser 15.1.2
|
||||||
yellowstone-grpc-proto 12.6.0
|
master yellowstone-grpc-client 13.3.0
|
||||||
prost/prost-types 0.14.x
|
master yellowstone-grpc-proto 12.6.0
|
||||||
tonic 0.14.x
|
master Agave Geyser / storage 4.2.0
|
||||||
|
master prost / prost-types / tonic 0.14.x
|
||||||
|
KSP yellowstone-grpc-proto direct ^12.6
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Le service `Geyser`, la shape de `SubscribeRequest` et les neuf variantes `SubscribeUpdate` retenues par KSP n'ont pas changé matériellement par rapport au gate `pre.001`. `SubscribeDeshred` reste explicitement hors scope `0.2.9`.
|
||||||
|
|
||||||
Les sources primaires restent :
|
Les sources primaires restent :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -530,18 +536,20 @@ La partie HTTP/WS de ce profil reste standard Solana ; seul l'endpoint gRPC est
|
|||||||
|
|
||||||
### 9.2 Testnet
|
### 9.2 Testnet
|
||||||
|
|
||||||
PublicNode affiche toujours une offre Solana Testnet gRPC, mais le hostname exact n'est pas exposé de façon suffisamment autoritative dans la surface publique inspectable pendant `pre.011`.
|
Le réaudit final du 2026-08-24 confirme que PublicNode annonce bien une capacité Solana Testnet gRPC. La surface officielle consultable ne fournit cependant toujours pas un hostname Testnet exact suffisamment autoritatif pour être versionné.
|
||||||
|
|
||||||
Décision :
|
Décision finale `0.2.9` :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
existence Testnet gRPC confirmée
|
existence Testnet gRPC confirmée
|
||||||
hostname Testnet exact non inventé
|
hostname Testnet exact non obtenu depuis une source autoritative
|
||||||
profil Testnet committé non en pre.011
|
hostname déduit ou tiers interdit
|
||||||
réaudit endpoint/live pre.012
|
profil Testnet committé non
|
||||||
|
smoke Testnet non
|
||||||
|
statut EXTERNAL BLOCK documentaire / NOT GUESSED
|
||||||
```
|
```
|
||||||
|
|
||||||
Un échec à confirmer le hostname Testnet ne bloque pas la fondation Mainnet ; il doit être documenté explicitement au gate final.
|
Ce bloc externe ne remet pas en cause la fondation Mainnet. Une release provider ultérieure peut matérialiser Testnet dès qu'une source PublicNode autoritative expose l'endpoint exact.
|
||||||
|
|
||||||
## 10. Threat model et bornes
|
## 10. Threat model et bornes
|
||||||
|
|
||||||
@@ -608,13 +616,16 @@ Les preuves détaillées restent dans les fichiers `deltas/0.2.9/*.md`. Le plan
|
|||||||
| `pre.008` + fix | Blocks + block_meta + entry | **CLOSED** |
|
| `pre.008` + fix | Blocks + block_meta + entry | **CLOSED** |
|
||||||
| `pre.009` + fix | bidi, Ping/Pong, backpressure, half-close, shutdown | **CLOSED** |
|
| `pre.009` + fix | bidi, Ping/Pong, backpressure, half-close, shutdown | **CLOSED** |
|
||||||
| `pre.010` + fix | reconnect, from_slot, ReplayInfo, gaps/duplicates | **CLOSED** |
|
| `pre.010` + fix | reconnect, from_slot, ReplayInfo, gaps/duplicates | **CLOSED** |
|
||||||
| `pre.011` | Config V3 + protocol/provider + PublicNode Mainnet | **ACTIVE CANDIDATE** |
|
| `pre.011` | Config V3 + protocol/provider + PublicNode Mainnet | **CLOSED** |
|
||||||
| `pre.012` | live/compliance/docs/graph/prompt suivant | **PLANNED** |
|
| `pre.012` | live/compliance/docs/graph/prompt suivant | **ACTIVE CANDIDATE** |
|
||||||
|
|
||||||
Gate opérateur de fermeture `pre.010-fix.001` :
|
Gate opérateur de fermeture `pre.011` :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
fmt/audit/check/clippy PASS sans warning
|
fmt/audit/check/clippy PASS sans warning
|
||||||
|
Config unit 113/113
|
||||||
|
Config public API 15/15
|
||||||
|
Config ownership 5/5
|
||||||
Transport unit 383/383
|
Transport unit 383/383
|
||||||
Transport public API 49/49
|
Transport public API 49/49
|
||||||
Transport completeness 43/43
|
Transport completeness 43/43
|
||||||
@@ -625,51 +636,31 @@ cargo test --workspace PASS
|
|||||||
|
|
||||||
## 13. Forecast restant
|
## 13. Forecast restant
|
||||||
|
|
||||||
### `pre.011` — Config V3 + PublicNode Mainnet
|
|
||||||
|
|
||||||
Cible :
|
|
||||||
|
|
||||||
```text
|
|
||||||
workspace.package.version = 0.2.9-pre.11
|
|
||||||
schema std.transport V3 strict + branches V1/V2
|
|
||||||
Config adapter gRPC
|
|
||||||
metadata publique/secrète + provenance
|
|
||||||
protocol/provider distincts
|
|
||||||
profil publicnode_mainnet
|
|
||||||
compatibilité API V2 conservée
|
|
||||||
plan 016 + validation 012 réorganisés
|
|
||||||
```
|
|
||||||
|
|
||||||
Preuves :
|
|
||||||
|
|
||||||
```text
|
|
||||||
schema Draft 2020-12 valide
|
|
||||||
fixtures V1/V2/V3
|
|
||||||
Config unit/public API/ownership
|
|
||||||
Transport non-régressé
|
|
||||||
workspace complet
|
|
||||||
```
|
|
||||||
|
|
||||||
### `pre.012` — fermeture technique et live
|
### `pre.012` — fermeture technique et live
|
||||||
|
|
||||||
Cible :
|
Cible active :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
workspace.package.version = 0.2.9-pre.12
|
||||||
réaudit upstream final
|
réaudit upstream final
|
||||||
réaudit PublicNode Testnet hostname
|
réaudit PublicNode Testnet sans endpoint inventé
|
||||||
smoke PublicNode Mainnet opt-in
|
smoke PublicNode Mainnet opt-in, programmatique et sans credential
|
||||||
Testnet opt-in seulement si endpoint exact confirmé
|
|
||||||
compliance HTTP 52 current + 14 historical
|
compliance HTTP 52 current + 14 historical
|
||||||
compliance Standard WS 18/18
|
compliance Standard WS 18/18
|
||||||
Helius WebSocket non régressé
|
Helius WebSocket non régressé
|
||||||
cargo tree direct + duplicates final
|
cargo tree direct + duplicates final
|
||||||
README/USAGE Transport synchronisés
|
README/USAGE Transport synchronisés
|
||||||
matrice validation fermée
|
règles Markdown sur les tableaux reformulées et auditées mécaniquement
|
||||||
prompt 0.2.10 préparé selon la séquence active
|
validation 012 fermée si les gates opérateur sont verts
|
||||||
|
prompt 0.2.10 OrbitFlare autonome
|
||||||
workspace final vert
|
workspace final vert
|
||||||
```
|
```
|
||||||
|
|
||||||
Si `pre.012` devient trop large, une `pre.013+` est créée ; le numéro n'est pas une deadline.
|
La candidate ajoute un smoke live **ignoré par défaut** ; elle ne modifie pas le runtime Yellowstone déjà fermé. Le smoke Mainnet utilise uniquement la façade provider-neutral KSP, `GetVersion` et `GetSlot`, avec TLS et sans metadata d'authentification.
|
||||||
|
|
||||||
|
Le Testnet reste `EXTERNAL BLOCK / NOT GUESSED` tant que PublicNode n'expose pas l'endpoint exact dans une source autoritative.
|
||||||
|
|
||||||
|
Si le gate opérateur révèle une anomalie réelle, un `pre.012-fix.001` est créé. Si la fermeture nécessite une nouvelle frontière fonctionnelle plutôt qu'un fix, une `pre.013+` est ouverte ; le numéro n'est pas une deadline.
|
||||||
|
|
||||||
## 14. Critères de split
|
## 14. Critères de split
|
||||||
|
|
||||||
@@ -689,27 +680,21 @@ moteur Yellowstone + façade Solana standard + Config provider-neutral + premiè
|
|||||||
|
|
||||||
## 15. Gates opérateur
|
## 15. Gates opérateur
|
||||||
|
|
||||||
Après changement Rust :
|
Gate `pre.012` :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all
|
cargo fmt --all
|
||||||
python3 scripts/audit_rust_workspace_rules.py
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.9
|
||||||
cargo check --workspace
|
cargo check --workspace
|
||||||
cargo clippy --workspace --all-targets
|
cargo clippy --workspace --all-targets
|
||||||
```
|
|
||||||
|
|
||||||
Pour `pre.011` :
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cargo test -p ksp-config-lib
|
cargo test -p ksp-config-lib
|
||||||
cargo test -p ksp-config-lib --test public_api
|
|
||||||
cargo test -p ksp-config-lib --test ownership
|
|
||||||
cargo test -p ksp-onchain-transport-lib
|
cargo test -p ksp-onchain-transport-lib
|
||||||
cargo test -p ksp-core-lib --test workspace_dependencies
|
cargo test -p ksp-core-lib --test workspace_dependencies
|
||||||
cargo test --workspace
|
cargo test --workspace
|
||||||
```
|
```
|
||||||
|
|
||||||
Le graphe de dépendances gRPC n'est pas modifié par `pre.011`; son gate final complet reste en `pre.012` :
|
Graphes finaux :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo tree -p ksp-onchain-transport-lib
|
cargo tree -p ksp-onchain-transport-lib
|
||||||
@@ -717,6 +702,14 @@ cargo tree -p ksp-onchain-transport-lib --duplicates
|
|||||||
cargo tree --duplicates
|
cargo tree --duplicates
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Smoke live opt-in Mainnet :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Le smoke n'est jamais déclaré réussi avant exécution. Un incident externe PublicNode/TLS/réseau est consigné comme tel et ne doit pas être maquillé en PASS local. Le Testnet n'est pas exécuté tant que son endpoint exact n'est pas confirmé par une source PublicNode autoritative.
|
||||||
|
|
||||||
## 16. Conditions de clôture `0.2.9`
|
## 16. Conditions de clôture `0.2.9`
|
||||||
|
|
||||||
```text
|
```text
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
|
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
|
||||||
<!-- version: 4 -->
|
<!-- version: 5 -->
|
||||||
|
|
||||||
# Règles de documentation
|
# Règles de documentation
|
||||||
|
|
||||||
@@ -32,6 +32,15 @@ Les règles `DOC-*` s'appliquent aux documents Markdown internes et à leur orga
|
|||||||
- **DOC-IDEAS-003** — Lorsqu'une idée devient un engagement, elle est transférée vers le roadmap ou un plan ; lorsqu'elle devient une décision durable, elle est reportée dans le document normatif ou architectural approprié. `IDEAS.md` conserve une trace concise de son issue.
|
- **DOC-IDEAS-003** — Lorsqu'une idée devient un engagement, elle est transférée vers le roadmap ou un plan ; lorsqu'elle devient une décision durable, elle est reportée dans le document normatif ou architectural approprié. `IDEAS.md` conserve une trace concise de son issue.
|
||||||
- **DOC-IDEAS-004** — `IDEAS.md` ne doit pas devenir un second roadmap ni une liste de tâches de développement promises.
|
- **DOC-IDEAS-004** — `IDEAS.md` ne doit pas devenir un second roadmap ni une liste de tâches de développement promises.
|
||||||
|
|
||||||
|
## Format des tableaux Markdown
|
||||||
|
|
||||||
|
- **DOC-TABLE-001** — Un tableau Markdown KSP utilise `|` uniquement comme séparateur structurel de colonnes. Un caractère `|` littéral, y compris sous forme échappée `\|`, est interdit dans le contenu d’une cellule ; reformuler le contenu, utiliser `/`, `et`, une liste ou un bloc de code hors tableau.
|
||||||
|
- **DOC-TABLE-002** — Toutes les lignes d’un même tableau ont leurs séparateurs verticaux aux mêmes positions. La largeur de chaque colonne est déterminée par le contenu le plus large de cette colonne, en comptant l’en-tête et les lignes de données.
|
||||||
|
- **DOC-TABLE-003** — Chaque cellule de contenu commence par exactement un espace après le séparateur `|` gauche. Dans la cellule qui porte le contenu le plus large d’une colonne, il existe aussi exactement un espace entre le contenu et le séparateur `|` droit. Les cellules plus courtes conservent l’unique espace gauche et reçoivent uniquement le padding droit nécessaire pour aligner les séparateurs verticaux.
|
||||||
|
- **DOC-TABLE-004** — La ligne séparatrice en tirets occupe exactement la même largeur que chaque colonne ; les marqueurs `:` de l’alignement Markdown restent autorisés lorsqu’ils sont intentionnels. Le résultat attendu est équivalent au reformatage de tableau produit par RustRover, mais la règle structurelle KSP prime sur l’éditeur utilisé.
|
||||||
|
- **DOC-TABLE-005** — Lorsqu’une modification touche une ligne d’un tableau, le tableau entier est réaligné avant livraison. `python3 scripts/audit_markdown_tables.py <fichiers-markdown-modifiés>` est le canari mécanique recommandé pour les fichiers concernés ; les blocs de code fenced ne sont pas interprétés comme des tableaux.
|
||||||
|
- **DOC-TABLE-006** — L’immuabilité des deltas déjà publiés prime sur un reformatage rétrospectif : un ancien fichier `deltas/` n’est jamais réécrit uniquement pour satisfaire une règle de présentation introduite ultérieurement. Tout nouveau delta et tout autre tableau modifiable créé ou touché doivent en revanche respecter immédiatement `DOC-TABLE-001` à `DOC-TABLE-005`.
|
||||||
|
|
||||||
## Contenu et exactitude
|
## Contenu et exactitude
|
||||||
|
|
||||||
- **DOC-CONTENT-001** — Une documentation décrit l'état réellement décidé ou validé et distingue explicitement les hypothèses, propositions, TODO et questions ouvertes.
|
- **DOC-CONTENT-001** — Une documentation décrit l'état réellement décidé ou validé et distingue explicitement les hypothèses, propositions, TODO et questions ouvertes.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
|
<!-- file: docs/validation/010-V0_2_7_ONCHAIN_WEBSOCKET.md -->
|
||||||
<!-- version: 17 -->
|
<!-- version: 18 -->
|
||||||
|
|
||||||
# Validation `0.2.7` — WebSocket Solana standard
|
# Validation `0.2.7` — WebSocket Solana standard
|
||||||
|
|
||||||
@@ -33,26 +33,26 @@ Pour une paire unstable, l'unsubscribe associé est classé `Unstable pair` dans
|
|||||||
|
|
||||||
## 2. Matrice exhaustive des 18 opérations
|
## 2. Matrice exhaustive des 18 opérations
|
||||||
|
|
||||||
| # | Méthode | Type | Statut `pre.001` | Paramètres / résultat essentiels | Notification / paire | Stratégie de test | Source officielle | Compliance |
|
| # | Méthode | Type | Statut `pre.001` | Paramètres / résultat essentiels | Notification / paire | Stratégie de test | Source officielle | Compliance |
|
||||||
|---:|---------------------------|-------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------------|-------------------|
|
|---:|---------------------------|-------------|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------|---------------------------------------------------------------|-----------------------------------------------------------------|----------------|
|
||||||
| 1 | `accountSubscribe` | subscribe | Stable/documented | pubkey ; config `commitment`, `encoding`, `dataSlice` ; result numeric id ; `minContextSlot` upstream actuellement ignoré, donc non promis | `accountNotification` | fixture encodings/config + subscribe/notify | `https://solana.com/docs/rpc/websocket/accountsubscribe` | Done `pre.009` |
|
| 1 | `accountSubscribe` | subscribe | Stable/documented | pubkey ; config `commitment`, `encoding`, `dataSlice` ; result numeric id ; `minContextSlot` upstream actuellement ignoré, donc non promis | `accountNotification` | fixture encodings/config + subscribe/notify | `https://solana.com/docs/rpc/websocket/accountsubscribe` | Done `pre.009` |
|
||||||
| 2 | `accountUnsubscribe` | unsubscribe | Stable/documented | remote id ; `true` or RPC error unknown id | account pair | handle local -> remote id fixture | `https://solana.com/docs/rpc/websocket/accountunsubscribe` | Done `pre.009` |
|
| 2 | `accountUnsubscribe` | unsubscribe | Stable/documented | remote id ; `true` or RPC error unknown id | account pair | handle local -> remote id fixture | `https://solana.com/docs/rpc/websocket/accountunsubscribe` | Done `pre.009` |
|
||||||
| 3 | `blockSubscribe` | subscribe | **Unstable** | `all`/mentions filter ; confirmed/finalized ; encoding ; tx details ; max tx version ; showRewards | `blockNotification` | all options + null block/error + validator capability fixture | `https://solana.com/docs/rpc/websocket/blocksubscribe` | Done `pre.011` |
|
| 3 | `blockSubscribe` | subscribe | **Unstable** | `all`/mentions filter ; confirmed/finalized ; encoding ; tx details ; max tx version ; showRewards | `blockNotification` | all options + null block/error + validator capability fixture | `https://solana.com/docs/rpc/websocket/blocksubscribe` | Done `pre.011` |
|
||||||
| 4 | `blockUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | block pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/blockunsubscribe` | Done `pre.011` |
|
| 4 | `blockUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | block pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/blockunsubscribe` | Done `pre.011` |
|
||||||
| 5 | `logsSubscribe` | subscribe | Stable/documented | `all`, `allWithVotes`, exactly one `mentions`; commitment | `logsNotification` | 3 filters + invalid multi-mention + notification | `https://solana.com/docs/rpc/websocket/logssubscribe` | Done `pre.009` |
|
| 5 | `logsSubscribe` | subscribe | Stable/documented | `all`, `allWithVotes`, exactly one `mentions`; commitment | `logsNotification` | 3 filters + invalid multi-mention + notification | `https://solana.com/docs/rpc/websocket/logssubscribe` | Done `pre.009` |
|
||||||
| 6 | `logsUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | logs pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/logsunsubscribe` | Done `pre.009` |
|
| 6 | `logsUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | logs pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/logsunsubscribe` | Done `pre.009` |
|
||||||
| 7 | `programSubscribe` | subscribe | Stable/documented | program pubkey ; commitment ; filters ; encoding ; dataSlice ; `withContext` | `programNotification` | contexted/non-contexted fixtures + filters | `https://solana.com/docs/rpc/websocket/programsubscribe` | Done `pre.009` |
|
| 7 | `programSubscribe` | subscribe | Stable/documented | program pubkey ; commitment ; filters ; encoding ; dataSlice ; `withContext` | `programNotification` | contexted/non-contexted fixtures + filters | `https://solana.com/docs/rpc/websocket/programsubscribe` | Done `pre.009` |
|
||||||
| 8 | `programUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | program pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/programunsubscribe` | Done `pre.009` |
|
| 8 | `programUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | program pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/programunsubscribe` | Done `pre.009` |
|
||||||
| 9 | `rootSubscribe` | subscribe | Stable/documented | no params ; numeric id | `rootNotification` => `u64` | exact root fixture | `https://solana.com/docs/rpc/websocket/rootsubscribe` | Done `pre.010` |
|
| 9 | `rootSubscribe` | subscribe | Stable/documented | no params ; numeric id | `rootNotification` => `u64` | exact root fixture | `https://solana.com/docs/rpc/websocket/rootsubscribe` | Done `pre.010` |
|
||||||
| 10 | `rootUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | root pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/rootunsubscribe` | Done `pre.010` |
|
| 10 | `rootUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | root pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/rootunsubscribe` | Done `pre.010` |
|
||||||
| 11 | `signatureSubscribe` | subscribe | Stable/documented | first transaction signature ; commitment ; `enableReceivedNotification` | `signatureNotification` early string or terminal error object | early + terminal + auto-close/no-resubscribe | `https://solana.com/docs/rpc/websocket/signaturesubscribe` | Done `pre.010` |
|
| 11 | `signatureSubscribe` | subscribe | Stable/documented | first transaction signature ; commitment ; `enableReceivedNotification` | `signatureNotification` early string or terminal error object | early + terminal + auto-close/no-resubscribe | `https://solana.com/docs/rpc/websocket/signaturesubscribe` | Done `pre.010` |
|
||||||
| 12 | `signatureUnsubscribe` | unsubscribe | Stable/documented | remote id before terminal fire ; boolean/error | signature pair | cancel before terminal + stale after terminal | `https://solana.com/docs/rpc/websocket/signatureunsubscribe` | Done `pre.010` |
|
| 12 | `signatureUnsubscribe` | unsubscribe | Stable/documented | remote id before terminal fire ; boolean/error | signature pair | cancel before terminal + stale after terminal | `https://solana.com/docs/rpc/websocket/signatureunsubscribe` | Done `pre.010` |
|
||||||
| 13 | `slotSubscribe` | subscribe | Stable/documented | no params ; numeric id | `slotNotification` `{slot,parent,root}` | exact fixture + live smoke Devnet passé | `https://solana.com/docs/rpc/websocket/slotsubscribe` | Done `pre.010` |
|
| 13 | `slotSubscribe` | subscribe | Stable/documented | no params ; numeric id | `slotNotification` `{slot,parent,root}` | exact fixture + live smoke Devnet passé | `https://solana.com/docs/rpc/websocket/slotsubscribe` | Done `pre.010` |
|
||||||
| 14 | `slotUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | slot pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotunsubscribe` | Done `pre.010` |
|
| 14 | `slotUnsubscribe` | unsubscribe | Stable/documented | remote id ; boolean/error | slot pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotunsubscribe` | Done `pre.010` |
|
||||||
| 15 | `slotsUpdatesSubscribe` | subscribe | **Unstable** | no params ; numeric id | tagged `slotsUpdatesNotification` | each known variant + unknown fallback | `https://solana.com/docs/rpc/websocket/slotsupdatessubscribe` | Done `pre.011` |
|
| 15 | `slotsUpdatesSubscribe` | subscribe | **Unstable** | no params ; numeric id | tagged `slotsUpdatesNotification` | each known variant + unknown fallback | `https://solana.com/docs/rpc/websocket/slotsupdatessubscribe` | Done `pre.011` |
|
||||||
| 16 | `slotsUpdatesUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | slotsUpdates pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotsupdatesunsubscribe` | Done `pre.011` |
|
| 16 | `slotsUpdatesUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | slotsUpdates pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/slotsupdatesunsubscribe` | Done `pre.011` |
|
||||||
| 17 | `voteSubscribe` | subscribe | **Unstable** | no params ; validator flag required | `voteNotification` | fields + timestamp omitted/null/value + warning | `https://solana.com/docs/rpc/websocket/votesubscribe` | Done `pre.011` |
|
| 17 | `voteSubscribe` | subscribe | **Unstable** | no params ; validator flag required | `voteNotification` | fields + timestamp omitted/null/value + warning | `https://solana.com/docs/rpc/websocket/votesubscribe` | Done `pre.011` |
|
||||||
| 18 | `voteUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | vote pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/voteunsubscribe` | Done `pre.011` |
|
| 18 | `voteUnsubscribe` | unsubscribe | **Unstable pair** | remote id ; boolean/error | vote pair | generic registry unsubscribe | `https://solana.com/docs/rpc/websocket/voteunsubscribe` | Done `pre.011` |
|
||||||
|
|
||||||
## 3. Notification matrix
|
## 3. Notification matrix
|
||||||
|
|
||||||
@@ -206,22 +206,22 @@ Les votes observés sont gossip/pre-consensus ; aucune garantie d'entrée dans l
|
|||||||
|
|
||||||
## 7. Threat/security compliance initiale
|
## 7. Threat/security compliance initiale
|
||||||
|
|
||||||
| Invariant | Preuve attendue | Statut |
|
| Invariant | Preuve attendue | Statut |
|
||||||
|---------------------------------------------------|----------------------------------------------|--------------------------------------------------------|
|
|---------------------------------------------------|----------------------------------------------|----------------------------------------------------|
|
||||||
| URL/credentials absents de `Debug` | unit tests URL wrapper | **Done `pre.002`** |
|
| URL/credentials absents de `Debug` | unit tests URL wrapper | **Done `pre.002`** |
|
||||||
| URL/credentials absents des erreurs | validation URL + connection errors safe | **Done through `pre.004`** |
|
| URL/credentials absents des erreurs | validation URL + connection errors safe | **Done through `pre.004`** |
|
||||||
| URL/credentials absents des logs | actor logs only safe endpoint metadata | **Done through `pre.011`, source audit `pre.013`** |
|
| URL/credentials absents des logs | actor logs only safe endpoint metadata | **Done through `pre.011`, source audit `pre.013`** |
|
||||||
| snapshots sans URL/raw payload | unit shape + public contract | **Done `pre.002`** |
|
| snapshots sans URL/raw payload | unit shape + public contract | **Done `pre.002`** |
|
||||||
| frame/message finis | settings bornés + `WebSocketConfig` raccordé | **Done `pre.005`** |
|
| frame/message finis | settings bornés + `WebSocketConfig` raccordé | **Done `pre.005`** |
|
||||||
| JSON borné indirectement par message | oversized + malformed fixture | **Done `pre.005`** |
|
| JSON borné indirectement par message | oversized + malformed fixture | **Done `pre.005`** |
|
||||||
| queues notifications bornées | queue typed bornée + overflow isolé | **Done `pre.008`** |
|
| queues notifications bornées | queue typed bornée + overflow isolé | **Done `pre.008`** |
|
||||||
| pending RPC borné + timeout | map actor bornée + timeout request | **Done `pre.004`** |
|
| pending RPC borné + timeout | map actor bornée + timeout request | **Done `pre.004`** |
|
||||||
| reconnect loop bornée | repeated disconnect fixture | Done `pre.007` |
|
| reconnect loop bornée | repeated disconnect fixture | Done `pre.007` |
|
||||||
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Done `pre.007` |
|
| unsubscribe pendant reconnect ne resubscribe pas | race fixture | Done `pre.007` |
|
||||||
| signature terminale ne resubscribe pas | terminal fixture | **Done `pre.010`** |
|
| signature terminale ne resubscribe pas | terminal fixture | **Done `pre.010`** |
|
||||||
| shutdown ne bloque pas | peer hostile/no close ack fixture | **Done `pre.005`** |
|
| shutdown ne bloque pas | peer hostile/no close ack fixture | **Done `pre.005`** |
|
||||||
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | **Done `pre.013`, source + cargo tree opérateur** |
|
| no Store/Program/Wallet/Config dep dans Transport | cargo tree + source canary | **Done `pre.013`, source + cargo tree opérateur** |
|
||||||
| no direct `tracing` dans Transport | workspace audit + source audit | **Done `pre.002`** |
|
| no direct `tracing` dans Transport | workspace audit + source audit | **Done `pre.002`** |
|
||||||
|
|
||||||
## 8. Dependency compliance initiale
|
## 8. Dependency compliance initiale
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md -->
|
<!-- file: docs/validation/011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md -->
|
||||||
<!-- version: 25 -->
|
<!-- version: 26 -->
|
||||||
|
|
||||||
# Validation `0.2.8` — Helius LaserStream WebSocket
|
# Validation `0.2.8` — Helius LaserStream WebSocket
|
||||||
|
|
||||||
@@ -108,23 +108,23 @@ Verdict : **gate `0.2.8-pre.001` positif ; `pre.002` + `fix.001` et `pre.003` so
|
|||||||
|
|
||||||
## 3. Matrice provider normative
|
## 3. Matrice provider normative
|
||||||
|
|
||||||
| Capability | Standard KSP | Helius doc actuelle | Décision `0.2.8` | Surface Helius attendue | Preuve finale attendue |
|
| Capability | Standard KSP | Helius doc actuelle | Décision `0.2.8` | Surface Helius attendue | Preuve finale attendue |
|
||||||
|------------------------------|----------------:|-------------------------------------------------|--------------------------|-------------------------|---------------------------------------|
|
|------------------------------|----------------:|-------------------------------------------------|--------------------------|-------------------------|---------------------------------------|
|
||||||
| `accountSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
| `accountSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
||||||
| `logsSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
| `logsSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
||||||
| `programSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
| `programSubscribe` pair | oui | supporté | réutiliser wire standard | présente | exact wire + no regression |
|
||||||
| `rootSubscribe` pair | oui | supporté | réutiliser standard | présente | exact wire + no regression |
|
| `rootSubscribe` pair | oui | supporté | réutiliser standard | présente | exact wire + no regression |
|
||||||
| `signatureSubscribe` pair | oui | supporté | réutiliser standard | présente | one-shot conservé |
|
| `signatureSubscribe` pair | oui | supporté | réutiliser standard | présente | one-shot conservé |
|
||||||
| `slotSubscribe` pair | oui | supporté | réutiliser standard | présente | exact wire + no regression |
|
| `slotSubscribe` pair | oui | supporté | réutiliser standard | présente | exact wire + no regression |
|
||||||
| `blockSubscribe` pair | oui, unstable | non supporté | ne pas exposer Helius | **absente** | API absence + guard interne avant I/O |
|
| `blockSubscribe` pair | oui, unstable | non supporté | ne pas exposer Helius | **absente** | API absence + guard interne avant I/O |
|
||||||
| `slotsUpdatesSubscribe` pair | oui, unstable | page spécifique + overview courant = disponible | réutiliser wire standard | présente | exact wire + warning unstable |
|
| `slotsUpdatesSubscribe` pair | oui, unstable | page spécifique + overview courant = disponible | réutiliser wire standard | présente | exact wire + warning unstable |
|
||||||
| `voteSubscribe` pair | oui, unstable | non supporté | ne pas exposer Helius | **absente** | API absence + guard interne avant I/O |
|
| `voteSubscribe` pair | oui, unstable | non supporté | ne pas exposer Helius | **absente** | API absence + guard interne avant I/O |
|
||||||
| `transactionSubscribe` | non standard | extension Helius | ajouter typed | présente | request/ack/notification fixtures |
|
| `transactionSubscribe` | non standard | extension Helius | ajouter typed | présente | request/ack/notification fixtures |
|
||||||
| `transactionUnsubscribe` | non standard | documenté dans référence transaction | ajouter via handle | présente | exact method + late-message race |
|
| `transactionUnsubscribe` | non standard | documenté dans référence transaction | ajouter via handle | présente | exact method + late-message race |
|
||||||
| `tokenAccounts` | non standard | `none/balanceChanged/all` | ajouter typed | présente dans filter | enum + serialization |
|
| `tokenAccounts` | non standard | `none/balanceChanged/all` | ajouter typed | présente dans filter | enum + serialization |
|
||||||
| `notifyOn` account | non standard | deprecated, no-op Agave 4.2 | ne pas exposer | absente | absence DTO public |
|
| `notifyOn` account | non standard | deprecated, no-op Agave 4.2 | ne pas exposer | absente | absence DTO public |
|
||||||
| `notifyOn` program | non standard | deprecated, no-op Agave 4.2 | ne pas exposer | absente | absence DTO public |
|
| `notifyOn` program | non standard | deprecated, no-op Agave 4.2 | ne pas exposer | absente | absence DTO public |
|
||||||
| enhanced account extra | non standard | mentionné, wire exact non publié | report explicite | absente | réaudit final |
|
| enhanced account extra | non standard | mentionné, wire exact non publié | report explicite | absente | réaudit final |
|
||||||
| proactive heartbeat | absent standard | 10 min idle, ping recommandé | Helius-only actor policy | interne | deterministic timer tests |
|
| proactive heartbeat | absent standard | 10 min idle, ping recommandé | Helius-only actor policy | interne | deterministic timer tests |
|
||||||
| replay historique | absent standard | pas de contrat WS KSP | interdit | absent | docs/canary no promise |
|
| replay historique | absent standard | pas de contrat WS KSP | interdit | absent | docs/canary no promise |
|
||||||
|
|
||||||
@@ -134,16 +134,16 @@ Verdict : **gate `0.2.8-pre.001` positif ; `pre.002` + `fix.001` et `pre.003` so
|
|||||||
|
|
||||||
| Famille | `SolanaStandardWsSession` | `HeliusLaserStreamWsSession` | DTO/wire |
|
| Famille | `SolanaStandardWsSession` | `HeliusLaserStreamWsSession` | DTO/wire |
|
||||||
|--------------------|:-------------------------:|:----------------------------:|--------------------|
|
|--------------------|:-------------------------:|:----------------------------:|--------------------|
|
||||||
| Account | oui | oui | partagé standard |
|
| Account | oui | oui | partagé standard |
|
||||||
| Block | oui | **non** | standard seulement |
|
| Block | oui | **non** | standard seulement |
|
||||||
| Logs | oui | oui | partagé standard |
|
| Logs | oui | oui | partagé standard |
|
||||||
| Program | oui | oui | partagé standard |
|
| Program | oui | oui | partagé standard |
|
||||||
| Root | oui | oui | partagé standard |
|
| Root | oui | oui | partagé standard |
|
||||||
| Signature | oui | oui | partagé standard |
|
| Signature | oui | oui | partagé standard |
|
||||||
| Slot | oui | oui | partagé standard |
|
| Slot | oui | oui | partagé standard |
|
||||||
| SlotsUpdates | oui | oui | partagé standard |
|
| SlotsUpdates | oui | oui | partagé standard |
|
||||||
| Vote | oui | **non** | standard seulement |
|
| Vote | oui | **non** | standard seulement |
|
||||||
| Helius Transaction | **non** | oui | provider-specific |
|
| Helius Transaction | **non** | oui | provider-specific |
|
||||||
|
|
||||||
### 4.2 Invariants architecture
|
### 4.2 Invariants architecture
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<!-- file: docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md -->
|
<!-- file: docs/validation/012-V0_2_9_YELLOWSTONE_GRPC.md -->
|
||||||
<!-- version: 24 -->
|
<!-- version: 25 -->
|
||||||
|
|
||||||
# Validation `0.2.9` — Yellowstone gRPC standard + PublicNode
|
# Validation `0.2.9` — Yellowstone gRPC standard + PublicNode
|
||||||
|
|
||||||
> **Statut courant : `pre.010-fix.001` est fermée sans warning. `pre.011` est candidate et doit prouver Config Transport V3, le mapping Config -> Yellowstone gRPC, la séparation protocol/provider et le profil PublicNode Mainnet. Ce document a été restructuré : les logs détaillés historiques vivent dans `deltas/0.2.9/`; cette matrice porte les exigences et le verdict courant.**
|
**Statut courant : `pre.011` est fermée par gate opérateur complet sans warning. `pre.012` est la candidate de fermeture technique : réaudit upstream, smoke PublicNode Mainnet opt-in, graphes Cargo finaux, documentation, audit des tableaux Markdown et prompt `0.2.10 — OrbitFlare Yellowstone gRPC`. Les logs historiques détaillés restent dans `deltas/0.2.9/`.**
|
||||||
|
|
||||||
## 1. Autorités et baseline courante
|
## 1. Autorités et baseline courante
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ deltas/0.2.9/* pour l'historique immuable et les décisions postérieures au pro
|
|||||||
upstream Yellowstone primaire
|
upstream Yellowstone primaire
|
||||||
```
|
```
|
||||||
|
|
||||||
Baseline opérateur immédiatement avant `pre.011` (`0.2.9-pre.010-fix.001`) :
|
Baseline opérateur immédiatement avant `pre.012` (`0.2.9-pre.011`) :
|
||||||
|
|
||||||
| Gate | Résultat |
|
| Gate | Résultat |
|
||||||
|------------------------------------------|--------------------------|
|
|------------------------------------------|--------------------------|
|
||||||
@@ -26,6 +26,9 @@ Baseline opérateur immédiatement avant `pre.011` (`0.2.9-pre.010-fix.001`) :
|
|||||||
| audit Rust workspace | PASS, 0 candidate export |
|
| audit Rust workspace | PASS, 0 candidate export |
|
||||||
| `cargo check --workspace` | PASS |
|
| `cargo check --workspace` | PASS |
|
||||||
| `cargo clippy --workspace --all-targets` | PASS sans warning |
|
| `cargo clippy --workspace --all-targets` | PASS sans warning |
|
||||||
|
| Config unit | 113/113 PASS |
|
||||||
|
| Config public API | 15/15 PASS |
|
||||||
|
| Config ownership | 5/5 PASS |
|
||||||
| Transport unit | 383/383 PASS |
|
| Transport unit | 383/383 PASS |
|
||||||
| Transport public API | 49/49 PASS |
|
| Transport public API | 49/49 PASS |
|
||||||
| Transport release completeness | 43/43 PASS |
|
| Transport release completeness | 43/43 PASS |
|
||||||
@@ -33,7 +36,7 @@ Baseline opérateur immédiatement avant `pre.011` (`0.2.9-pre.010-fix.001`) :
|
|||||||
| workspace dependency canary | 3/3 PASS |
|
| workspace dependency canary | 3/3 PASS |
|
||||||
| `cargo test --workspace` | PASS |
|
| `cargo test --workspace` | PASS |
|
||||||
|
|
||||||
Cette baseline est le seuil de non-régression de `pre.011` pour Transport.
|
Cette baseline est le seuil de non-régression de `pre.012`.
|
||||||
|
|
||||||
## 2. Gate dépendances et licence
|
## 2. Gate dépendances et licence
|
||||||
|
|
||||||
@@ -47,7 +50,7 @@ Cette baseline est le seuil de non-régression de `pre.011` pour Transport.
|
|||||||
| raw client Tonic public | aucun | **PASS** |
|
| raw client Tonic public | aucun | **PASS** |
|
||||||
| graph final | réinspection `pre.012` | **PENDING FINAL** |
|
| graph final | réinspection `pre.012` | **PENDING FINAL** |
|
||||||
|
|
||||||
Le graphe n'est pas modifié par `pre.011`; aucune nouvelle dépendance Cargo n'est introduite dans cette tranche.
|
Le graphe de dépendances n'est pas modifié par `pre.012`; aucune nouvelle dépendance Cargo n'est introduite dans cette tranche.
|
||||||
|
|
||||||
## 3. Matrice service `Geyser`
|
## 3. Matrice service `Geyser`
|
||||||
|
|
||||||
@@ -215,17 +218,17 @@ state/error code safe
|
|||||||
|
|
||||||
### 8.1 Schema et backward compatibility
|
### 8.1 Schema et backward compatibility
|
||||||
|
|
||||||
Exigences candidate :
|
Le gate opérateur `pre.011` ferme les exigences suivantes :
|
||||||
|
|
||||||
| Exigence | Preuve source actuelle | Verdict avant gate opérateur |
|
| Exigence | Preuve | Verdict |
|
||||||
|------------------------------------------|------------------------------------------|------------------------------|
|
|------------------------------------------|-----------------------------------------|----------|
|
||||||
| schema `$id` V3 | `urn:ksp:schema:std.transport:v3` | **SOURCE OK** |
|
| schema `$id` V3 | `urn:ksp:schema:std.transport:v3` | **PASS** |
|
||||||
| branches V1/V2 conservées | `documentV1`, `documentV2`, `documentV3` | **SOURCE OK** |
|
| branches V1/V2 conservées | fixtures V1, V2 et document committé | **PASS** |
|
||||||
| V1 HTTP-only | fixture historique | **PENDING TEST** |
|
| V1 HTTP-only | `v1_transport_fixture...` | **PASS** |
|
||||||
| V2 HTTP+WS | fixture historique | **PENDING TEST** |
|
| V2 HTTP+WS | fixture V2 + compatibilité constructeur | **PASS** |
|
||||||
| V3 HTTP+WS+gRPC | fixture V3 + config committée | **PENDING TEST** |
|
| V3 HTTP+WS+gRPC | 113 tests Config | **PASS** |
|
||||||
| `grpc_endpoints` optionnel par profil V3 | profiles génériques sans gRPC | **PENDING TEST** |
|
| `grpc_endpoints` optionnel par profil V3 | profil `devnet_public` sans gRPC | **PASS** |
|
||||||
| no `additionalProperties` relaxation | branches strictes | **SOURCE OK** |
|
| propriétés inconnues refusées | branches schema strictes | **PASS** |
|
||||||
|
|
||||||
### 8.2 Mapping runtime
|
### 8.2 Mapping runtime
|
||||||
|
|
||||||
@@ -248,13 +251,13 @@ API :
|
|||||||
|---------------------------------|-------------------------------------|---------------|
|
|---------------------------------|-------------------------------------|---------------|
|
||||||
| `http_settings()` | inchangée | **OK** |
|
| `http_settings()` | inchangée | **OK** |
|
||||||
| `ws_settings()` | V1 None, V2/V3 selon profil | **OK** |
|
| `ws_settings()` | V1 None, V2/V3 selon profil | **OK** |
|
||||||
| `grpc_settings()` | V1/V2 None, V3 optionnel | **ADDED** |
|
| `grpc_settings()` | V1/V2 None, V3 optionnel | **PASS** |
|
||||||
| `into_transport_settings()` | tuple historique HTTP + WS inchangé | **PRESERVED** |
|
| `into_transport_settings()` | tuple historique HTTP + WS inchangé | **PASS** |
|
||||||
| `into_all_transport_settings()` | nouveau tuple HTTP + WS + gRPC | **ADDED** |
|
| `into_all_transport_settings()` | nouveau tuple HTTP + WS + gRPC | **PASS** |
|
||||||
|
|
||||||
### 8.3 Provenance et secrets
|
### 8.3 Provenance et secrets
|
||||||
|
|
||||||
Règles candidate :
|
Règles validées :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
metadata publique + provenance KSP_SECRET_* -> reject
|
metadata publique + provenance KSP_SECRET_* -> reject
|
||||||
@@ -266,11 +269,11 @@ safe_value -> secret segment ********
|
|||||||
Transport Debug -> URL/metadata secret absents
|
Transport Debug -> URL/metadata secret absents
|
||||||
```
|
```
|
||||||
|
|
||||||
Le test V3 doit démontrer le cas valide et les deux croisements invalides sans exposer les canaris.
|
Les tests V3 démontrent le cas valide et les deux croisements invalides sans exposer les canaris.
|
||||||
|
|
||||||
### 8.4 PublicNode Mainnet
|
### 8.4 PublicNode Mainnet
|
||||||
|
|
||||||
Profil committé attendu :
|
Profil committé et validé :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
profile_id = publicnode_mainnet
|
profile_id = publicnode_mainnet
|
||||||
@@ -281,31 +284,32 @@ url = https://solana-yellowstone-grpc.publicnode.com:443 # provider affi
|
|||||||
metadata = aucune
|
metadata = aucune
|
||||||
```
|
```
|
||||||
|
|
||||||
Le mapping doit produire un endpoint TLS Yellowstone standard et `Debug` ne doit pas exposer l'URL.
|
Le mapping produit un endpoint TLS Yellowstone standard ; le test `committed_v3_publicnode_mainnet_maps_provider_neutral_yellowstone_grpc` passe et `Debug` ne doit pas exposer l'URL.
|
||||||
|
|
||||||
### 8.5 PublicNode Testnet
|
### 8.5 PublicNode Testnet
|
||||||
|
|
||||||
Verdict `pre.011` : **DEFERRED, NOT GUESSED**.
|
Verdict final documentaire : **EXTERNAL BLOCK, NOT GUESSED**.
|
||||||
|
|
||||||
La page publique réauditée le 2026-08-24 expose une capacité Solana Testnet gRPC, mais l'hostname exact n'a pas été obtenu depuis une source suffisamment autoritative/indexable. Aucun profil Testnet n'est committé avant confirmation.
|
Le réaudit officiel du 2026-08-24 confirme une capacité Solana Testnet gRPC chez PublicNode, mais l'hostname exact n'a pas été obtenu depuis une source PublicNode suffisamment autoritative. Aucun profil, aucun hostname déduit et aucun smoke Testnet ne sont versionnés.
|
||||||
|
|
||||||
`pre.012` doit soit :
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
confirmer hostname + réussir le smoke -> PASS
|
capacité Testnet gRPC confirmée
|
||||||
ou documenter l'impossibilité externe -> EXTERNAL BLOCK, sans endpoint inventé
|
hostname exact non confirmé
|
||||||
|
profil KSP absent
|
||||||
|
smoke KSP absent
|
||||||
|
raison interdiction d'inventer un endpoint provider
|
||||||
```
|
```
|
||||||
|
|
||||||
## 9. Provider-neutrality
|
## 9. Provider-neutrality
|
||||||
|
|
||||||
| Point | Verdict |
|
| Point | Verdict |
|
||||||
|-----------------------------------------------|----------------------|
|
|-----------------------------------------------|------------------|
|
||||||
| type public `PublicNodeGrpc*` sans divergence | absent, **PASS** |
|
| type public `PublicNodeGrpc*` sans divergence | absent, **PASS** |
|
||||||
| protocol standard encodé comme provider | non, **PASS** |
|
| protocol standard encodé comme provider | non, **PASS** |
|
||||||
| provider descriptif séparé | oui, **PASS source** |
|
| provider descriptif séparé | oui, **PASS** |
|
||||||
| auth PublicNode hardcodée dans Transport | non, **PASS** |
|
| auth PublicNode hardcodée dans Transport | non, **PASS** |
|
||||||
| Helius/OrbitFlare runtime gRPC dans `0.2.9` | non, **PASS** |
|
| Helius/OrbitFlare runtime gRPC dans `0.2.9` | non, **PASS** |
|
||||||
| provider extensions dans N2 | aucune, **PASS** |
|
| provider extensions dans N2 | aucune, **PASS** |
|
||||||
|
|
||||||
## 10. Non-régressions obligatoires
|
## 10. Non-régressions obligatoires
|
||||||
|
|
||||||
@@ -322,7 +326,7 @@ Transport -> std::env KSP_* interdit
|
|||||||
tracing direct Transport interdit
|
tracing direct Transport interdit
|
||||||
```
|
```
|
||||||
|
|
||||||
`pre.011` ne modifie pas Transport runtime ; son seuil est donc au minimum la baseline `pre.010-fix.001`.
|
`pre.012` ne modifie pas le runtime Transport ; elle ajoute uniquement un smoke live ignoré par défaut et de la documentation/audit. Son seuil de non-régression est la baseline `pre.011`.
|
||||||
|
|
||||||
## 11. Historique des gates fermé
|
## 11. Historique des gates fermé
|
||||||
|
|
||||||
@@ -340,84 +344,79 @@ Les détails de commandes, warnings corrigés et fichiers exacts restent dans le
|
|||||||
| `pre.008` + `fix.001` | Blocks fermé |
|
| `pre.008` + `fix.001` | Blocks fermé |
|
||||||
| `pre.009` + `fix.001` | bidi/backpressure fermé |
|
| `pre.009` + `fix.001` | bidi/backpressure fermé |
|
||||||
| `pre.010` + `fix.001` | reconnect/replay fermé sans warning |
|
| `pre.010` + `fix.001` | reconnect/replay fermé sans warning |
|
||||||
|
| `pre.011` | Config V3/PublicNode mapping fermé |
|
||||||
|
|
||||||
Cette table remplace les anciens appendices numérotés successivement `19.x`, `20`, `21`, etc. qui rendaient le document ambigu.
|
Cette table remplace les anciens appendices numérotés successivement `19.x`, `20`, `21`, etc. qui rendaient le document ambigu.
|
||||||
|
|
||||||
## 12. Gate opérateur `pre.011`
|
## 12. Gate opérateur `pre.012`
|
||||||
|
|
||||||
Commandes requises :
|
### 12.1 Preuves source déjà matérialisées
|
||||||
|
|
||||||
|
| Exigence | État candidate |
|
||||||
|
|----------------------------------------------|----------------------|
|
||||||
|
| réaudit `master` Yellowstone | **PASS SOURCE** |
|
||||||
|
| service `Geyser` et wire N2 inchangés | **PASS SOURCE** |
|
||||||
|
| licence proto Apache-2.0 toujours déclarée | **PASS SOURCE** |
|
||||||
|
| PublicNode Mainnet endpoint officiel | **PASS SOURCE** |
|
||||||
|
| PublicNode Testnet hostname exact | **EXTERNAL BLOCK** |
|
||||||
|
| smoke Mainnet programmatique sans credential | **ADDED, NOT RUN** |
|
||||||
|
| README/USAGE Yellowstone + Config V3 | **SOURCE OK** |
|
||||||
|
| règles tableaux Markdown | **ADDED** |
|
||||||
|
| audit mécanique tableaux | **ADDED** |
|
||||||
|
| prompt `0.2.10` OrbitFlare | **ADDED** |
|
||||||
|
| graphes Cargo finaux | **PENDING OPERATOR** |
|
||||||
|
| workspace final | **PENDING OPERATOR** |
|
||||||
|
|
||||||
|
Le réaudit `master` distingue explicitement le plugin courant du dernier tag GitHub indexé : `master` déclare `yellowstone-grpc-geyser 15.1.2`, `yellowstone-grpc-client 13.3.0`, `yellowstone-grpc-proto 12.6.0` et Agave `4.2.0`, alors que la page des releases indexée expose encore `v14.2.2+solana.4.1.0` comme dernière release publiée. Aucun numéro n'est fusionné artificiellement.
|
||||||
|
|
||||||
|
### 12.2 Commandes requises
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo fmt --all
|
cargo fmt --all
|
||||||
python3 scripts/audit_rust_workspace_rules.py
|
python3 scripts/audit_rust_workspace_rules.py
|
||||||
|
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.9
|
||||||
cargo check --workspace
|
cargo check --workspace
|
||||||
cargo clippy --workspace --all-targets
|
cargo clippy --workspace --all-targets
|
||||||
cargo test -p ksp-config-lib
|
cargo test -p ksp-config-lib
|
||||||
cargo test -p ksp-config-lib --test public_api
|
|
||||||
cargo test -p ksp-config-lib --test ownership
|
|
||||||
cargo test -p ksp-onchain-transport-lib
|
cargo test -p ksp-onchain-transport-lib
|
||||||
cargo test -p ksp-core-lib --test workspace_dependencies
|
cargo test -p ksp-core-lib --test workspace_dependencies
|
||||||
cargo test --workspace
|
cargo test --workspace
|
||||||
```
|
cargo tree -p ksp-onchain-transport-lib
|
||||||
|
cargo tree -p ksp-onchain-transport-lib --duplicates
|
||||||
Résultats attendus si aucun fix n'est requis :
|
|
||||||
|
|
||||||
```text
|
|
||||||
audit Rust clean / 0 export candidate
|
|
||||||
check/clippy PASS sans warning
|
|
||||||
Config unit baseline 110 + 3 nouveaux tests V3 = 113 attendus
|
|
||||||
Config public API 15 attendus, canari enrichi
|
|
||||||
Config ownership 5 attendus
|
|
||||||
Transport unit >= 383 sans régression
|
|
||||||
Transport public API >= 49 sans régression
|
|
||||||
Transport completeness >= 43 sans régression
|
|
||||||
Transport doctests 4 sans régression
|
|
||||||
workspace dependencies 3 sans régression
|
|
||||||
cargo test --workspace PASS
|
|
||||||
```
|
|
||||||
|
|
||||||
Ces nombres sont des attentes de candidate, pas un résultat déclaré avant exécution opérateur.
|
|
||||||
|
|
||||||
## 13. Gate `pre.012` et clôture stable
|
|
||||||
|
|
||||||
### 13.1 Live PublicNode
|
|
||||||
|
|
||||||
Mainnet minimal :
|
|
||||||
|
|
||||||
```text
|
|
||||||
opt-in seulement
|
|
||||||
settings Transport programmatic
|
|
||||||
aucun secret
|
|
||||||
connexion TLS
|
|
||||||
unary simple et/ou Subscribe borné selon smoke retenu
|
|
||||||
close borné
|
|
||||||
aucune dépendance Config ajoutée au test Transport pur
|
|
||||||
```
|
|
||||||
|
|
||||||
Testnet seulement après endpoint exact confirmé.
|
|
||||||
|
|
||||||
### 13.2 Compliance finale
|
|
||||||
|
|
||||||
```text
|
|
||||||
réaudit upstream release/proto
|
|
||||||
cargo tree Transport
|
|
||||||
cargo tree Transport --duplicates
|
|
||||||
cargo tree --duplicates
|
cargo tree --duplicates
|
||||||
HTTP 52 + 14
|
|
||||||
Standard WS 18/18
|
|
||||||
Helius WS
|
|
||||||
public API crate-root
|
|
||||||
release completeness
|
|
||||||
Config V1/V2/V3
|
|
||||||
security/redaction
|
|
||||||
README/USAGE
|
|
||||||
prompt release suivante
|
|
||||||
workspace complet
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Smoke live séparé :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Une commande non exécutée n'est jamais déclarée réussie. Le smoke peut révéler un incident externe ; ce résultat doit être consigné sans transformer un échec réseau/provider en défaut local fictif.
|
||||||
|
|
||||||
|
## 13. Compliance finale et verdict stable
|
||||||
|
|
||||||
|
### 13.1 Inventaires à préserver
|
||||||
|
|
||||||
|
```text
|
||||||
|
HTTP current typed 52/52
|
||||||
|
HTTP historical 14/14 Deprecated/Removed
|
||||||
|
Standard WebSocket 9 familles / 18 opérations
|
||||||
|
Helius LaserStream WebSocket 7 familles standard + transaction + slotsUpdates
|
||||||
|
Yellowstone unary 7/7
|
||||||
|
Yellowstone Subscribe standard N2 + 9 updates
|
||||||
|
Config Transport V1/V2/V3 backward-readable
|
||||||
|
```
|
||||||
|
|
||||||
|
### 13.2 Documentation et règles
|
||||||
|
|
||||||
|
Le format des tableaux Markdown devient normatif dans `RULES_DOCUMENTATION.md` : aucun pipe littéral ou échappé dans une cellule, colonnes alignées sur le contenu le plus large, une seule marge d'espace autour du contenu maximal, et séparateurs dimensionnés exactement. Le canari `scripts/audit_markdown_tables.py` vérifie mécaniquement les fichiers Markdown modifiés hors blocs de code.
|
||||||
|
|
||||||
|
Le nettoyage `pre.012` a également normalisé les neuf documents modifiables qui présentaient encore des écarts connus. Le scan de préparation sur les documents KSP, crates et deltas `0.2.9` est vert sur 87 tableaux dans 116 fichiers. Les seuls écarts trouvés par un scan de tout le repository appartiennent à d'anciens deltas `0.1.4` immuables ; ils ne sont pas réécrits uniquement pour du formatage.
|
||||||
|
|
||||||
### 13.3 Verdict stable
|
### 13.3 Verdict stable
|
||||||
|
|
||||||
`0.2.9` peut devenir stable seulement si tous les éléments suivants sont vrais :
|
`0.2.9` peut devenir stable lorsque le gate opérateur `pre.012` confirme tous les points locaux suivants :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
standard vs extension explicitement classifié
|
standard vs extension explicitement classifié
|
||||||
@@ -428,10 +427,14 @@ resource/backpressure/lifecycle verts
|
|||||||
reconnect/replay sans promesse lossless
|
reconnect/replay sans promesse lossless
|
||||||
Config V3 backward V1/V2
|
Config V3 backward V1/V2
|
||||||
provider/protocol distincts
|
provider/protocol distincts
|
||||||
PublicNode Mainnet validé ou incident externe précisément documenté
|
PublicNode Mainnet smoke exécuté avec résultat consigné
|
||||||
Testnet jamais inventé
|
Testnet jamais inventé
|
||||||
HTTP/WS/Helius non régressés
|
HTTP/WS/Helius non régressés
|
||||||
dependency firewall vert
|
dependency firewall vert
|
||||||
cargo graphs inspectés
|
cargo graphs inspectés
|
||||||
|
README/USAGE finaux
|
||||||
|
prompt 0.2.10 prêt
|
||||||
workspace final vert
|
workspace final vert
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Le bloc Testnet n'est pas un faux FAIL local : l'existence du service est confirmée, mais l'endpoint exact reste indisponible dans la source officielle consultée. Il est donc fermé comme limite externe documentée, sans profil ni smoke inventé.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: prompts/000-README.md -->
|
<!-- file: prompts/000-README.md -->
|
||||||
<!-- version: 25 -->
|
<!-- version: 26 -->
|
||||||
|
|
||||||
# Prompts KSP
|
# Prompts KSP
|
||||||
|
|
||||||
@@ -35,3 +35,4 @@ Le prompt générique `0.1.x` a été affiné pendant `0.0.3` puis remplacé par
|
|||||||
- [`012-V0_2_7_START_PROMPT.md`](012-V0_2_7_START_PROMPT.md) — prompt réaligné par `0.2.6-pre.015` puis renforcé en contrat de reprise autonome par `0.2.6-pre.018-fix.002`; prompt historique consommé pour ouvrir `0.2.7 — WebSocket Solana standard` depuis `v0.2.6`, avec lectures/règles ordonnées, audit officiel et historique, threat-model session/subscription/reconnect/backpressure, matrice de compliance, gate `pre.001` strict et prévision souple de prereleases avant toute implémentation lourde.
|
- [`012-V0_2_7_START_PROMPT.md`](012-V0_2_7_START_PROMPT.md) — prompt réaligné par `0.2.6-pre.015` puis renforcé en contrat de reprise autonome par `0.2.6-pre.018-fix.002`; prompt historique consommé pour ouvrir `0.2.7 — WebSocket Solana standard` depuis `v0.2.6`, avec lectures/règles ordonnées, audit officiel et historique, threat-model session/subscription/reconnect/backpressure, matrice de compliance, gate `pre.001` strict et prévision souple de prereleases avant toute implémentation lourde.
|
||||||
- [`013-V0_2_8_START_PROMPT.md`](013-V0_2_8_START_PROMPT.md) — prompt historique consommé pour ouvrir puis conduire la release stable `0.2.8 — Helius LaserStream WebSocket` depuis `v0.2.7`; préparé par `0.2.7-pre.014` puis renforcé en version 2 par `pre.014-fix.001`, il imposait relecture des règles, réaudit Helius, gate `pre.001` strict audit/brainstorming/sizing, actor standard partagé, frontières provider/Config/secrets et forecast souple avant implémentation lourde.
|
- [`013-V0_2_8_START_PROMPT.md`](013-V0_2_8_START_PROMPT.md) — prompt historique consommé pour ouvrir puis conduire la release stable `0.2.8 — Helius LaserStream WebSocket` depuis `v0.2.7`; préparé par `0.2.7-pre.014` puis renforcé en version 2 par `pre.014-fix.001`, il imposait relecture des règles, réaudit Helius, gate `pre.001` strict audit/brainstorming/sizing, actor standard partagé, frontières provider/Config/secrets et forecast souple avant implémentation lourde.
|
||||||
- [`014-V0_2_9_START_PROMPT.md`](014-V0_2_9_START_PROMPT.md) — prompt actif après publication `0.2.8-rel.001` et tag stable `v0.2.8`, préparé par `0.2.8-pre.011`; il ouvre `0.2.9 — Yellowstone gRPC standard/provider-neutral` et impose la base stable autoritaire, la relecture ordonnée des règles/architectures/compliances Transport, un réaudit Yellowstone actuel (service/proto/releases/crates), un audit dépendances/licences/MSRV avant choix du client/proto, la séparation standard/provider/deshred, un gate `pre.001` strict audit/brainstorming/sizing et une prévision souple détaillée avant toute implémentation gRPC lourde.
|
- [`014-V0_2_9_START_PROMPT.md`](014-V0_2_9_START_PROMPT.md) — prompt actif après publication `0.2.8-rel.001` et tag stable `v0.2.8`, préparé par `0.2.8-pre.011`; il ouvre `0.2.9 — Yellowstone gRPC standard/provider-neutral` et impose la base stable autoritaire, la relecture ordonnée des règles/architectures/compliances Transport, un réaudit Yellowstone actuel (service/proto/releases/crates), un audit dépendances/licences/MSRV avant choix du client/proto, la séparation standard/provider/deshred, un gate `pre.001` strict audit/brainstorming/sizing et une prévision souple détaillée avant toute implémentation gRPC lourde.
|
||||||
|
- [`015-V0_2_10_START_PROMPT.md`](015-V0_2_10_START_PROMPT.md) — prompt préparé par `0.2.9-pre.012` pour ouvrir `0.2.10 — OrbitFlare Yellowstone gRPC` depuis la future base stable `v0.2.9`; il impose la réutilisation du moteur Yellowstone N1 et du standard N2, un gate `pre.001` d’audit actuel des endpoints/auth/capabilities/heartbeat OrbitFlare, la distinction control-plane/data-plane/IP whitelist/credentials, le sizing avant toute extension provider et la non-régression PublicNode/Yellowstone standard.
|
||||||
|
|||||||
1120
prompts/015-V0_2_10_START_PROMPT.md
Normal file
1120
prompts/015-V0_2_10_START_PROMPT.md
Normal file
File diff suppressed because it is too large
Load Diff
166
scripts/audit_markdown_tables.py
Executable file
166
scripts/audit_markdown_tables.py
Executable file
@@ -0,0 +1,166 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# file: scripts/audit_markdown_tables.py
|
||||||
|
# version: 1
|
||||||
|
|
||||||
|
"""Validate KSP Markdown table formatting for explicitly supplied files or directories."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_SEPARATOR_CELL = re.compile(r"^:?-{3,}:?$")
|
||||||
|
|
||||||
|
|
||||||
|
def _markdown_files(paths: list[str]) -> list[pathlib.Path]:
|
||||||
|
files: list[pathlib.Path] = []
|
||||||
|
for raw_path in paths:
|
||||||
|
path = pathlib.Path(raw_path)
|
||||||
|
if path.is_dir():
|
||||||
|
files.extend(sorted(candidate for candidate in path.rglob("*.md") if candidate.is_file()))
|
||||||
|
elif path.is_file() and path.suffix.lower() == ".md":
|
||||||
|
files.append(path)
|
||||||
|
else:
|
||||||
|
print(f"Markdown table audit: unsupported or missing path: {path}", file=sys.stderr)
|
||||||
|
return sorted(set(files))
|
||||||
|
|
||||||
|
|
||||||
|
def _is_table_row(line: str) -> bool:
|
||||||
|
return line.startswith("|") and line.endswith("|")
|
||||||
|
|
||||||
|
|
||||||
|
def _cells(line: str) -> list[str]:
|
||||||
|
return line.split("|")[1:-1]
|
||||||
|
|
||||||
|
|
||||||
|
def _is_separator_row(line: str) -> bool:
|
||||||
|
if not _is_table_row(line):
|
||||||
|
return False
|
||||||
|
cells = _cells(line)
|
||||||
|
return bool(cells) and all(_SEPARATOR_CELL.fullmatch(cell) is not None for cell in cells)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> list[str]:
|
||||||
|
errors: list[str] = []
|
||||||
|
if any("\\|" in row for row in rows):
|
||||||
|
errors.append(f"{path}:{start_line}: escaped pipe is forbidden inside Markdown table cells")
|
||||||
|
|
||||||
|
header_cells = _cells(rows[0])
|
||||||
|
column_count = len(header_cells)
|
||||||
|
parsed_rows = [_cells(row) for row in rows]
|
||||||
|
for offset, row_cells in enumerate(parsed_rows):
|
||||||
|
if len(row_cells) != column_count:
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line + offset}: table row has {len(row_cells)} columns; expected {column_count}; "
|
||||||
|
"a literal pipe inside a cell is forbidden"
|
||||||
|
)
|
||||||
|
return errors
|
||||||
|
|
||||||
|
for column_index in range(column_count):
|
||||||
|
raw_cells = [row[column_index] for row in parsed_rows]
|
||||||
|
widths = [len(cell) for cell in raw_cells]
|
||||||
|
expected_width = widths[0]
|
||||||
|
if any(width != expected_width for width in widths):
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line}: column {column_index + 1} is not vertically aligned; raw widths are {widths}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
|
content_cells = [cell for cell in raw_cells if _SEPARATOR_CELL.fullmatch(cell) is None]
|
||||||
|
if not content_cells:
|
||||||
|
errors.append(f"{path}:{start_line}: column {column_index + 1} has no header/data content")
|
||||||
|
continue
|
||||||
|
max_content_width = max(len(cell.strip()) for cell in content_cells)
|
||||||
|
required_width = max_content_width + 2
|
||||||
|
if expected_width != required_width:
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line}: column {column_index + 1} width is {expected_width}; expected {required_width} "
|
||||||
|
"(longest content plus exactly one space on each side)"
|
||||||
|
)
|
||||||
|
|
||||||
|
for cell in content_cells:
|
||||||
|
if len(cell) < 2 or not cell.startswith(" ") or cell.startswith(" ") or not cell.endswith(" "):
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line}: column {column_index + 1} content cells must start with exactly one space and use right padding only"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
if len(cell.strip()) == max_content_width and cell.endswith(" "):
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line}: column {column_index + 1} widest content must have exactly one space before the closing pipe"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
separator = raw_cells[1]
|
||||||
|
if len(separator) != expected_width or _SEPARATOR_CELL.fullmatch(separator) is None:
|
||||||
|
errors.append(
|
||||||
|
f"{path}:{start_line + 1}: separator for column {column_index + 1} must fill the exact column width with hyphens and optional alignment colons"
|
||||||
|
)
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
|
||||||
|
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
|
||||||
|
lines = path.read_text(encoding="utf-8").splitlines()
|
||||||
|
errors: list[str] = []
|
||||||
|
table_count = 0
|
||||||
|
fence_marker: str | None = None
|
||||||
|
index = 0
|
||||||
|
while index < len(lines):
|
||||||
|
stripped = lines[index].lstrip()
|
||||||
|
if stripped.startswith("```") or stripped.startswith("~~~"):
|
||||||
|
marker = stripped[:3]
|
||||||
|
if fence_marker is None:
|
||||||
|
fence_marker = marker
|
||||||
|
elif marker == fence_marker:
|
||||||
|
fence_marker = None
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if fence_marker is not None:
|
||||||
|
index += 1
|
||||||
|
continue
|
||||||
|
if index + 1 < len(lines) and _is_table_row(lines[index]) and _is_separator_row(lines[index + 1]):
|
||||||
|
start = index
|
||||||
|
rows = [lines[index], lines[index + 1]]
|
||||||
|
index += 2
|
||||||
|
while index < len(lines) and _is_table_row(lines[index]):
|
||||||
|
rows.append(lines[index])
|
||||||
|
index += 1
|
||||||
|
table_count += 1
|
||||||
|
errors.extend(_validate_table(path, start + 1, rows))
|
||||||
|
continue
|
||||||
|
index += 1
|
||||||
|
return table_count, errors
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
"""Audit Markdown tables in the explicitly selected scope."""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
|
||||||
|
arguments = parser.parse_args()
|
||||||
|
files = _markdown_files(arguments.paths)
|
||||||
|
if not files:
|
||||||
|
print("Markdown table audit: no Markdown files selected", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
total_tables = 0
|
||||||
|
all_errors: list[str] = []
|
||||||
|
for path in files:
|
||||||
|
table_count, errors = _audit_file(path)
|
||||||
|
total_tables += table_count
|
||||||
|
all_errors.extend(errors)
|
||||||
|
|
||||||
|
if all_errors:
|
||||||
|
for error in all_errors:
|
||||||
|
print(error, file=sys.stderr)
|
||||||
|
print(f"Markdown table audit: {len(all_errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
print(f"Markdown table audit: clean ({total_tables} table(s), {len(files)} file(s))")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user