v0.2.10-pre.002
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 262
|
# version: 263
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
|
members = ["crates/ksp-app-config-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-logging-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.2.10-pre.1"
|
version = "0.2.10-pre.2"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -79,6 +79,59 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"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": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"profile_id": "mainnet_public",
|
"profile_id": "mainnet_public",
|
||||||
"endpoints": [
|
"endpoints": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-config-lib/unit_tests/transport.rs
|
// file: crates/ksp-config-lib/unit_tests/transport.rs
|
||||||
// version: 10
|
// version: 11
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fixture_transport_profile_maps_complete_runtime_contract() {
|
fn fixture_transport_profile_maps_complete_runtime_contract() {
|
||||||
@@ -133,6 +133,45 @@ fn committed_transport_document_maps_default_and_explicit_profiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn committed_v3_orbitflare_devnet_profile_maps_provider_neutral_yellowstone_grpc_without_metadata() {
|
||||||
|
let engine = committed_engine();
|
||||||
|
let engine = match engine {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let environment = crate::ConfigEnvironment::from_maps(std::collections::BTreeMap::new(), 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 without gRPC metadata: {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!(endpoint.metadata().is_empty(), "OrbitFlare Devnet Free profile must not invent gRPC metadata before live proof requires it");
|
||||||
|
let debug = format!("{endpoint:?}");
|
||||||
|
assert!(!debug.contains("orbitflare.com"), "Transport settings Debug must not expose OrbitFlare gRPC endpoint URLs");
|
||||||
|
assert!(!debug.contains("X-ORBIT-KEY"), "OrbitFlare Customer API credentials must never enter Yellowstone Transport settings");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn committed_v3_publicnode_profiles_map_provider_neutral_yellowstone_grpc_with_network_scoped_secret_x_tokens() {
|
fn committed_v3_publicnode_profiles_map_provider_neutral_yellowstone_grpc_with_network_scoped_secret_x_tokens() {
|
||||||
let engine = committed_engine();
|
let engine = committed_engine();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
<!-- file: crates/ksp-onchain-transport-lib/README.md -->
|
||||||
<!-- version: 22 -->
|
<!-- version: 23 -->
|
||||||
|
|
||||||
# `ksp-onchain-transport-lib`
|
# `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`.
|
LaserStream **gRPC** reste un backend distinct, hors de cette façade, de `WsProtocolKind` et de la Config WebSocket `helius_laserstream`.
|
||||||
|
|
||||||
|
|
||||||
## Yellowstone gRPC standard
|
## Yellowstone gRPC standard
|
||||||
|
|
||||||
La foundation `0.2.9` ajoute un troisième backend réseau distinct de HTTP et WebSocket. Le moteur est KSP-owned : `yellowstone-grpc-proto` fournit le wire publié, tandis que Tonic reste encapsulé derrière les types crate-root KSP. Aucun client Tonic brut ni type protobuf upstream n’est réexporté.
|
La 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é.
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// file: crates/ksp-onchain-transport-lib/tests/yellowstone_orbitflare_smoke.rs
|
||||||
|
// version: 1
|
||||||
|
|
||||||
|
//! Opt-in live OrbitFlare Devnet characterization smoke for provider-neutral Yellowstone gRPC Subscribe.
|
||||||
|
|
||||||
|
fn orbitflare_devnet_endpoint() -> 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,
|
||||||
|
);
|
||||||
|
return std::result::Result::Ok(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,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
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; connects without metadata, waits for Slot plus standard server Ping, then closes"]
|
||||||
|
async fn orbitflare_devnet_yellowstone_streams_slots_and_emits_standard_server_ping_without_metadata() {
|
||||||
|
let endpoint = match orbitflare_devnet_endpoint() {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(error) => panic!("programmatic OrbitFlare Devnet Yellowstone settings must be valid without metadata: {error:?}"),
|
||||||
|
};
|
||||||
|
assert!(endpoint.metadata().is_empty(), "OrbitFlare Devnet characterization must not invent gRPC metadata");
|
||||||
|
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-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 connection without metadata must succeed or classify the provider auth gate: {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 without metadata must open or classify the provider auth gate: {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"
|
||||||
|
);
|
||||||
|
}
|
||||||
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.
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
<!-- file: docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md -->
|
<!-- file: docs/plans/017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
|
|
||||||
# Plan `0.2.10` — OrbitFlare Yellowstone gRPC
|
# Plan `0.2.10` — OrbitFlare Yellowstone gRPC
|
||||||
|
|
||||||
**Statut courant : `0.2.10-pre.001` ouvre la release par un audit provider actuel. Le gate d'architecture est positif avec une contrainte renforcée : le moteur gRPC N1 et le standard Yellowstone N2 livrés par `0.2.9` sont immuables pour cette release. OrbitFlare doit être composé au-dessus de ces couches ; aucune modification du moteur n'est autorisée pour satisfaire une policy provider.**
|
**Statut courant : `0.2.10-pre.002` matérialise le profil Config V3 `orbitflare_devnet` et un smoke opt-in de caractérisation `Subscribe -> Slot + Ping` construit exclusivement sur le standard Yellowstone existant. Le moteur gRPC N1 et le standard N2 restent inchangés ; le verdict live Devnet est un gate opérateur de cette tranche.**
|
||||||
|
|
||||||
## 1. Base et autorité
|
## 1. Base et autorité
|
||||||
|
|
||||||
@@ -158,21 +158,21 @@ Une façade OrbitFlare publique n'est créée que si un consumer KSP doit réell
|
|||||||
|
|
||||||
Preuves fournies le 2026-08-25 :
|
Preuves fournies le 2026-08-25 :
|
||||||
|
|
||||||
| Gate | Résultat |
|
| Gate | Résultat |
|
||||||
|-------------------------------------------|----------------------------------|
|
|-------------------------------------------|------------------------------------------|
|
||||||
| `cargo fmt --all` | PASS |
|
| `cargo fmt --all` | PASS |
|
||||||
| audit Rust workspace | PASS, 0 candidate export |
|
| audit Rust workspace | PASS, 0 candidate export |
|
||||||
| audit Markdown tables | PASS, 87 tables et 261 files |
|
| audit Markdown tables | PASS, 97 tables et 233 files sur `pre.1` |
|
||||||
| `cargo check --workspace` | PASS |
|
| `cargo check --workspace` | PASS |
|
||||||
| `cargo clippy --workspace --all-targets` | PASS |
|
| `cargo clippy --workspace --all-targets` | PASS |
|
||||||
| `cargo test --workspace` | PASS |
|
| `cargo test --workspace` | PASS |
|
||||||
| Transport unit | 383 sur 383 PASS |
|
| Transport unit | 383 sur 383 PASS |
|
||||||
| Transport public API | 49 sur 49 PASS |
|
| Transport public API | 49 sur 49 PASS |
|
||||||
| Transport release completeness | 43 sur 43 PASS |
|
| Transport release completeness | 43 sur 43 PASS |
|
||||||
| Config unit | 113 sur 113 PASS |
|
| Config unit | 113 sur 113 PASS |
|
||||||
| PublicNode Yellowstone live | ignored opt-in comme attendu |
|
| PublicNode Yellowstone live | ignored opt-in comme attendu |
|
||||||
| `cargo tree --duplicates` Transport | fourni et inspecté |
|
| `cargo tree --duplicates` Transport | fourni et inspecté |
|
||||||
| `cargo tree -p ksp-onchain-transport-lib` | à rejouer avant commit `pre.001` |
|
| `cargo tree -p ksp-onchain-transport-lib` | fourni sur `0.2.10-pre.1` |
|
||||||
|
|
||||||
Versions visibles dans le graphe fourni :
|
Versions visibles dans le graphe fourni :
|
||||||
|
|
||||||
@@ -419,12 +419,24 @@ pas de heartbeat dans grpc_defaults
|
|||||||
pas de secret tant que le Devnet Free n'en exige pas
|
pas de secret tant que le Devnet Free n'en exige pas
|
||||||
```
|
```
|
||||||
|
|
||||||
Profil prévu :
|
Profil matérialisé en `pre.002` :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
orbitflare_devnet
|
orbitflare_devnet
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Le profil conserve les companions HTTP/WS Solana Devnet standards et ajoute exactement un endpoint gRPC :
|
||||||
|
|
||||||
|
```text
|
||||||
|
name = orbitflare_solana_devnet_yellowstone
|
||||||
|
provider = orbitflare
|
||||||
|
cluster = devnet
|
||||||
|
protocol = solana_yellowstone
|
||||||
|
url = http://devnet.rpc.orbitflare.com:10000
|
||||||
|
metadata = []
|
||||||
|
secret = []
|
||||||
|
```
|
||||||
|
|
||||||
Si le service opérateur réel impose ensuite un token gRPC :
|
Si le service opérateur réel impose ensuite un token gRPC :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -437,7 +449,7 @@ Cette variable n'est ajoutée à `.env.example` qu'après preuve qu'un secret da
|
|||||||
|
|
||||||
### 12.1 Premier canari
|
### 12.1 Premier canari
|
||||||
|
|
||||||
Le premier canari doit utiliser **le standard N2 existant directement** :
|
`pre.002` ajoute `tests/yellowstone_orbitflare_smoke.rs`. Ce canari opt-in utilise **le standard N2 existant directement** et ne dépend pas de Config, conformément à la frontière Transport -> Config interdite :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
endpoint = http://devnet.rpc.orbitflare.com:10000
|
endpoint = http://devnet.rpc.orbitflare.com:10000
|
||||||
@@ -533,8 +545,8 @@ pre.001 audit actuel + architecture immuable N1/N2 + auth/endpoints + free Devn
|
|||||||
preuve : plan 017 + validation 013 + delta + baseline
|
preuve : plan 017 + validation 013 + delta + baseline
|
||||||
|
|
||||||
pre.002 profil Config V3 OrbitFlare Devnet + smoke de caractérisation standard N2
|
pre.002 profil Config V3 OrbitFlare Devnet + smoke de caractérisation standard N2
|
||||||
preuve : Subscribe -> Slot + observation Ping serveur si disponible + probes provider ciblés
|
statique : profil sans metadata + canari Subscribe slots confirmed + fenêtre Ping 45 s + close borné
|
||||||
aucune modification moteur gRPC
|
live : Subscribe -> Slot + observation Ping serveur ; aucune modification moteur gRPC
|
||||||
|
|
||||||
pre.003 soit gate technique final si OrbitFlare reste 100 pourcent standard,
|
pre.003 soit gate technique final si OrbitFlare reste 100 pourcent standard,
|
||||||
soit tranche provider-specific minimale uniquement si pre.002 démontre une divergence réelle
|
soit tranche provider-specific minimale uniquement si pre.002 démontre une divergence réelle
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
|
<!-- file: docs/rules/RULES_DOCUMENTATION.md -->
|
||||||
<!-- version: 5 -->
|
<!-- version: 6 -->
|
||||||
|
|
||||||
# Règles de documentation
|
# 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-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`.
|
- **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
|
## Contenu et exactitude
|
||||||
|
|
||||||
- **DOC-CONTENT-001** — Une documentation décrit l'état réellement décidé ou validé et distingue explicitement les hypothèses, propositions, TODO et questions ouvertes.
|
- **DOC-CONTENT-001** — Une documentation décrit l'état réellement décidé ou validé et distingue explicitement les hypothèses, propositions, TODO et questions ouvertes.
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<!-- file: docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md -->
|
<!-- file: docs/validation/013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
|
|
||||||
# Validation `0.2.10` — OrbitFlare Yellowstone gRPC
|
# Validation `0.2.10` — OrbitFlare Yellowstone gRPC
|
||||||
|
|
||||||
**Statut courant : matrice ouverte par `0.2.10-pre.001`. Le gate d'architecture est positif. Le premier objectif live est le Devnet gratuit OrbitFlare via le standard Yellowstone KSP inchangé. Les verdicts provider non encore testés restent explicitement `PENDING` ou `UNKNOWN`.**
|
**Statut courant : `0.2.10-pre.002` matérialise le profil Config V3 OrbitFlare Devnet et le smoke opt-in de caractérisation sur le standard Yellowstone KSP inchangé. Les preuves statiques sont fermées ; `connect`, `Subscribe`, `Slot` et `Ping` restent `PENDING` jusqu'au run live opérateur.**
|
||||||
|
|
||||||
## 1. Autorités
|
## 1. Autorités
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ Yellowstone upstream actuel
|
|||||||
| Transport release completeness | 43 sur 43 PASS |
|
| Transport release completeness | 43 sur 43 PASS |
|
||||||
| Config unit | 113 sur 113 PASS |
|
| Config unit | 113 sur 113 PASS |
|
||||||
| graph duplicates Transport | fourni, aucun conflit N1 visible |
|
| graph duplicates Transport | fourni, aucun conflit N1 visible |
|
||||||
| graph complet Transport | PENDING avant commit |
|
| graph complet Transport | fourni sur `0.2.10-pre.1` PASS |
|
||||||
|
|
||||||
## 3. Invariant architecture
|
## 3. Invariant architecture
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ KSP ne prétend pas qu'un canal gRPC plaintext bénéficie d'une sécurité TLS
|
|||||||
| aucune metadata gRPC | SDK Go OrbitFlare | **DOCUMENTED** |
|
| aucune metadata gRPC | SDK Go OrbitFlare | **DOCUMENTED** |
|
||||||
| auth Devnet Free réelle | smoke KSP à exécuter | **PENDING** |
|
| auth Devnet Free réelle | smoke KSP à exécuter | **PENDING** |
|
||||||
|
|
||||||
Aucun secret opérateur n'est demandé pour `pre.001`.
|
Aucun secret opérateur n’est demandé pour le premier smoke `pre.002` ; la tentative initiale est explicitement sans metadata.
|
||||||
|
|
||||||
## 7. Heartbeat
|
## 7. Heartbeat
|
||||||
|
|
||||||
@@ -163,17 +163,17 @@ Ces valeurs restent provider-owned et ne deviennent pas des validations généri
|
|||||||
|
|
||||||
## 11. Config V3
|
## 11. Config V3
|
||||||
|
|
||||||
| Exigence | Verdict |
|
| Exigence | Verdict |
|
||||||
|-------------------------------------|-------------|
|
|-------------------------------------|-----------------|
|
||||||
| nouveau format Config nécessaire | **NO** |
|
| nouveau format Config nécessaire | **NO** |
|
||||||
| `provider = orbitflare` | **PLANNED** |
|
| `provider = orbitflare` | **PASS STATIC** |
|
||||||
| `protocol = solana_yellowstone` | **PASS** |
|
| `protocol = solana_yellowstone` | **PASS STATIC** |
|
||||||
| `cluster = devnet` | **PLANNED** |
|
| `cluster = devnet` | **PASS STATIC** |
|
||||||
| Devnet URL publique | **PLANNED** |
|
| Devnet URL publique | **PASS STATIC** |
|
||||||
| secret metadata par défaut | **NO** |
|
| secret metadata par défaut | **NO / PASS** |
|
||||||
| `X-ORBIT-KEY` dans Transport Config | **FORBID** |
|
| `X-ORBIT-KEY` dans Transport Config | **FORBID** |
|
||||||
| `x-token` si token gRPC prouvé | **DEFER** |
|
| `x-token` si token gRPC prouvé | **DEFER** |
|
||||||
| heartbeat dans `grpc_defaults` | **NO** |
|
| heartbeat dans `grpc_defaults` | **NO** |
|
||||||
|
|
||||||
## 12. Smoke Devnet attendu
|
## 12. Smoke Devnet attendu
|
||||||
|
|
||||||
@@ -194,15 +194,15 @@ close borné
|
|||||||
|
|
||||||
Verdicts actuels :
|
Verdicts actuels :
|
||||||
|
|
||||||
| Preuve | Verdict |
|
| Preuve | Verdict |
|
||||||
|-----------------------------|-------------|
|
|------------------------------|----------------------------|
|
||||||
| endpoint parsé par N1 | EXPECTED |
|
| endpoint parsé par Config/N1 | **PASS STATIC** |
|
||||||
| connect Devnet | **PENDING** |
|
| connect Devnet | **PENDING** |
|
||||||
| Subscribe accepté | **PENDING** |
|
| Subscribe accepté | **PENDING** |
|
||||||
| Slot reçu | **PENDING** |
|
| Slot reçu | **PENDING** |
|
||||||
| server Ping reçu | **PENDING** |
|
| server Ping reçu | **PENDING** |
|
||||||
| auto reply KSP déterministe | **PASS** |
|
| auto reply KSP déterministe | **PASS N1** |
|
||||||
| close borné | **PASS N1** |
|
| close borné | **PASS N1 / LIVE PENDING** |
|
||||||
|
|
||||||
## 13. Provider overlay gate
|
## 13. Provider overlay gate
|
||||||
|
|
||||||
@@ -246,7 +246,7 @@ ownership/close provider bornés
|
|||||||
| baseline fmt/audits/check/clippy | **PASS** |
|
| baseline fmt/audits/check/clippy | **PASS** |
|
||||||
| workspace test | **PASS** |
|
| workspace test | **PASS** |
|
||||||
| graph duplicates | **PASS** |
|
| graph duplicates | **PASS** |
|
||||||
| graph complet Transport | **PENDING OPERATOR** |
|
| graph complet Transport | **PASS** |
|
||||||
| sources OrbitFlare actuelles | **PASS** |
|
| sources OrbitFlare actuelles | **PASS** |
|
||||||
| sources Yellowstone actuelles | **PASS** |
|
| sources Yellowstone actuelles | **PASS** |
|
||||||
| Free Devnet gRPC confirmé | **PASS** |
|
| Free Devnet gRPC confirmé | **PASS** |
|
||||||
@@ -267,6 +267,47 @@ Verdict :
|
|||||||
|
|
||||||
```text
|
```text
|
||||||
architecture/sizing gate = POSITIVE
|
architecture/sizing gate = POSITIVE
|
||||||
operator commit gate = PENDING full cargo tree + validations overlay
|
operator pre.001 gate = PASS
|
||||||
live provider gate = reserved for pre.002+
|
pre.002 static gate = READY FOR OPERATOR VALIDATION
|
||||||
|
live provider gate = PENDING pre.002 characterization
|
||||||
|
```
|
||||||
|
|
||||||
|
## 16. Gate `pre.002` candidat
|
||||||
|
|
||||||
|
| Critère | Verdict |
|
||||||
|
|-------------------------------------------|----------------------|
|
||||||
|
| Cargo `0.2.10-pre.2` | **PASS STATIC** |
|
||||||
|
| profil Config `orbitflare_devnet` | **PASS STATIC** |
|
||||||
|
| endpoint gRPC sans metadata | **PASS STATIC** |
|
||||||
|
| companions HTTP/WS Devnet préservés | **PASS STATIC** |
|
||||||
|
| nouveau format Config | **NO** |
|
||||||
|
| `.env.example` / secret OrbitFlare ajouté | **NO** |
|
||||||
|
| moteur N1 modifié | **NO** |
|
||||||
|
| standard N2 modifié | **NO** |
|
||||||
|
| SDK OrbitFlare ajouté | **NO** |
|
||||||
|
| smoke provider dans Transport | **PASS STATIC** |
|
||||||
|
| reconnect du smoke | zéro retry |
|
||||||
|
| fenêtre caractérisation | 45 secondes |
|
||||||
|
| `Subscribe -> Slot` live | **PENDING OPERATOR** |
|
||||||
|
| `SubscribeUpdate::Ping` live | **PENDING OPERATOR** |
|
||||||
|
| close live | **PENDING OPERATOR** |
|
||||||
|
| auth Devnet Free sans metadata | **PENDING OPERATOR** |
|
||||||
|
|
||||||
|
Commande live dédiée :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test -p ksp-onchain-transport-lib --test yellowstone_orbitflare_smoke -- --ignored --nocapture
|
||||||
|
```
|
||||||
|
|
||||||
|
Le résultat live décide la suite :
|
||||||
|
|
||||||
|
```text
|
||||||
|
Slot + Ping PASS
|
||||||
|
-> OrbitFlare reste standard ; aucun provider heartbeat/facade
|
||||||
|
|
||||||
|
connection/auth failure
|
||||||
|
-> classifier le service/licence réel avant toute metadata
|
||||||
|
|
||||||
|
Slot PASS mais Ping absent
|
||||||
|
-> divergence heartbeat à prouver avant une couche provider-specific
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# file: scripts/audit_markdown_tables.py
|
# 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
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -12,6 +12,7 @@ import re
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
_SEPARATOR_CELL = re.compile(r"^:?-{3,}:?$")
|
_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]:
|
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:
|
for raw_path in paths:
|
||||||
path = pathlib.Path(raw_path)
|
path = pathlib.Path(raw_path)
|
||||||
if path.is_dir():
|
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":
|
elif path.is_file() and path.suffix.lower() == ".md":
|
||||||
files.append(path)
|
files.append(path)
|
||||||
else:
|
else:
|
||||||
@@ -101,9 +108,47 @@ def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> lis
|
|||||||
return errors
|
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]]:
|
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
|
||||||
lines = path.read_text(encoding="utf-8").splitlines()
|
lines = path.read_text(encoding="utf-8").splitlines()
|
||||||
errors: list[str] = []
|
errors = _validate_blank_lines(path, lines)
|
||||||
table_count = 0
|
table_count = 0
|
||||||
fence_marker: str | None = None
|
fence_marker: str | None = None
|
||||||
index = 0
|
index = 0
|
||||||
@@ -135,7 +180,7 @@ def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
|
|||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
"""Audit Markdown tables in the explicitly selected scope."""
|
"""Audit KSP Markdown formatting in the explicitly selected scope."""
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
|
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
|
||||||
|
|||||||
Reference in New Issue
Block a user