Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| afaa9c0239 | |||
| 7d456b41dc | |||
| 0edeed1c48 | |||
| be5e3464ee | |||
| 1967e845b0 | |||
| af807afff5 | |||
| 7f567bc1bb |
@@ -1,5 +1,5 @@
|
||||
# file: .env.example
|
||||
# version: 8
|
||||
# version: 9
|
||||
|
||||
# KSP Logging root directory. Used by config/std.logging.json for relative log output paths.
|
||||
# The current Config document fallback is "logs" when neither the process environment nor .env defines this variable.
|
||||
@@ -42,6 +42,10 @@ KSP_PUBLIC_SOLANA_MAINNET_WS_URL=wss://api.mainnet-beta.solana.com
|
||||
# Keep the real value only in the process environment or local .env; do not assume that a Mainnet token is authorized on Testnet.
|
||||
# KSP_SECRET_PUBLICNODE_TESTNET_GRPC_X_TOKEN=replace-me
|
||||
|
||||
# OrbitFlare Solana Free License Key used as secret x-token metadata by the committed Devnet Yellowstone gRPC profile.
|
||||
# Keep the real ORBIT-* value only in the process environment or local .env; do not substitute the Customer API X-ORBIT-KEY.
|
||||
# KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN=replace-me
|
||||
|
||||
# Helius API key used by the LaserStream WebSocket endpoint in config/examples/std.transport.example.json.
|
||||
# Keep the real credential only in the process environment or local .env; never commit it.
|
||||
# KSP_SECRET_HELIUS_API_KEY=replace-me
|
||||
|
||||
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,8 +1,16 @@
|
||||
<!-- file: CHANGELOG.md -->
|
||||
<!-- version: 13 -->
|
||||
<!-- version: 14 -->
|
||||
|
||||
# Changelog KSP
|
||||
|
||||
## 0.2.10 — OrbitFlare Yellowstone gRPC — 2026-08-25
|
||||
|
||||
`0.2.10` ajoute OrbitFlare comme provider Yellowstone gRPC sur le moteur N1 et le standard N2 acquis dans `0.2.9`, sans modifier le moteur gRPC ni créer de façade provider inutile. L'audit et le smoke live ont établi le contrat réel du service Solana Free Devnet : endpoint `http://devnet.rpc.orbitflare.com:10000`, authentification par metadata gRPC secrète `x-token` portant la License Key OrbitFlare, et émission du Ping Yellowstone standard. Config Transport V3 représente ce provider avec `provider = orbitflare`, `cluster = devnet`, `protocol = solana_yellowstone` et `secret_metadata`, tandis que `.env.example` inventorie `KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN` sans valeur réelle.
|
||||
|
||||
La première tentative live sans metadata a volontairement échoué avec `Unauthenticated`, ce qui a conduit à `pre.002-fix.001` après audit des sources OrbitFlare actuelles. Le smoke corrigé reçoit la License Key uniquement par stdin opérateur, ouvre `Subscribe`, observe un Slot non nul et un `SubscribeUpdate::Ping`, puis ferme la session proprement. Le même smoke est repassé au gate technique final `pre.003`. La clôture conserve donc N1/N2 inchangés, n'ajoute ni heartbeat OrbitFlare, ni SDK provider, ni Config V4, et confirme que la réponse automatique au Ping standard existante suffit.
|
||||
|
||||
Le gate final conserve l'ensemble du workspace vert : audits Rust/Markdown, `cargo check`, Clippy, tests Config et Transport, `cargo test --workspace`, canaris de dépendances et graphes Cargo. Helius LaserStream gRPC, audité comme largement wire-compatible Yellowstone mais non raisonnablement live-testable sans abonnement payant, est reporté dans les TODO provider sans numéro de release. La séquence active passe donc à `0.2.11 — off-chain price transport`; `prompts/016-V0_2_11_START_PROMPT.md` l'ouvre exclusivement depuis le tag stable `v0.2.10` avec audit actuel des sources de prix, de leurs sémantiques et de leur testabilité avant toute implémentation lourde.
|
||||
|
||||
Ce changelog résume uniquement les releases KSP considérées comme stables, dans l'ordre chronologique décroissant. Les détails de chaque livraison restent dans `deltas/`.
|
||||
|
||||
## 0.2.9 — Yellowstone gRPC standard/provider-neutral — 2026-08-24
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 261
|
||||
# version: 268
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
14
ROADMAP.md
14
ROADMAP.md
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 86 -->
|
||||
<!-- version: 87 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -54,15 +54,15 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
|
||||
- [X] `0.2.7` — WebSocket Solana standard stable : 9 familles subscribe/unsubscribe typées (18/18 opérations), sessions physiques multiples explicites, subscriptions logiques typées, lifecycle/reconnect/resubscribe/backpressure/shutdown bornés, Config V2, non-régression HTTP 52+14, compliance finale, smoke WebSocket Devnet et audit de dépendances validés ; publication `rel.001` et prompt `0.2.8` prêts.
|
||||
- [X] `0.2.8` — Helius LaserStream WebSocket stable : façade provider dédiée sur l’actor WebSocket partagé, sept familles standard réutilisées (`account/logs/program/root/signature/slot/slotsUpdates`) + `transactionSubscribe`/`transactionUnsubscribe`, `block/vote` absents, heartbeat Ping 60 s Helius-only, Config V2/secrets redacted, lifecycle adversarial, compliance HTTP 52+14 / Standard WS 18/18 et graphes Cargo finaux validés ; prompt `0.2.9` prêt.
|
||||
- [X] `0.2.9` — Yellowstone gRPC standard/provider-neutral stable : moteur Tonic/Protobuf KSP partagé, sept unary standard retenues, `Subscribe` bidi et neuf variantes d’update, lifecycle/backpressure/reconnect/replay bornés sans promesse lossless, Config Transport V3 backward V1/V2 avec provider/protocol séparés, profils PublicNode Mainnet/Testnet authentifiés par `x-token`, smoke live `Subscribe -> Slot` 2/2 PASS et graphes Cargo finaux inspectés ; `SubscribeDeshred` reste hors scope.
|
||||
- [ ] `0.2.10` — Ajouter l’intégration Yellowstone gRPC OrbitFlare sur le moteur/standard acquis, avec audit explicite des auth/capabilities/restrictions/extensions et Devnet comme cible gratuite prioritaire.
|
||||
- [ ] `0.2.11` — Ajouter l’intégration Helius LaserStream gRPC sur le moteur Yellowstone partagé, avec audit de compatibilité/replay/auth/extensions, sans confondre cette surface avec LaserStream WebSocket.
|
||||
- [ ] `0.2.12` — Introduire `ksp-offchain-transport-lib` avec un premier lecteur de prix, au minimum SOL/USD et SOL/EUR.
|
||||
- [ ] `0.2.13` — Introduire une petite application desk de visualisation/validation des prix offchain, puis intégrer cette capacité dans `ksp-app-wallet-desk` sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé.
|
||||
- [ ] `0.2.14` — Introduire la première surface de `ksp-interface-lib`, comprenant une API wire publique utilisable par les implémentations officielles et externes.
|
||||
- [ ] `0.2.15` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet.
|
||||
- [X] `0.2.10` — OrbitFlare Yellowstone gRPC stable : profil Config V3 Devnet, License Key injectée comme metadata secrète `x-token`, smoke live `Subscribe -> Slot + Ping` validé deux fois, sans modification du moteur N1/N2 ni heartbeat provider.
|
||||
- [ ] `0.2.11` — Introduire `ksp-offchain-transport-lib` avec un premier lecteur de prix provider-neutral, au minimum SOL/USD et SOL/EUR, après audit actuel des sémantiques provider et de la testabilité live.
|
||||
- [ ] `0.2.12` — Introduire une petite application desk de visualisation/validation des prix offchain, puis intégrer cette capacité dans `ksp-app-wallet-desk` sans dupliquer la logique de récupération/normalisation possédée par le composant spécialisé.
|
||||
- [ ] `0.2.13` — Introduire la première surface de `ksp-interface-lib`, comprenant une API wire publique utilisable par les implémentations officielles et externes.
|
||||
- [ ] `0.2.14` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet.
|
||||
|
||||
### TODO/IDEAS — providers Yellowstone non planifiés
|
||||
|
||||
- [ ] **TODO** — Helius LaserStream gRPC : réauditer lorsque l'accès live gRPC est raisonnablement disponible ; conserver N1/N2 Yellowstone inchangés, vérifier auth/endpoints/Subscribe/Ping/replay/from_slot/erreurs provider et traiter les preprocessed transactions comme extension Helius séparée.
|
||||
- [ ] **TODO** — eRPC : réauditer accès, auth/IP policy, capabilities et produits complémentaires avant toute décision d’implémentation.
|
||||
- [ ] **TODO** — Triton : réauditer la frontière Yellowstone upstream / extensions Triton, notamment Deshred et futures extensions.
|
||||
- [ ] **TODO** — Alchemy : réauditer auth, replay, limites et capabilities Yellowstone avant toute intégration.
|
||||
|
||||
@@ -79,6 +79,64 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"profile_id": "orbitflare_devnet",
|
||||
"endpoints": [
|
||||
{
|
||||
"name": "solana_devnet_public",
|
||||
"enabled": true,
|
||||
"provider": "solana-public",
|
||||
"cluster": "devnet",
|
||||
"url": "${KSP_PUBLIC_SOLANA_DEVNET_HTTP_URL:-https://api.devnet.solana.com}",
|
||||
"connect_timeout_ms": 5000,
|
||||
"request_timeout_ms": 15000,
|
||||
"max_idle_connections_per_host": 8,
|
||||
"roles": [
|
||||
{
|
||||
"role": "default",
|
||||
"enabled": true,
|
||||
"request_kinds": [
|
||||
"*"
|
||||
],
|
||||
"priority": 100,
|
||||
"limits": {
|
||||
"requests_per_second": 5,
|
||||
"burst_capacity": 10,
|
||||
"max_concurrent_requests": 8,
|
||||
"pause_after_rate_limit_ms": 1000
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"ws_endpoints": [
|
||||
{
|
||||
"name": "solana_devnet_public_ws",
|
||||
"enabled": true,
|
||||
"provider": "solana-public",
|
||||
"cluster": "devnet",
|
||||
"kind": "solana_standard",
|
||||
"url": "${KSP_PUBLIC_SOLANA_DEVNET_WS_URL:-wss://api.devnet.solana.com}"
|
||||
}
|
||||
],
|
||||
"grpc_endpoints": [
|
||||
{
|
||||
"name": "orbitflare_solana_devnet_yellowstone",
|
||||
"enabled": true,
|
||||
"provider": "orbitflare",
|
||||
"cluster": "devnet",
|
||||
"protocol": "solana_yellowstone",
|
||||
"url": "http://devnet.rpc.orbitflare.com:10000",
|
||||
"metadata": [],
|
||||
"secret_metadata": [
|
||||
{
|
||||
"key": "x-token",
|
||||
"value": "${KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"profile_id": "mainnet_public",
|
||||
"endpoints": [
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-config-lib/unit_tests/transport.rs
|
||||
// version: 10
|
||||
// version: 12
|
||||
|
||||
#[test]
|
||||
fn fixture_transport_profile_maps_complete_runtime_contract() {
|
||||
@@ -133,6 +133,52 @@ fn committed_transport_document_maps_default_and_explicit_profiles() {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_v3_orbitflare_devnet_profile_maps_provider_neutral_yellowstone_grpc_with_license_x_token() {
|
||||
let engine = committed_engine();
|
||||
let engine = match engine {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let canary = "ORBITFLARE-DEVNET-LICENSE-X-TOKEN-CANARY";
|
||||
let mut process = std::collections::BTreeMap::<String, String>::new();
|
||||
process.insert("KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN".to_owned(), canary.to_owned());
|
||||
let environment = crate::ConfigEnvironment::from_maps(process, std::collections::BTreeMap::new());
|
||||
let resolved = engine.load_resolved_transport_config(std::option::Option::Some("orbitflare_devnet"), &environment);
|
||||
assert!(resolved.is_ok(), "committed OrbitFlare Devnet Transport profile should map from its License Key x-token: {resolved:?}");
|
||||
if let std::result::Result::Ok(resolved) = resolved {
|
||||
assert_eq!(resolved.profile_id(), "orbitflare_devnet");
|
||||
assert_eq!(resolved.selection_source(), crate::ConfigProfileSelectionSource::Explicit);
|
||||
assert_eq!(resolved.settings().endpoints()[0].cluster().as_str(), "devnet");
|
||||
assert_eq!(resolved.settings().endpoints()[0].url().as_str(), "https://api.devnet.solana.com");
|
||||
let ws = resolved.ws_settings();
|
||||
assert!(ws.is_some(), "OrbitFlare Devnet profile should retain the standard Solana Devnet WebSocket companion endpoint");
|
||||
if let std::option::Option::Some(ws) = ws {
|
||||
assert_eq!(ws.endpoints()[0].url().as_str(), "wss://api.devnet.solana.com");
|
||||
assert_eq!(ws.endpoints()[0].protocol(), ksp_onchain_transport_lib::WsProtocolKind::SolanaStandard);
|
||||
}
|
||||
let grpc = resolved.grpc_settings();
|
||||
assert!(grpc.is_some(), "OrbitFlare Devnet profile should expose one provider-neutral Yellowstone gRPC endpoint");
|
||||
if let std::option::Option::Some(grpc) = grpc {
|
||||
assert_eq!(grpc.endpoints().len(), 1);
|
||||
let endpoint = &grpc.endpoints()[0];
|
||||
assert_eq!(endpoint.name(), "orbitflare_solana_devnet_yellowstone");
|
||||
assert_eq!(endpoint.provider().as_str(), "orbitflare");
|
||||
assert_eq!(endpoint.cluster().as_str(), "devnet");
|
||||
assert_eq!(endpoint.url().as_str(), "http://devnet.rpc.orbitflare.com:10000");
|
||||
assert!(!endpoint.url().uses_tls(), "OrbitFlare shared Devnet URL must remain explicitly HTTP/2 plaintext");
|
||||
assert_eq!(endpoint.metadata().len(), 1);
|
||||
assert_eq!(endpoint.metadata()[0].key(), "x-token");
|
||||
assert!(endpoint.metadata()[0].is_secret());
|
||||
assert!(grpc.validate().is_ok(), "Config-produced OrbitFlare Yellowstone gRPC settings should satisfy Transport validation");
|
||||
let debug = format!("{grpc:?}");
|
||||
assert!(!debug.contains("orbitflare.com"), "Transport settings Debug must not expose OrbitFlare gRPC endpoint URLs");
|
||||
assert!(!debug.contains(canary), "OrbitFlare License Key x-token must stay redacted from Transport settings Debug");
|
||||
assert!(!debug.contains("X-ORBIT-KEY"), "OrbitFlare Customer API credentials must never enter Yellowstone Transport settings");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_v3_publicnode_profiles_map_provider_neutral_yellowstone_grpc_with_network_scoped_secret_x_tokens() {
|
||||
let engine = committed_engine();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
||||
<!-- version: 22 -->
|
||||
<!-- version: 24 -->
|
||||
|
||||
# `ksp-onchain-transport-lib`
|
||||
|
||||
@@ -220,7 +220,6 @@ 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`.
|
||||
|
||||
|
||||
## 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é.
|
||||
@@ -246,6 +245,8 @@ Config Transport V3 peut mapper des `grpc_endpoints` vers ces settings sans inve
|
||||
|
||||
Le smoke live opt-in ouvre un `Subscribe` slots authentifié sur PublicNode Mainnet et Testnet, attend un update `Slot` non nul puis ferme de manière bornée. Les deux endpoints sont versionnés. Le harness reçoit ses personal tokens sur stdin ; aucun secret n’est committé ni placé dans l’URL. Le même token a été validé par l’opérateur sur les deux réseaux, même si Config conserve deux variables distinctes pour laisser cette policy flexible.
|
||||
|
||||
`0.2.10` ajoute le profil `orbitflare_devnet` sur le même moteur provider-neutral. L’endpoint validé est `http://devnet.rpc.orbitflare.com:10000`; la License Key `ORBIT-*` est fournie par Config via `KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN` et devient la metadata secrète `x-token`. Le smoke live dédié a validé `Subscribe` slots à commitment confirmed, un `Slot` non nul et un `SubscribeUpdate::Ping` standard. Cette preuve confirme qu’aucune façade OrbitFlare, aucun heartbeat provider et aucune modification N1/N2 ne sont nécessaires.
|
||||
|
||||
## Résilience
|
||||
|
||||
L'admission est calculée par couple endpoint/rôle. Le pool applique :
|
||||
@@ -300,16 +301,20 @@ Transport WebSocket pur : settings programmatiques -> WsSession
|
||||
Composition historique : Config -> std.transport/devnet_public -> HttpTransportPool
|
||||
-> getHealth/getGenesisHash/getVersion/getBalance
|
||||
|
||||
Transport Yellowstone gRPC : settings programmatiques + x-token secret
|
||||
-> PublicNode Mainnet + Testnet
|
||||
-> TLS -> Subscribe slots -> Slot non nul -> close borné
|
||||
Transport Yellowstone gRPC PublicNode : settings programmatiques + x-token secret
|
||||
-> Mainnet + Testnet
|
||||
-> TLS -> Subscribe slots -> Slot non nul -> close borné
|
||||
|
||||
Transport Yellowstone gRPC OrbitFlare : settings programmatiques + License Key x-token
|
||||
-> Devnet
|
||||
-> Subscribe slots -> Slot non nul + server Ping -> close borné
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Les quatre tests sont `ignored` par défaut ; le test Yellowstone contient deux cas live Mainnet/Testnet. Les trois familles de 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 cinq tests sont `ignored` par défaut ; le test PublicNode Yellowstone contient deux cas live Mainnet/Testnet et le test OrbitFlare contient un cas Devnet. Les trois familles de 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.
|
||||
|
||||
@@ -325,4 +330,6 @@ Aucun smoke Helius live supplémentaire n’est committé en `0.2.8-pre.010`. Un
|
||||
- [`../../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/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 ;
|
||||
- [`../../docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md`](../../docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md) — composition OrbitFlare Devnet sur le standard Yellowstone ;
|
||||
- [`../../docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md`](../../docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md) — validation finale OrbitFlare `x-token`, `Slot + Ping` et non-régression N1/N2 ;
|
||||
- [`../../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 -->
|
||||
<!-- version: 22 -->
|
||||
<!-- version: 23 -->
|
||||
|
||||
# Utilisation de `ksp-onchain-transport-lib`
|
||||
|
||||
@@ -331,6 +331,36 @@ let channel = ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(endpoin
|
||||
|
||||
`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.
|
||||
|
||||
### Profil OrbitFlare Devnet
|
||||
|
||||
Le profil committé `orbitflare_devnet` réutilise exactement le même accès Config -> Transport :
|
||||
|
||||
```rust
|
||||
let resolved = match engine.load_resolved_transport_config(Some("orbitflare_devnet"), &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 OrbitFlare 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 OrbitFlare profile has no enabled Yellowstone gRPC endpoint",
|
||||
)),
|
||||
};
|
||||
let channel = ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(endpoint).await;
|
||||
```
|
||||
|
||||
Config résout `KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN` vers la metadata secrète `x-token`. Sa valeur effective est la License Key `ORBIT-*` du produit Solana ; `X-ORBIT-KEY` et le Bearer du Customer API ne doivent pas être utilisés pour Yellowstone. Transport ne lit jamais cette variable lui-même.
|
||||
|
||||
L’endpoint validé par `0.2.10` est `http://devnet.rpc.orbitflare.com:10000`. Il reste volontairement en `http` : KSP ne remplace pas le transport provider par `https` sans endpoint TLS explicitement fourni.
|
||||
|
||||
### Subscribe bidirectionnel
|
||||
|
||||
Une session standard part d’une requête typed complète :
|
||||
@@ -519,6 +549,26 @@ Testnet https://solana-testnet-yellowstone-grpc.publicnode.com:443
|
||||
|
||||
Les profils Config conservent deux variables secrètes distinctes afin d'autoriser des credentials différents si nécessaire ; cette séparation ne signifie pas que PublicNode impose actuellement un token différent par réseau. Un timeout KSP de half-close après réception du slot est accepté par le smoke comme fermeture bornée du provider ; aucune absence de slot ni autre erreur n'est masquée.
|
||||
|
||||
Le smoke **Transport Yellowstone gRPC OrbitFlare** est lui aussi indépendant de Config. Il lit une seule License Key sur stdin, la classe comme metadata secrète `x-token`, ouvre le standard `Subscribe`, demande `slots` à commitment confirmed, attend un Slot non nul et un `SubscribeUpdate::Ping`, puis ferme la session de manière bornée :
|
||||
|
||||
```bash
|
||||
read -rsp 'OrbitFlare License Key: ' ORBITFLARE_LICENSE_KEY
|
||||
echo
|
||||
printf '%s\n' "$ORBITFLARE_LICENSE_KEY" \
|
||||
| cargo test -p ksp-onchain-transport-lib \
|
||||
--test yellowstone_orbitflare_smoke \
|
||||
-- --ignored --nocapture
|
||||
unset ORBITFLARE_LICENSE_KEY
|
||||
```
|
||||
|
||||
Endpoint validé :
|
||||
|
||||
```text
|
||||
Devnet http://devnet.rpc.orbitflare.com:10000
|
||||
```
|
||||
|
||||
Le gate `0.2.10-pre.003` a passé ce scénario en live avec `Slot + Ping`. Le Ping reçu est le message Yellowstone standard auquel N1 sait déjà répondre sans remplacer la dernière requête complète mémorisée ; aucun heartbeat OrbitFlare supplémentaire n’est donc requis.
|
||||
|
||||
Le smoke de **composition Config -> Transport** reste également disponible :
|
||||
|
||||
```bash
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
// file: crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
|
||||
// version: 2
|
||||
|
||||
//! Opt-in live OrbitFlare Devnet characterization smoke for authenticated provider-neutral Yellowstone gRPC Subscribe.
|
||||
|
||||
use std::io::IsTerminal; // rust-rules: trait-import
|
||||
|
||||
fn orbitflare_license_x_token() -> std::string::String {
|
||||
assert!(
|
||||
!std::io::stdin().is_terminal(),
|
||||
"pipe the OrbitFlare Solana Free License Key to this ignored smoke on stdin; never pass it as a command-line argument"
|
||||
);
|
||||
let mut token = std::string::String::new();
|
||||
match std::io::stdin().read_line(&mut token) {
|
||||
std::result::Result::Ok(_) => {},
|
||||
std::result::Result::Err(error) => panic!("OrbitFlare License Key x-token must be readable from smoke stdin: {error}"),
|
||||
}
|
||||
let token = token.trim().to_owned();
|
||||
assert!(!token.is_empty(), "OrbitFlare License Key x-token provided on smoke stdin must not be empty");
|
||||
return token;
|
||||
}
|
||||
|
||||
fn orbitflare_devnet_endpoint(x_token: &str) -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings> {
|
||||
let url = match ksp_onchain_transport_lib::YellowstoneGrpcEndpointUrl::parse("http://devnet.rpc.orbitflare.com:10000") {
|
||||
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,
|
||||
);
|
||||
let endpoint = ksp_onchain_transport_lib::YellowstoneGrpcEndpointSettings::new(
|
||||
"orbitflare_devnet_yellowstone",
|
||||
true,
|
||||
ksp_onchain_transport_lib::YellowstoneGrpcProviderName::new("orbitflare"),
|
||||
ksp_onchain_transport_lib::YellowstoneGrpcClusterName::new("devnet"),
|
||||
url,
|
||||
session,
|
||||
);
|
||||
let metadata = match ksp_onchain_transport_lib::YellowstoneGrpcMetadataEntry::secret("x-token", x_token) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
return endpoint.with_metadata(vec![metadata]);
|
||||
}
|
||||
|
||||
fn slot_request() -> ksp_core_lib::Result<ksp_onchain_transport_lib::YellowstoneSubscribeRequest> {
|
||||
let mut request = ksp_onchain_transport_lib::YellowstoneSubscribeRequest::new();
|
||||
let name = match ksp_onchain_transport_lib::YellowstoneSubscribeFilterName::new("slots") {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
match request.insert_slot_filter(name, ksp_onchain_transport_lib::YellowstoneSubscribeSlotFilter::new()) {
|
||||
std::result::Result::Ok(()) => {},
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
}
|
||||
request.set_commitment(std::option::Option::Some(ksp_onchain_transport_lib::SolanaCommitment::Confirmed));
|
||||
return std::result::Result::Ok(request);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
#[ignore = "opt-in live OrbitFlare Devnet Yellowstone gRPC characterization; reads one Solana Free License Key x-token from stdin, waits for Slot plus standard server Ping, then closes"]
|
||||
async fn orbitflare_devnet_yellowstone_streams_slots_and_emits_standard_server_ping_with_license_x_token() {
|
||||
let x_token = orbitflare_license_x_token();
|
||||
let endpoint = match orbitflare_devnet_endpoint(x_token.as_str()) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
panic!("programmatic OrbitFlare Devnet Yellowstone settings must accept the License Key as secret x-token metadata: {error:?}")
|
||||
},
|
||||
};
|
||||
assert_eq!(endpoint.metadata().len(), 1);
|
||||
assert_eq!(endpoint.metadata()[0].key(), "x-token");
|
||||
assert!(endpoint.metadata()[0].is_secret());
|
||||
assert!(!endpoint.url().uses_tls(), "the documented OrbitFlare shared Devnet endpoint is intentionally HTTP/2 plaintext");
|
||||
let endpoint_debug = format!("{endpoint:?}");
|
||||
assert!(!endpoint_debug.contains("orbitflare.com"), "OrbitFlare endpoint URL must not appear in endpoint Debug");
|
||||
assert!(!endpoint_debug.contains(x_token.as_str()), "OrbitFlare License Key x-token must not appear in endpoint Debug");
|
||||
assert!(!endpoint_debug.contains("X-ORBIT-KEY"), "OrbitFlare Customer API credentials must not enter Yellowstone settings");
|
||||
let channel = match ksp_onchain_transport_lib::YellowstoneGrpcChannel::connect(&endpoint).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("OrbitFlare Devnet Yellowstone authenticated connection must succeed: {error:?}"),
|
||||
};
|
||||
assert_eq!(channel.endpoint_name(), "orbitflare_devnet_yellowstone");
|
||||
assert_eq!(channel.provider().as_str(), "orbitflare");
|
||||
assert_eq!(channel.cluster().as_str(), "devnet");
|
||||
let request = match slot_request() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("OrbitFlare Yellowstone slot request must be valid: {error:?}"),
|
||||
};
|
||||
let mut session = match channel.open_standard_subscribe(request).await {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("OrbitFlare Devnet standard Subscribe with License Key x-token must open: {error:?}"),
|
||||
};
|
||||
let deadline = tokio::time::sleep(std::time::Duration::from_secs(45));
|
||||
tokio::pin!(deadline);
|
||||
let mut slot_seen = false;
|
||||
let mut ping_seen = false;
|
||||
loop {
|
||||
tokio::select! {
|
||||
() = &mut deadline => break,
|
||||
next_update = session.next_update() => {
|
||||
let next_update = match next_update {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => panic!("OrbitFlare Devnet Yellowstone Subscribe update must decode: {error:?}"),
|
||||
};
|
||||
match next_update {
|
||||
std::option::Option::Some(ksp_onchain_transport_lib::YellowstoneSubscribeUpdate::Slot(update)) => {
|
||||
if update.slot() > 0 {
|
||||
slot_seen = true;
|
||||
}
|
||||
},
|
||||
std::option::Option::Some(ksp_onchain_transport_lib::YellowstoneSubscribeUpdate::Ping(_)) => ping_seen = true,
|
||||
std::option::Option::Some(_) => {},
|
||||
std::option::Option::None => break,
|
||||
}
|
||||
if slot_seen && ping_seen {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
let close_timeout_result = tokio::time::timeout(std::time::Duration::from_secs(7), session.close()).await;
|
||||
let close_result = match close_timeout_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => {
|
||||
panic!("KSP Yellowstone Subscribe close must remain bounded beyond the configured five-second provider half-close deadline: {error}")
|
||||
},
|
||||
};
|
||||
match close_result {
|
||||
std::result::Result::Ok(()) => {},
|
||||
std::result::Result::Err(error) => {
|
||||
assert_eq!(
|
||||
error.code(),
|
||||
ksp_onchain_transport_lib::ERROR_CODE_TIMEOUT,
|
||||
"after live characterization, OrbitFlare close may time out waiting for provider half-close but must not fail for another reason: {error:?}"
|
||||
);
|
||||
},
|
||||
}
|
||||
assert!(slot_seen, "OrbitFlare Devnet Yellowstone must publish at least one non-zero confirmed slot during the 45-second characterization window");
|
||||
assert!(
|
||||
ping_seen,
|
||||
"OrbitFlare Devnet must emit the standard Yellowstone server Ping during the 45-second characterization window before any provider-specific heartbeat is justified"
|
||||
);
|
||||
}
|
||||
327
deltas/0.2.10/pre.001.md
Normal file
327
deltas/0.2.10/pre.001.md
Normal file
@@ -0,0 +1,327 @@
|
||||
<!-- file: deltas/0.2.10/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.001` — audit/sizing OrbitFlare Yellowstone gRPC
|
||||
|
||||
## 1. Base requise et vérifiée
|
||||
|
||||
Archive autoritaire fournie :
|
||||
|
||||
```text
|
||||
khadhroony-solana-project-v0.2.9-full-from-gitea.zip
|
||||
```
|
||||
|
||||
État vérifié :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.9
|
||||
deltas/0.2.9/rel.001.md présent
|
||||
prompts/015-V0_2_10_START_PROMPT.md présent
|
||||
metadata .git absente de l'archive Gitea
|
||||
```
|
||||
|
||||
Cette livraison ouvre :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10-pre.1
|
||||
commit attendu = v0.2.10-pre.001
|
||||
aucun tag prerelease
|
||||
```
|
||||
|
||||
## 2. Objet
|
||||
|
||||
`pre.001` exécute le gate documentaire obligatoire :
|
||||
|
||||
```text
|
||||
lecture base/règles/architecture
|
||||
baseline stable
|
||||
réaudit OrbitFlare actuel
|
||||
réaudit Yellowstone actuel
|
||||
auth control-plane/data-plane
|
||||
endpoints/network/security
|
||||
Free Devnet gRPC
|
||||
heartbeat
|
||||
capabilities/unary/replay
|
||||
limits/quotas
|
||||
architecture N1/N2 immuable
|
||||
threat model
|
||||
sizing et forecast
|
||||
```
|
||||
|
||||
Aucun code provider lourd, SDK OrbitFlare, metadata secrète ou heartbeat supplémentaire n'est ajouté.
|
||||
|
||||
## 3. Baseline opérateur acquise
|
||||
|
||||
Preuves fournies le 2026-08-25 sur `v0.2.9` :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
python3 scripts/audit_rust_workspace_rules.py OK / clean
|
||||
python3 scripts/audit_markdown_tables.py OK / 87 tables / 261 files
|
||||
cargo check --workspace OK
|
||||
cargo clippy --workspace --all-targets OK
|
||||
cargo test --workspace OK
|
||||
cargo tree -p ksp-onchain-transport-lib --duplicates fourni
|
||||
```
|
||||
|
||||
Transport pendant le workspace test :
|
||||
|
||||
```text
|
||||
383 unit
|
||||
49 public_api
|
||||
43 release_completeness
|
||||
4 doctests
|
||||
```
|
||||
|
||||
Les live smokes restent opt-in/ignored par défaut.
|
||||
|
||||
Le `cargo tree -p ksp-onchain-transport-lib` complet n'a pas encore été fourni et doit être rejoué avant commit.
|
||||
|
||||
## 4. Graphe de dépendances inspecté
|
||||
|
||||
Versions utiles visibles :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.0
|
||||
tonic 0.14.6
|
||||
tonic-prost 0.14.6
|
||||
prost 0.14.4
|
||||
tokio 1.53.1
|
||||
http 1.5.0
|
||||
reqwest 0.13.4
|
||||
```
|
||||
|
||||
Aucune divergence Tonic/Prost/Yellowstone ne justifie une intervention. Les doublons restants sont sans impact matériel pour OrbitFlare.
|
||||
|
||||
## 5. Réaudit OrbitFlare du 2026-08-25
|
||||
|
||||
### Free Devnet
|
||||
|
||||
Le pricing actuel confirme :
|
||||
|
||||
```text
|
||||
Free 0 USD/mois
|
||||
RPC 10 RPS
|
||||
transactions 1 TPS
|
||||
gRPC Devnet only
|
||||
credit limits unlimited
|
||||
```
|
||||
|
||||
Le CLI documente :
|
||||
|
||||
```text
|
||||
RPC Devnet = http://devnet.rpc.orbitflare.com
|
||||
gRPC Devnet = http://devnet.rpc.orbitflare.com:10000
|
||||
```
|
||||
|
||||
Objectif opérationnel fermé : utiliser OrbitFlare comme provider gRPC Devnet gratuit pour les tests KSP futurs, en complément de PublicNode Mainnet/Testnet.
|
||||
|
||||
### Auth
|
||||
|
||||
Classification :
|
||||
|
||||
```text
|
||||
X-ORBIT-KEY Customer API only
|
||||
Bearer Customer API v2
|
||||
RPC api_key HTTP RPC only
|
||||
account API key ne prouve pas une auth Yellowstone
|
||||
gRPC Dashboard token possible selon licence/service
|
||||
x-token mécanisme Yellowstone plausible si token gRPC distinct
|
||||
aucune metadata documentée par SDK Go pour endpoints régionaux
|
||||
```
|
||||
|
||||
La clé de compte opérateur ne doit pas être fournie au dépôt ni injectée par supposition dans gRPC.
|
||||
|
||||
### Heartbeat
|
||||
|
||||
OrbitFlare recommande un `SubscribeRequest::Ping` périodique. Yellowstone upstream envoie déjà un `SubscribeUpdate::Ping` périodique et KSP N1 répond automatiquement par un Ping standard sans modifier le dernier full request mémorisé.
|
||||
|
||||
Décision :
|
||||
|
||||
```text
|
||||
aucun timer OrbitFlare ajouté au moteur
|
||||
aucun changement YellowstoneGrpcSessionSettings
|
||||
aucune modification grpc_stream.rs
|
||||
pre.002 doit observer le Ping serveur live OrbitFlare Devnet
|
||||
```
|
||||
|
||||
Si ce Ping est observé, la policy standard N1 est suffisante. Sinon, une divergence provider doit être démontrée puis composée au-dessus de N1 sans le modifier.
|
||||
|
||||
### Limits
|
||||
|
||||
```text
|
||||
50 connexions gRPC simultanées par IP sur shared
|
||||
subscriptions par connexion annoncées unlimited
|
||||
idle timeout environ 10 minutes
|
||||
RESOURCE_EXHAUSTED au dépassement
|
||||
backoff exponentiel conseillé
|
||||
```
|
||||
|
||||
Ces valeurs restent provider-owned.
|
||||
|
||||
## 6. Réaudit Yellowstone actuel
|
||||
|
||||
État observé :
|
||||
|
||||
```text
|
||||
release GitHub courante v15.1.2+solana.4.2.0
|
||||
yellowstone-grpc-proto publié 12.6.0
|
||||
```
|
||||
|
||||
Aucune évolution matérielle ne remet en cause le standard N2 de `0.2.9`. Aucune dependency n'est modifiée.
|
||||
|
||||
## 7. Invariant architectural supersédant l'hypothèse initiale
|
||||
|
||||
Décision opérateur explicite :
|
||||
|
||||
```text
|
||||
le moteur gRPC ne change jamais pour un provider
|
||||
le moteur WebSocket ne change jamais pour un provider
|
||||
les fonctionnalités provider se composent au-dessus du moteur
|
||||
```
|
||||
|
||||
Pour `0.2.10` :
|
||||
|
||||
```text
|
||||
N1 moteur Yellowstone = IMMUTABLE
|
||||
N2 standard Solana = IMMUTABLE
|
||||
N3 OrbitFlare = profile/capability/facade seulement si besoin démontré
|
||||
```
|
||||
|
||||
Le prompt `015` reste autoritatif sauf sur toute formulation qui permettrait de mettre une policy OrbitFlare directement dans le moteur partagé.
|
||||
|
||||
## 8. Config V3
|
||||
|
||||
La shape existante suffit :
|
||||
|
||||
```text
|
||||
profile_id = orbitflare_devnet
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
protocol = solana_yellowstone
|
||||
url = http://devnet.rpc.orbitflare.com:10000
|
||||
metadata = []
|
||||
secret_metadata = []
|
||||
```
|
||||
|
||||
Pas de V4. Pas de secret ajouté avant preuve live. Pas de champ heartbeat moteur.
|
||||
|
||||
## 9. Smoke prévu
|
||||
|
||||
`pre.002` doit commencer par un canari standard N2 :
|
||||
|
||||
```text
|
||||
connect OrbitFlare Devnet Free sans metadata
|
||||
Subscribe slots confirmed
|
||||
recevoir Slot non nul
|
||||
observer SubscribeUpdate::Ping pendant une fenêtre bornée de caractérisation
|
||||
fermer proprement
|
||||
```
|
||||
|
||||
Puis sonder séparément les unary et replay sans rendre le smoke minimal dépendant d'entitlements provider non garantis.
|
||||
|
||||
## 10. Forecast recalibré
|
||||
|
||||
Chemin standard probable :
|
||||
|
||||
```text
|
||||
pre.001 audit/sizing
|
||||
pre.002 Config Devnet + characterization smoke standard N2
|
||||
pre.003 gate technique/live final
|
||||
pre.004 réconciliation documentaire finale
|
||||
pre.005 publication minimale
|
||||
rel.001 stable
|
||||
```
|
||||
|
||||
Chemin avec divergence provider démontrée :
|
||||
|
||||
```text
|
||||
pre.001 audit/sizing
|
||||
pre.002 Config Devnet + characterization smoke
|
||||
pre.003 provider overlay minimal au-dessus de N1/N2
|
||||
pre.004 gate technique/live final
|
||||
pre.005 réconciliation documentaire finale
|
||||
pre.006 publication minimale
|
||||
rel.001 stable
|
||||
```
|
||||
|
||||
## 11. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
deltas/0.2.10/pre.001.md
|
||||
```
|
||||
|
||||
## 12. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/validation/000-README.md
|
||||
```
|
||||
|
||||
## 13. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
.env.example
|
||||
config/**
|
||||
crates/**
|
||||
docs/architecture/**
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/USAGE.md
|
||||
```
|
||||
|
||||
Aucune implémentation provider ou Config runtime n'est introduite dans `pre.001`.
|
||||
|
||||
## 14. Sources externes réauditées
|
||||
|
||||
```text
|
||||
https://docs.orbitflare.com/llms.txt
|
||||
https://docs.orbitflare.com/cli
|
||||
https://docs.orbitflare.com/authentication
|
||||
https://docs.orbitflare.com/data-streaming/yellowstone
|
||||
https://docs.orbitflare.com/data-streaming/yellowstone-quickstart
|
||||
https://docs.orbitflare.com/sdk/go-grpc
|
||||
https://orbitflare.com/pricing
|
||||
https://orbitflare.com/products/rpc-nodes
|
||||
https://orbitflare.com/products/solana-grpc
|
||||
https://github.com/rpcpool/yellowstone-grpc
|
||||
https://github.com/rpcpool/yellowstone-grpc/releases
|
||||
https://github.com/rpcpool/yellowstone-grpc/blob/master/README.md
|
||||
https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto
|
||||
```
|
||||
|
||||
## 15. Validations de préparation
|
||||
|
||||
Le sandbox a exécuté :
|
||||
|
||||
```text
|
||||
inspection archive/version/rel/prompt OK
|
||||
lecture code N1/N2/Config et docs 0.2.9 OK
|
||||
réaudit OrbitFlare/Yellowstone actuel OK
|
||||
inspection cargo tree --duplicates fourni par opérateur OK
|
||||
```
|
||||
|
||||
Le sandbox ne dispose pas de Cargo ; aucun `cargo check/clippy/test/tree` post-overlay n'est déclaré réussi localement.
|
||||
|
||||
## 16. Validation opérateur attendue avant commit
|
||||
|
||||
Comme `pre.001` change uniquement la version Cargo et la documentation :
|
||||
|
||||
```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.10
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-onchain-transport-lib
|
||||
cargo tree -p ksp-onchain-transport-lib --duplicates
|
||||
```
|
||||
|
||||
Attendu : aucun changement de dependency et aucun changement sous `crates/`.
|
||||
196
deltas/0.2.10/pre.002-fix.001.md
Normal file
196
deltas/0.2.10/pre.002-fix.001.md
Normal file
@@ -0,0 +1,196 @@
|
||||
<!-- file: deltas/0.2.10/pre.002-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.002-fix.001` — OrbitFlare License Key `x-token`
|
||||
|
||||
## 1. Base et identité
|
||||
|
||||
Base exacte :
|
||||
|
||||
```text
|
||||
0.2.10-pre.002 commité
|
||||
```
|
||||
|
||||
Le fix porte une correction runtime/configuration de l’auth provider. La version Cargo devient donc :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10-pre.2.fix.1
|
||||
commit attendu = v0.2.10-pre.002-fix.001
|
||||
aucun tag prerelease
|
||||
```
|
||||
|
||||
## 2. Défaut démontré par le live `pre.002`
|
||||
|
||||
Le gate statique/workspace `pre.002` est vert. Le smoke live sans metadata a atteint OrbitFlare puis l’ouverture du stream a échoué de manière sûre :
|
||||
|
||||
```text
|
||||
grpc_operation = SubscribeOpen
|
||||
grpc_status = Unauthenticated
|
||||
grpc_code = The request does not have valid authentication credentials
|
||||
```
|
||||
|
||||
Le Dashboard opérateur montre un produit `Solana Free` avec License Key `ORBIT-*` et `API Key Mode Active`.
|
||||
|
||||
La référence Yellowstone OrbitFlare précise ensuite le contrat data-plane :
|
||||
|
||||
```text
|
||||
ORBITFLARE_LICENSE_KEY
|
||||
-> metadata gRPC x-token
|
||||
-> Yellowstone
|
||||
```
|
||||
|
||||
Le `X-ORBIT-KEY` et le Bearer Device Flow restent des credentials Customer API et ne sont pas utilisés par Transport Yellowstone.
|
||||
|
||||
## 3. Correction Config V3
|
||||
|
||||
`config/std.transport.json` conserve le même endpoint et ajoute uniquement la metadata secrète requise :
|
||||
|
||||
```text
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
protocol = solana_yellowstone
|
||||
url = http://devnet.rpc.orbitflare.com:10000
|
||||
metadata = []
|
||||
secret_metadata = x-token <- ${KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN}
|
||||
```
|
||||
|
||||
Aucun format Config V4 n’est créé.
|
||||
|
||||
`.env.example` inventorie désormais :
|
||||
|
||||
```text
|
||||
KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN
|
||||
```
|
||||
|
||||
La valeur locale attendue est la License Key `ORBIT-*`. Une `X-ORBIT-KEY` Customer API ne doit jamais être placée dans cette variable.
|
||||
|
||||
## 4. Preuve Config déterministe
|
||||
|
||||
Le test `committed_v3_orbitflare_devnet_profile_maps_provider_neutral_yellowstone_grpc_with_license_x_token` injecte un canari secret via `ConfigEnvironment` et prouve :
|
||||
|
||||
```text
|
||||
profil explicite orbitflare_devnet
|
||||
companions HTTP/WS Devnet inchangés
|
||||
endpoint Yellowstone OrbitFlare inchangé
|
||||
metadata key = x-token
|
||||
metadata classée secret
|
||||
validation Transport PASS
|
||||
URL provider absente du Debug
|
||||
canari secret absent du Debug
|
||||
X-ORBIT-KEY absent du Transport
|
||||
```
|
||||
|
||||
## 5. Smoke live corrigé
|
||||
|
||||
`yellowstone_orbitflare_smoke.rs` ne dépend toujours pas de Config et ne lit aucun environnement. Il suit le pattern de sécurité déjà utilisé par les smokes PublicNode :
|
||||
|
||||
```text
|
||||
une License Key lue sur stdin
|
||||
aucun secret en argument de ligne de commande
|
||||
YellowstoneGrpcMetadataEntry::secret("x-token", ...)
|
||||
reconnect max_retries = 0
|
||||
Subscribe slots confirmed
|
||||
fenêtre Slot + Ping = 45 s
|
||||
close borné
|
||||
```
|
||||
|
||||
Le smoke vérifie également que la License Key n’apparaît pas dans `Debug`.
|
||||
|
||||
Commande opérateur :
|
||||
|
||||
```bash
|
||||
read -rsp 'OrbitFlare License Key: ' ORBITFLARE_LICENSE_KEY; echo
|
||||
printf '%s\n' "$ORBITFLARE_LICENSE_KEY" | cargo test -p ksp-onchain-transport-lib --test yellowstone_orbitflare_smoke -- --ignored --nocapture
|
||||
unset ORBITFLARE_LICENSE_KEY
|
||||
```
|
||||
|
||||
## 6. Invariant architectural
|
||||
|
||||
Toujours inchangés :
|
||||
|
||||
```text
|
||||
src/grpc_settings.rs
|
||||
src/grpc_channel.rs
|
||||
src/grpc_unary.rs
|
||||
src/grpc_subscribe.rs
|
||||
src/grpc_stream.rs
|
||||
```
|
||||
|
||||
Le standard Yellowstone N2 reste inchangé. Aucun SDK OrbitFlare runtime n’est ajouté.
|
||||
|
||||
L’auth provider est entièrement composée par la surface metadata secrète déjà existante.
|
||||
|
||||
## 7. Heartbeat
|
||||
|
||||
Ce fix ne matérialise aucun heartbeat OrbitFlare.
|
||||
|
||||
Le rerun authentifié doit d’abord qualifier :
|
||||
|
||||
```text
|
||||
Slot non nul
|
||||
SubscribeUpdate::Ping serveur
|
||||
```
|
||||
|
||||
Si les deux sont observés, N1 répond déjà automatiquement au Ping standard et aucune couche provider heartbeat n’est requise.
|
||||
|
||||
Si le stream authentifié fonctionne mais n’émet aucun Ping serveur dans la fenêtre de caractérisation, `pre.003` devient une tranche provider-specific au-dessus de N1/N2. Il reste interdit d’ajouter un timer OrbitFlare au moteur gRPC.
|
||||
|
||||
## 8. Validation disponible dans l’environnement de génération
|
||||
|
||||
Exécuté :
|
||||
|
||||
```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.10
|
||||
Markdown table audit: clean (99 table(s), 99 file(s))
|
||||
|
||||
config/std.transport.json
|
||||
JSON parse PASS
|
||||
JSON Schema validation PASS
|
||||
|
||||
comparaison N1 avec pre.002
|
||||
grpc_settings.rs inchangé
|
||||
grpc_channel.rs inchangé
|
||||
grpc_unary.rs inchangé
|
||||
grpc_subscribe.rs inchangé
|
||||
grpc_stream.rs inchangé
|
||||
```
|
||||
|
||||
Aucune commande Cargo n’est déclarée exécutée dans l’environnement de génération.
|
||||
|
||||
## 9. Gates opérateur
|
||||
|
||||
Après application du fix :
|
||||
|
||||
```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.10
|
||||
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
|
||||
```
|
||||
|
||||
Puis exécuter le live authentifié décrit en section 5.
|
||||
|
||||
## 10. Fichiers ajoutés/modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
.env.example
|
||||
config/std.transport.json
|
||||
crates/ksp-config-lib/unit_tests/transport.rs
|
||||
crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
deltas/0.2.10/pre.002-fix.001.md
|
||||
```
|
||||
|
||||
Le delta commité `deltas/0.2.10/pre.002.md` reste immuable.
|
||||
287
deltas/0.2.10/pre.002.md
Normal file
287
deltas/0.2.10/pre.002.md
Normal file
@@ -0,0 +1,287 @@
|
||||
<!-- file: deltas/0.2.10/pre.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.002` — OrbitFlare Devnet Config + characterization smoke
|
||||
|
||||
## 1. Base et version
|
||||
|
||||
Base de travail :
|
||||
|
||||
```text
|
||||
0.2.10-pre.001
|
||||
```
|
||||
|
||||
Validation opérateur fournie sur cette base le 2026-08-25 :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py PASS / 97 tables / 233 files
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-onchain-transport-lib fourni
|
||||
cargo tree -p ksp-onchain-transport-lib --duplicates fourni
|
||||
```
|
||||
|
||||
Le graphe confirme notamment :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.0
|
||||
tonic 0.14.6
|
||||
tonic-prost 0.14.6
|
||||
prost 0.14.4
|
||||
tokio 1.53.1
|
||||
```
|
||||
|
||||
Cette livraison passe à :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10-pre.2
|
||||
commit attendu = v0.2.10-pre.002
|
||||
aucun tag prerelease
|
||||
```
|
||||
|
||||
## 2. Invariant architectural
|
||||
|
||||
Aucun moteur physique n'est modifié :
|
||||
|
||||
```text
|
||||
src/grpc_settings.rs inchangé
|
||||
src/grpc_channel.rs inchangé
|
||||
src/grpc_unary.rs inchangé
|
||||
src/grpc_subscribe.rs inchangé
|
||||
src/grpc_stream.rs inchangé
|
||||
```
|
||||
|
||||
Le standard Yellowstone N2 reste également inchangé.
|
||||
|
||||
OrbitFlare est matérialisé uniquement par :
|
||||
|
||||
```text
|
||||
Config provider profile
|
||||
provider-neutral Yellowstone smoke
|
||||
provider validation/documentation
|
||||
```
|
||||
|
||||
Aucun SDK OrbitFlare, second client Tonic, proto provider, heartbeat moteur ou metadata secrète n'est ajouté.
|
||||
|
||||
## 3. Profil Config V3 `orbitflare_devnet`
|
||||
|
||||
`config/std.transport.json` ajoute un profil dédié :
|
||||
|
||||
```text
|
||||
profile_id = orbitflare_devnet
|
||||
```
|
||||
|
||||
Il conserve les companions standards déjà utilisés sur Devnet :
|
||||
|
||||
```text
|
||||
HTTP = https://api.devnet.solana.com
|
||||
WS = wss://api.devnet.solana.com
|
||||
```
|
||||
|
||||
et ajoute exactement un endpoint Yellowstone :
|
||||
|
||||
```text
|
||||
name = orbitflare_solana_devnet_yellowstone
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
protocol = solana_yellowstone
|
||||
url = http://devnet.rpc.orbitflare.com:10000
|
||||
metadata = []
|
||||
secret_metadata = []
|
||||
```
|
||||
|
||||
Le format reste V3. `.env.example` n'est pas modifié et aucune API key de compte OrbitFlare n'est reclassifiée comme credential gRPC.
|
||||
|
||||
`ksp-config-lib` ajoute un test déterministe qui prouve :
|
||||
|
||||
```text
|
||||
sélection explicite orbitflare_devnet
|
||||
companions HTTP/WS Devnet préservés
|
||||
provider/cluster/protocol gRPC corrects
|
||||
URL plaintext conservée telle quelle
|
||||
aucune metadata inventée
|
||||
Debug gRPC sans URL provider
|
||||
absence de X-ORBIT-KEY dans Transport settings
|
||||
```
|
||||
|
||||
## 4. Smoke OrbitFlare Devnet
|
||||
|
||||
Nouveau test opt-in :
|
||||
|
||||
```text
|
||||
crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
|
||||
```
|
||||
|
||||
Le test utilise directement les API publiques Yellowstone existantes de Transport, sans dépendre de Config :
|
||||
|
||||
```text
|
||||
endpoint Devnet OrbitFlare sans metadata
|
||||
reconnect max_retries = 0
|
||||
Subscribe slots
|
||||
commitment = confirmed
|
||||
fenêtre de caractérisation = 45 s
|
||||
preuve Slot non nul
|
||||
preuve SubscribeUpdate::Ping serveur
|
||||
close borné
|
||||
```
|
||||
|
||||
Le `Ping` reçu reste traité par le moteur N1 déjà livré en `0.2.9`, qui répond automatiquement sur le même stream. Le test n'ajoute aucune policy heartbeat.
|
||||
|
||||
Commande live :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-onchain-transport-lib --test yellowstone_orbitflare_smoke -- --ignored --nocapture
|
||||
```
|
||||
|
||||
Interprétation :
|
||||
|
||||
```text
|
||||
Slot + Ping PASS
|
||||
OrbitFlare reste standard ; aucune façade/policy provider heartbeat requise
|
||||
|
||||
connection/auth failure
|
||||
classifier le service/licence réel avant toute metadata
|
||||
|
||||
Slot PASS mais Ping absent
|
||||
qualifier une divergence heartbeat provider avant toute implémentation spécifique
|
||||
```
|
||||
|
||||
## 5. Audit Markdown étendu
|
||||
|
||||
`scripts/audit_markdown_tables.py` passe en version 2 et contrôle désormais aussi l'équivalent structurel de :
|
||||
|
||||
```text
|
||||
\n\s*\n\s*\n
|
||||
```
|
||||
|
||||
c'est-à-dire au moins deux lignes vides consécutives hors fenced code block.
|
||||
|
||||
Le contrôle :
|
||||
|
||||
```text
|
||||
considère une ligne whitespace-only comme vide
|
||||
signale fichier + première ligne + longueur de la séquence
|
||||
n'interprète pas les blancs internes aux ``` / ~~~ fenced blocks
|
||||
ignore les répertoires générés ou tiers en parcours récursif
|
||||
```
|
||||
|
||||
Répertoires récursifs exclus :
|
||||
|
||||
```text
|
||||
.git
|
||||
.idea
|
||||
.venv
|
||||
__pycache__
|
||||
dist
|
||||
node_modules
|
||||
target
|
||||
```
|
||||
|
||||
Cette exclusion rend le résultat déterministe entre une archive Gitea propre et un checkout développeur contenant des `node_modules`. Le nombre de fichiers audités peut donc diminuer par rapport à l'ancien script sans signifier une perte de couverture KSP-owned.
|
||||
|
||||
Une seule séquence de deux lignes vides existait dans le scope KSP actif de l'archive : elle est supprimée dans `crates/ksp-onchain-transport-lib/README.md`.
|
||||
|
||||
`docs/rules/RULES_DOCUMENTATION.md` formalise `DOC-BLANK-001` à `DOC-BLANK-003`, y compris l'immuabilité des anciens deltas publiés.
|
||||
|
||||
## 6. Documents de plan/validation
|
||||
|
||||
Le plan 017 et la validation 013 passent en version 2 pour enregistrer :
|
||||
|
||||
```text
|
||||
pre.001 operator gate fermé
|
||||
profil orbitflare_devnet matérialisé
|
||||
smoke de caractérisation matérialisé
|
||||
N1/N2 inchangés
|
||||
live Devnet encore PENDING
|
||||
```
|
||||
|
||||
Aucun README/USAGE OrbitFlare durable n'est finalisé ici ; cette responsabilité reste réservée au couloir documentaire final.
|
||||
|
||||
## 7. Validation disponible dans l'environnement de génération
|
||||
|
||||
Exécuté sans Cargo :
|
||||
|
||||
```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.10
|
||||
clean / 98 tables / 98 KSP-owned files
|
||||
|
||||
config/std.transport.json
|
||||
JSON parse PASS
|
||||
JSON Schema validation PASS
|
||||
```
|
||||
|
||||
Le nouvel audit Markdown a aussi été caractérisé avec des fixtures temporaires :
|
||||
|
||||
```text
|
||||
deux lignes vides hors fence FAIL attendu
|
||||
plusieurs lignes vides dans fence PASS attendu
|
||||
node_modules récursif ignoré attendu
|
||||
```
|
||||
|
||||
Aucune commande Cargo n'est déclarée exécutée dans l'environnement de génération.
|
||||
|
||||
## 8. Gates opérateur `pre.002`
|
||||
|
||||
Exécuter :
|
||||
|
||||
```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.10
|
||||
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
|
||||
```
|
||||
|
||||
Puis le live dédié :
|
||||
|
||||
```bash
|
||||
cargo test -p ksp-onchain-transport-lib --test yellowstone_orbitflare_smoke -- --ignored --nocapture
|
||||
```
|
||||
|
||||
`pre.002` ne ferme son gate provider que lorsque le résultat live est classifié. Un échec d'auth ou l'absence de `Ping` ne doit jamais être corrigé par modification du moteur N1.
|
||||
|
||||
## 9. Fichiers ajoutés/modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
config/std.transport.json
|
||||
crates/ksp-config-lib/unit_tests/transport.rs
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
docs/rules/RULES_DOCUMENTATION.md
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
scripts/audit_markdown_tables.py
|
||||
deltas/0.2.10/pre.002.md
|
||||
```
|
||||
|
||||
## 10. Suite conditionnelle
|
||||
|
||||
Si le live retourne `Slot + Ping PASS` :
|
||||
|
||||
```text
|
||||
pre.003 = gate technique/live final
|
||||
```
|
||||
|
||||
Si une divergence provider réelle est démontrée :
|
||||
|
||||
```text
|
||||
pre.003 = tranche provider-specific minimale au-dessus de N1/N2
|
||||
pre.004 = gate technique/live final
|
||||
```
|
||||
|
||||
Le couloir documentaire final puis la prerelease de publication restent distincts dans les deux cas.
|
||||
252
deltas/0.2.10/pre.003.md
Normal file
252
deltas/0.2.10/pre.003.md
Normal file
@@ -0,0 +1,252 @@
|
||||
<!-- file: deltas/0.2.10/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.003` — gate technique/live final OrbitFlare Yellowstone
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Base directe attendue :
|
||||
|
||||
```text
|
||||
livraison : 0.2.10-pre.002-fix.001
|
||||
Cargo : 0.2.10-pre.2.fix.1
|
||||
commit : v0.2.10-pre.002-fix.001
|
||||
```
|
||||
|
||||
Identité de cette tranche :
|
||||
|
||||
```text
|
||||
livraison : 0.2.10-pre.003
|
||||
Cargo : 0.2.10-pre.3
|
||||
commit : v0.2.10-pre.003
|
||||
aucun tag prerelease
|
||||
```
|
||||
|
||||
Cette prerelease est exclusivement le couloir **technique/live final** de `0.2.10`. Elle ne porte aucune réconciliation README/USAGE/plan/validation, aucune finalisation CHANGELOG/ROADMAP et aucun prompt `0.2.11`.
|
||||
|
||||
## 2. Gate acquis de `pre.002-fix.001`
|
||||
|
||||
La validation opérateur reçue le 2026-08-25 ferme le défaut d'auth classifié dans `pre.002`.
|
||||
|
||||
Le gate déterministe est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py clean / 0 export candidate / clean
|
||||
python3 scripts/audit_markdown_tables.py PASS, 99 tables / 99 files
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test --workspace PASS
|
||||
Config unit 114/114 PASS
|
||||
Config ownership 5/5 PASS
|
||||
Config public API 15/15 PASS
|
||||
Transport unit 383/383 PASS
|
||||
Transport public API 49/49 PASS
|
||||
Transport release completeness 43/43 PASS
|
||||
Transport doctests 4/4 PASS
|
||||
workspace dependency canary 3/3 PASS
|
||||
```
|
||||
|
||||
Le smoke OrbitFlare Devnet authentifié est également vert :
|
||||
|
||||
```text
|
||||
endpoint http://devnet.rpc.orbitflare.com:10000
|
||||
auth License Key ORBIT-* -> secret metadata x-token
|
||||
Subscribe PASS
|
||||
Slot > 0 PASS
|
||||
server Ping PASS
|
||||
close borné PASS
|
||||
résultat 1 passed / 0 failed
|
||||
```
|
||||
|
||||
Cette preuve ferme la branche de divergence heartbeat : OrbitFlare émet le `SubscribeUpdate::Ping` Yellowstone standard et le moteur N1 `0.2.9` possède déjà la réponse automatique déterministe. Aucun heartbeat provider, aucune façade OrbitFlare et aucune modification N1/N2 ne sont nécessaires.
|
||||
|
||||
## 3. Responsabilité de `pre.003`
|
||||
|
||||
`pre.003` ne matérialise aucun nouveau comportement. Elle rejoue et ferme les preuves techniques finales après le fix d'auth :
|
||||
|
||||
```text
|
||||
version Cargo prerelease synchronisée
|
||||
workspace complet sans warning
|
||||
invariants Rust/Markdown
|
||||
Config V3 OrbitFlare x-token non régressée
|
||||
Yellowstone N1/N2 non régressés
|
||||
HTTP 52 current + 14 historical non régressés
|
||||
WebSocket standard et Helius non régressés
|
||||
smoke live OrbitFlare Devnet final
|
||||
smokes PublicNode Mainnet/Testnet finaux si credentials opérateur disponibles
|
||||
graphes Cargo Transport et doublons inspectés
|
||||
aucun SDK OrbitFlare runtime
|
||||
aucune dépendance Transport -> Config
|
||||
```
|
||||
|
||||
Le payload de `pre.003` ne change ni code runtime, ni test, ni Config, ni schema, ni dépendance. Le seul changement technique est le signal de version Cargo obligatoire pour une prerelease non-fix.
|
||||
|
||||
## 4. Invariants à fermer
|
||||
|
||||
Les fichiers moteur Yellowstone restent hors modification :
|
||||
|
||||
```text
|
||||
crates/ksp-onchain-transport-lib/src/grpc_settings.rs
|
||||
crates/ksp-onchain-transport-lib/src/grpc_channel.rs
|
||||
crates/ksp-onchain-transport-lib/src/grpc_unary.rs
|
||||
crates/ksp-onchain-transport-lib/src/grpc_subscribe.rs
|
||||
crates/ksp-onchain-transport-lib/src/grpc_stream.rs
|
||||
```
|
||||
|
||||
Le gate doit confirmer :
|
||||
|
||||
```text
|
||||
N1 gRPC provider-neutral inchangé
|
||||
N2 Yellowstone standard inchangé
|
||||
OrbitFlare composé par endpoint + provider + cluster + x-token Config V3
|
||||
X-ORBIT-KEY absent du data-plane Yellowstone
|
||||
License Key jamais exposée par Debug/CLI
|
||||
pas de format Config V4
|
||||
pas de provider proto
|
||||
pas de second raw Tonic client
|
||||
pas de orbitflare-sdk runtime
|
||||
```
|
||||
|
||||
## 5. Gate déterministe final
|
||||
|
||||
Après application de `pre.003` :
|
||||
|
||||
```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.10
|
||||
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
|
||||
```
|
||||
|
||||
Seuils minimaux attendus :
|
||||
|
||||
```text
|
||||
Config unit 114
|
||||
Config ownership 5
|
||||
Config public API 15
|
||||
Transport unit 383
|
||||
Transport public API 49
|
||||
Transport release completeness 43
|
||||
Transport doctests 4
|
||||
workspace dependency canary 3
|
||||
```
|
||||
|
||||
Toute régression imputable à KSP ouvre `pre.003-fix.NNN`. Elle ne doit pas être repoussée dans le couloir documentaire `pre.004`.
|
||||
|
||||
## 6. Smoke OrbitFlare Devnet final
|
||||
|
||||
Saisir la License Key sans l'inscrire dans l'historique :
|
||||
|
||||
```bash
|
||||
read -rsp 'OrbitFlare License Key: ' ORBITFLARE_LICENSE_KEY; echo
|
||||
printf '%s\n' "$ORBITFLARE_LICENSE_KEY" \
|
||||
| cargo test -p ksp-onchain-transport-lib --test yellowstone_orbitflare_smoke -- --ignored --nocapture
|
||||
unset ORBITFLARE_LICENSE_KEY
|
||||
```
|
||||
|
||||
Attendu :
|
||||
|
||||
```text
|
||||
orbitflare_devnet_yellowstone_streams_slots_and_emits_standard_server_ping_with_license_x_token ... ok
|
||||
1 passed
|
||||
0 failed
|
||||
0 ignored
|
||||
```
|
||||
|
||||
Le smoke doit encore prouver dans une même session bornée :
|
||||
|
||||
```text
|
||||
auth x-token acceptée
|
||||
Subscribe standard ouvert
|
||||
Slot non nul reçu
|
||||
SubscribeUpdate::Ping standard observé
|
||||
fermeture bornée
|
||||
```
|
||||
|
||||
Un incident externe OrbitFlare/réseau démontré comme tel est documenté comme `EXTERNAL BLOCK`. Un échec de mapping, metadata, moteur, protocol ou fermeture imputable à KSP ouvre un fix technique.
|
||||
|
||||
## 7. PublicNode et graphes finaux
|
||||
|
||||
Les smokes PublicNode Mainnet/Testnet restent les canaris provider du standard livré par `0.2.9`. Si les deux credentials opérateur sont disponibles pendant ce gate, les rejouer :
|
||||
|
||||
```bash
|
||||
read -rsp 'PublicNode Mainnet Yellowstone x-token: ' PUBLICNODE_MAINNET_TOKEN; echo
|
||||
read -rsp 'PublicNode Testnet Yellowstone x-token: ' PUBLICNODE_TESTNET_TOKEN; echo
|
||||
printf '%s\n%s\n' "$PUBLICNODE_MAINNET_TOKEN" "$PUBLICNODE_TESTNET_TOKEN" \
|
||||
| cargo test -p ksp-onchain-transport-lib --test yellowstone_publicnode_smoke -- --ignored --nocapture
|
||||
unset PUBLICNODE_MAINNET_TOKEN PUBLICNODE_TESTNET_TOKEN
|
||||
```
|
||||
|
||||
Attendu lorsque rejoué :
|
||||
|
||||
```text
|
||||
2 passed
|
||||
0 failed
|
||||
0 ignored
|
||||
```
|
||||
|
||||
Inspecter ensuite :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-onchain-transport-lib
|
||||
cargo tree -p ksp-onchain-transport-lib --duplicates
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Points obligatoires :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.x sur la stack attendue
|
||||
Tonic/Prost KSP-owned sans seconde génération incompatible
|
||||
aucun yellowstone-grpc-client runtime
|
||||
aucun orbitflare-sdk runtime
|
||||
aucune dépendance ksp-onchain-transport-lib -> ksp-config-lib
|
||||
aucun tracing direct Transport
|
||||
aucun nouveau doublon introduit par 0.2.10
|
||||
```
|
||||
|
||||
Les smokes PublicNode ne deviennent pas un blocker si leurs credentials ne sont simplement pas disponibles au moment du gate : leur non-régression déterministe reste couverte par les suites Transport/Config et le code live n'a pas changé. En revanche, tout échec effectivement observé lors d'un rerun doit être classifié, jamais ignoré.
|
||||
|
||||
## 8. Critère de fermeture technique
|
||||
|
||||
`pre.003` est fermée lorsque :
|
||||
|
||||
```text
|
||||
gate déterministe final vert
|
||||
OrbitFlare Devnet Subscribe -> Slot + Ping live PASS
|
||||
graphes Cargo finaux inspectés
|
||||
N1 inchangé
|
||||
N2 inchangé
|
||||
Config V3 x-token cohérente et redacted
|
||||
aucun provider overlay nécessaire
|
||||
aucun heartbeat provider nécessaire
|
||||
aucun SDK OrbitFlare ajouté
|
||||
aucun défaut technique reporté vers pre.004
|
||||
```
|
||||
|
||||
Une fois ce gate acquis, la prochaine tranche est obligatoirement :
|
||||
|
||||
```text
|
||||
0.2.10-pre.004 — réconciliation documentaire finale
|
||||
```
|
||||
|
||||
Elle portera plan, validation, README/USAGE et références durables. Elle ne doit pas porter de nouveau correctif technique.
|
||||
|
||||
## 9. Modifications de cette livraison
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
# version: 264 -> 265
|
||||
workspace.package.version: 0.2.10-pre.2.fix.1 -> 0.2.10-pre.3
|
||||
|
||||
deltas/0.2.10/pre.003.md
|
||||
ajout du présent gate technique/live final
|
||||
```
|
||||
|
||||
Aucun autre fichier n'est modifié.
|
||||
128
deltas/0.2.10/pre.004.md
Normal file
128
deltas/0.2.10/pre.004.md
Normal file
@@ -0,0 +1,128 @@
|
||||
<!-- file: deltas/0.2.10/pre.004.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.004` — réconciliation documentaire finale OrbitFlare Yellowstone
|
||||
|
||||
## 1. Base
|
||||
|
||||
```text
|
||||
0.2.10-pre.003
|
||||
```
|
||||
|
||||
Cette tranche est exclusivement le couloir de réconciliation documentaire finale. Le gate technique/live de `pre.003` est vert ; aucun correctif runtime, Config exécutable, test, schema, dependency ou feature n'est introduit ici.
|
||||
|
||||
## 2. Version technique
|
||||
|
||||
Comme toute prerelease non-fix, la version Cargo est synchronisée mécaniquement :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10-pre.4
|
||||
```
|
||||
|
||||
Aucune sémantique runtime ne change.
|
||||
|
||||
## 3. Preuve technique réconciliée
|
||||
|
||||
Le gate opérateur `pre.003` du 2026-08-25 est fermé avec :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
Rust workspace audit PASS / 0 export candidate
|
||||
Markdown audit PASS / 99 tables / 100 files
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
Config unit 114/114 PASS
|
||||
Config ownership 5/5 PASS
|
||||
Config public API 15/15 PASS
|
||||
Transport unit 383/383 PASS
|
||||
Transport public API 49/49 PASS
|
||||
Transport release completeness 43/43 PASS
|
||||
Transport doctests 4/4 PASS
|
||||
workspace dependency canary 3/3 PASS
|
||||
cargo test --workspace PASS
|
||||
OrbitFlare Devnet Subscribe + Slot + Ping 1/1 PASS, 5.19 s
|
||||
```
|
||||
|
||||
Les graphes Cargo direct Transport, doublons Transport et doublons workspace ont été inspectés. La pile reste :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.0
|
||||
tonic / tonic-prost 0.14.6
|
||||
prost / prost-types 0.14.4
|
||||
```
|
||||
|
||||
Aucun `yellowstone-grpc-client` runtime, aucun `orbitflare-sdk` runtime et aucune dépendance `Transport -> Config` n'ont été ajoutés.
|
||||
|
||||
## 4. OrbitFlare final
|
||||
|
||||
Contrat durable réconcilié :
|
||||
|
||||
```text
|
||||
Devnet endpoint http://devnet.rpc.orbitflare.com:10000
|
||||
auth License Key ORBIT-* -> secret metadata x-token
|
||||
Config secret KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN
|
||||
Subscribe standard Yellowstone N2
|
||||
live Slot non nul + server Ping
|
||||
N1 inchangé
|
||||
N2 inchangé
|
||||
provider facade non nécessaire
|
||||
heartbeat N3 non nécessaire
|
||||
Config V4 non nécessaire
|
||||
```
|
||||
|
||||
Le premier échec `pre.002` sans metadata reste conservé dans son delta historique comme caractérisation ayant conduit au fix d'auth `pre.002-fix.001`.
|
||||
|
||||
## 5. Documents réconciliés
|
||||
|
||||
```text
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/USAGE.md
|
||||
docs/000-README.md
|
||||
```
|
||||
|
||||
Les anciennes affirmations `PENDING` sont remplacées par les résultats `pre.003` réellement observés. README/USAGE documentent désormais le profil OrbitFlare Devnet et son smoke live durable.
|
||||
|
||||
## 6. Frontière avec `pre.005`
|
||||
|
||||
Cette tranche ne touche pas :
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompt suivant
|
||||
```
|
||||
|
||||
La décision sur la release suivante est prise pendant cette réconciliation, sans générer encore son prompt : Helius LaserStream gRPC est reporté dans les TODO Yellowstone sans numéro de release faute d'accès live raisonnable ; la séquence active avance et `0.2.11` devient `off-chain price transport`, suivie de `0.2.12` Price Desk + intégration Wallet Desk, `0.2.13` interface/wire foundation et `0.2.14` program-api foundation. Le futur `ROADMAP.md` de `pre.005` devra refléter exactement ce report et cette renumérotation.
|
||||
|
||||
Une fois cette décision prise, `pre.005` reste strictement publication-minimal : prompt suivant + `CHANGELOG.md` + `ROADMAP.md` + signal Cargo + delta.
|
||||
|
||||
Si un défaut technique de `0.2.10` est découvert après ce gate documentaire, il ne doit pas être glissé dans `pre.005`; ouvrir une nouvelle prerelease du couloir approprié puis rejouer les tranches finales nécessaires.
|
||||
|
||||
## 7. Fichiers modifiés/ajoutés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
crates/ksp-onchain-transport-lib/README.md
|
||||
crates/ksp-onchain-transport-lib/USAGE.md
|
||||
deltas/0.2.10/pre.004.md
|
||||
```
|
||||
|
||||
## 8. Gate opérateur
|
||||
|
||||
```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.10
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke live ni `cargo tree` n'est à rejouer si le delta est appliqué exactement : aucune surface technique ou dépendance n'est modifiée.
|
||||
132
deltas/0.2.10/pre.005.md
Normal file
132
deltas/0.2.10/pre.005.md
Normal file
@@ -0,0 +1,132 @@
|
||||
<!-- file: deltas/0.2.10/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-pre.005` — préparation de publication minimale
|
||||
|
||||
## 1. Base
|
||||
|
||||
```text
|
||||
0.2.10-pre.004
|
||||
```
|
||||
|
||||
Cette tranche est exclusivement le couloir de préparation de publication. Elle ne modifie aucun code, test, schema, config, README, USAGE, plan, validation ou règle normative.
|
||||
|
||||
## 2. Gate `pre.003` et réconciliation `pre.004`
|
||||
|
||||
Le gate technique final `pre.003` a confirmé :
|
||||
|
||||
```text
|
||||
Rust workspace audit PASS
|
||||
Markdown audit PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test --workspace PASS
|
||||
OrbitFlare live Subscribe -> Slot+Ping PASS en 5.19 s
|
||||
graphes Cargo inspectés
|
||||
```
|
||||
|
||||
`pre.004` a ensuite réconcilié les documents durables : plan/validation OrbitFlare, README/USAGE Transport, index documentaire et séquence fonctionnelle. Helius LaserStream gRPC a été reporté dans les TODO faute d'accès live raisonnable sans abonnement payant, sans remise en cause de sa compatibilité wire Yellowstone largement observée.
|
||||
|
||||
## 3. Version technique
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10-pre.5
|
||||
```
|
||||
|
||||
La modification est mécanique ; aucune sémantique runtime ne change.
|
||||
|
||||
## 4. `CHANGELOG.md`
|
||||
|
||||
Le changelog stable est préparé pour `0.2.10 — OrbitFlare Yellowstone gRPC` avec les faits consolidés :
|
||||
|
||||
```text
|
||||
N1/N2 Yellowstone inchangés
|
||||
Config V3 orbitflare_devnet
|
||||
x-token = License Key via secret_metadata
|
||||
premier live sans metadata -> Unauthenticated
|
||||
fix auth documenté
|
||||
live Subscribe -> Slot + standard Ping PASS
|
||||
second live final PASS
|
||||
aucun heartbeat/provider SDK/Config V4 ajouté
|
||||
workspace + graphes finaux verts
|
||||
```
|
||||
|
||||
## 5. `ROADMAP.md`
|
||||
|
||||
`0.2.10` passe à l'état réalisé. Helius LaserStream gRPC quitte la séquence numérotée et rejoint les TODO Yellowstone. La séquence active devient :
|
||||
|
||||
```text
|
||||
0.2.11 off-chain price transport
|
||||
0.2.12 Price Desk + intégration prix Wallet Desk
|
||||
0.2.13 interface/wire foundation
|
||||
0.2.14 program-api foundation
|
||||
```
|
||||
|
||||
## 6. Audit préparatoire de la future `0.2.11`
|
||||
|
||||
Avant de rédiger le prompt suivant, un audit externe rapide au 2026-08-25 a comparé plusieurs familles de sources :
|
||||
|
||||
```text
|
||||
CoinGecko agrégateur, REST Demo, multi quote USD/EUR
|
||||
Jupiter V3 prix Solana heuristique issu des swaps, USD seulement
|
||||
Pyth Hermes oracle, REST/SSE, publish_time/confidence, auth en transition immédiate
|
||||
Birdeye market data Solana, spot/batch/historique, API key
|
||||
DexScreener prix DEX par pair/pool, accès public courant
|
||||
```
|
||||
|
||||
Ce snapshot ne choisit pas le provider. Il démontre surtout que les sémantiques diffèrent et que `0.2.11-pre.001` doit auditer/choisir explicitement le contrat prix, le modèle numérique, la fraîcheur et le provider initial avant code lourd.
|
||||
|
||||
Pyth annonce un changement d'authentification le 2026-08-26 à 16:00 UTC ; le prompt exige donc un réaudit immédiat de Pyth à l'ouverture et interdit de figer le snapshot de `pre.005`.
|
||||
|
||||
## 7. Prompt `0.2.11`
|
||||
|
||||
Ajout de :
|
||||
|
||||
```text
|
||||
prompts/016-V0_2_11_START_PROMPT.md
|
||||
```
|
||||
|
||||
Le prompt ouvre `0.2.11 — Off-chain price transport` uniquement depuis `v0.2.10` et impose `pre.001 = lecture + audit actuel providers + matrice sémantique + numeric model + threat model + sizing + planification`.
|
||||
|
||||
Le scope initial reste volontairement borné :
|
||||
|
||||
```text
|
||||
ksp-offchain-transport-lib
|
||||
prix SOL/USD + SOL/EUR
|
||||
premier provider live-testable sans abonnement payant dédié
|
||||
Config -> Off-chain Transport
|
||||
pas de Price Desk
|
||||
pas de Wallet Desk
|
||||
pas d'OHLCV/historique/quotes/metadata/multi-provider complexe
|
||||
```
|
||||
|
||||
## 8. Fichiers modifiés/ajoutés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/016-V0_2_11_START_PROMPT.md
|
||||
deltas/0.2.10/pre.005.md
|
||||
```
|
||||
|
||||
Aucun autre fichier ne doit changer dans cette tranche.
|
||||
|
||||
## 9. Gate opérateur
|
||||
|
||||
Comme cette tranche ne modifie aucun code/runtime/config/schema :
|
||||
|
||||
```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.10
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke live ni `cargo tree` n'est à rejouer si le delta est appliqué exactement.
|
||||
|
||||
## 10. Suite
|
||||
|
||||
Si ce gate est vert, `0.2.10-rel.001` est la seule étape restante. Elle est limitée à la mécanique de publication stable : version Cargo `0.2.10`, delta `rel.001`, commit final et tag stable `v0.2.10`, sans rattrapage technique ou documentaire.
|
||||
197
deltas/0.2.10/rel.001.md
Normal file
197
deltas/0.2.10/rel.001.md
Normal file
@@ -0,0 +1,197 @@
|
||||
<!-- file: deltas/0.2.10/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.10-rel.001` — publication stable OrbitFlare Yellowstone gRPC
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Base directe attendue :
|
||||
|
||||
```text
|
||||
0.2.10-pre.005
|
||||
workspace.package.version = 0.2.10-pre.5
|
||||
```
|
||||
|
||||
Commit attendu pour cette livraison :
|
||||
|
||||
```text
|
||||
v0.2.10-rel.001
|
||||
```
|
||||
|
||||
Tag stable attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.10
|
||||
```
|
||||
|
||||
## 2. Responsabilité de `rel.001`
|
||||
|
||||
Cette livraison effectue uniquement la mécanique de publication stable définie par le cycle KSP.
|
||||
|
||||
Elle :
|
||||
|
||||
- passe `workspace.package.version` de `0.2.10-pre.5` à `0.2.10` ;
|
||||
- ajoute le présent delta `rel.001` ;
|
||||
- ne corrige ni code, ni test, ni config/schema, ni README/USAGE, ni plan/validation, ni règle, ni prompt, ni `CHANGELOG.md`, ni `ROADMAP.md`.
|
||||
|
||||
Tout défaut appartenant à un couloir antérieur doit renvoyer vers une prerelease appropriée ; `rel.001` n'est jamais une tranche de rattrapage.
|
||||
|
||||
## 3. Preuves techniques acquises avant publication
|
||||
|
||||
Le gate technique/live final `0.2.10-pre.003` a été validé le **25 août 2026** avec :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
KSP workspace Rust rule audit clean
|
||||
python3 scripts/audit_markdown_tables.py PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-config-lib PASS
|
||||
cargo test -p ksp-onchain-transport-lib PASS
|
||||
cargo test -p ksp-core-lib --test workspace_dependencies PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Les suites directement concernées restent notamment :
|
||||
|
||||
```text
|
||||
Config unit 114 passed
|
||||
Transport unit 383 passed
|
||||
Transport public API 49 passed
|
||||
Transport release completeness 43 passed
|
||||
Transport doctests 4 passed
|
||||
```
|
||||
|
||||
Le smoke live final OrbitFlare a également été rejoué en `pre.003` :
|
||||
|
||||
```text
|
||||
OrbitFlare Devnet Yellowstone
|
||||
x-token = License Key
|
||||
Subscribe -> Slot + standard server Ping
|
||||
1/1 PASS en 5.19 s
|
||||
```
|
||||
|
||||
Les graphes Cargo finaux ont été inspectés dans le même couloir. `pre.004` et `pre.005` n'ont ensuite modifié aucune source runtime, dépendance, config ou schema.
|
||||
|
||||
## 4. Version stable publiée
|
||||
|
||||
La version Cargo devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.10
|
||||
```
|
||||
|
||||
La release stable publiée est :
|
||||
|
||||
```text
|
||||
0.2.10 — OrbitFlare Yellowstone gRPC
|
||||
```
|
||||
|
||||
Les acquis fonctionnels et documentaires finalisés avant `rel.001` comprennent :
|
||||
|
||||
```text
|
||||
réutilisation stricte du moteur N1 Yellowstone gRPC existant
|
||||
réutilisation stricte du contrat N2 Yellowstone standard existant
|
||||
aucune modification provider du moteur gRPC
|
||||
profil Config V3 orbitflare_devnet
|
||||
endpoint Devnet http://devnet.rpc.orbitflare.com:10000
|
||||
authentification gRPC x-token via License Key secrète
|
||||
premier smoke sans metadata -> Unauthenticated, caractérisé puis corrigé
|
||||
live authentifié Subscribe -> Slot + standard Ping PASS
|
||||
aucun heartbeat provider supplémentaire
|
||||
aucun SDK OrbitFlare ajouté
|
||||
aucun Config V4
|
||||
```
|
||||
|
||||
La release confirme donc qu'OrbitFlare compose au-dessus de N1/N2 par configuration provider et metadata secrète, sans divergence protocolaire nécessitant une façade gRPC dédiée.
|
||||
|
||||
## 5. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.2.10/rel.001.md
|
||||
```
|
||||
|
||||
## 6. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
```
|
||||
|
||||
## 7. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 8. Validations de préparation du delta
|
||||
|
||||
Contrôles statiques de l'overlay :
|
||||
|
||||
```text
|
||||
Cargo.toml version 0.2.10
|
||||
payload rel.001 2 fichiers exactement
|
||||
aucun fichier de rattrapage présent
|
||||
```
|
||||
|
||||
Aucune nouvelle compilation n'est requise pour construire l'archive elle-même. Le gate stable final doit toutefois être exécuté après application du delta et avant le commit/tag.
|
||||
|
||||
## 9. Validation stable après application
|
||||
|
||||
Exécuter avant publication :
|
||||
|
||||
```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.10
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Le changement étant limité au signal de version Cargo et au présent delta :
|
||||
|
||||
- aucun smoke live OrbitFlare n'est à rejouer si l'overlay appliqué est exactement `0.2.10-rel.001` ;
|
||||
- aucun `cargo tree` n'est à rejouer ;
|
||||
- aucun smoke PublicNode n'est à rejouer.
|
||||
|
||||
## 10. Commit et tag stable
|
||||
|
||||
Après succès du gate stable :
|
||||
|
||||
```text
|
||||
commit : v0.2.10-rel.001
|
||||
tag : v0.2.10
|
||||
```
|
||||
|
||||
Aucun tag intermédiaire `rel.001` n'est requis.
|
||||
|
||||
Commandes Git typiques :
|
||||
|
||||
```bash
|
||||
git add Cargo.toml deltas/0.2.10/rel.001.md
|
||||
git commit -m "v0.2.10-rel.001"
|
||||
git tag v0.2.10
|
||||
git push
|
||||
git push origin v0.2.10
|
||||
```
|
||||
|
||||
## 11. Suite
|
||||
|
||||
Après publication du tag stable `v0.2.10`, ouvrir :
|
||||
|
||||
```text
|
||||
0.2.11-pre.001 — Off-chain price transport
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
prompts/016-V0_2_11_START_PROMPT.md
|
||||
```
|
||||
|
||||
`pre.001` reste une tranche d'audit actuel des providers, sémantiques de prix, modèle numérique, fraîcheur/provenance, threat model et sizing avant toute implémentation lourde.
|
||||
|
||||
Helius LaserStream gRPC reste reporté dans les TODO Yellowstone jusqu'à disponibilité d'un accès live pertinent ; il ne fait plus partie de la séquence numérotée active.
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 60 -->
|
||||
<!-- version: 61 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -24,7 +24,8 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
- [`013-V0_2_6_WALLET_DESK_PLAN.md`](013-V0_2_6_WALLET_DESK_PLAN.md) — plan historique clôturé de la release stable `0.2.6 — Wallet Desk`, ouvert par `pre.001`, étendu en `pre.015`–`pre.017` au wire binaire `.kspwallet` V2, aux APIs multi-version et à la migration V1 -> V2, puis fermé par `pre.018`/`fix.001` avec le runtime Tauri packagé et le build final vert avant publication `rel.001`.
|
||||
- [`014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md`](014-V0_2_7_ONCHAIN_WEBSOCKET_PLAN.md) — plan historique clôturé de la release stable `0.2.7 — WebSocket Solana standard`, ouvert par `pre.001`, exécuté jusqu’à `pre.014`, corrigé documentairement par `pre.014-fix.001` puis publié par `rel.001`; il conserve l’inventaire officiel 18 méthodes, le modèle session/subscription, le threat model, les preuves de compliance/smoke/dépendances et la préparation de `0.2.8`.
|
||||
- [`015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md`](015-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET_PLAN.md) — plan historique clôturé de la release stable `0.2.8 — Helius LaserStream WebSocket`, ouvert par `pre.001`, fermé techniquement/documentairement par `pre.011` puis publié par `rel.001`; il conserve la surface finale Helius `7 standard + transaction`, heartbeat/Config/secrets, l’historique des fixes heartbeat, la stratégie live architecture-safe, les graphes Cargo finaux et la préparation du prompt `0.2.9`.
|
||||
- [`016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md`](016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md) — plan actif de `0.2.9 — Yellowstone gRPC standard/provider-neutral`, ouvert par `pre.001`; il fixe la stratégie `yellowstone-grpc-proto + Tonic KSP`, la surface `Subscribe + 7 unary`, l’exclusion de `SubscribeDeshred`, Config V3, les règles replay/backpressure et les smokes gratuits PublicNode puis OrbitFlare.
|
||||
- [`016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md`](016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md) — plan historique clôturé de la release stable `0.2.9 — Yellowstone gRPC standard/provider-neutral`, publiée par `rel.001`; il fixe le moteur N1, le standard N2, Config V3, le replay prudent et la validation PublicNode Mainnet/Testnet.
|
||||
- [`017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md`](017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md) — plan actif de `0.2.10 — OrbitFlare Yellowstone gRPC`, ouvert par `pre.001`; il confirme le Devnet gRPC gratuit, rend N1/N2 immuables pour la release, classe auth/heartbeat/limits et dimensionne un chemin standard prioritaire sans code provider inutile.
|
||||
|
||||
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
|
||||
<!-- version: 88 -->
|
||||
<!-- version: 89 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -37,7 +37,7 @@ Séquence par défaut :
|
||||
0.1.4 ksp-app-config-desk
|
||||
```
|
||||
|
||||
`0.1.1`, `0.1.2`, `0.1.3`, `0.1.4` et `0.2.0` à `0.2.5` sont désormais des releases stables.
|
||||
`0.1.1`, `0.1.2`, `0.1.3`, `0.1.4` et `0.2.0` à `0.2.9` sont désormais des releases stables.
|
||||
|
||||
`0.1.4 — ksp-app-config-desk` établit le modèle de référence des futures applications Tauri KSP sans déplacer la logique Config dans l'application. Sa matrice finale a été validée avant `rel.001`, avec le build Tauri exécuté en dernière opération.
|
||||
|
||||
@@ -365,11 +365,10 @@ Par défaut :
|
||||
0.2.8 Helius LaserStream WebSocket
|
||||
0.2.9 Yellowstone gRPC engine + Solana standard + PublicNode
|
||||
0.2.10 OrbitFlare Yellowstone gRPC
|
||||
0.2.11 Helius LaserStream gRPC
|
||||
0.2.12 off-chain price transport
|
||||
0.2.13 price visualization desk + intégration prix dans Wallet Desk
|
||||
0.2.14 interface/wire foundation
|
||||
0.2.15 program-api foundation
|
||||
0.2.11 off-chain price transport
|
||||
0.2.12 price visualization desk + intégration prix dans Wallet Desk
|
||||
0.2.13 interface/wire foundation
|
||||
0.2.14 program-api foundation
|
||||
```
|
||||
|
||||
`0.2.1-pre.001` a appliqué le gate de sizing et refusé le scope HTTP monolithique initial : l'inventaire du 2026-08-17 contient 52 méthodes courantes et 14 méthodes Deprecated historiques. Ce premier delta avait réparti la couverture typée sur `0.2.1`–`0.2.6`. `0.2.1-pre.001-fix.001` recalibre ensuite les 48 méthodes restantes sur trois releases complémentaires `0.2.2`–`0.2.4`, soit trois sessions nominales au maximum si chaque release utilise sa session complète. Si une release se clôt plus vite que prévu, la même session peut enchaîner la suivante après clôture complète de la précédente et nouveau gate de sizing positif. Un Wallet Desk utile doit pouvoir lire le solde du wallet : `getBalance` fait donc partie des quatre canaris de la foundation `0.2.1`, avant Wallet. Les transports live arrivent ensuite ; Interface/Program restent préparés avant les couches de données décodées.
|
||||
@@ -475,26 +474,24 @@ Le réaudit final Helius du 23 août 2026 retient `helius_laserstream` comme pro
|
||||
|
||||
### `0.2.9` — Yellowstone gRPC engine + standard Solana + PublicNode
|
||||
|
||||
Mission : construire un moteur client Yellowstone gRPC partagé dans `ksp-onchain-transport-lib`, exposer la façade Solana Yellowstone standard puis valider une première intégration concrète PublicNode Mainnet/Testnet sans recopier le moteur.
|
||||
Mission accomplie : `0.2.9-rel.001` publie le moteur Yellowstone N1, le standard Solana N2, Config Transport V3 et la première intégration provider-neutral PublicNode. Les smokes Mainnet et Testnet ont validé `Subscribe -> Slot` avec metadata `x-token` secrète sans façade PublicNode spécifique.
|
||||
|
||||
Le `pre.001` est un gate de sizing : chaque prerelease vise 15–20 minutes de travail effectif et la release complète doit rester clôturable dans une seule session. Si cette clôture devient incertaine, `0.2.9` est scindée avant implémentation lourde supplémentaire.
|
||||
Cette release devient la fondation stable des providers suivants. Le moteur physique et la surface standard ne sont pas redéfinis par une release provider : une divergence provider se compose au-dessus, ou devient un blocker architectural explicite si elle ne peut pas être composée proprement.
|
||||
|
||||
La séparation cible reprend le modèle WebSocket : moteur physique partagé -> protocole standard -> adaptations provider. PublicNode est la première intégration provider. Le moteur n'est jamais dupliqué ; le standard n'est réutilisé que pour les capacités réellement compatibles. Une couche provider peut restreindre le standard ou porter des extensions wire/lifecycle explicites.
|
||||
### `0.2.10` — OrbitFlare Yellowstone gRPC
|
||||
|
||||
### `0.2.10`–`0.2.11` — providers Yellowstone retenus
|
||||
Mission active : obtenir en priorité un provider Yellowstone gratuit sur **Devnet** pour les tests futurs, puis matérialiser uniquement les divergences OrbitFlare réellement prouvées. Le plan Free actuel annonce `gRPC Devnet only` et le CLI documente `http://devnet.rpc.orbitflare.com:10000`.
|
||||
|
||||
```text
|
||||
0.2.10 OrbitFlare Yellowstone gRPC
|
||||
0.2.11 Helius LaserStream gRPC
|
||||
```
|
||||
`0.2.10-pre.001` fixe un invariant renforcé : N1 gRPC et N2 Yellowstone restent immuables. L'auth Customer API, le token gRPC éventuel, le heartbeat, les quotas et les capabilities sont classifiés séparément. Le premier smoke doit tenter le standard N2 sans secret sur Devnet, observer un `Slot` et caractériser le `Ping` serveur Yellowstone avant toute façade/policy provider.
|
||||
|
||||
Chaque release réutilise le moteur de `0.2.9`, audite son delta avec Yellowstone upstream et matérialise uniquement les restrictions/extensions réelles du provider.
|
||||
Le plan actif est [`017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md`](017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md) et la matrice active [`../validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md`](../validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md).
|
||||
|
||||
### TODO/IDEAS — providers Yellowstone en attente
|
||||
|
||||
Aucune release n'est réservée pour :
|
||||
|
||||
```text
|
||||
TODO Helius LaserStream gRPC — réauditer lorsque l'accès live gRPC est disponible
|
||||
TODO eRPC
|
||||
TODO Triton
|
||||
TODO Alchemy
|
||||
@@ -507,23 +504,25 @@ IDEAS NodeFlare
|
||||
IDEAS autres providers à réauditer
|
||||
```
|
||||
|
||||
Helius LaserStream gRPC est explicitement reporté : l'audit 2026-08-25 indique une compatibilité wire Yellowstone élevée et une intégration KSP probablement légère au-dessus de N1/N2, mais aucun accès live Helius gRPC n'est actuellement disponible sans plan payant. Il ne reçoit donc plus de numéro de release tant que l'auth, les endpoints, le Subscribe, le Ping, le replay/from_slot et les erreurs provider ne peuvent pas être validés live. Les extensions Helius non standard, notamment les preprocessed transactions, restent un sujet provider séparé.
|
||||
|
||||
Ces providers ne déplacent pas la séquence active et ne reçoivent ni façade, ni Config profile, ni smoke tant qu'une décision explicite d'implémentation n'est pas prise.
|
||||
|
||||
### `0.2.12` / `0.2.13` — Off-chain price + app
|
||||
### `0.2.11` / `0.2.12` — Off-chain price + app
|
||||
|
||||
`0.2.12` introduit `ksp-offchain-transport-lib` avec au minimum SOL/USD et SOL/EUR via une abstraction indépendante du premier provider.
|
||||
`0.2.11` introduit `ksp-offchain-transport-lib` avec au minimum SOL/USD et SOL/EUR via une abstraction indépendante du premier provider.
|
||||
|
||||
`0.2.13` ajoute une petite application desk de visualisation/validation. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé.
|
||||
`0.2.12` ajoute une petite application desk de visualisation/validation. Après stabilisation de cette application spécialisée, la même release doit intégrer la capacité de prix offchain dans `ksp-app-wallet-desk` sans dupliquer la récupération/normalisation appartenant au composant spécialisé.
|
||||
|
||||
Metadata HTTP/IPFS/Arweave viendra au premier besoin Metadata réel.
|
||||
|
||||
### `0.2.14` — Interface foundation
|
||||
### `0.2.13` — Interface foundation
|
||||
|
||||
`ksp-interface-lib` devient la façade wire officielle et expose une API publique wire utilisable par les implementations officielles et externes.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue pour l'instant.
|
||||
|
||||
### `0.2.15` — Program API foundation
|
||||
### `0.2.14` — Program API foundation
|
||||
|
||||
Introduire `ksp-program-api`, sans suffixe `-lib`, comme contrat d'extension Program.
|
||||
|
||||
|
||||
659
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
Normal file
659
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
Normal file
@@ -0,0 +1,659 @@
|
||||
<!-- file: docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Plan `0.2.10` — OrbitFlare Yellowstone gRPC
|
||||
|
||||
**Statut courant : le gate technique/live final `0.2.10-pre.003` est vert. OrbitFlare Devnet est validé avec la License Key `ORBIT-*` portée par la metadata secrète `x-token` ; le smoke final observe un Slot non nul puis le `SubscribeUpdate::Ping` Yellowstone standard et ferme proprement la session. N1 et N2 restent inchangés, aucune façade provider ni heartbeat N3 n’est nécessaire. `0.2.10-pre.004` est exclusivement la réconciliation documentaire finale.**
|
||||
|
||||
## 1. Base et autorité
|
||||
|
||||
Base stable autoritaire :
|
||||
|
||||
```text
|
||||
v0.2.9
|
||||
```
|
||||
|
||||
État vérifié dans l'archive Gitea fournie :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.9
|
||||
deltas/0.2.9/rel.001.md présent
|
||||
prompts/015-V0_2_10_START_PROMPT.md présent
|
||||
plan 016 Yellowstone présent
|
||||
validation 012 Yellowstone présente
|
||||
Config Transport V3 présente
|
||||
PublicNode Mainnet + Testnet présents
|
||||
```
|
||||
|
||||
Ordre d'autorité pendant `0.2.10` :
|
||||
|
||||
```text
|
||||
règles normatives KSP
|
||||
archive stable v0.2.9 et code réellement livré
|
||||
décisions du présent plan et validation 013
|
||||
deltas immuables de 0.2.10
|
||||
prompt 015 pour les contraintes non supersédées
|
||||
sources provider/upstream actuelles pour les faits externes
|
||||
```
|
||||
|
||||
Le présent gate supersède une hypothèse du prompt : une divergence lifecycle OrbitFlare ne doit jamais être résolue par modification du moteur N1. Si elle ne peut pas être proprement composée au-dessus du moteur, elle devient un blocker/split explicite.
|
||||
|
||||
## 2. Mission opérationnelle réelle
|
||||
|
||||
L'objectif prioritaire de `0.2.10` est de disposer d'au moins un provider Yellowstone **gratuit et durable sur Solana Devnet** pour les validations futures de KSP.
|
||||
|
||||
PublicNode/Allnodes a déjà validé le standard KSP sur :
|
||||
|
||||
```text
|
||||
Mainnet
|
||||
Testnet
|
||||
```
|
||||
|
||||
OrbitFlare complète cette couverture avec :
|
||||
|
||||
```text
|
||||
Devnet
|
||||
```
|
||||
|
||||
Le pricing OrbitFlare observé le 2026-08-25 confirme :
|
||||
|
||||
```text
|
||||
plan Free 0 USD/mois
|
||||
RPC 10 RPS
|
||||
transactions 1 TPS
|
||||
gRPC Devnet only
|
||||
credit limits unlimited
|
||||
carte bancaire non requise selon la page d'accueil
|
||||
```
|
||||
|
||||
Sources principales :
|
||||
|
||||
```text
|
||||
https://orbitflare.com/pricing
|
||||
https://orbitflare.com/products/rpc-nodes
|
||||
https://docs.orbitflare.com/cli
|
||||
```
|
||||
|
||||
Mainnet OrbitFlare payant n'est pas un gate de cette release. Le résultat minimal utile est un smoke Yellowstone standard KSP sur l'endpoint Devnet gratuit.
|
||||
|
||||
## 3. Invariant architectural renforcé
|
||||
|
||||
### 3.1 N1 gRPC immuable
|
||||
|
||||
Les modules qui constituent le moteur Yellowstone livré par `0.2.9` ne doivent pas être modifiés pour OrbitFlare :
|
||||
|
||||
```text
|
||||
src/grpc_settings.rs
|
||||
src/grpc_channel.rs
|
||||
src/grpc_unary.rs
|
||||
src/grpc_subscribe.rs
|
||||
src/grpc_stream.rs
|
||||
```
|
||||
|
||||
Le même principe vaut durablement pour les moteurs physiques :
|
||||
|
||||
```text
|
||||
moteur HTTP provider-neutral
|
||||
moteur WebSocket provider-neutral
|
||||
moteur gRPC provider-neutral
|
||||
```
|
||||
|
||||
Une release provider peut modifier :
|
||||
|
||||
```text
|
||||
provider facade
|
||||
provider policy
|
||||
provider capability projection
|
||||
Config provider profile
|
||||
provider smoke/compliance
|
||||
provider-specific tests
|
||||
```
|
||||
|
||||
Elle ne modifie pas le moteur pour faire rentrer une différence fournisseur.
|
||||
|
||||
### 3.2 N2 standard Yellowstone immuable
|
||||
|
||||
La surface Solana Yellowstone standard publiée par `0.2.9` reste la seule surface wire de référence :
|
||||
|
||||
```text
|
||||
Subscribe
|
||||
SubscribeReplayInfo
|
||||
Ping
|
||||
GetLatestBlockhash
|
||||
GetBlockHeight
|
||||
GetSlot
|
||||
IsBlockhashValid
|
||||
GetVersion
|
||||
|
||||
accounts
|
||||
slots
|
||||
transactions
|
||||
transactions_status
|
||||
blocks
|
||||
blocks_meta
|
||||
entry
|
||||
commitment
|
||||
accounts_data_slice
|
||||
ping
|
||||
from_slot
|
||||
|
||||
9 variantes SubscribeUpdate
|
||||
```
|
||||
|
||||
OrbitFlare ne redéfinit aucun DTO, filtre, unary, request ou update standard.
|
||||
|
||||
### 3.3 N3 provider uniquement si divergence démontrée
|
||||
|
||||
Architecture cible :
|
||||
|
||||
```text
|
||||
OrbitFlare N3
|
||||
-> standard Yellowstone N2 inchangé
|
||||
-> moteur gRPC N1 inchangé
|
||||
```
|
||||
|
||||
Une façade OrbitFlare publique n'est créée que si un consumer KSP doit réellement voir une restriction ou une extension provider. Un simple endpoint, un `provider = orbitflare`, une policy Config ou un smoke ne suffisent pas à justifier une nouvelle API publique.
|
||||
|
||||
## 4. Baseline opérateur `v0.2.9`
|
||||
|
||||
Preuves fournies le 2026-08-25 :
|
||||
|
||||
| Gate | Résultat |
|
||||
|-------------------------------------------|------------------------------------------|
|
||||
| `cargo fmt --all` | PASS |
|
||||
| audit Rust workspace | PASS, 0 candidate export |
|
||||
| audit Markdown tables | PASS, 97 tables et 233 files sur `pre.1` |
|
||||
| `cargo check --workspace` | PASS |
|
||||
| `cargo clippy --workspace --all-targets` | PASS |
|
||||
| `cargo test --workspace` | PASS |
|
||||
| Transport unit | 383 sur 383 PASS |
|
||||
| Transport public API | 49 sur 49 PASS |
|
||||
| Transport release completeness | 43 sur 43 PASS |
|
||||
| Config unit | 113 sur 113 PASS |
|
||||
| PublicNode Yellowstone live | ignored opt-in comme attendu |
|
||||
| `cargo tree --duplicates` Transport | fourni et inspecté |
|
||||
| `cargo tree -p ksp-onchain-transport-lib` | fourni sur `0.2.10-pre.1` |
|
||||
|
||||
Versions visibles dans le graphe fourni :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.0
|
||||
tonic 0.14.6
|
||||
tonic-prost 0.14.6
|
||||
prost 0.14.4
|
||||
tokio 1.53.1
|
||||
http 1.5.0
|
||||
reqwest 0.13.4
|
||||
```
|
||||
|
||||
Aucune seconde génération Tonic/Prost/Yellowstone incompatible n'est observée. Les doublons restants ne justifient aucun changement pour `0.2.10`.
|
||||
|
||||
## 5. Réaudit Yellowstone upstream du 2026-08-25
|
||||
|
||||
État courant observé :
|
||||
|
||||
```text
|
||||
release GitHub courante v15.1.2+solana.4.2.0
|
||||
publication 2026-08-18
|
||||
yellowstone-grpc-proto publié 12.6.0
|
||||
stack proto prost 0.14 / tonic 0.14
|
||||
```
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://github.com/rpcpool/yellowstone-grpc/releases
|
||||
https://github.com/rpcpool/yellowstone-grpc/blob/master/README.md
|
||||
https://github.com/rpcpool/yellowstone-grpc/blob/master/yellowstone-grpc-proto/proto/geyser.proto
|
||||
https://crates.io/crates/yellowstone-grpc-proto
|
||||
```
|
||||
|
||||
Aucune évolution matérielle n'impose de changer le contrat KSP de `0.2.9`. Il n'y a donc aucun bump de dependency Yellowstone/Tonic/Prost prévu dans `0.2.10`.
|
||||
|
||||
## 6. Endpoint et network OrbitFlare
|
||||
|
||||
Les sources actuelles distinguent plusieurs formes de service.
|
||||
|
||||
| Élément | Observation actuelle | Décision KSP |
|
||||
|------------------------|-----------------------------------------------|---------------------------------------------|
|
||||
| Devnet gRPC | `http://devnet.rpc.orbitflare.com:10000` | premier endpoint live à tester |
|
||||
| endpoint régional | `http://{region}.rpc.orbitflare.com:10000` | descriptif, pas de fallback inventé |
|
||||
| endpoint licence/dédié | `https://your-endpoint.grpc.orbitflare.com` | utiliser uniquement si Dashboard le fournit |
|
||||
| `http` | HTTP/2 plaintext | ne jamais présenter comme TLS |
|
||||
| `https` | HTTP/2 TLS | conserver tel quel |
|
||||
| Mainnet | disponible selon plan/service | non requis pour le gate gratuit |
|
||||
| Devnet | explicitement documenté | **IN** |
|
||||
| Testnet | CLI accepte le label mais endpoint non prouvé | non requis, ne rien inventer |
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://docs.orbitflare.com/cli
|
||||
https://docs.orbitflare.com/sdk/go-grpc
|
||||
https://docs.orbitflare.com/data-streaming/yellowstone-quickstart
|
||||
```
|
||||
|
||||
L'endpoint Dashboard opérateur reste autoritaire lorsqu'il existe. KSP ne transforme jamais automatiquement une URL `http` en `https`, ne change pas de région et ne construit pas un hostname provider non documenté.
|
||||
|
||||
## 7. Auth OrbitFlare : classification live corrigée
|
||||
|
||||
Le live `pre.002` et les sources OrbitFlare permettent désormais de séparer les credentials sans supposition.
|
||||
|
||||
| Credential ou mécanisme | Usage observé | Classification après `pre.002` |
|
||||
|-------------------------|---------------------------|------------------------------------------------------|
|
||||
| `X-ORBIT-KEY` | Customer API | control-plane, interdit sur Yellowstone |
|
||||
| Bearer Device Flow | Customer API v2 | control-plane |
|
||||
| `api_key` RPC | Solana HTTP RPC | data-plane HTTP |
|
||||
| License Key `ORBIT-*` | produit Solana Free | data-plane provider |
|
||||
| metadata `x-token` | Yellowstone gRPC | transport prouvé de la License Key |
|
||||
| aucune metadata | premier smoke KSP | rejetée `Unauthenticated` au `SubscribeOpen` |
|
||||
| IP whitelist | autre mode d’auth produit | non retenu pour le service opérateur en API Key Mode |
|
||||
|
||||
La référence Yellowstone OrbitFlare donne explicitement le modèle suivant :
|
||||
|
||||
```text
|
||||
ORBITFLARE_LICENSE_KEY
|
||||
-> metadata gRPC x-token
|
||||
-> Yellowstone
|
||||
```
|
||||
|
||||
Le Dashboard opérateur confirme parallèlement que le produit `Solana Free` est en `API Key Mode Active`, donc utilisable depuis toute IP avec la License Key. Le `X-ORBIT-KEY` et le Bearer issus du Device Flow restent réservés au Customer API.
|
||||
|
||||
Le CLI OrbitFlare courant ne constitue pas un canari gRPC d’auth fiable : son `ping` ouvre le canal sans injecter la License Key et reçoit `invalid x-token: api key not found`. Ce défaut du CLI ne modifie pas le contrat provider documenté.
|
||||
|
||||
Décision :
|
||||
|
||||
```text
|
||||
ne jamais versionner la License Key réelle
|
||||
ne jamais injecter X-ORBIT-KEY dans Yellowstone
|
||||
représenter la License Key par secret_metadata x-token dans Config V3
|
||||
faire lire le secret du smoke par stdin, jamais par argument CLI
|
||||
ne modifier ni N1 ni N2 pour cette auth provider
|
||||
```
|
||||
|
||||
## 8. Heartbeat : réconciliation KSP / Yellowstone / OrbitFlare
|
||||
|
||||
### 8.1 Faits upstream
|
||||
|
||||
Yellowstone upstream documente que :
|
||||
|
||||
```text
|
||||
les load balancers peuvent fermer un stream si le client reste silencieux
|
||||
le serveur Yellowstone envoie un SubscribeUpdate::Ping périodique
|
||||
le client peut répondre par un SubscribeRequest::Ping
|
||||
le serveur répond alors par SubscribeUpdate::Pong
|
||||
```
|
||||
|
||||
Source :
|
||||
|
||||
```text
|
||||
https://github.com/rpcpool/yellowstone-grpc/blob/master/README.md
|
||||
```
|
||||
|
||||
### 8.2 Faits OrbitFlare
|
||||
|
||||
OrbitFlare documente :
|
||||
|
||||
```text
|
||||
idle timeout partagé environ 10 minutes
|
||||
client ping recommandé toutes les 30 secondes
|
||||
produit gRPC recommandation 15 à 30 secondes
|
||||
SDK Go PingInterval default 10 secondes
|
||||
SDK Go MaxMissedPongs 3
|
||||
```
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://docs.orbitflare.com/data-streaming/yellowstone
|
||||
https://docs.orbitflare.com/authentication
|
||||
https://docs.orbitflare.com/sdk/go-grpc
|
||||
https://orbitflare.com/products/solana-grpc
|
||||
```
|
||||
|
||||
### 8.3 Couverture KSP déjà présente
|
||||
|
||||
Le moteur `0.2.9` possède déjà exactement la réponse standard :
|
||||
|
||||
```text
|
||||
SubscribeUpdate::Ping reçu
|
||||
-> send_automatic_ping(...)
|
||||
-> SubscribeRequest::Ping envoyé sur le stream existant
|
||||
-> request de subscription mémorisée inchangée
|
||||
```
|
||||
|
||||
Cette propriété est testée déterministiquement par le moteur N1.
|
||||
|
||||
### 8.4 Décision `pre.001`
|
||||
|
||||
La décision initiale de ne pas modifier le moteur est confirmée par le live final.
|
||||
|
||||
Le smoke authentifié `pre.002-fix.001`, puis son rerun dans `pre.003`, ont observé le `SubscribeUpdate::Ping` standard sur OrbitFlare Devnet :
|
||||
|
||||
```text
|
||||
OrbitFlare server Ping live
|
||||
+
|
||||
KSP N1 automatic Ping reply deterministic test
|
||||
=
|
||||
activité bidirectionnelle standard suffisante sans code provider supplémentaire
|
||||
```
|
||||
|
||||
Résultat final :
|
||||
|
||||
```text
|
||||
heartbeat OrbitFlare N3 non nécessaire
|
||||
façade provider non nécessaire
|
||||
YellowstoneGrpcSessionSettings inchangé
|
||||
grpc_stream.rs inchangé
|
||||
latest_request reconnect sémantique N1 préservée
|
||||
```
|
||||
|
||||
Il reste interdit d'ajouter un timer dans `grpc_stream.rs` ou `YellowstoneGrpcSessionSettings` pour OrbitFlare. La recommandation provider d’un ping client périodique ne devient pas une policy globale tant que le chemin standard serveur Ping -> réponse automatique N1 satisfait le service live.
|
||||
|
||||
Le point de sécurité initial reste durable : envoyer naïvement une requête `ping` seule via la mutation publique remplacerait la dernière subscription mémorisée pour reconnect. Si un futur provider exige un heartbeat proactif indépendant, cette policy doit être composée au-dessus de N1 sans corrompre cette sémantique.
|
||||
|
||||
## 9. Capabilities OrbitFlare
|
||||
|
||||
### 9.1 Streaming documenté
|
||||
|
||||
OrbitFlare documente actuellement :
|
||||
|
||||
```text
|
||||
accounts
|
||||
transactions
|
||||
slots
|
||||
blocks
|
||||
blocks_meta
|
||||
entry
|
||||
commitment
|
||||
accounts_data_slice
|
||||
ping
|
||||
```
|
||||
|
||||
Le CLI/SDK montre également les filtres account/transaction/slot/block standard nécessaires aux canaris principaux.
|
||||
|
||||
### 9.2 Surface non encore prouvée provider
|
||||
|
||||
Ces capacités existent dans N2 KSP mais n'ont pas été exhaustivement sondées sur le plan OrbitFlare Free pendant `0.2.10` :
|
||||
|
||||
```text
|
||||
SubscribeReplayInfo
|
||||
Ping unary
|
||||
GetLatestBlockhash
|
||||
GetBlockHeight
|
||||
GetSlot
|
||||
IsBlockhashValid
|
||||
GetVersion
|
||||
from_slot et retention réelle
|
||||
transactions_status complet
|
||||
champs récents compressed/cuckoo/token expansion selon endpoint déployé
|
||||
```
|
||||
|
||||
La clôture de `0.2.10` ne transforme pas l'absence de probe en absence de support. Le live final requis portait sur le chemin opérationnel utile à la release : authentification, standard Subscribe, Slot, Ping serveur et close borné.
|
||||
|
||||
Classification durable :
|
||||
|
||||
```text
|
||||
standard KSP disponible oui dans N2
|
||||
provider support live prouvé Subscribe slots + commitment + Ping
|
||||
provider entitlement éventuel provider-owned
|
||||
reste unknown / non exhaustivement testé
|
||||
```
|
||||
|
||||
Aucune capacité N2 n'est supprimée du standard global à cause d'une restriction ou d'un inconnu OrbitFlare.
|
||||
|
||||
## 10. Limits et quotas utiles
|
||||
|
||||
La documentation actuelle des services partagés indique :
|
||||
|
||||
| Limite | Valeur observée | Traitement KSP |
|
||||
|-----------------------------|------------------------------------------|---------------------------------------------|
|
||||
| connexions gRPC simultanées | 50 par IP | information provider, pas borne N1 |
|
||||
| portée du cap | globale par IP et régions gRPC partagées | éviter les reconnect storms |
|
||||
| subscriptions par connexion | unlimited | ne pas convertir en garantie universelle |
|
||||
| idle timeout | environ 10 minutes | chemin Ping standard validé live |
|
||||
| dépassement | gRPC `RESOURCE_EXHAUSTED` | status distant safe existant |
|
||||
| reconnect conseillé | exponential backoff | KSP N1 possède déjà un budget/backoff borné |
|
||||
|
||||
Ces valeurs commerciales/opérationnelles ne deviennent pas des constantes du standard KSP.
|
||||
|
||||
## 11. Config V3
|
||||
|
||||
Le schéma V3 existant représente directement le contrat live corrigé :
|
||||
|
||||
```text
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
protocol = solana_yellowstone
|
||||
url = http://devnet.rpc.orbitflare.com:10000
|
||||
metadata = []
|
||||
secret_metadata = x-token <- ${KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN}
|
||||
```
|
||||
|
||||
La variable porte la License Key `ORBIT-*` du produit Solana Free. Elle ne porte jamais `X-ORBIT-KEY`.
|
||||
|
||||
Décision :
|
||||
|
||||
```text
|
||||
pas de format_version 4
|
||||
pas de champ region si l’URL suffit
|
||||
pas de heartbeat dans grpc_defaults
|
||||
secret provider géré par Config V3 existante
|
||||
redaction KSP obligatoire dans safe/debug projections
|
||||
```
|
||||
|
||||
Le profil `orbitflare_devnet` conserve les companions HTTP/WS Solana Devnet standards et ajoute exactement un endpoint gRPC authentifié par secret metadata `x-token`.
|
||||
|
||||
## 12. Stratégie live Devnet
|
||||
|
||||
### 12.1 Résultat du premier canari `pre.002`
|
||||
|
||||
Le smoke initial utilisait le standard N2 directement, sans Config et sans metadata. Le canal physique a atteint le service OrbitFlare, puis l’ouverture du Subscribe a retourné :
|
||||
|
||||
```text
|
||||
grpc_operation = SubscribeOpen
|
||||
grpc_status = Unauthenticated
|
||||
grpc_code = The request does not have valid authentication credentials
|
||||
```
|
||||
|
||||
Cette preuve ferme l’hypothèse « Devnet Free sans metadata ».
|
||||
|
||||
### 12.2 Canari corrigé `pre.002-fix.001`
|
||||
|
||||
Le même test reste provider-neutral et ne dépend toujours pas de Config. Il lit une seule License Key sur stdin puis construit la metadata secrète standard :
|
||||
|
||||
```text
|
||||
endpoint = http://devnet.rpc.orbitflare.com:10000
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
protocol = solana_yellowstone
|
||||
auth = x-token <- License Key lue sur stdin
|
||||
request = Subscribe slots à commitment confirmed
|
||||
preuve = au moins un Slot non nul + SubscribeUpdate::Ping
|
||||
close = borné
|
||||
```
|
||||
|
||||
La valeur secrète n'apparaît ni dans Debug ni dans la ligne de commande.
|
||||
|
||||
Résultats opérateur :
|
||||
|
||||
```text
|
||||
pre.002-fix.001 Subscribe -> Slot + Ping PASS en 5.10 s
|
||||
pre.003 final Subscribe -> Slot + Ping PASS en 5.19 s
|
||||
```
|
||||
|
||||
Le second passage ferme le gate live sur la version `0.2.10-pre.3` utilisée pour la clôture technique.
|
||||
|
||||
### 12.3 Preuve heartbeat
|
||||
|
||||
Le `SubscribeUpdate::Ping` standard est observé live sur OrbitFlare Devnet avec l'auth correcte.
|
||||
|
||||
La combinaison suivante est donc prouvée :
|
||||
|
||||
```text
|
||||
Subscribe authentifié
|
||||
-> Slot non nul
|
||||
-> SubscribeUpdate::Ping serveur
|
||||
-> chemin de réponse automatique N1 déjà couvert déterministiquement
|
||||
-> close borné
|
||||
```
|
||||
|
||||
Verdict final : aucune divergence heartbeat OrbitFlare ne justifie une façade ou une policy provider. Le moteur gRPC et le standard Yellowstone restent inchangés.
|
||||
|
||||
### 12.4 Unary et replay
|
||||
|
||||
Les sept unary N2, `SubscribeReplayInfo` et la retention `from_slot` n'ont pas été rendus obligatoires pour le gate OrbitFlare Free.
|
||||
|
||||
Cette décision évite de confondre :
|
||||
|
||||
```text
|
||||
complétude du standard KSP N2
|
||||
support/entitlement d'un provider particulier
|
||||
preuve minimale nécessaire à la mission Devnet de 0.2.10
|
||||
```
|
||||
|
||||
Le moteur N1 reste capable d'utiliser `SubscribeReplayInfo` quand il est disponible et tolère son indisponibilité pendant reconnect en poursuivant avec le `from_slot` conservateur demandé. Aucun comportement provider n'est introduit pour combler un inconnu de service.
|
||||
|
||||
## 13. Threat model recalibré
|
||||
|
||||
Le gate retient :
|
||||
|
||||
```text
|
||||
Customer API key injectée sur le mauvais plan
|
||||
gRPC token confondu avec X-ORBIT-KEY
|
||||
secret metadata leak
|
||||
endpoint Dashboard sensible
|
||||
plaintext http présenté comme TLS
|
||||
IP/network entitlement mal classifié
|
||||
heartbeat ajouté au moteur global par erreur
|
||||
ping provider écrasant le last accepted full request
|
||||
ping flood
|
||||
missed pong surinterprété
|
||||
RESOURCE_EXHAUSTED et reconnect storm
|
||||
50 connections par IP consommées par des smokes mal fermés
|
||||
region failover changeant de node/fork
|
||||
from_slot hors retention
|
||||
provider unary unavailable
|
||||
remote Status arbitraire
|
||||
SDK OrbitFlare introduit sans nécessité
|
||||
```
|
||||
|
||||
## 14. Surface de code autorisée et interdite
|
||||
|
||||
### 14.1 Interdit par défaut
|
||||
|
||||
```text
|
||||
modification grpc_stream.rs
|
||||
modification grpc_channel.rs pour une policy OrbitFlare
|
||||
modification grpc_settings.rs pour un heartbeat OrbitFlare
|
||||
modification des DTOs grpc_subscribe.rs
|
||||
second raw Tonic client
|
||||
orbitflare-sdk-rs dependency
|
||||
provider-specific proto
|
||||
Transport -> Config/env
|
||||
```
|
||||
|
||||
### 14.2 Autorisé si nécessaire
|
||||
|
||||
```text
|
||||
profil Config V3 orbitflare_devnet
|
||||
smoke provider utilisant les APIs N2 existantes
|
||||
provider capability descriptor sans wire nouveau
|
||||
petite façade OrbitFlare au-dessus de N2 seulement si divergence live prouvée
|
||||
provider-specific tests/compliance
|
||||
README/USAGE dans la tranche documentaire finale
|
||||
```
|
||||
|
||||
## 15. Forecast recalibré
|
||||
|
||||
Le chemin effectif de `0.2.10` est désormais figé :
|
||||
|
||||
```text
|
||||
pre.001 audit actuel + architecture immuable N1/N2 + auth/endpoints + Free Devnet + heartbeat + sizing
|
||||
pre.002 profil Config V3 OrbitFlare Devnet + smoke de caractérisation sans metadata
|
||||
pre.002-fix.001 auth corrigée : License Key -> secret x-token ; live Subscribe -> Slot + Ping PASS
|
||||
pre.003 gate technique/live final ; workspace + graphes + rerun OrbitFlare PASS
|
||||
pre.004 réconciliation documentaire finale
|
||||
pre.005 publication minimale après décision explicite sur la release suivante
|
||||
rel.001 publication stable stricte
|
||||
```
|
||||
|
||||
La branche de divergence heartbeat n'a pas été déclenchée. Aucun couloir supplémentaire n'est requis.
|
||||
|
||||
Le numéro n'est jamais le critère de clôture ; l'ordre technique, documentaire puis publication reste obligatoire.
|
||||
|
||||
## 16. Critères de split
|
||||
|
||||
Les critères de split définis pendant l'audit étaient :
|
||||
|
||||
```text
|
||||
OrbitFlare n'émet pas le Ping standard et exige un Ping client proactif
|
||||
l’auth x-token fonctionne mais révèle une exigence provider supplémentaire non composable au-dessus de N1/N2
|
||||
le service requiert un mécanisme TLS/channel absent du moteur stable
|
||||
un method/filter standard est remplacé par une extension wire OrbitFlare
|
||||
le replay/from_slot exige une policy provider visible au consumer
|
||||
un failover provider impose une sémantique que N1 ne peut pas composer sans modification
|
||||
```
|
||||
|
||||
**Aucun de ces critères n'a été déclenché par le gate live final.**
|
||||
|
||||
Le principe reste durable pour les providers futurs : si une divergence ne peut pas être composée proprement au-dessus de N1/N2, ne pas modifier le moteur pour le provider ; qualifier le blocker et replanifier l'architecture.
|
||||
|
||||
## 17. Critères de clôture
|
||||
|
||||
État à l'entrée de `pre.004` :
|
||||
|
||||
```text
|
||||
Devnet OrbitFlare Free atteint par KSP PASS
|
||||
N1 gRPC inchangé PASS
|
||||
N2 Yellowstone inchangé PASS
|
||||
aucun SDK OrbitFlare runtime PASS
|
||||
provider/auth correctement classifiés PASS
|
||||
aucune Customer API key sur le data-plane Yellowstone PASS
|
||||
heartbeat live classifié PASS
|
||||
Config V3 cohérente sans nouveau format PASS
|
||||
smoke provider architecture-safe PASS
|
||||
PublicNode non régressé déterministiquement PASS
|
||||
Yellowstone standard non régressé PASS
|
||||
HTTP 52+14 non régressé PASS
|
||||
WebSocket standard 18/18 non régressé PASS
|
||||
Helius WebSocket non régressé PASS
|
||||
workspace complet vert PASS
|
||||
graphes Cargo inspectés PASS
|
||||
réconciliation documentaire séparée EN COURS pre.004
|
||||
publication minimale séparée À FAIRE pre.005
|
||||
```
|
||||
|
||||
Le gate technique est donc fermé. La stabilité `0.2.10` reste conditionnée à la validation documentaire `pre.004`, au couloir publication-minimal `pre.005`, puis à `rel.001`.
|
||||
|
||||
## 18. Release suivante
|
||||
|
||||
La décision préalable à `pre.005` est désormais prise. L'ancien forecast :
|
||||
|
||||
```text
|
||||
0.2.11 — Helius LaserStream gRPC
|
||||
```
|
||||
|
||||
est reporté dans les TODO Yellowstone sans numéro de release. L'audit du 2026-08-25 conclut que la surface Helius reste largement wire-compatible Yellowstone et pourrait probablement se composer au-dessus de N1/N2, mais l'accès gRPC Helius exige actuellement un plan payant que l'opérateur ne retient pas uniquement pour ce test. La release provider est donc différée jusqu'à disponibilité d'un accès live permettant de valider réellement auth, endpoints, Subscribe, Ping, replay/from_slot et erreurs provider. Les extensions Helius non standard restent un sujet séparé.
|
||||
|
||||
La séquence active avance d'un cran :
|
||||
|
||||
```text
|
||||
0.2.11 — off-chain price transport
|
||||
0.2.12 — Price Desk + intégration prix Wallet Desk
|
||||
0.2.13 — interface/wire foundation
|
||||
0.2.14 — program-api foundation
|
||||
```
|
||||
|
||||
Décision de publication :
|
||||
|
||||
```text
|
||||
aucun prompt suivant dans pre.004
|
||||
aucun changement CHANGELOG/ROADMAP dans pre.004
|
||||
Helius gRPC -> TODO futur sans numéro
|
||||
0.2.11 -> off-chain price transport
|
||||
pre.005 préparera seulement le prompt 0.2.11 + CHANGELOG + ROADMAP
|
||||
```
|
||||
|
||||
Quel que soit le provider futur, l'invariant reste le même : N1 gRPC et N2 Yellowstone sont des fondations stables ; les différences provider se composent au-dessus et ne modifient jamais le moteur pour satisfaire un fournisseur.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
|
||||
<!-- version: 5 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Règles de documentation
|
||||
|
||||
@@ -41,6 +41,12 @@ Les règles `DOC-*` s'appliquent aux documents Markdown internes et à leur orga
|
||||
- **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`.
|
||||
|
||||
## Espacement vertical Markdown
|
||||
|
||||
- **DOC-BLANK-001** — Hors bloc de code fenced, un document Markdown KSP ne contient jamais plus d’une ligne vide consécutive. Une ligne composée uniquement d’espaces ou de tabulations est considérée comme vide.
|
||||
- **DOC-BLANK-002** — `python3 scripts/audit_markdown_tables.py <fichiers-ou-répertoires>` contrôle aussi les lignes vides multiples. Lors d’un parcours récursif, les répertoires générés ou tiers tels que `node_modules`, `dist`, `target`, `.git`, `.idea`, `.venv` et `__pycache__` sont exclus afin que le résultat porte uniquement sur les Markdown KSP-owned. Les blocs de code fenced conservent librement leur espacement interne.
|
||||
- **DOC-BLANK-003** — Les deltas déjà publiés restent immuables et ne sont jamais réécrits uniquement pour satisfaire `DOC-BLANK-001`. Les audits de release portent sur le répertoire de delta actif et sur les autres Markdown modifiables ; un audit historique explicite peut donc signaler des écarts hérités sans autoriser leur correction rétroactive.
|
||||
|
||||
## 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.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/000-README.md -->
|
||||
<!-- version: 24 -->
|
||||
<!-- version: 25 -->
|
||||
|
||||
# Validations KSP
|
||||
|
||||
@@ -20,4 +20,5 @@ Documents :
|
||||
- [`009-V0_2_6_WALLET_DESK_COMPLIANCE.md`](009-V0_2_6_WALLET_DESK_COMPLIANCE.md) — matrice finale validée de la release stable `0.2.6`, couvrant Wallet Desk, les wires V1/V2, la migration explicite, le runtime Tauri packagé, les frontières sécurité/ownership et le gate opérateur `pre.018-fix.001` avec build final Linux vert.
|
||||
- [`010-V0_2_7_ONCHAIN_WEBSOCKET.md`](010-V0_2_7_ONCHAIN_WEBSOCKET.md) — matrice finale validée de la release stable `0.2.7`, ouverte par `pre.001`, fermée techniquement par `pre.014` puis publiée par `rel.001` : inventaire 9 subscribe + 9 unsubscribe, lifecycle borné, statuts unstable, compliance 18/18, non-régression HTTP 52+14, composition Config V2, smoke WebSocket Devnet et audit de dépendances.
|
||||
- [`011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md`](011-V0_2_8_HELIUS_LASERSTREAM_WEBSOCKET.md) — matrice finale validée de la release stable `0.2.8`, ouverte par `pre.001`, consolidée jusqu’à `pre.011` puis publiée par `rel.001` : Helius `account/logs/program/root/signature/slot/slotsUpdates + transaction`, `block/vote` absents, heartbeat provider, sécurité/redaction, lifecycle adversarial, non-régressions HTTP/WS, stratégie smoke live et graphes Cargo finaux.
|
||||
- [`012-V0_2_9_YELLOWSTONE_GRPC.md`](012-V0_2_9_YELLOWSTONE_GRPC.md) — matrice active ouverte par `0.2.9-pre.001` : service Geyser courant, `Subscribe` standard, 7 unary, filtres/updates, dépendances/licence, replay/backpressure, Config V3 et interopérabilité PublicNode/OrbitFlare.
|
||||
- [`012-V0_2_9_YELLOWSTONE_GRPC.md`](012-V0_2_9_YELLOWSTONE_GRPC.md) — matrice finale de la release stable `0.2.9` : service Geyser courant, `Subscribe` standard, 7 unary, filtres/updates, dépendances/licence, replay/backpressure, Config V3 et smoke PublicNode Mainnet/Testnet.
|
||||
- [`013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md`](013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md) — matrice active ouverte par `0.2.10-pre.001` : Free Devnet, auth provider, endpoint security, heartbeat standard, capabilities, Config V3, smoke live et invariant N1/N2 immuable.
|
||||
|
||||
394
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
Normal file
394
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
Normal file
@@ -0,0 +1,394 @@
|
||||
<!-- file: docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Validation `0.2.10` — OrbitFlare Yellowstone gRPC
|
||||
|
||||
**Statut courant : `0.2.10-pre.003` ferme le gate technique/live final. Le workspace complet est vert, les graphes Cargo ont été inspectés et le smoke OrbitFlare Devnet authentifié par License Key `ORBIT-*` en secret `x-token` observe `Subscribe -> Slot + Ping` puis ferme proprement. N1/N2 restent inchangés ; `pre.004` réconcilie uniquement la documentation finale.**
|
||||
|
||||
## 1. Autorités
|
||||
|
||||
```text
|
||||
RULES.md + docs/rules/*
|
||||
archive stable v0.2.9
|
||||
plan 016 et validation 012 pour N1/N2
|
||||
plan 017 courant
|
||||
prompt 015 pour les contraintes non supersédées
|
||||
deltas/0.2.10/*
|
||||
OrbitFlare docs/pricing/SDK/CLI actuels
|
||||
Yellowstone upstream actuel
|
||||
```
|
||||
|
||||
## 2. Baseline stable
|
||||
|
||||
| Gate | Résultat |
|
||||
|------------------------------------------|----------------------------------|
|
||||
| version de base | `0.2.9` PASS |
|
||||
| `deltas/0.2.9/rel.001.md` | PASS |
|
||||
| prompt `015` | PASS |
|
||||
| `cargo fmt --all` | PASS |
|
||||
| audit Rust | PASS |
|
||||
| audit Markdown | PASS |
|
||||
| `cargo check --workspace` | PASS |
|
||||
| `cargo clippy --workspace --all-targets` | PASS |
|
||||
| `cargo test --workspace` | PASS |
|
||||
| Transport unit | 383 sur 383 PASS |
|
||||
| Transport public API | 49 sur 49 PASS |
|
||||
| Transport release completeness | 43 sur 43 PASS |
|
||||
| Config unit | 113 sur 113 PASS |
|
||||
| graph duplicates Transport | fourni, aucun conflit N1 visible |
|
||||
| graph complet Transport | fourni sur `0.2.10-pre.1` PASS |
|
||||
|
||||
## 3. Invariant architecture
|
||||
|
||||
| Exigence | Verdict |
|
||||
|----------------------------------------|----------|
|
||||
| moteur gRPC N1 modifié pour OrbitFlare | **NO** |
|
||||
| standard Yellowstone N2 modifié | **NO** |
|
||||
| second client Tonic | **NO** |
|
||||
| SDK OrbitFlare runtime | **NO** |
|
||||
| provider séparé du protocol | **PASS** |
|
||||
| Config -> Transport seulement | **PASS** |
|
||||
| Transport -> Config/env | **PASS** |
|
||||
| façade provider sans divergence | **NO** |
|
||||
|
||||
Toute modification de `grpc_stream.rs`, `grpc_channel.rs`, `grpc_settings.rs`, `grpc_unary.rs` ou `grpc_subscribe.rs` motivée uniquement par OrbitFlare invalide ce gate.
|
||||
|
||||
## 4. Pricing et réseau
|
||||
|
||||
| Point | Preuve actuelle | Verdict |
|
||||
|----------------------|------------------------------------------|---------------|
|
||||
| plan Solana Free | 0 USD par mois | **PASS** |
|
||||
| gRPC Free | Devnet only | **PASS** |
|
||||
| RPS Free | 10 | INFO |
|
||||
| TPS Free | 1 | INFO |
|
||||
| crédit | unlimited dans le RPS | INFO |
|
||||
| Devnet gRPC endpoint | `http://devnet.rpc.orbitflare.com:10000` | **PASS** |
|
||||
| Devnet live KSP | Subscribe authentifié, Slot + Ping | **PASS LIVE** |
|
||||
| Mainnet gratuit | non documenté | **OUT** |
|
||||
| Testnet endpoint | non prouvé | **UNKNOWN** |
|
||||
|
||||
Sources :
|
||||
|
||||
```text
|
||||
https://orbitflare.com/pricing
|
||||
https://orbitflare.com/products/rpc-nodes
|
||||
https://docs.orbitflare.com/cli
|
||||
```
|
||||
|
||||
## 5. Transport security
|
||||
|
||||
| Forme endpoint | Classification | Verdict |
|
||||
|---------------------------------------|-----------------------|----------|
|
||||
| `http://*.rpc.orbitflare.com:10000` | HTTP/2 plaintext | **PASS** |
|
||||
| `https://*.grpc.orbitflare.com` | HTTP/2 TLS | **PASS** |
|
||||
| transformation automatique http/https | interdite | **PASS** |
|
||||
| endpoint Dashboard | autoritaire si fourni | **PASS** |
|
||||
|
||||
KSP ne prétend pas qu'un canal gRPC plaintext bénéficie d'une sécurité TLS implicite.
|
||||
|
||||
## 6. Auth classification
|
||||
|
||||
| Élément | Usage prouvé | Verdict |
|
||||
|-----------------------|-----------------------------|------------------------------|
|
||||
| `X-ORBIT-KEY` | Customer API | **CONTROL-PLANE** |
|
||||
| Bearer Device Flow | Customer API v2 | **CONTROL-PLANE** |
|
||||
| RPC `api_key` | Solana HTTP RPC | **HTTP ONLY** |
|
||||
| License Key `ORBIT-*` | produit Solana Free | **DATA-PLANE PROVIDER** |
|
||||
| metadata `x-token` | Yellowstone gRPC OrbitFlare | **REQUIRED / PROVEN DOC** |
|
||||
| sans metadata | live KSP `pre.002` | **REJECTED UNAUTHENTICATED** |
|
||||
| IP whitelist | autre mode produit | **NOT ACTIVE FOR OPERATOR** |
|
||||
|
||||
Preuve live `pre.002` :
|
||||
|
||||
```text
|
||||
grpc_operation = SubscribeOpen
|
||||
grpc_status = Unauthenticated
|
||||
grpc_code = The request does not have valid authentication credentials
|
||||
```
|
||||
|
||||
Preuve provider : la référence Yellowstone OrbitFlare construit le client avec `X_TOKEN = ORBITFLARE_LICENSE_KEY` et indique que le token est porté par la metadata gRPC `x-token`.
|
||||
|
||||
Le Dashboard opérateur classe le produit `Solana Free` en `API Key Mode Active`. La License Key est donc le secret data-plane à utiliser ; elle n’est pas une `X-ORBIT-KEY` Customer API.
|
||||
|
||||
Le CLI OrbitFlare courant n’est pas utilisé comme oracle positif pour l’auth gRPC : après stockage de la License Key, `orbitflare ping --service grpc --network devnet` retourne `invalid x-token: api key not found`, et son implémentation courante n’injecte pas le secret dans le canal gRPC.
|
||||
|
||||
## 7. Heartbeat
|
||||
|
||||
| Point | Preuve | Verdict |
|
||||
|----------------------------------------|---------------------------------------------|----------|
|
||||
| OrbitFlare idle timeout partagé | environ 10 minutes | **PASS** |
|
||||
| OrbitFlare recommande client Ping | 30 secondes | **PASS** |
|
||||
| Yellowstone serveur Ping périodique | upstream documenté | **PASS** |
|
||||
| KSP auto reply au serveur Ping | test N1 `0.2.9` et non-régression `pre.003` | **PASS** |
|
||||
| moteur N1 à modifier | non | **PASS** |
|
||||
| Ping serveur OrbitFlare Devnet observé | live `pre.002-fix.001` + `pre.003` | **PASS** |
|
||||
| heartbeat provider additionnel | aucune divergence live | **NO** |
|
||||
|
||||
Le gate est fermé : OrbitFlare émet le Ping Yellowstone standard et le chemin de réponse automatique N1 reste suffisant sans timer provider.
|
||||
|
||||
## 8. Capabilities streaming
|
||||
|
||||
| Capability | Docs OrbitFlare | KSP N2 | Live provider |
|
||||
|---------------------|-----------------|--------|--------------------------|
|
||||
| accounts | oui | PASS | non sondé exhaustivement |
|
||||
| slots | oui | PASS | **PASS** |
|
||||
| transactions | oui | PASS | non sondé exhaustivement |
|
||||
| transactions_status | partiel | PASS | non sondé exhaustivement |
|
||||
| blocks | oui | PASS | non sondé exhaustivement |
|
||||
| blocks_meta | oui | PASS | non sondé exhaustivement |
|
||||
| entry | oui | PASS | non sondé exhaustivement |
|
||||
| commitment | oui | PASS | **PASS confirmed** |
|
||||
| accounts_data_slice | oui | PASS | non sondé exhaustivement |
|
||||
| Subscribe Ping/Pong | oui | PASS | **PASS Ping serveur** |
|
||||
|
||||
La release prouve le chemin provider nécessaire à sa mission sans transformer les familles non sondées en capacités absentes.
|
||||
|
||||
## 9. Unary et replay
|
||||
|
||||
| Capability | N2 KSP | OrbitFlare docs | Verdict provider |
|
||||
|---------------------|--------|-----------------|-----------------------------------|
|
||||
| SubscribeReplayInfo | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| Ping unary | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| GetLatestBlockhash | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| GetBlockHeight | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| GetSlot | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| IsBlockhashValid | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| GetVersion | PASS | non prouvé | UNKNOWN / non bloquant |
|
||||
| from_slot | PASS | non prouvé | N1 disponible, provider non sondé |
|
||||
| retention | N/A | non documentée | UNKNOWN / provider-owned |
|
||||
|
||||
Une restriction ou un inconnu provider ne rétrograde jamais la disponibilité de la méthode dans le standard global KSP. Le reconnect N1 tolère déjà l'indisponibilité de `SubscribeReplayInfo` et poursuit avec le `from_slot` conservateur demandé.
|
||||
|
||||
## 10. Limits provider
|
||||
|
||||
| Limite | Valeur | Verdict |
|
||||
|------------------------------|--------------------------|---------|
|
||||
| concurrent gRPC connections | 50 par IP | INFO |
|
||||
| subscriptions par connection | unlimited | INFO |
|
||||
| cap partagé entre régions | oui | INFO |
|
||||
| idle timeout | environ 10 minutes | INFO |
|
||||
| dépassement | `RESOURCE_EXHAUSTED` | INFO |
|
||||
| backoff recommandé | exponentiel jusqu'à 30 s | INFO |
|
||||
|
||||
Ces valeurs restent provider-owned et ne deviennent pas des validations génériques de `YellowstoneGrpcSessionSettings`.
|
||||
|
||||
## 11. Config V3
|
||||
|
||||
| Exigence | Verdict |
|
||||
|---------------------------------------|----------|
|
||||
| nouveau format Config nécessaire | **NO** |
|
||||
| `provider = orbitflare` | **PASS** |
|
||||
| `protocol = solana_yellowstone` | **PASS** |
|
||||
| `cluster = devnet` | **PASS** |
|
||||
| Devnet URL publique | **PASS** |
|
||||
| secret metadata `x-token` | **PASS** |
|
||||
| valeur License Key via `KSP_SECRET_*` | **PASS** |
|
||||
| `X-ORBIT-KEY` dans Transport Config | **NO** |
|
||||
| heartbeat dans `grpc_defaults` | **NO** |
|
||||
|
||||
Contrat final :
|
||||
|
||||
```text
|
||||
secret_metadata = x-token <- ${KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN}
|
||||
```
|
||||
|
||||
Le test Config prouve la classification secrète et la redaction ; le live prouve que ce credential ouvre le Subscribe OrbitFlare Devnet.
|
||||
|
||||
## 12. Smoke Devnet final
|
||||
|
||||
Smoke durable :
|
||||
|
||||
```text
|
||||
License Key lue sur stdin
|
||||
YellowstoneGrpcMetadataEntry::secret("x-token", ...)
|
||||
provider = orbitflare
|
||||
cluster = devnet
|
||||
url = http://devnet.rpc.orbitflare.com:10000
|
||||
open standard Subscribe
|
||||
request slots confirmed
|
||||
receive Slot non nul
|
||||
observe Ping serveur
|
||||
close borné
|
||||
```
|
||||
|
||||
| Preuve | Verdict |
|
||||
|----------------------------------------------|--------------------------------|
|
||||
| endpoint parsé par N1 | **PASS** |
|
||||
| sans metadata | **FAIL EXPECTED / CLASSIFIED** |
|
||||
| secret `x-token` représentable par Config V3 | **PASS** |
|
||||
| License Key redacted | **PASS** |
|
||||
| connect authentifié | **PASS LIVE** |
|
||||
| Subscribe authentifié | **PASS LIVE** |
|
||||
| Slot reçu | **PASS LIVE** |
|
||||
| server Ping reçu | **PASS LIVE** |
|
||||
| auto reply KSP déterministe | **PASS N1** |
|
||||
| close borné | **PASS LIVE** |
|
||||
|
||||
Résultats :
|
||||
|
||||
```text
|
||||
pre.002-fix.001 1/1 PASS en 5.10 s
|
||||
pre.003 final 1/1 PASS en 5.19 s
|
||||
```
|
||||
|
||||
## 13. Provider overlay gate
|
||||
|
||||
Verdict final : **aucune façade/policy OrbitFlare n'est nécessaire**.
|
||||
|
||||
Les conditions de réutilisation directe sont toutes satisfaites :
|
||||
|
||||
```text
|
||||
standard Subscribe fonctionne
|
||||
heartbeat standard fonctionne
|
||||
Config V3 exprime endpoint/auth
|
||||
aucune restriction consumer-visible ne requiert un type provider
|
||||
```
|
||||
|
||||
Les interdictions restent durables :
|
||||
|
||||
```text
|
||||
N1 ne change pas
|
||||
N2 ne change pas
|
||||
pas de raw Tonic
|
||||
pas de SDK OrbitFlare
|
||||
```
|
||||
|
||||
## 14. Non-régressions finales
|
||||
|
||||
| Surface | Baseline | Final |
|
||||
|-----------------------------------|--------------|------------------------|
|
||||
| HTTP current typed | 52 sur 52 | **PASS** |
|
||||
| HTTP historical | 14 sur 14 | **PASS** |
|
||||
| WebSocket standard | 18 sur 18 | **PASS** |
|
||||
| Helius LaserStream WebSocket | stable 0.2.8 | **PASS** |
|
||||
| Yellowstone N1/N2 | stable 0.2.9 | **PASS** |
|
||||
| PublicNode Mainnet/Testnet | stable 0.2.9 | **PASS deterministic** |
|
||||
| Config V1/V2/V3 backward readable | stable 0.2.9 | **PASS** |
|
||||
| dependency firewall | stable 0.2.9 | **PASS** |
|
||||
|
||||
Les smokes PublicNode live n'ont pas été rejoués en `pre.003` car N1/N2 et les profils PublicNode n'ont pas changé ; leurs preuves live de `0.2.9` restent la baseline et la non-régression déterministe est verte.
|
||||
|
||||
## 15. Gate `pre.001`
|
||||
|
||||
| Critère | Verdict |
|
||||
|-------------------------------------|----------------------|
|
||||
| base stable `v0.2.9` | **PASS** |
|
||||
| baseline fmt/audits/check/clippy | **PASS** |
|
||||
| workspace test | **PASS** |
|
||||
| graph duplicates | **PASS** |
|
||||
| graph complet Transport | **PASS** |
|
||||
| sources OrbitFlare actuelles | **PASS** |
|
||||
| sources Yellowstone actuelles | **PASS** |
|
||||
| Free Devnet gRPC confirmé | **PASS** |
|
||||
| endpoints classifiés | **PASS** |
|
||||
| auth planes distingués | **PASS** |
|
||||
| heartbeat KSP vs provider classifié | **PASS FINAL** |
|
||||
| capabilities auditées | **PASS** |
|
||||
| replay/from_slot | **UNKNOWN PROVIDER** |
|
||||
| N1 immutable | **PASS** |
|
||||
| N2 immutable | **PASS** |
|
||||
| Config V3 shape | **PASS** |
|
||||
| smoke ownership | **PASS** |
|
||||
| threat model | **PASS** |
|
||||
| sizing/forecast | **PASS** |
|
||||
| provider runtime lourd ajouté | **NO** |
|
||||
|
||||
Verdict final : architecture positive, inconnus provider non requis qualifiés, aucun split déclenché.
|
||||
|
||||
## 16. Gate `pre.002` commité
|
||||
|
||||
Validation opérateur du 2026-08-25 :
|
||||
|
||||
| Critère | Verdict |
|
||||
|------------------------------------------|---------------------------------|
|
||||
| Cargo `0.2.10-pre.2` | **PASS** |
|
||||
| `cargo fmt --all` | **PASS** |
|
||||
| audit Rust | **PASS** |
|
||||
| audit Markdown | **PASS / 98 tables / 98 files** |
|
||||
| `cargo check --workspace` | **PASS** |
|
||||
| `cargo clippy --workspace --all-targets` | **PASS** |
|
||||
| Config unit | **114 sur 114 PASS** |
|
||||
| Transport unit | **383 sur 383 PASS** |
|
||||
| Transport public API | **49 sur 49 PASS** |
|
||||
| Transport release completeness | **43 sur 43 PASS** |
|
||||
| workspace test | **PASS** |
|
||||
| graphes Transport | **FOURNIS / PAS DE CONFLIT N1** |
|
||||
| moteur N1 modifié | **NO** |
|
||||
| standard N2 modifié | **NO** |
|
||||
| live sans metadata | **FAIL CLASSIFIED** |
|
||||
| `SubscribeOpen` | **UNAUTHENTICATED** |
|
||||
|
||||
Le failure live est la caractérisation historique qui a imposé le fix d'auth, pas une régression du moteur.
|
||||
|
||||
## 17. Gate `pre.002-fix.001`
|
||||
|
||||
| Critère | Verdict |
|
||||
|-----------------------------------------------------------------|------------------------|
|
||||
| Cargo `0.2.10-pre.2.fix.1` | **PASS** |
|
||||
| `.env.example` inventorie le secret OrbitFlare | **PASS** |
|
||||
| Config `secret_metadata` contient `x-token` | **PASS** |
|
||||
| valeur provenant de `KSP_SECRET_ORBITFLARE_DEVNET_GRPC_X_TOKEN` | **PASS** |
|
||||
| test Config prouve redaction et classification secrète | **PASS** |
|
||||
| smoke lit la License Key sur stdin | **PASS** |
|
||||
| secret absent des arguments CLI | **PASS** |
|
||||
| moteur N1 modifié | **NO** |
|
||||
| standard N2 modifié | **NO** |
|
||||
| SDK OrbitFlare ajouté | **NO** |
|
||||
| connect authentifié | **PASS LIVE** |
|
||||
| `Subscribe -> Slot` live | **PASS LIVE / 5.10 s** |
|
||||
| `SubscribeUpdate::Ping` live | **PASS LIVE** |
|
||||
| close live | **PASS LIVE** |
|
||||
|
||||
Le fix ferme l'auth et confirme que le chemin standard suffit.
|
||||
|
||||
## 18. Gate `pre.003` technique/live final
|
||||
|
||||
Gate opérateur du 2026-08-25 :
|
||||
|
||||
| Critère | Verdict |
|
||||
|------------------------------------------|----------------------------------|
|
||||
| Cargo `0.2.10-pre.3` | **PASS** |
|
||||
| `cargo fmt --all` | **PASS** |
|
||||
| audit Rust | **PASS / 0 export candidate** |
|
||||
| audit Markdown | **PASS / 99 tables / 100 files** |
|
||||
| `cargo check --workspace` | **PASS** |
|
||||
| `cargo clippy --workspace --all-targets` | **PASS** |
|
||||
| Config unit | **114 sur 114 PASS** |
|
||||
| Config ownership | **5 sur 5 PASS** |
|
||||
| Config public API | **15 sur 15 PASS** |
|
||||
| Transport unit | **383 sur 383 PASS** |
|
||||
| Transport public API | **49 sur 49 PASS** |
|
||||
| Transport release completeness | **43 sur 43 PASS** |
|
||||
| Transport doctests | **4 sur 4 PASS** |
|
||||
| workspace dependency canary | **3 sur 3 PASS** |
|
||||
| `cargo test --workspace` | **PASS** |
|
||||
| OrbitFlare Devnet live | **1 sur 1 PASS / 5.19 s** |
|
||||
| graphes Cargo | **INSPECTÉS / PAS DE BLOCAGE** |
|
||||
| moteur N1 modifié | **NO** |
|
||||
| standard N2 modifié | **NO** |
|
||||
|
||||
Pile directe réconciliée :
|
||||
|
||||
```text
|
||||
yellowstone-grpc-proto 12.6.0
|
||||
tonic / tonic-prost 0.14.6
|
||||
prost / prost-types 0.14.4
|
||||
```
|
||||
|
||||
Verdict : **gate technique/live final fermé**.
|
||||
|
||||
## 19. Gate `pre.004` documentaire
|
||||
|
||||
Cette tranche doit uniquement synchroniser :
|
||||
|
||||
```text
|
||||
plan 017
|
||||
validation 013
|
||||
README Transport
|
||||
USAGE Transport
|
||||
docs/000-README.md
|
||||
```
|
||||
|
||||
Elle ne change ni code, ni Config runtime, ni schema, ni test, ni dependency. `CHANGELOG.md`, `ROADMAP.md` et le prompt suivant restent réservés au couloir publication-minimal.
|
||||
|
||||
La décision de séquence est prise avant `pre.005` : Helius LaserStream gRPC est reporté dans les TODO Yellowstone sans numéro de release faute d'accès live raisonnable, et `0.2.11` devient `off-chain price transport`. Aucun prompt suivant n'est généré dans `pre.004`.
|
||||
878
prompts/016-V0_2_11_START_PROMPT.md
Normal file
878
prompts/016-V0_2_11_START_PROMPT.md
Normal file
@@ -0,0 +1,878 @@
|
||||
<!-- file: prompts/016-V0_2_11_START_PROMPT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Prompt de démarrage `0.2.11` — Off-chain price transport
|
||||
|
||||
## 1. Identité de la release et base exacte requise
|
||||
|
||||
La base attendue est **exclusivement** la release stable :
|
||||
|
||||
```text
|
||||
v0.2.10
|
||||
```
|
||||
|
||||
Ne pas ouvrir `0.2.11` depuis `0.2.10-pre.*`, depuis un ZIP intermédiaire ou depuis un souvenir de session. Si une archive opérateur de `v0.2.10` est fournie, cette archive réelle est l'autorité première devant les snippets, anciens prompts, anciens ZIP et mémoire de conversation.
|
||||
|
||||
La release à ouvrir est :
|
||||
|
||||
```text
|
||||
0.2.11 — Off-chain price transport
|
||||
```
|
||||
|
||||
La première tranche est :
|
||||
|
||||
```text
|
||||
0.2.11-pre.001
|
||||
```
|
||||
|
||||
`pre.001` est obligatoirement une tranche **lecture + audit externe actuel + comparaison des sémantiques de prix + brainstorming + threat model + sizing + planification**. Elle ne commence pas par coder un client CoinGecko, Jupiter, Pyth, Birdeye ou DexScreener, ni par figer un type numérique ou une API provider-neutral avant l'audit.
|
||||
|
||||
À l'ouverture, vérifier au minimum :
|
||||
|
||||
```text
|
||||
git describe / tag stable si metadata Git disponible
|
||||
workspace.package.version = 0.2.10
|
||||
deltas/0.2.10/rel.001.md présent
|
||||
prompts/016-V0_2_11_START_PROMPT.md présent
|
||||
```
|
||||
|
||||
État fonctionnel attendu depuis `v0.2.10` :
|
||||
|
||||
```text
|
||||
HTTP Solana standard 52/52 current typed + 14 historiques
|
||||
WebSocket Solana standard 9 familles / 18 opérations
|
||||
Helius LaserStream WebSocket façade provider existante
|
||||
Yellowstone gRPC N1/N2 moteur + standard provider-neutral stables
|
||||
PublicNode Yellowstone Mainnet/Testnet validés
|
||||
OrbitFlare Yellowstone Devnet validé avec License Key x-token
|
||||
Config Transport V3 backward-readable
|
||||
Wallet .kspwallet V1/V2 + Wallet Desk stables
|
||||
ksp-offchain-transport-lib absent au démarrage
|
||||
Price Desk hors scope de cette release
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Mission et résultat attendu
|
||||
|
||||
`0.2.11` doit créer `ksp-offchain-transport-lib` à partir d'un premier besoin métier réel : **lire des prix off-chain**, au minimum :
|
||||
|
||||
```text
|
||||
SOL/USD
|
||||
SOL/EUR
|
||||
```
|
||||
|
||||
La release doit séparer le contrat KSP « lire un prix » de l'API propriétaire du premier provider retenu, sans créer de `ksp-offchain-transport-api` globale ni de trait universel artificiel couvrant prix, metadata, quotes, IPFS, Arweave et autres domaines hétérogènes.
|
||||
|
||||
Résultat attendu à la clôture :
|
||||
|
||||
```text
|
||||
ksp-offchain-transport-lib créée
|
||||
surface prix publique petite, typée et documentée
|
||||
sémantique du prix explicitement définie
|
||||
représentation numérique auditée et non choisie par facilité
|
||||
settings runtime publics possédés par Off-chain Transport
|
||||
premier provider réellement audité et live-testable
|
||||
SOL/USD + SOL/EUR disponibles selon un contrat explicite
|
||||
provenance/fraîcheur/absence de prix représentées sans ambiguïté
|
||||
timeout + erreurs + observabilité sûrs
|
||||
Config -> Off-chain Transport composé sans dépendance inverse
|
||||
aucun secret provider dans code/logs/debug
|
||||
smoke live opt-in contre un accès non payant raisonnable
|
||||
README/USAGE + plan/validation finalisés
|
||||
```
|
||||
|
||||
Le principe directeur est :
|
||||
|
||||
```text
|
||||
contrat prix KSP minimal
|
||||
!=
|
||||
modèle universel de toute donnée de marché
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Sources de vérité internes obligatoires — ordre de lecture
|
||||
|
||||
### 3.1 Règles globales
|
||||
|
||||
Lire d'abord :
|
||||
|
||||
```text
|
||||
RULES.md
|
||||
docs/000-README.md
|
||||
|
||||
docs/rules/RULES_GENERAL.md
|
||||
docs/rules/RULES_KSP.md
|
||||
docs/rules/RULES_RUST.md
|
||||
docs/rules/RULES_DEPENDENCIES.md
|
||||
docs/rules/RULES_DOCUMENTATION.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/PROMPT_STRUCTURE.md
|
||||
```
|
||||
|
||||
Rappels directement applicables :
|
||||
|
||||
```text
|
||||
Rust 2024
|
||||
unsafe / unwrap / expect / panic interdits selon les règles KSP
|
||||
retours explicites et audit structurel KSP
|
||||
third-party deps déclarées une seule fois au workspace
|
||||
ksp-logging-lib propriétaire du tracing
|
||||
ksp-config-lib propriétaire config/env/secrets
|
||||
aucune lecture directe de KSP_* par Off-chain Transport
|
||||
pas de pub mod ; exports crate-root explicites
|
||||
```
|
||||
|
||||
Après toute modification Rust :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Pour les Markdown touchés :
|
||||
|
||||
```bash
|
||||
python3 scripts/audit_markdown_tables.py <fichiers-ou-répertoires-ciblés>
|
||||
```
|
||||
|
||||
### 3.2 Architecture durable à préserver
|
||||
|
||||
Lire ensuite :
|
||||
|
||||
```text
|
||||
docs/architecture/000-README.md
|
||||
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
|
||||
docs/architecture/003-COMPONENT_CONTRACTS.md
|
||||
docs/architecture/004-COMPONENT_INVENTORY.md
|
||||
docs/architecture/005-DEPENDENCY_GRAPH.md
|
||||
```
|
||||
|
||||
Frontières acquises :
|
||||
|
||||
```text
|
||||
ksp-offchain-transport-lib est distinct de ksp-onchain-transport-lib
|
||||
aucune ksp-offchain-transport-api globale
|
||||
Off-chain Transport -X-> Config
|
||||
Config -> Off-chain Transport autorisé via adapter/composition
|
||||
Off-chain Transport peut contenir à terme plusieurs modules/APIs distincts
|
||||
la première surface engagée est le prix
|
||||
metadata HTTP/IPFS/Arweave et quotes attendent leur besoin réel
|
||||
```
|
||||
|
||||
### 3.3 Plans et historique fonctionnel
|
||||
|
||||
Lire :
|
||||
|
||||
```text
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/007-V0_2_0_SERIES_PLANNING.md
|
||||
docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md
|
||||
|
||||
docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md
|
||||
deltas/0.2.10/rel.001.md
|
||||
```
|
||||
|
||||
Références historiques utiles, sans reprendre leurs anciens numéros de release :
|
||||
|
||||
```text
|
||||
sections Off-chain price transport de docs/plans/007-V0_2_0_SERIES_PLANNING.md
|
||||
ancienne préparation 0.2.x dans prompts/014-V0_2_9_START_PROMPT.md
|
||||
TODO Wallet Desk demandant la future réutilisation de la capacité prix
|
||||
```
|
||||
|
||||
### 3.4 Code réel à inventorier
|
||||
|
||||
Avant design, inspecter au minimum :
|
||||
|
||||
```text
|
||||
Cargo.toml workspace
|
||||
crates/ksp-core-lib
|
||||
crates/ksp-logging-lib
|
||||
crates/ksp-config-lib
|
||||
crates/ksp-onchain-transport-lib uniquement comme référence de patterns, pas comme dépendance automatique
|
||||
.env.example
|
||||
config/
|
||||
config/schemas/
|
||||
```
|
||||
|
||||
Vérifier notamment les primitives déjà disponibles : `reqwest`, `serde`, `serde_json`, `tokio`, `http`, les contrats Error KSP et les adapters Config existants. Ne pas ajouter un SDK provider si `reqwest` + types KSP suffisent.
|
||||
|
||||
---
|
||||
|
||||
## 4. Sources externes à réauditer en `pre.001`
|
||||
|
||||
La fraîcheur est importante. Les faits ci-dessous sont un snapshot informatif au **2026-08-25**, jamais un contrat à recopier sans vérification.
|
||||
|
||||
### 4.1 CoinGecko
|
||||
|
||||
Sources primaires :
|
||||
|
||||
```text
|
||||
https://docs.coingecko.com/reference/simple-price
|
||||
https://docs.coingecko.com/docs/data-delivery-methods
|
||||
https://docs.coingecko.com/reference/endpoint-overview
|
||||
```
|
||||
|
||||
Snapshot :
|
||||
|
||||
```text
|
||||
REST disponible y compris sur plan Demo
|
||||
/simple/price accepte plusieurs vs_currencies, dont usd et eur
|
||||
API Demo utilise typiquement x-cg-demo-api-key
|
||||
la sémantique est celle d'un agrégateur de marché CoinGecko, pas d'un oracle on-chain
|
||||
```
|
||||
|
||||
Vérifier limites réelles, auth, fraîcheur/cache, IDs d'actifs, disponibilité SOL/USD et SOL/EUR et conditions d'usage.
|
||||
|
||||
### 4.2 Jupiter Price API V3
|
||||
|
||||
Sources primaires :
|
||||
|
||||
```text
|
||||
https://developers.jup.ag/docs/price
|
||||
https://developers.jup.ag/docs/api-reference/price
|
||||
```
|
||||
|
||||
Snapshot :
|
||||
|
||||
```text
|
||||
GET https://api.jup.ag/price/v3
|
||||
x-api-key requis
|
||||
jusqu'à 50 mint addresses par requête
|
||||
usdPrice unique par token
|
||||
prix heuristique dérivé des swaps/liquidité/activité Solana
|
||||
V2 deprecated
|
||||
```
|
||||
|
||||
Jupiter est naturellement intéressant pour les SPL tokens mais son `usdPrice` ne satisfait pas à lui seul SOL/EUR. Ne pas introduire une conversion EUR externe silencieuse simplement pour forcer ce provider en premier.
|
||||
|
||||
### 4.3 Pyth Hermes
|
||||
|
||||
Sources primaires :
|
||||
|
||||
```text
|
||||
https://docs.pyth.network/price-feeds/core/how-pyth-works/hermes
|
||||
https://docs.pyth.network/price-feeds/core/fetch-price-updates
|
||||
https://docs.pyth.network/price-feeds/core/api-instances-and-providers/hermes
|
||||
```
|
||||
|
||||
Snapshot très sensible à la date :
|
||||
|
||||
```text
|
||||
Hermes expose REST + SSE
|
||||
prix = entier + exponent + confidence + publish_time
|
||||
endpoint public soumis à rate limit
|
||||
une transition Pyth Core est annoncée le 2026-08-26 à 16:00 UTC
|
||||
authentication API key devient obligatoire selon la documentation courante
|
||||
```
|
||||
|
||||
Comme cette transition intervient immédiatement après la préparation de ce prompt, `pre.001` doit **réauditer Pyth en priorité** et ne jamais utiliser le snapshot ci-dessus comme vérité actuelle.
|
||||
|
||||
Pyth représente une sémantique oracle différente d'un prix DEX/agrégateur. Cette différence doit rester visible dans le design.
|
||||
|
||||
### 4.4 Birdeye
|
||||
|
||||
Sources primaires :
|
||||
|
||||
```text
|
||||
https://docs.birdeye.so/reference/get-defi-price
|
||||
https://docs.birdeye.so/reference/get-defi-multi_price
|
||||
https://docs.birdeye.so/reference/birdeye-api-authentication
|
||||
```
|
||||
|
||||
Snapshot :
|
||||
|
||||
```text
|
||||
X-API-KEY requis
|
||||
x-chain = solana
|
||||
spot single + batch jusqu'à 100 tokens
|
||||
prix, liquidité et surfaces historiques/OHLCV plus larges disponibles
|
||||
```
|
||||
|
||||
Ne pas élargir `0.2.11` vers OHLCV/historique simplement parce que le provider les offre.
|
||||
|
||||
### 4.5 DexScreener
|
||||
|
||||
Source primaire :
|
||||
|
||||
```text
|
||||
https://docs.dexscreener.com/api/reference
|
||||
```
|
||||
|
||||
Snapshot :
|
||||
|
||||
```text
|
||||
API publique sans credential pour les endpoints DEX courants
|
||||
prix porté par des paires/pools
|
||||
jusqu'à 30 token addresses sur l'endpoint tokens courant
|
||||
limite documentée autour de 300 requêtes/minute pour les endpoints DEX/pairs
|
||||
```
|
||||
|
||||
La sémantique est pair/pool/DEX. Un `priceUsd` DexScreener ne doit pas être confondu sans audit avec un prix oracle ou le prix agrégé canonique d'un token.
|
||||
|
||||
### 4.6 Autres candidats
|
||||
|
||||
Coinbase, Kraken, Binance, CoinMarketCap et autres sources peuvent être audités si cela aide à satisfaire SOL/USD + SOL/EUR avec un accès stable et testable. Ils ne sont pas automatiquement dans le scope.
|
||||
|
||||
---
|
||||
|
||||
## 5. État validé à préserver depuis `v0.2.10`
|
||||
|
||||
### 5.1 Core / Logging / Config
|
||||
|
||||
Préserver :
|
||||
|
||||
```text
|
||||
Error/Result central KSP
|
||||
Pubkey via Core lorsque nécessaire
|
||||
Logging facade KSP uniquement
|
||||
Config seul propriétaire des fichiers/env/secrets
|
||||
.env.example comme inventaire versionné
|
||||
```
|
||||
|
||||
### 5.2 On-chain Transport
|
||||
|
||||
`ksp-onchain-transport-lib` reste indépendant et inchangé sauf nécessité architecturale démontrée. `0.2.11` n'est pas l'occasion de déplacer HTTP générique Solana, WebSocket ou Yellowstone dans une abstraction réseau universelle.
|
||||
|
||||
### 5.3 Wallet et prochaine Price Desk
|
||||
|
||||
La future `0.2.12` doit pouvoir consommer la surface prix dans une Price Desk puis dans Wallet Desk sans dupliquer récupération/normalisation. Cela justifie une API publique propre dès `0.2.11`, mais **pas** une UI ou une intégration Wallet anticipée.
|
||||
|
||||
---
|
||||
|
||||
## 6. Décisions acquises — ne pas redébattre sans contradiction réelle
|
||||
|
||||
```text
|
||||
nom de crate : ksp-offchain-transport-lib
|
||||
aucune ksp-offchain-transport-api globale
|
||||
première surface : prix
|
||||
minimum fonctionnel : SOL/USD + SOL/EUR
|
||||
pas de Price Desk dans 0.2.11
|
||||
pas d'intégration Wallet Desk dans 0.2.11
|
||||
pas de metadata HTTP/IPFS/Arweave dans cette release
|
||||
pas de quotes/routing dans cette release
|
||||
pas d'agrégation multi-provider complexe dans cette release
|
||||
Off-chain Transport ne dépend pas de Config
|
||||
Config peut adapter ses documents vers les settings publics Off-chain Transport
|
||||
premier provider doit être raisonnablement live-testable sans abonnement payant dédié
|
||||
```
|
||||
|
||||
Helius LaserStream gRPC est en TODO provider Yellowstone et ne doit pas être réintroduit dans `0.2.11`.
|
||||
|
||||
---
|
||||
|
||||
## 7. Questions réellement ouvertes à trancher pendant `pre.001`
|
||||
|
||||
### 7.1 Sémantique du prix KSP
|
||||
|
||||
Décider ce que signifie précisément le résultat commun minimal :
|
||||
|
||||
```text
|
||||
spot courant ou snapshot provider
|
||||
base asset / quote asset
|
||||
provider/source
|
||||
instant de requête KSP
|
||||
instant de publication/update provider lorsqu'il existe
|
||||
fraîcheur/staleness
|
||||
absence de prix
|
||||
```
|
||||
|
||||
Ne pas inventer un champ commun `confidence`, `liquidity`, `block_id` ou `market_cap` si tous les providers ne partagent pas réellement cette sémantique. Les données provider spécifiques peuvent rester dans un DTO/provider API séparé ou un sous-contrat explicitement typé.
|
||||
|
||||
### 7.2 Représentation numérique
|
||||
|
||||
Auditer explicitement :
|
||||
|
||||
```text
|
||||
f64 interdit ou accepté seulement comme wire temporaire ?
|
||||
fixed-point / decimal string / mantissa + exponent ?
|
||||
arrondis
|
||||
comparaisons
|
||||
conversion quote currency
|
||||
serialization publique
|
||||
```
|
||||
|
||||
Pour une future logique de trading, ne pas figer `f64` comme canon uniquement parce que certaines API renvoient un JSON number.
|
||||
|
||||
### 7.3 Identité des assets
|
||||
|
||||
Décider la forme minimale :
|
||||
|
||||
```text
|
||||
SOL natif
|
||||
mint SPL
|
||||
symbol/provider id
|
||||
quote fiat USD/EUR
|
||||
```
|
||||
|
||||
Le contrat doit éviter les collisions de symboles. Si le premier provider utilise un ID propriétaire (`solana` chez CoinGecko, mint chez Jupiter/Birdeye, feed ID chez Pyth), ce mapping appartient au provider/adaptateur et ne devient pas automatiquement l'identité canonique KSP.
|
||||
|
||||
### 7.4 Provider initial
|
||||
|
||||
Comparer au minimum :
|
||||
|
||||
```text
|
||||
CoinGecko Demo
|
||||
Jupiter Price V3
|
||||
Pyth Hermes
|
||||
Birdeye
|
||||
DexScreener
|
||||
```
|
||||
|
||||
Critères :
|
||||
|
||||
```text
|
||||
SOL/USD + SOL/EUR réalisables proprement
|
||||
accès gratuit/live raisonnable
|
||||
auth et secret ownership
|
||||
fraîcheur et limites
|
||||
batching
|
||||
stabilité/documentation
|
||||
sémantique du prix
|
||||
surface Rust nécessaire
|
||||
risque de lock-in
|
||||
```
|
||||
|
||||
Le provider initial peut être CoinGecko si l'audit actuel confirme qu'il satisfait directement les deux quotes avec un accès Demo raisonnable. Ce n'est pas une décision pré-écrite : `pre.001` doit le démontrer.
|
||||
|
||||
### 7.5 Conversion SOL/EUR
|
||||
|
||||
Priorité : utiliser une source qui expose directement la quote EUR lorsque possible.
|
||||
|
||||
Si un provider ne donne que USD, ne pas calculer SOL/EUR à partir d'un FX externe non tracé. Toute dérivation doit être explicitement décidée, avec provenance complète et sans franchir le hors-périmètre multi-provider complexe.
|
||||
|
||||
### 7.6 HTTP, retry, cache et fraîcheur
|
||||
|
||||
Décider :
|
||||
|
||||
```text
|
||||
request timeout
|
||||
retry safe GET
|
||||
traitement 429 / Retry-After
|
||||
eventuel cache local minimal ou aucun cache
|
||||
TTL/staleness contract
|
||||
batch size
|
||||
concurrency
|
||||
```
|
||||
|
||||
Ne pas copier mécaniquement le moteur de résilience on-chain si le besoin prix est plus petit. Réutiliser des patterns, pas une dépendance injustifiée.
|
||||
|
||||
### 7.7 Config
|
||||
|
||||
Auditer la forme documentaire nécessaire pour la future Price Desk :
|
||||
|
||||
```text
|
||||
nouveau document offchain ?
|
||||
extension d'un document existant ?
|
||||
provider id
|
||||
base URL
|
||||
API key/header secret
|
||||
timeouts
|
||||
profil par environnement
|
||||
```
|
||||
|
||||
Toute variable ajoutée doit respecter `KSP_SECRET_*` / `KSP_PUBLIC_*` et être inventoriée dans `.env.example`.
|
||||
|
||||
### 7.8 Live smoke
|
||||
|
||||
Définir un smoke opt-in qui :
|
||||
|
||||
```text
|
||||
ne hardcode aucun secret
|
||||
n'affiche aucun secret
|
||||
interroge réellement SOL/USD + SOL/EUR
|
||||
vérifie valeurs positives/plausibles sans figer un cours exact
|
||||
vérifie les identités/quotes/provenance
|
||||
reste borné par timeout
|
||||
```
|
||||
|
||||
Si un secret gratuit est requis, préférer un chemin operator-safe cohérent avec l'ownership Config et les smokes KSP existants.
|
||||
|
||||
---
|
||||
|
||||
## 8. Objectifs et livrables de `0.2.11`
|
||||
|
||||
Livrables attendus, sous réserve du sizing `pre.001` :
|
||||
|
||||
```text
|
||||
crates/ksp-offchain-transport-lib/
|
||||
Cargo workspace member
|
||||
price module/API publique provider-neutral
|
||||
settings runtime publics
|
||||
provider initial + wire DTOs privés ou bornés
|
||||
unit/integration tests
|
||||
adapter Config -> Off-chain Transport
|
||||
config/schema/example nécessaires
|
||||
.env.example si secret/provider config
|
||||
smoke live opt-in
|
||||
README.md
|
||||
USAGE.md
|
||||
plan 0.2.11
|
||||
validation 0.2.11
|
||||
deltas complets
|
||||
prompt 0.2.12 à la fermeture seulement
|
||||
```
|
||||
|
||||
Noms documentaires recommandés :
|
||||
|
||||
```text
|
||||
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
|
||||
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Hors périmètre explicite
|
||||
|
||||
```text
|
||||
Price Desk Tauri
|
||||
modification Wallet Desk
|
||||
OHLCV/candles
|
||||
historique/backfill prix complet
|
||||
order books
|
||||
DEX routing/quotes
|
||||
swap execution
|
||||
metadata token
|
||||
IPFS/Arweave
|
||||
news/sentiment
|
||||
agrégation/consensus multi-provider complexe
|
||||
fallback automatique multi-provider avant besoin démontré
|
||||
WebSocket/SSE streaming sauf si pre.001 démontre qu'il est indispensable au minimum de release
|
||||
nouvelle abstraction réseau universelle partagée avec ksp-onchain-transport-lib
|
||||
Helius gRPC
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Contraintes sécurité, erreurs et API
|
||||
|
||||
### 10.1 Secrets
|
||||
|
||||
```text
|
||||
aucune API key en source/config versionnée/delta/log/debug
|
||||
Config possède la résolution des secrets
|
||||
Off-chain Transport reçoit des settings déjà résolus
|
||||
redaction des URLs/headers/DTO Debug
|
||||
les erreurs remote ne recopient pas des payloads arbitraires dans KspError context
|
||||
```
|
||||
|
||||
### 10.2 Numeric safety
|
||||
|
||||
Les prix et conversions doivent avoir des limites de taille/format déterministes. Un provider malveillant ou cassé ne doit pas provoquer allocations non bornées, NaN/Inf silencieux ou overflow.
|
||||
|
||||
### 10.3 API provider-neutral
|
||||
|
||||
Le contrat commun ne doit pas prétendre que toutes les sources sont équivalentes. La provenance provider et le type de donnée doivent rester observables. Les extensions propres à un provider ne gonflent pas le DTO commun sans justification.
|
||||
|
||||
### 10.4 Observabilité
|
||||
|
||||
Logging via `ksp-logging-lib` uniquement. Les logs peuvent exposer provider, opération, pair, latence, status/catégorie d'erreur et fraîcheur sûre ; jamais credential, URL secrète ou réponse brute non bornée.
|
||||
|
||||
---
|
||||
|
||||
## 11. Première mission `0.2.11-pre.001` — gate obligatoire
|
||||
|
||||
### 11.1 Baseline stable
|
||||
|
||||
Avant modification lourde :
|
||||
|
||||
```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.11
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Si `deltas/0.2.11` n'existe pas encore, adapter seulement le chemin de l'audit Markdown ; ne pas considérer son absence comme erreur.
|
||||
|
||||
### 11.2 Audit interne
|
||||
|
||||
Inventorier :
|
||||
|
||||
```text
|
||||
frontières architecture Off-chain Transport
|
||||
patterns settings/errors/logging existants
|
||||
adapter Config actuel
|
||||
features reqwest/tokio déjà disponibles
|
||||
aucune crate/naming collision
|
||||
besoins futurs Price Desk/Wallet Desk qui imposent une API durable
|
||||
```
|
||||
|
||||
### 11.3 Audit externe actuel
|
||||
|
||||
Pour chaque candidat retenu, consigner :
|
||||
|
||||
```text
|
||||
source primaire
|
||||
endpoint(s)
|
||||
auth
|
||||
plan gratuit réellement utilisable
|
||||
rate limits
|
||||
batch limit
|
||||
quotes disponibles
|
||||
freshness/cache/update time
|
||||
identifiants d'actifs
|
||||
wire types
|
||||
null/missing/error semantics
|
||||
historique/streaming seulement comme inventaire, pas comme scope automatique
|
||||
```
|
||||
|
||||
Réauditer spécialement Pyth après le changement annoncé du 2026-08-26 16:00 UTC.
|
||||
|
||||
### 11.4 Matrice sémantique
|
||||
|
||||
Comparer séparément :
|
||||
|
||||
```text
|
||||
market aggregator
|
||||
Solana swap-derived heuristic price
|
||||
oracle price + confidence
|
||||
DEX pair/pool price
|
||||
```
|
||||
|
||||
Identifier quelles données peuvent partager un contrat KSP sans perte de sens.
|
||||
|
||||
### 11.5 Threat model
|
||||
|
||||
Au minimum :
|
||||
|
||||
```text
|
||||
credential leak
|
||||
provider spoof/redirect
|
||||
hostile JSON / huge body
|
||||
NaN/Inf/extreme exponent
|
||||
stale price
|
||||
wrong asset mapping
|
||||
symbol collision
|
||||
wrong quote currency
|
||||
partial batch response
|
||||
rate-limit storm
|
||||
retry amplification
|
||||
provider returns null/missing
|
||||
silent USD->EUR conversion error
|
||||
```
|
||||
|
||||
### 11.6 Sizing
|
||||
|
||||
Estimer chaque tranche pour rester sous environ 15–20 minutes de travail effectif. Si l'intégration Config + provider + numeric model + live smoke dépasse une session raisonnable, scinder avant code lourd.
|
||||
|
||||
### 11.7 Documents de sortie
|
||||
|
||||
`pre.001` doit produire au minimum :
|
||||
|
||||
```text
|
||||
docs/plans/018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md
|
||||
docs/validation/014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md
|
||||
deltas/0.2.11/pre.001.md
|
||||
```
|
||||
|
||||
Aucun README final n'est requis avant que le contrat réel soit stabilisé.
|
||||
|
||||
### Critères de sortie de `pre.001`
|
||||
|
||||
Le gate est vert seulement si :
|
||||
|
||||
```text
|
||||
baseline stable comprise
|
||||
sources externes actuelles citées
|
||||
auth/limites/testabilité des providers comparées
|
||||
sémantique de prix explicitée
|
||||
représentation numérique décidée ou question bloquante clairement isolée
|
||||
provider initial choisi avec justification
|
||||
SOL/USD + SOL/EUR faisables sans conversion opaque
|
||||
surface Config envisagée
|
||||
threat model écrit
|
||||
forecast prerelease recalibré
|
||||
aucun code provider lourd commencé prématurément
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. Prévision souple initiale des prereleases
|
||||
|
||||
Prévision initiale, à recalibrer à `pre.001` :
|
||||
|
||||
```text
|
||||
pre.001 audit actuel providers + sémantique prix + numeric model + threat model + sizing + plan
|
||||
pre.002 crate foundation + contrats prix/settings/errors provider-neutral + tests canaris
|
||||
pre.003 premier provider + parsing/batching/fraîcheur + tests déterministes
|
||||
pre.004 composition Config + profil/secret éventuel + smoke live provider
|
||||
pre.005 gate technique/live final + graphes si dépendances changées
|
||||
pre.006 réconciliation documentaire finale plan/validation/README/USAGE
|
||||
pre.007 publication minimale : prompt 0.2.12 + CHANGELOG + ROADMAP
|
||||
rel.001 publication stable
|
||||
```
|
||||
|
||||
Cette numérotation est **souple**. Si `pre.001` démontre que Config peut être inclus proprement dans `pre.003`, fusionner plutôt que créer une tranche artificielle. Si un défaut nécessite un fix ou une tranche supplémentaire, l'insérer sans mélanger les couloirs finaux.
|
||||
|
||||
La séparation de fermeture reste normative :
|
||||
|
||||
```text
|
||||
gate technique/live
|
||||
puis réconciliation documentaire
|
||||
puis publication minimale
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 13. Versionnement, deltas, commits, archives et tags
|
||||
|
||||
Rappels :
|
||||
|
||||
```text
|
||||
workspace.package.version suit chaque prerelease non-fix
|
||||
0.2.11-pre.001 -> Cargo 0.2.11-pre.1
|
||||
fix -> 0.2.11-pre.1.fix.1
|
||||
```
|
||||
|
||||
Deltas :
|
||||
|
||||
```text
|
||||
deltas/0.2.11/pre.001.md
|
||||
deltas/0.2.11/pre.001-fix.001.md
|
||||
...
|
||||
deltas/0.2.11/rel.001.md
|
||||
```
|
||||
|
||||
Commit identifiers :
|
||||
|
||||
```text
|
||||
v0.2.11-pre.001
|
||||
v0.2.11-pre.001-fix.001
|
||||
...
|
||||
v0.2.11-rel.001
|
||||
```
|
||||
|
||||
Aucun tag Git prerelease. Seule la publication stable crée :
|
||||
|
||||
```text
|
||||
v0.2.11
|
||||
```
|
||||
|
||||
Les archives d'échange restent des deltas minimaux `ksp-general-<delivery-id>.zip` contenant uniquement les fichiers ajoutés/modifiés et le delta correspondant.
|
||||
|
||||
---
|
||||
|
||||
## 14. Validation opérateur et application
|
||||
|
||||
Après chaque tranche Rust :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Puis tests ciblés. Aux gates finaux :
|
||||
|
||||
```bash
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.11
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-offchain-transport-lib
|
||||
cargo tree -p ksp-offchain-transport-lib --duplicates
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Ne jamais déclarer une commande PASS si elle n'a pas été exécutée.
|
||||
|
||||
Si un live smoke nécessite une clé gratuite, ne pas la fournir en argument CLI visible et ne jamais la recopier dans les deltas.
|
||||
|
||||
---
|
||||
|
||||
## 15. Tests attendus selon le scope retenu
|
||||
|
||||
Au minimum :
|
||||
|
||||
```text
|
||||
construction/validation settings
|
||||
redaction Debug
|
||||
asset/quote identity
|
||||
numeric decode and bounds
|
||||
missing/null price semantics
|
||||
partial batch response
|
||||
provider wire fixtures
|
||||
HTTP status/timeout/429 mapping
|
||||
secret non-leak errors
|
||||
Config adapter/provenance si secret
|
||||
public API canaries
|
||||
live SOL/USD + SOL/EUR opt-in
|
||||
```
|
||||
|
||||
Tester aussi les cas adversariaux du provider choisi : prix à zéro/négatif si wire possible, valeur exponentielle énorme, timestamp absent/futur, token inconnu et corps de réponse oversized selon les capacités HTTP retenues.
|
||||
|
||||
---
|
||||
|
||||
## 16. Critères de clôture de `0.2.11`
|
||||
|
||||
La release ne peut être clôturée que si :
|
||||
|
||||
```text
|
||||
ksp-offchain-transport-lib existe et respecte les frontières
|
||||
surface prix provider-neutral petite et documentée
|
||||
premier provider réellement intégré sans SDK inutile
|
||||
SOL/USD + SOL/EUR validés
|
||||
représentation numérique déterministe
|
||||
provenance/fraîcheur explicites
|
||||
Config compose sans dépendance inverse
|
||||
secrets redacted
|
||||
smoke live accessible et vert
|
||||
workspace complet vert
|
||||
README/USAGE/plan/validation réconciliés
|
||||
prompt 0.2.12 préparé seulement dans la dernière prerelease
|
||||
```
|
||||
|
||||
Aucune obligation de supporter plusieurs providers dans cette release. L'interchangeabilité doit être démontrée par la séparation du contrat et de l'adapter, pas par l'ajout prématuré de cinq implémentations.
|
||||
|
||||
---
|
||||
|
||||
## 17. Release/session suivante envisagée
|
||||
|
||||
Sous réserve du sizing futur :
|
||||
|
||||
```text
|
||||
0.2.12 — Price Desk + intégration prix Wallet Desk
|
||||
```
|
||||
|
||||
Mission envisagée :
|
||||
|
||||
```text
|
||||
petite app Tauri spécialisée pour visualiser/rafraîchir les prix
|
||||
provenance/état/fraîcheur observables
|
||||
Config + ksp-offchain-transport-lib réutilisés
|
||||
puis intégration de la même capacité dans ksp-app-wallet-desk
|
||||
aucune duplication de récupération/normalisation dans les apps
|
||||
```
|
||||
|
||||
Puis :
|
||||
|
||||
```text
|
||||
0.2.13 — interface/wire foundation
|
||||
0.2.14 — program-api foundation
|
||||
```
|
||||
|
||||
Helius LaserStream gRPC reste en TODO jusqu'à disponibilité d'un accès live raisonnable.
|
||||
|
||||
---
|
||||
|
||||
## 18. Instruction d'ouverture
|
||||
|
||||
Au démarrage de la nouvelle session :
|
||||
|
||||
1. vérifier que la base réelle est exactement `v0.2.10` ;
|
||||
2. lire les sources internes dans l'ordre imposé ;
|
||||
3. exécuter la baseline avant modification lourde ;
|
||||
4. réauditer les providers de prix depuis leurs sources primaires actuelles, **avec priorité au changement Pyth du 2026-08-26** ;
|
||||
5. comparer les sémantiques agrégateur / swap-derived / oracle / DEX pair ;
|
||||
6. trancher numeric model, asset identity, freshness et provider initial ;
|
||||
7. produire plan + validation + sizing `pre.001` ;
|
||||
8. **ne pas commencer le provider lourd avant que ce gate soit vert**.
|
||||
|
||||
Le premier message de la session doit donc commencer par l'audit et le sizing, pas par une proposition de code déjà figée.
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
# file: scripts/audit_markdown_tables.py
|
||||
# version: 1
|
||||
# version: 2
|
||||
|
||||
"""Validate KSP Markdown table formatting for explicitly supplied files or directories."""
|
||||
"""Validate KSP Markdown tables and vertical spacing for explicitly supplied files or directories."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -12,6 +12,7 @@ import re
|
||||
import sys
|
||||
|
||||
_SEPARATOR_CELL = re.compile(r"^:?-{3,}:?$")
|
||||
_IGNORED_DIRECTORY_NAMES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target"})
|
||||
|
||||
|
||||
def _markdown_files(paths: list[str]) -> list[pathlib.Path]:
|
||||
@@ -19,7 +20,13 @@ def _markdown_files(paths: list[str]) -> 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()))
|
||||
files.extend(
|
||||
sorted(
|
||||
candidate
|
||||
for candidate in path.rglob("*.md")
|
||||
if candidate.is_file() and not any(part in _IGNORED_DIRECTORY_NAMES for part in candidate.parts)
|
||||
)
|
||||
)
|
||||
elif path.is_file() and path.suffix.lower() == ".md":
|
||||
files.append(path)
|
||||
else:
|
||||
@@ -101,9 +108,47 @@ def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> lis
|
||||
return errors
|
||||
|
||||
|
||||
def _validate_blank_lines(path: pathlib.Path, lines: list[str]) -> list[str]:
|
||||
errors: list[str] = []
|
||||
fence_marker: str | None = None
|
||||
blank_run_start: int | None = None
|
||||
blank_run_length = 0
|
||||
|
||||
def flush_blank_run() -> None:
|
||||
nonlocal blank_run_start, blank_run_length
|
||||
if blank_run_start is not None and blank_run_length >= 2:
|
||||
errors.append(
|
||||
f"{path}:{blank_run_start}: {blank_run_length} consecutive blank lines are forbidden outside fenced code blocks; keep at most one"
|
||||
)
|
||||
blank_run_start = None
|
||||
blank_run_length = 0
|
||||
|
||||
for line_number, line in enumerate(lines, start=1):
|
||||
stripped = line.lstrip()
|
||||
if stripped.startswith("```") or stripped.startswith("~~~"):
|
||||
flush_blank_run()
|
||||
marker = stripped[:3]
|
||||
if fence_marker is None:
|
||||
fence_marker = marker
|
||||
elif marker == fence_marker:
|
||||
fence_marker = None
|
||||
continue
|
||||
if fence_marker is not None:
|
||||
continue
|
||||
if line.strip() == "":
|
||||
if blank_run_start is None:
|
||||
blank_run_start = line_number
|
||||
blank_run_length += 1
|
||||
continue
|
||||
flush_blank_run()
|
||||
|
||||
flush_blank_run()
|
||||
return errors
|
||||
|
||||
|
||||
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
|
||||
lines = path.read_text(encoding="utf-8").splitlines()
|
||||
errors: list[str] = []
|
||||
errors = _validate_blank_lines(path, lines)
|
||||
table_count = 0
|
||||
fence_marker: str | None = None
|
||||
index = 0
|
||||
@@ -135,7 +180,7 @@ def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
|
||||
|
||||
|
||||
def main() -> int:
|
||||
"""Audit Markdown tables in the explicitly selected scope."""
|
||||
"""Audit KSP Markdown formatting in the explicitly selected scope."""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
|
||||
|
||||
Reference in New Issue
Block a user