diff --git a/Cargo.toml b/Cargo.toml index 0554a0a..ed7d708 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 604 +# version: 605 [workspace] resolver = "3" members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-raw-transaction-ingest-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-store-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-raw-transaction-lib", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib", "crates/ksp-worker-api", "crates/ksp-worker-raw-transaction-ingest-lib"] [workspace.package] -version = "0.3.15-pre.6.fix.2" +version = "0.3.15-pre.6.fix.3" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-app-raw-transaction-ingest-desk/README.md b/crates/ksp-app-raw-transaction-ingest-desk/README.md index 41506e3..179b1fd 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/README.md +++ b/crates/ksp-app-raw-transaction-ingest-desk/README.md @@ -1,5 +1,5 @@ - + # `ksp-app-raw-transaction-ingest-desk` @@ -28,6 +28,7 @@ Worker -> acquisition continue et lifecycle d'exécution L'inventaire de routes est calculé côté Rust à partir du composite Config validé et des settings Transport/Store résolus. Il ne lance aucun probe réseau et n'ouvre ni Store ni Worker. Les profils applicatifs sont réseau-centriques (`devnet`, `mainnet`, `testnet`). Un profil peut agréger plusieurs profils Transport du même réseau : le provider reste une source de capability et ne devient jamais une identité réseau ni un choix de profil applicatif. +Une route explicitement liée à un provider n’est projetée pour un réseau que si le composite déclare une source Transport de ce provider. Ainsi, la route Helius Transaction existe sur Devnet/Mainnet mais n’est pas présentée sur Testnet tant qu’Helius ne fournit pas de source Testnet configurée. Le frontend ne reçoit aucune URL, credential, URI Store, metadata secrète, source key, handle runtime ou payload `RawTransaction`. diff --git a/crates/ksp-app-raw-transaction-ingest-desk/USAGE.md b/crates/ksp-app-raw-transaction-ingest-desk/USAGE.md index 5eb4b1a..1ec96ee 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/USAGE.md +++ b/crates/ksp-app-raw-transaction-ingest-desk/USAGE.md @@ -1,5 +1,5 @@ - + # Utilisation de `ksp-app-raw-transaction-ingest-desk` @@ -32,6 +32,7 @@ génération d'inventaire `Configured` signifie uniquement que toutes les requirements Config nécessaires à la route sont cohérentes. Les profils `solana-public` standard committés déclarent explicitement les capabilities `Logs` et `Block`; `standard-block-direct` est donc Configured sur les trois réseaux logiques tant que ce socle Config reste valide. Aucun probe réseau, aucune ouverture de Store et aucun Worker ne sont déclenchés par l'inventaire. Un refresh reconstruit l'inventaire depuis Config et publie une nouvelle génération. La sélection visuelle d'un réseau ne choisit aucune URL, provider ou ressource physique et ne démarre aucune acquisition. Une capability optionnelle dont le secret n'est pas résolu rend uniquement la route qui en dépend indisponible ; les routes satisfaites par le Transport de base du même réseau restent composables. +Une route provider-specific dont aucune source n’est déclarée pour le réseau n’est pas une erreur de configuration : elle est hors inventaire pour ce réseau. Par exemple, Helius Transaction est projetée sur Devnet/Mainnet lorsque `transport.helius` existe, mais pas sur Testnet lorsqu’aucune source Helius Testnet n’est déclarée. Les URLs, tokens, metadata secrètes, handles Transport/Store/Worker, URI Store, source keys et payloads RAW restent backend-only. diff --git a/crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs b/crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs index 5e4d733..b76a442 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/src/dto_route.rs -// version: 2 +// version: 3 //! Safe route-identity, Config-composability and lifecycle DTOs for Raw Transaction Ingest Desk. @@ -206,7 +206,7 @@ pub(crate) struct RawIngestProfileInventoryDto { pub(crate) network: std::option::Option, /// Stable composite profile identifier. pub(crate) profile_id: String, - /// Five logical routes in stable V1 presentation order. + /// Logical routes applicable to this network profile in stable V1 presentation order; provider-specific routes may be absent when their Config source is not declared. pub(crate) routes: std::vec::Vec, } diff --git a/crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs b/crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs index a45121e..03ff16f 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/src/route_inventory.rs -// version: 2 +// version: 3 //! Config-only logical route inventory for Raw Transaction Ingest Desk. @@ -16,6 +16,7 @@ struct RouteCapabilities { has_standard_logs: bool, has_standard_block: bool, has_helius_transaction: bool, + helius_source_declared: bool, helius_source_missing_secret: bool, yellowstone_source_missing_secret: bool, } @@ -199,6 +200,9 @@ fn build_profile_inventory( crate::RawIngestRouteUnavailableReason::ProfileUnresolved, ); } + if component_id == crate::COMPOSITE_COMPONENT_ID_TRANSPORT_HELIUS { + capabilities.helius_source_declared = true; + } if component.resolved().file_id().as_str() != ksp_config_lib::FILE_ID_STD_TRANSPORT { return unavailable_profile( profile_id, @@ -257,7 +261,7 @@ fn build_configured_profile_routes(capabilities: &RouteCapabilities, network: &s } else { crate::RawIngestRouteUnavailableReason::MissingHeliusTransactionCapability }; - return vec![ + let mut routes = vec![ route_with_requirements( crate::RawIngestRouteId::YellowstoneHydrated, network, @@ -279,20 +283,23 @@ fn build_configured_profile_routes(capabilities: &RouteCapabilities, network: &s network, &[(capabilities.has_standard_block, crate::RawIngestRouteUnavailableReason::MissingWsBlockCapability)], ), - route_with_requirements( + ]; + if capabilities.helius_source_declared { + routes.push(route_with_requirements( crate::RawIngestRouteId::HeliusTransactionHydrated, network, &[ (capabilities.has_helius_transaction, helius_reason), (capabilities.has_get_transaction, crate::RawIngestRouteUnavailableReason::MissingHttpGetTransaction), ], - ), - route_with_requirements( - crate::RawIngestRouteId::HttpBlockPolling, - network, - &[(capabilities.has_http_block_scan, crate::RawIngestRouteUnavailableReason::MissingHttpBlockScan)], - ), - ]; + )); + } + routes.push(route_with_requirements( + crate::RawIngestRouteId::HttpBlockPolling, + network, + &[(capabilities.has_http_block_scan, crate::RawIngestRouteUnavailableReason::MissingHttpBlockScan)], + )); + return routes; } fn route_with_requirements( diff --git a/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_security.rs b/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_security.rs index 3101f92..9058c2a 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_security.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_security.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/tests/desktop_security.rs -// version: 2 +// version: 3 //! Desktop security canaries for the Raw Transaction Ingest Desk scaffold. @@ -64,7 +64,7 @@ fn pre_006_frontend_tracing_is_control_inventory_and_command_oriented_only() { assert!(main.contains("navigation tab clicked")); assert!(main.contains("runtime status refresh requested")); assert!(main.contains("Config route inventory refresh requested")); - assert!(main.contains("logical profile selected")); + assert!(main.contains("logical network selected")); let invoke = read_text(app_root().join("frontend/ts/invoke.ts").as_path()); assert!(invoke.contains("Frontend IPC command requested")); for forbidden in ["apiKey", "authorization", "connectionUri", "endpointUrl", "sourceKey", "rawTransaction", "transactionPayload", "x-token"] { diff --git a/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_inventory.rs b/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_inventory.rs index c43c44f..21ea64b 100644 --- a/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_inventory.rs +++ b/crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_inventory.rs @@ -1,5 +1,5 @@ // file: crates/ksp-app-raw-transaction-ingest-desk/unit_tests/route_inventory.rs -// version: 3 +// version: 4 #[test] fn pre_006_route_requirement_projection_is_fail_closed_and_ordered() { @@ -38,7 +38,7 @@ fn pre_006_unavailable_profile_projects_all_five_routes_without_physical_materia } #[test] -fn pre_006_fix_002_network_profiles_aggregate_same_network_transport_capabilities_and_standard_block() { +fn pre_006_fix_003_network_profiles_aggregate_same_network_capabilities_and_omit_undeclared_provider_routes() { let management = committed_management(); assert!(management.is_ok()); let management = match management { @@ -91,12 +91,8 @@ fn pre_006_fix_002_network_profiles_aggregate_same_network_transport_capabilitie assert_optional_secret_route(testnet, crate::RawIngestRouteId::YellowstoneHydrated); assert_route(testnet, crate::RawIngestRouteId::StandardLogsHydrated, true, std::option::Option::None); assert_route(testnet, crate::RawIngestRouteId::StandardBlockDirect, true, std::option::Option::None); - assert_route( - testnet, - crate::RawIngestRouteId::HeliusTransactionHydrated, - false, - std::option::Option::Some(crate::RawIngestRouteUnavailableReason::MissingHeliusTransactionCapability), - ); + assert_route_absent(testnet, crate::RawIngestRouteId::HeliusTransactionHydrated); + assert_eq!(testnet.routes.len(), 4); assert_route(testnet, crate::RawIngestRouteId::HttpBlockPolling, true, std::option::Option::None); } let serialized = serde_json::to_string(&inventory); @@ -121,7 +117,7 @@ fn pre_006_fix_002_network_profiles_aggregate_same_network_transport_capabilitie } #[test] -fn pre_006_fix_002_base_network_routes_remain_configured_independently_of_optional_sources() { +fn pre_006_fix_003_base_network_routes_remain_configured_independently_of_optional_sources() { let management = committed_management(); assert!(management.is_ok()); let management = match management { @@ -198,6 +194,11 @@ fn assert_optional_secret_route(profile: &crate::RawIngestProfileInventoryDto, r } } +fn assert_route_absent(profile: &crate::RawIngestProfileInventoryDto, route_id: crate::RawIngestRouteId) { + let route = profile.routes.iter().find(|route| return route.route_id == route_id); + assert!(route.is_none()); +} + fn assert_route( profile: &crate::RawIngestProfileInventoryDto, route_id: crate::RawIngestRouteId, diff --git a/deltas/0.3.15/pre.006-fix.003.md b/deltas/0.3.15/pre.006-fix.003.md new file mode 100644 index 0000000..86c7989 --- /dev/null +++ b/deltas/0.3.15/pre.006-fix.003.md @@ -0,0 +1,44 @@ + + + +# Delta `0.3.15-pre.006-fix.003` + +## Objet + +Corriger la classification de `helius-transaction-hydrated` sur Testnet sans inventer une capability provider absente, et réaligner le canari de tracing frontend sur le modèle réseau-centrique. + +## Applicabilité des routes provider-specific + +Le catalogue V1 reste globalement borné à cinq IDs. Un profil réseau ne projette cependant une route explicitement liée à un provider que si son composite déclare la source Transport correspondante. + +Pour Helius : + +- Devnet déclare `transport.helius` et projette `helius-transaction-hydrated` ; +- Mainnet déclare `transport.helius` et projette `helius-transaction-hydrated` ; +- Testnet ne déclare pas `transport.helius` et ne projette donc pas cette route. + +L'absence d'une source provider-specific n'est pas transformée en faux `Configured`, ni en faux incident `Unavailable`. La route est simplement hors inventaire pour ce réseau. + +## Testnet + +Le profil Testnet expose donc quatre routes applicables : + +1. `yellowstone-hydrated` ; +2. `standard-logs-hydrated` ; +3. `standard-block-direct` ; +4. `http-block-polling`. + +`helius-transaction-hydrated` reste dans le catalogue global V1 et dans les profils Devnet/Mainnet, mais n'est pas présenté sur Testnet. + +## Canari frontend + +Le test `desktop_security` attend désormais la trace `logical network selected`, conforme au frontend réseau-centrique introduit par `pre.006-fix.001`, au lieu de l'ancien libellé `logical profile selected`. + +## Version + +- header racine `604 -> 605` ; +- workspace `0.3.15-pre.6.fix.2 -> 0.3.15-pre.6.fix.3`. + +## Non-claims + +Ce fix n'ajoute aucun endpoint Helius Testnet, aucun fallback cross-network, aucun probe réseau, aucun Store ouvert, aucun Worker et aucun Start/Stop runtime. diff --git a/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md b/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md index ea90093..9951066 100644 --- a/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md +++ b/docs/plans/036-V0_3_15_RAW_TRANSACTION_INGEST_DESK_PLAN.md @@ -1,5 +1,5 @@ - + # Plan v0.3.15 — Raw Transaction Ingest Desk @@ -728,7 +728,7 @@ Restauration du template Desk KSP clair, bornage de la grille de routes et corre Résoudre Config côté Rust et projeter les routes composables/non composables avec raisons sûres et génération d'inventaire, sans endpoint, URL, secret ou source key côté frontend. -**État : implémenté puis corrigé par `pre.006-fix.001` et `pre.006-fix.002`.** Le Desk ouvre uniquement la dépendance directe `ksp-onchain-transport-lib` nécessaire aux capabilities typées. Le composite applicatif est réseau-centrique (`devnet`, `mainnet`, `testnet`) et peut référencer plusieurs profils Transport du même réseau. Le backend agrège leurs capabilities sans inférer quoi que ce soit du provider : PublicNode Mainnet Yellowstone est donc une capability de `mainnet`, pas un pseudo-réseau ni un profil opérateur séparé. Les sources optionnelles Helius/Yellowstone dont le secret manque ne désactivent que la route qui dépend de cette source. HTTP est prouvé directement par rôles + `request_kinds`, WS par `WsProtocolKind` + `WsSubscriptionKind`, Yellowstone par présence d'un endpoint gRPC activé. Aucun Store, session Transport ou Worker n'est ouvert. +**État : implémenté puis corrigé par `pre.006-fix.001`, `pre.006-fix.002` et `pre.006-fix.003`.** Le Desk ouvre uniquement la dépendance directe `ksp-onchain-transport-lib` nécessaire aux capabilities typées. Le composite applicatif est réseau-centrique (`devnet`, `mainnet`, `testnet`) et peut référencer plusieurs profils Transport du même réseau. Le backend agrège leurs capabilities sans inférer quoi que ce soit du provider : PublicNode Mainnet Yellowstone est donc une capability de `mainnet`, pas un pseudo-réseau ni un profil opérateur séparé. Les sources optionnelles Helius/Yellowstone dont le secret manque ne désactivent que la route qui dépend de cette source. HTTP est prouvé directement par rôles + `request_kinds`, WS par `WsProtocolKind` + `WsSubscriptionKind`, Yellowstone par présence d'un endpoint gRPC activé. Aucun Store, session Transport ou Worker n'est ouvert. Budget cible : une tranche composition. @@ -736,9 +736,17 @@ Budget cible : une tranche composition. Correction du modèle de classification : les providers redeviennent des sources Transport same-network et le sélecteur applicatif ne porte plus que `devnet`, `mainnet` et `testnet`. Ajout d'un profil `testnet_public` sans secret pour dissocier le Transport standard Testnet de PublicNode Yellowstone. Les canaris d'inventaire utilisent désormais des racines Config committées et un environnement injecté, sans dépendre du Config utilisateur de la machine. +#### `pre.006-fix.002` — Standard Block explicite + +Qualification explicite de `Block` sur les endpoints Standard WS publics de Devnet/Mainnet/Testnet et correction des canaris qui appelaient une API Config crate-private. + +#### `pre.006-fix.003` — applicabilité provider-specific par réseau + +Une route liée à un provider n'est projetée que si le composite réseau déclare la source Transport correspondante. L'absence de `transport.helius` sur Testnet signifie donc « route Helius non applicable/non exposée », et non « route en panne ». Le catalogue V1 garde cinq IDs globaux ; un profil réseau peut en exposer un sous-ensemble applicable. + ### `pre.007` — reconstruction Start des ressources Transport -Revalider Config au Start et reconstruire les ressources Transport exactes nécessaires aux cinq routes, sans lancer encore le Worker. Le choix des endpoints physiques reste Transport-owned. +Revalider Config au Start et reconstruire les ressources Transport exactes nécessaires aux routes applicables du réseau sélectionné, dans le catalogue global de cinq IDs V1, sans lancer encore le Worker. Le choix des endpoints physiques reste Transport-owned. Budget cible : une tranche intégration Transport/Desk. diff --git a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md index 59a7d5a..9fe5986 100644 --- a/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md +++ b/docs/validation/032-V0_3_15_RAW_TRANSACTION_INGEST_DESK.md @@ -1,5 +1,5 @@ - + # Validation v0.3.15 — Raw Transaction Ingest Desk @@ -362,7 +362,7 @@ Le forecast durable est porté par la section 20 du plan `036` sous forme hiéra ### `pre.006` — inventaire composable -**Statut : gate opérateur de `pre.006` en échec fonctionnel, puis corrections `pre.006-fix.001` et `pre.006-fix.002`.** Le premier inventaire classait encore les capabilities par profil Transport fournisseur : `Yellowstone + HTTP hydration` Mainnet n'était donc `Configured` que sous `publicnode_mainnet`. Le fix remplace cette projection par trois profils réseau (`devnet`, `mainnet`, `testnet`) qui agrègent les sources Transport same-network. PublicNode, Helius et OrbitFlare restent des sources de capabilities et ne deviennent jamais des identités réseau. Un secret optionnel absent n'invalide que la route dépendante. Le canari qui dépendait du Config utilisateur de la machine est remplacé par un moteur Config committé et un environnement injecté. Aucun I/O runtime n'est ajouté. +**Statut : gate opérateur de `pre.006` en échec fonctionnel, puis corrections `pre.006-fix.001`, `pre.006-fix.002` et `pre.006-fix.003`.** Le premier inventaire classait encore les capabilities par profil Transport fournisseur : `Yellowstone + HTTP hydration` Mainnet n'était donc `Configured` que sous `publicnode_mainnet`. Le fix remplace cette projection par trois profils réseau (`devnet`, `mainnet`, `testnet`) qui agrègent les sources Transport same-network. PublicNode, Helius et OrbitFlare restent des sources de capabilities et ne deviennent jamais des identités réseau. Un secret optionnel absent n'invalide que la route dépendante. Le canari qui dépendait du Config utilisateur de la machine est remplacé par un moteur Config committé et un environnement injecté. Aucun I/O runtime n'est ajouté. #### `pre.006-fix.001` — correction classification réseau @@ -376,9 +376,15 @@ Le fix déclare explicitement `Block` sur les endpoints `solana-public` Standard Les canaris Desk n'utilisent plus l'API crate-private de Config. Ils valident les routes standard à partir de `ConfigEnvironment::load()` et acceptent que les routes optionnelles Helius/Yellowstone soient soit `Configured`, soit `missing_required_secret` selon l'environnement opérateur. +#### `pre.006-fix.003` — Helius Testnet non applicable + +Le parcours visuel de `pre.006-fix.002` montre toutes les routes composables en vert sauf `helius-transaction-hydrated` sur Testnet. Ce rouge était trompeur : le composite Testnet ne déclare aucune source `transport.helius`, et Helius Enhanced WebSocket `transactionSubscribe` n'est pas une capability Testnet configurée. Le fix ne falsifie donc pas la capability ; il retire cette route provider-specific de l'inventaire Testnet. Devnet/Mainnet continuent à la projeter et à la qualifier selon leur source Helius. + +Le catalogue global reste exactement cinq IDs V1, mais l'inventaire d'un profil réseau contient uniquement les routes applicables à ses sources déclarées. Le canari frontend obsolète `logical profile selected` est également réaligné sur le tracing réseau-centrique `logical network selected`. + ### `pre.007` — ressources Start -Reconstruction/revalidation Start des ressources Transport pour les cinq routes, sans launch Worker. +Reconstruction/revalidation Start des ressources Transport pour les routes applicables du réseau sélectionné, dans le catalogue global de cinq IDs V1, sans launch Worker. ### `pre.008` — runtime mono-route