v0.3.7-pre.006
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
# file: Cargo.toml
|
# file: Cargo.toml
|
||||||
# version: 422
|
# version: 423
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
resolver = "3"
|
||||||
members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-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-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
members = ["crates/ksp-app-backfill-desk", "crates/ksp-app-config-desk", "crates/ksp-app-solprices-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-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.3.7-pre.5.fix.1"
|
version = "0.3.7-pre.6"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"format_version": 1,
|
"format_version": 1,
|
||||||
"default_profile": "devnet",
|
"default_profile": "mainnet",
|
||||||
"profiles": [
|
"profiles": [
|
||||||
{
|
{
|
||||||
"profile_id": "devnet",
|
"profile_id": "devnet",
|
||||||
@@ -28,12 +28,12 @@
|
|||||||
{
|
{
|
||||||
"component_id": "logging",
|
"component_id": "logging",
|
||||||
"file_id": "cfg.std.logging",
|
"file_id": "cfg.std.logging",
|
||||||
"profile_id": "console_info"
|
"profile_id": "supertrace"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"component_id": "transport",
|
"component_id": "transport",
|
||||||
"file_id": "cfg.std.transport",
|
"file_id": "cfg.std.transport",
|
||||||
"profile_id": "mainnet_public"
|
"profile_id": "mainnet_backfill_pool"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"component_id": "store",
|
"component_id": "store",
|
||||||
|
|||||||
@@ -178,6 +178,101 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"profile_id": "mainnet_backfill_pool",
|
||||||
|
"endpoints": [
|
||||||
|
{
|
||||||
|
"name": "solana_mainnet_public",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "${KSP_PUBLIC_SOLANA_MAINNET_HTTP_URL:-https://api.mainnet-beta.solana.com}",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 15000,
|
||||||
|
"max_idle_connections_per_host": 8,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "backfill_pool",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"priority": 100,
|
||||||
|
"limits": {
|
||||||
|
"requests_per_second": 5,
|
||||||
|
"burst_capacity": 10,
|
||||||
|
"max_concurrent_requests": 8,
|
||||||
|
"pause_after_rate_limit_ms": 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "backfill_solana_public",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"priority": 100,
|
||||||
|
"limits": {
|
||||||
|
"requests_per_second": 5,
|
||||||
|
"burst_capacity": 10,
|
||||||
|
"max_concurrent_requests": 8,
|
||||||
|
"pause_after_rate_limit_ms": 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "publicnode_solana_mainnet_http",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "publicnode",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"url": "https://solana-rpc.publicnode.com",
|
||||||
|
"connect_timeout_ms": 5000,
|
||||||
|
"request_timeout_ms": 15000,
|
||||||
|
"max_idle_connections_per_host": 8,
|
||||||
|
"roles": [
|
||||||
|
{
|
||||||
|
"role": "backfill_pool",
|
||||||
|
"enabled": true,
|
||||||
|
"request_kinds": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"priority": 100,
|
||||||
|
"limits": {
|
||||||
|
"requests_per_second": 5,
|
||||||
|
"burst_capacity": 10,
|
||||||
|
"max_concurrent_requests": 8,
|
||||||
|
"pause_after_rate_limit_ms": 1000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"role": "backfill_publicnode",
|
||||||
|
"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_mainnet_public_ws",
|
||||||
|
"enabled": true,
|
||||||
|
"provider": "solana-public",
|
||||||
|
"cluster": "mainnet-beta",
|
||||||
|
"kind": "solana_standard",
|
||||||
|
"url": "${KSP_PUBLIC_SOLANA_MAINNET_WS_URL:-wss://api.mainnet-beta.solana.com}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"profile_id": "publicnode_mainnet",
|
"profile_id": "publicnode_mainnet",
|
||||||
"endpoints": [
|
"endpoints": [
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!-- file: crates/ksp-app-backfill-desk/frontend/main.html -->
|
<!-- file: crates/ksp-app-backfill-desk/frontend/main.html -->
|
||||||
<!-- version: 1 -->
|
<!-- version: 2 -->
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="fr">
|
<html lang="fr">
|
||||||
|
|
||||||
@@ -51,11 +51,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<span id="appVersionBadge" class="badge text-bg-secondary">—</span>
|
<span id="appVersionBadge" class="badge text-bg-secondary">—</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-placeholder">
|
<div class="row g-4">
|
||||||
|
<div class="col-xl-7">
|
||||||
|
<div class="card shadow-sm h-100">
|
||||||
|
<div class="card-header fw-semibold">Transport HTTP</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<label for="backfillHttpRoute" class="form-label">Route de lecture</label>
|
||||||
|
<select id="backfillHttpRoute" class="form-select" disabled>
|
||||||
|
<option value="">Chargement des routes…</option>
|
||||||
|
</select>
|
||||||
|
<div id="backfillHttpRouteHelp" class="form-text">Le choix reste logique : aucune URL ni clé provider n'est exposée au frontend.</div>
|
||||||
|
<dl class="row mt-4 mb-0 app-runtime-list">
|
||||||
|
<dt class="col-sm-5">Réseau</dt><dd id="backfillNetwork" class="col-sm-7">—</dd>
|
||||||
|
<dt class="col-sm-5">Transport</dt><dd id="backfillTransportReady" class="col-sm-7">—</dd>
|
||||||
|
<dt class="col-sm-5">Store</dt><dd id="backfillStoreReady" class="col-sm-7">—</dd>
|
||||||
|
<dt class="col-sm-5">Composition</dt><dd id="backfillCompositionReady" class="col-sm-7">—</dd>
|
||||||
|
</dl>
|
||||||
|
<div id="backfillOptionsDiagnostic" class="alert alert-warning mt-3 mb-0" role="status" aria-live="polite" hidden></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xl-5">
|
||||||
|
<div class="app-placeholder h-100">
|
||||||
<i class="fa-solid fa-clock-rotate-left text-body-secondary" aria-hidden="true"></i>
|
<i class="fa-solid fa-clock-rotate-left text-body-secondary" aria-hidden="true"></i>
|
||||||
<div>
|
<div>
|
||||||
<h2 class="h5">Backfill runtime non ouvert dans pre.002</h2>
|
<h2 class="h5">Campagne Backfill</h2>
|
||||||
<p class="text-body-secondary mb-0">Aucun Transport, Store ou Job Backfill n'est encore créé par le frontend.</p>
|
<p class="text-body-secondary mb-0">Les scopes, commitments et le bouton Start seront branchés dans la tranche suivante. Le transport reste HTTP uniquement en v0.3.7.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/frontend/ts/main.ts
|
// file: crates/ksp-app-backfill-desk/frontend/ts/main.ts
|
||||||
// version: 1
|
// version: 2
|
||||||
|
|
||||||
import "bootstrap";
|
import "bootstrap";
|
||||||
import ResizeObserver from "resize-observer-polyfill";
|
import ResizeObserver from "resize-observer-polyfill";
|
||||||
import "simplebar";
|
import "simplebar";
|
||||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
|
import type { BackfillDeskOptionsDto } from "./bindings/ksp_app_backfill_desk/dto_common/BackfillDeskOptionsDto.ts";
|
||||||
|
import type { BackfillHttpRouteOptionDto } from "./bindings/ksp_app_backfill_desk/dto_common/BackfillHttpRouteOptionDto.ts";
|
||||||
import type { ShellStatusDto } from "./bindings/ksp_app_backfill_desk/dto_common/ShellStatusDto.ts";
|
import type { ShellStatusDto } from "./bindings/ksp_app_backfill_desk/dto_common/ShellStatusDto.ts";
|
||||||
import { frontendDebug, frontendInfo, frontendTrace, frontendWarn, installFrontendConsoleBridge } from "./frontend_log";
|
import { frontendDebug, frontendInfo, frontendTrace, frontendWarn, installFrontendConsoleBridge } from "./frontend_log";
|
||||||
import { invokeKsp } from "./invoke";
|
import { invokeKsp } from "./invoke";
|
||||||
@@ -77,6 +79,74 @@ function bindNavigation(): void {
|
|||||||
frontendTrace("main", "Backfill Desk navigation handlers installed");
|
frontendTrace("main", "Backfill Desk navigation handlers installed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function routeLabel(route: BackfillHttpRouteOptionDto): string {
|
||||||
|
if (route.pooled) {
|
||||||
|
return `Pool multi-provider — ${route.providers.join(" + ")}`;
|
||||||
|
}
|
||||||
|
return route.providers.length === 1 ? `Provider — ${route.providers[0]}` : route.role;
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderBackfillOptions(options: BackfillDeskOptionsDto): void {
|
||||||
|
const select = document.querySelector<HTMLSelectElement>("#backfillHttpRoute");
|
||||||
|
if (select) {
|
||||||
|
const previous = select.value;
|
||||||
|
select.replaceChildren();
|
||||||
|
for (const route of options.httpRoutes) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.value = route.role;
|
||||||
|
option.textContent = routeLabel(route);
|
||||||
|
select.append(option);
|
||||||
|
}
|
||||||
|
select.disabled = !options.transportReady || options.httpRoutes.length === 0;
|
||||||
|
const reusable = options.httpRoutes.some(route => route.role === previous);
|
||||||
|
if (reusable) {
|
||||||
|
select.value = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const values: Record<string, string> = {
|
||||||
|
backfillNetwork: options.configuredNetworks.length === 1 ? options.configuredNetworks[0] : options.configuredNetworks.join(", ") || "indisponible",
|
||||||
|
backfillTransportReady: options.transportReady ? "ready" : "non ready",
|
||||||
|
backfillStoreReady: options.storeReady ? "ready" : "non ready",
|
||||||
|
backfillCompositionReady: options.compositionReady ? "ready" : "non ready",
|
||||||
|
};
|
||||||
|
for (const [id, value] of Object.entries(values)) {
|
||||||
|
const element = document.querySelector<HTMLElement>(`#${id}`);
|
||||||
|
if (element) {
|
||||||
|
element.textContent = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const diagnostic = document.querySelector<HTMLElement>("#backfillOptionsDiagnostic");
|
||||||
|
if (diagnostic) {
|
||||||
|
const error = options.transportDiagnostic ?? options.storeDiagnostic;
|
||||||
|
diagnostic.hidden = error === null;
|
||||||
|
diagnostic.textContent = error === null ? "" : `${error.domain}/${error.code}: ${error.message}`;
|
||||||
|
}
|
||||||
|
frontendTrace("main", "Backfill Desk HTTP route options rendered", {
|
||||||
|
compositionReady: options.compositionReady,
|
||||||
|
routeCount: options.httpRoutes.length,
|
||||||
|
transportReady: options.transportReady,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadBackfillOptions(source: "startup" | "user"): Promise<void> {
|
||||||
|
frontendDebug("main", "Backfill Desk HTTP route options load started", { source });
|
||||||
|
const options = await invokeKsp<BackfillDeskOptionsDto>("main", "backfill_options");
|
||||||
|
renderBackfillOptions(options);
|
||||||
|
frontendDebug("main", "Backfill Desk HTTP route options load completed", { source, routeCount: options.httpRoutes.length });
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindBackfillRouteSelection(): void {
|
||||||
|
const select = document.querySelector<HTMLSelectElement>("#backfillHttpRoute");
|
||||||
|
if (!select) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
select.addEventListener("change", () => {
|
||||||
|
frontendDebug("main", "Backfill Desk HTTP route selection changed", { role: select.value || "none" });
|
||||||
|
});
|
||||||
|
frontendTrace("main", "Backfill Desk HTTP route selection handler installed");
|
||||||
|
}
|
||||||
|
|
||||||
function renderRuntimeStatus(status: ShellStatusDto): void {
|
function renderRuntimeStatus(status: ShellStatusDto): void {
|
||||||
const values: Record<string, string> = {
|
const values: Record<string, string> = {
|
||||||
runtimeVersion: status.applicationVersion,
|
runtimeVersion: status.applicationVersion,
|
||||||
@@ -131,9 +201,10 @@ async function initializeMain(): Promise<void> {
|
|||||||
bindFrontendInteractions();
|
bindFrontendInteractions();
|
||||||
bindNavigation();
|
bindNavigation();
|
||||||
bindRuntimeStatusRefresh();
|
bindRuntimeStatusRefresh();
|
||||||
|
bindBackfillRouteSelection();
|
||||||
activateView("backfill", "startup");
|
activateView("backfill", "startup");
|
||||||
try {
|
try {
|
||||||
await loadRuntimeStatus("startup");
|
await Promise.all([loadRuntimeStatus("startup"), loadBackfillOptions("startup")]);
|
||||||
} catch {
|
} catch {
|
||||||
frontendWarn("main", "Backfill Desk startup runtime status load failed");
|
frontendWarn("main", "Backfill Desk startup runtime status load failed");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/app_state.rs
|
// file: crates/ksp-app-backfill-desk/src/app_state.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Shared backend state owned by the Backfill Desk Tauri application.
|
//! Shared backend state owned by the Backfill Desk Tauri application.
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ impl crate::AppState {
|
|||||||
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
application_version: env!("CARGO_PKG_VERSION").to_owned(),
|
||||||
config_document_count: document_count,
|
config_document_count: document_count,
|
||||||
fallback_logging_active: runtime.fallback_active,
|
fallback_logging_active: runtime.fallback_active,
|
||||||
shell_phase: "pre.005-store-readiness".to_owned(),
|
shell_phase: "pre.006-mainnet-http-routing".to_owned(),
|
||||||
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
startup_diagnostic: runtime.startup_diagnostic.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -132,7 +132,7 @@ impl crate::AppState {
|
|||||||
let options = match runtime {
|
let options = match runtime {
|
||||||
std::option::Option::Some(value) => value.options(),
|
std::option::Option::Some(value) => value.options(),
|
||||||
std::option::Option::None => std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
std::option::Option::None => std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
||||||
compatible_roles: std::vec::Vec::new(),
|
http_routes: std::vec::Vec::new(),
|
||||||
composition_ready: false,
|
composition_ready: false,
|
||||||
configured_networks: std::vec::Vec::new(),
|
configured_networks: std::vec::Vec::new(),
|
||||||
network_coherent: false,
|
network_coherent: false,
|
||||||
|
|||||||
@@ -1,20 +1,35 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/dto_common.rs
|
// file: crates/ksp-app-backfill-desk/src/dto_common.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
//! Common Tauri DTOs shared by the Backfill Desk shell.
|
//! Common Tauri DTOs shared by the Backfill Desk shell.
|
||||||
|
|
||||||
use ts_rs::TS; // rust-rules: trait-import
|
use ts_rs::TS; // rust-rules: trait-import
|
||||||
|
|
||||||
/// Safe Transport-readiness subset of the Backfill Desk options contract.
|
/// Safe HTTP route exposed for operator selection before a Backfill run.
|
||||||
///
|
///
|
||||||
/// Campaign scopes, commitments and backend-owned bounds are added in the dedicated request/DTO slice. Endpoint URLs, provider identities and credentials
|
/// The route is identified only by the logical Transport role. Provider labels are safe metadata used for operator choice; endpoint URLs and credentials never
|
||||||
/// are intentionally absent.
|
/// cross IPC.
|
||||||
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_backfill_desk/dto_common/BackfillHttpRouteOptionDto.ts")]
|
||||||
|
pub(crate) struct BackfillHttpRouteOptionDto {
|
||||||
|
/// Whether more than one configured provider participates in this logical route.
|
||||||
|
pub(crate) pooled: bool,
|
||||||
|
/// Safe provider labels participating in the route, sorted and deduplicated.
|
||||||
|
pub(crate) providers: std::vec::Vec<String>,
|
||||||
|
/// Logical Transport role later passed to the Backfill runtime.
|
||||||
|
pub(crate) role: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Safe Transport-and-Store readiness subset of the Backfill Desk options contract.
|
||||||
|
///
|
||||||
|
/// Campaign scopes, commitments and backend-owned bounds are added in the dedicated request/DTO slice. Endpoint URLs and credentials are intentionally absent.
|
||||||
#[derive(Clone, Debug, serde::Serialize, TS)]
|
#[derive(Clone, Debug, serde::Serialize, TS)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_backfill_desk/dto_common/BackfillDeskOptionsDto.ts")]
|
#[ts(export, export_to = "../frontend/ts/bindings/ksp_app_backfill_desk/dto_common/BackfillDeskOptionsDto.ts")]
|
||||||
pub(crate) struct BackfillDeskOptionsDto {
|
pub(crate) struct BackfillDeskOptionsDto {
|
||||||
/// Logical roles that can route both RPC methods required by the Backfill runtime.
|
/// Selectable logical HTTP routes that support both RPC methods required by the Backfill runtime.
|
||||||
pub(crate) compatible_roles: std::vec::Vec<String>,
|
pub(crate) http_routes: std::vec::Vec<BackfillHttpRouteOptionDto>,
|
||||||
/// Whether the Transport and Store readiness gates jointly permit later Backfill composition.
|
/// Whether the Transport and Store readiness gates jointly permit later Backfill composition.
|
||||||
pub(crate) composition_ready: bool,
|
pub(crate) composition_ready: bool,
|
||||||
/// Distinct enabled HTTP cluster labels selected by the active Transport profile.
|
/// Distinct enabled HTTP cluster labels selected by the active Transport profile.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/lib.rs
|
// file: crates/ksp-app-backfill-desk/src/lib.rs
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
//! Tauri desktop application scaffold for controlling and inspecting KSP RAW backfill jobs.
|
//! Tauri desktop application scaffold for controlling and inspecting KSP RAW backfill jobs.
|
||||||
|
|
||||||
@@ -62,8 +62,10 @@ pub(crate) use self::constants::TRACING_TARGET_FRONTEND;
|
|||||||
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_MAIN;
|
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_MAIN;
|
||||||
/// Owning target for splash-window frontend events.
|
/// Owning target for splash-window frontend events.
|
||||||
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_SPLASH;
|
pub(crate) use self::constants::TRACING_TARGET_FRONTEND_SPLASH;
|
||||||
/// Safe Transport-readiness subset of the Backfill Desk options contract.
|
/// Safe Transport-and-Store readiness subset of the Backfill Desk options contract.
|
||||||
pub(crate) use self::dto_common::BackfillDeskOptionsDto;
|
pub(crate) use self::dto_common::BackfillDeskOptionsDto;
|
||||||
|
/// Safe logical HTTP route exposed for operator selection.
|
||||||
|
pub(crate) use self::dto_common::BackfillHttpRouteOptionDto;
|
||||||
/// Safe command error projection exposed to Tauri commands.
|
/// Safe command error projection exposed to Tauri commands.
|
||||||
pub(crate) use self::dto_common::CommandErrorDto;
|
pub(crate) use self::dto_common::CommandErrorDto;
|
||||||
/// Safe scaffold/runtime snapshot exposed to the shell.
|
/// Safe scaffold/runtime snapshot exposed to the shell.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/src/transport_runtime.rs
|
// file: crates/ksp-app-backfill-desk/src/transport_runtime.rs
|
||||||
// version: 2
|
// version: 3
|
||||||
|
|
||||||
//! Composite-selected HTTP Transport readiness owned by Backfill Desk.
|
//! Composite-selected HTTP Transport readiness and route inventory owned by Backfill Desk.
|
||||||
|
|
||||||
/// Safe and executable Transport runtime retained by the application state.
|
/// Safe and executable Transport runtime retained by the application state.
|
||||||
pub(crate) struct TransportRuntime {
|
pub(crate) struct TransportRuntime {
|
||||||
@@ -30,16 +30,16 @@ impl TransportRuntime {
|
|||||||
pub(crate) fn options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
|
pub(crate) fn options(&self) -> ksp_core_lib::Result<crate::BackfillDeskOptionsDto> {
|
||||||
let snapshot = self.pool.snapshot();
|
let snapshot = self.pool.snapshot();
|
||||||
let configured_networks = configured_networks(&snapshot);
|
let configured_networks = configured_networks(&snapshot);
|
||||||
let compatible_roles = compatible_backfill_roles(&self.pool, &snapshot);
|
let http_routes = compatible_backfill_http_routes(&self.pool, &snapshot);
|
||||||
let compatible_roles = match compatible_roles {
|
let http_routes = match http_routes {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
let transport_ready = configured_networks.len() == 1 && !compatible_roles.is_empty() && snapshot.available_endpoint_count() > 0;
|
let transport_ready = configured_networks.len() == 1 && !http_routes.is_empty() && snapshot.available_endpoint_count() > 0;
|
||||||
return std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
return std::result::Result::Ok(crate::BackfillDeskOptionsDto {
|
||||||
compatible_roles,
|
|
||||||
composition_ready: false,
|
composition_ready: false,
|
||||||
configured_networks,
|
configured_networks,
|
||||||
|
http_routes,
|
||||||
network_coherent: false,
|
network_coherent: false,
|
||||||
store_diagnostic: std::option::Option::None,
|
store_diagnostic: std::option::Option::None,
|
||||||
store_network: std::option::Option::None,
|
store_network: std::option::Option::None,
|
||||||
@@ -89,17 +89,17 @@ pub(crate) fn initialize_transport(management: &ksp_config_lib::ConfigManagement
|
|||||||
domain = crate::TRACING_DOMAIN_TRANSPORT,
|
domain = crate::TRACING_DOMAIN_TRANSPORT,
|
||||||
transport_profile = runtime.profile_id(),
|
transport_profile = runtime.profile_id(),
|
||||||
network_count = options.configured_networks.len(),
|
network_count = options.configured_networks.len(),
|
||||||
compatible_role_count = options.compatible_roles.len(),
|
http_route_count = options.http_routes.len(),
|
||||||
transport_ready = options.transport_ready,
|
transport_ready = options.transport_ready,
|
||||||
"initialized Backfill Desk HTTP Transport readiness from composite-managed configuration"
|
"initialized Backfill Desk HTTP Transport readiness from composite-managed configuration"
|
||||||
);
|
);
|
||||||
return std::result::Result::Ok(runtime);
|
return std::result::Result::Ok(runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compatible_backfill_roles(
|
fn compatible_backfill_http_routes(
|
||||||
pool: &ksp_onchain_transport_lib::HttpTransportPool,
|
pool: &ksp_onchain_transport_lib::HttpTransportPool,
|
||||||
snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot,
|
snapshot: &ksp_onchain_transport_lib::HttpTransportPoolSnapshot,
|
||||||
) -> ksp_core_lib::Result<std::vec::Vec<String>> {
|
) -> ksp_core_lib::Result<std::vec::Vec<crate::BackfillHttpRouteOptionDto>> {
|
||||||
let signatures = required_http_rpc_method("getSignaturesForAddress");
|
let signatures = required_http_rpc_method("getSignaturesForAddress");
|
||||||
let signatures = match signatures {
|
let signatures = match signatures {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
@@ -110,22 +110,23 @@ fn compatible_backfill_roles(
|
|||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||||
};
|
};
|
||||||
let mut candidates = std::collections::BTreeSet::new();
|
let mut candidates = std::collections::BTreeMap::<String, std::collections::BTreeSet<String>>::new();
|
||||||
for endpoint in snapshot.endpoints() {
|
for endpoint in snapshot.endpoints() {
|
||||||
if !endpoint.enabled() {
|
if !endpoint.enabled() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for role in endpoint.roles() {
|
for role in endpoint.roles() {
|
||||||
if role.enabled() {
|
if role.enabled() {
|
||||||
candidates.insert(role.role().to_owned());
|
candidates.entry(role.role().to_owned()).or_default().insert(endpoint.provider().to_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut compatible = std::vec::Vec::new();
|
let mut compatible = std::vec::Vec::new();
|
||||||
for candidate in candidates {
|
for (candidate, providers) in candidates {
|
||||||
let role = ksp_onchain_transport_lib::HttpRoleName::new(candidate.clone());
|
let role = ksp_onchain_transport_lib::HttpRoleName::new(candidate.clone());
|
||||||
if pool.select_for_method(&role, signatures).is_ok() && pool.select_for_method(&role, transaction).is_ok() {
|
if pool.select_for_method(&role, signatures).is_ok() && pool.select_for_method(&role, transaction).is_ok() {
|
||||||
compatible.push(candidate);
|
let providers = providers.into_iter().collect::<std::vec::Vec<_>>();
|
||||||
|
compatible.push(crate::BackfillHttpRouteOptionDto { pooled: providers.len() > 1, providers, role: candidate });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::result::Result::Ok(compatible);
|
return std::result::Result::Ok(compatible);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/config_composition.rs
|
// file: crates/ksp-app-backfill-desk/tests/config_composition.rs
|
||||||
// version: 4
|
// version: 5
|
||||||
|
|
||||||
//! Config composite, Transport readiness and Store-network composition contracts for Backfill Desk through pre.005.
|
//! Config composite, Transport readiness and Store-network composition contracts for Backfill Desk through pre.006.
|
||||||
|
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![deny(unreachable_pub)]
|
#![deny(unreachable_pub)]
|
||||||
@@ -32,7 +32,7 @@ fn assert_component(composite: &ksp_config_lib::ResolvedConfigComposite, compone
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pre_003_default_composite_selects_trace_devnet_logging_transport_and_store() {
|
fn pre_003_devnet_profile_selects_trace_logging_transport_and_store() {
|
||||||
let engine = workspace_engine();
|
let engine = workspace_engine();
|
||||||
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
|
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
|
||||||
let engine = match engine {
|
let engine = match engine {
|
||||||
@@ -45,8 +45,8 @@ fn pre_003_default_composite_selects_trace_devnet_logging_transport_and_store()
|
|||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(_) => return,
|
std::result::Result::Err(_) => return,
|
||||||
};
|
};
|
||||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
let composite = engine.load_resolved_composite(&file_id, std::option::Option::Some("devnet"));
|
||||||
assert!(composite.is_ok(), "committed Backfill Desk composite should resolve: {composite:?}");
|
assert!(composite.is_ok(), "committed Backfill Desk devnet profile should resolve: {composite:?}");
|
||||||
if let std::result::Result::Ok(composite) = composite {
|
if let std::result::Result::Ok(composite) = composite {
|
||||||
assert_eq!(composite.profile_id(), "devnet");
|
assert_eq!(composite.profile_id(), "devnet");
|
||||||
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "supertrace");
|
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "supertrace");
|
||||||
@@ -74,7 +74,7 @@ fn pre_003_named_profiles_keep_transport_and_store_network_selection_paired() {
|
|||||||
std::result::Result::Err(_) => return,
|
std::result::Result::Err(_) => return,
|
||||||
};
|
};
|
||||||
for (profile_id, logging_profile, transport_profile, store_profile) in
|
for (profile_id, logging_profile, transport_profile, store_profile) in
|
||||||
[("mainnet", "console_info", "mainnet_public", "mainnet"), ("testnet", "console_info", "publicnode_testnet", "testnet")]
|
[("mainnet", "supertrace", "mainnet_backfill_pool", "mainnet"), ("testnet", "console_info", "publicnode_testnet", "testnet")]
|
||||||
{
|
{
|
||||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::Some(profile_id));
|
let composite = engine.load_resolved_composite(&file_id, std::option::Option::Some(profile_id));
|
||||||
assert!(composite.is_ok(), "Backfill Desk composite profile {profile_id} should resolve: {composite:?}");
|
assert!(composite.is_ok(), "Backfill Desk composite profile {profile_id} should resolve: {composite:?}");
|
||||||
@@ -100,8 +100,8 @@ fn pre_004_default_composite_builds_http_pool_for_both_backfill_rpc_methods() {
|
|||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(_) => return,
|
std::result::Result::Err(_) => return,
|
||||||
};
|
};
|
||||||
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
let composite = engine.load_resolved_composite(&file_id, std::option::Option::Some("devnet"));
|
||||||
assert!(composite.is_ok(), "committed Backfill Desk composite should resolve: {composite:?}");
|
assert!(composite.is_ok(), "committed Backfill Desk devnet profile should resolve: {composite:?}");
|
||||||
let composite = match composite {
|
let composite = match composite {
|
||||||
std::result::Result::Ok(value) => value,
|
std::result::Result::Ok(value) => value,
|
||||||
std::result::Result::Err(_) => return,
|
std::result::Result::Err(_) => return,
|
||||||
@@ -215,3 +215,52 @@ fn pre_005_all_composite_profiles_keep_declared_http_and_store_networks_identica
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_006_default_mainnet_profile_exposes_pool_and_targeted_http_routes_without_secret_provider_data() {
|
||||||
|
let engine = workspace_engine();
|
||||||
|
assert!(engine.is_ok(), "workspace Config engine should be constructible: {engine:?}");
|
||||||
|
let engine = match engine {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let file_id = ksp_config_lib::ConfigFileId::new(ksp_config_lib::FILE_ID_COMPOSITE_KSP_APP_BACKFILL_DESK);
|
||||||
|
let file_id = match file_id {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
let composite = engine.load_resolved_composite(&file_id, std::option::Option::None);
|
||||||
|
assert!(composite.is_ok(), "default Backfill Desk composite should resolve: {composite:?}");
|
||||||
|
let composite = match composite {
|
||||||
|
std::result::Result::Ok(value) => value,
|
||||||
|
std::result::Result::Err(_) => return,
|
||||||
|
};
|
||||||
|
assert_eq!(composite.profile_id(), "mainnet");
|
||||||
|
assert_component(&composite, "logging", ksp_config_lib::FILE_ID_STD_LOGGING, "supertrace");
|
||||||
|
assert_component(&composite, "transport", ksp_config_lib::FILE_ID_STD_TRANSPORT, "mainnet_backfill_pool");
|
||||||
|
assert_component(&composite, "store", ksp_config_lib::FILE_ID_STD_STORE, "mainnet");
|
||||||
|
let transport = match composite.component("transport") {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let profile = transport.resolved().profile();
|
||||||
|
let endpoints = profile.get("endpoints").and_then(serde_json::Value::as_array);
|
||||||
|
assert!(endpoints.is_some(), "mainnet Backfill Transport profile should expose HTTP endpoints");
|
||||||
|
let endpoints = match endpoints {
|
||||||
|
std::option::Option::Some(value) => value,
|
||||||
|
std::option::Option::None => return,
|
||||||
|
};
|
||||||
|
let providers = endpoints
|
||||||
|
.iter()
|
||||||
|
.filter_map(|endpoint| endpoint.get("provider").and_then(serde_json::Value::as_str))
|
||||||
|
.collect::<std::collections::BTreeSet<_>>();
|
||||||
|
assert_eq!(providers, std::collections::BTreeSet::from(["publicnode", "solana-public"]));
|
||||||
|
let roles = endpoints
|
||||||
|
.iter()
|
||||||
|
.flat_map(|endpoint| endpoint.get("roles").and_then(serde_json::Value::as_array).into_iter().flatten())
|
||||||
|
.filter_map(|role| role.get("role").and_then(serde_json::Value::as_str))
|
||||||
|
.collect::<std::collections::BTreeSet<_>>();
|
||||||
|
assert!(roles.contains("backfill_pool"));
|
||||||
|
assert!(roles.contains("backfill_publicnode"));
|
||||||
|
assert!(roles.contains("backfill_solana_public"));
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs
|
// file: crates/ksp-app-backfill-desk/tests/desktop_contract.rs
|
||||||
// version: 5
|
// version: 6
|
||||||
|
|
||||||
//! Structural desktop contract checks for the Backfill Desk scaffold.
|
//! Structural desktop contract checks for the Backfill Desk scaffold.
|
||||||
|
|
||||||
@@ -193,8 +193,9 @@ fn pre_004_transport_runtime_builds_pool_and_validates_both_required_rpc_methods
|
|||||||
assert!(transport.contains("getTransaction"));
|
assert!(transport.contains("getTransaction"));
|
||||||
assert!(transport.contains("select_for_method"));
|
assert!(transport.contains("select_for_method"));
|
||||||
assert!(transport.contains("configured_networks"));
|
assert!(transport.contains("configured_networks"));
|
||||||
assert!(transport.contains("compatible_backfill_roles"));
|
assert!(transport.contains("compatible_backfill_http_routes"));
|
||||||
for forbidden in ["provider()", "url()", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
|
assert!(transport.contains("endpoint.provider()"));
|
||||||
|
for forbidden in ["url()", "Store::open", "BackfillJobRuntime", "BackfillRequest"] {
|
||||||
assert!(!transport.contains(forbidden), "pre.004 opens or projects forbidden surface {forbidden}");
|
assert!(!transport.contains(forbidden), "pre.004 opens or projects forbidden surface {forbidden}");
|
||||||
}
|
}
|
||||||
let tauri = read_text(root.join("src/tauri.rs").as_path());
|
let tauri = read_text(root.join("src/tauri.rs").as_path());
|
||||||
@@ -220,7 +221,6 @@ fn pre_005_store_readiness_proves_network_before_open_and_closes_on_main_window_
|
|||||||
assert!(!store.contains("BackfillRequest"));
|
assert!(!store.contains("BackfillRequest"));
|
||||||
let app_state = read_text(root.join("src/app_state.rs").as_path());
|
let app_state = read_text(root.join("src/app_state.rs").as_path());
|
||||||
assert!(app_state.contains("initialize_store"));
|
assert!(app_state.contains("initialize_store"));
|
||||||
assert!(app_state.contains("pre.005-store-readiness"));
|
|
||||||
assert!(app_state.contains("composition_ready"));
|
assert!(app_state.contains("composition_ready"));
|
||||||
assert!(app_state.contains("close_store"));
|
assert!(app_state.contains("close_store"));
|
||||||
let tauri = read_text(root.join("src/tauri.rs").as_path());
|
let tauri = read_text(root.join("src/tauri.rs").as_path());
|
||||||
@@ -228,3 +228,26 @@ fn pre_005_store_readiness_proves_network_before_open_and_closes_on_main_window_
|
|||||||
assert!(tauri.contains(required), "missing bounded Store shutdown lifecycle marker {required}");
|
assert!(tauri.contains(required), "missing bounded Store shutdown lifecycle marker {required}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_006_mainnet_default_and_http_route_selector_are_explicit_without_start_runtime() {
|
||||||
|
let root = app_root();
|
||||||
|
let workspace = root.join("../..");
|
||||||
|
let composite = read_text(workspace.join("config/composite.ksp-app-backfill-desk.json").as_path());
|
||||||
|
assert!(composite.contains("\"default_profile\": \"mainnet\""));
|
||||||
|
assert!(composite.contains("\"profile_id\": \"mainnet_backfill_pool\""));
|
||||||
|
let transport = read_text(workspace.join("config/std.transport.json").as_path());
|
||||||
|
for required in ["mainnet_backfill_pool", "backfill_pool", "backfill_publicnode", "backfill_solana_public", "solana-rpc.publicnode.com"] {
|
||||||
|
assert!(transport.contains(required), "missing Backfill HTTP route marker {required}");
|
||||||
|
}
|
||||||
|
let app_state = read_text(root.join("src/app_state.rs").as_path());
|
||||||
|
assert!(app_state.contains("pre.006-mainnet-http-routing"));
|
||||||
|
let frontend = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||||
|
assert!(frontend.contains("Backfill Desk HTTP route selection changed"));
|
||||||
|
assert!(frontend.contains("backfill_options"));
|
||||||
|
let html = read_text(root.join("frontend/main.html").as_path());
|
||||||
|
assert!(html.contains("backfillHttpRoute"));
|
||||||
|
for forbidden in ["backfill_start", "BackfillJobRuntime", "grpc", "websocket"] {
|
||||||
|
assert!(!frontend.contains(forbidden), "pre.006 frontend opens deferred runtime marker {forbidden}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/tests/desktop_security.rs
|
// file: crates/ksp-app-backfill-desk/tests/desktop_security.rs
|
||||||
// version: 5
|
// version: 6
|
||||||
|
|
||||||
//! Security and dependency-boundary checks for the Backfill Desk scaffold.
|
//! Security and dependency-boundary checks for the Backfill Desk scaffold.
|
||||||
|
|
||||||
@@ -137,7 +137,23 @@ fn pre_005_opens_store_facade_without_backend_or_job_dependencies() {
|
|||||||
}
|
}
|
||||||
let dto = read_text(root.join("src/dto_common.rs").as_path());
|
let dto = read_text(root.join("src/dto_common.rs").as_path());
|
||||||
assert!(dto.contains("BackfillDeskOptionsDto"));
|
assert!(dto.contains("BackfillDeskOptionsDto"));
|
||||||
for forbidden in ["pub(crate) provider", "endpoint_url", "pub(crate) url", "pub(crate) credential", "pub(crate) token", "connection_uri"] {
|
for forbidden in ["endpoint_url", "pub(crate) url", "pub(crate) credential", "pub(crate) token", "connection_uri"] {
|
||||||
assert!(!dto.contains(forbidden), "readiness options DTO source contains forbidden field marker {forbidden}");
|
assert!(!dto.contains(forbidden), "readiness options DTO source contains forbidden field marker {forbidden}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn pre_006_frontend_receives_only_safe_http_route_metadata_and_no_endpoint_material() {
|
||||||
|
let root = app_root();
|
||||||
|
let dto = read_text(root.join("src/dto_common.rs").as_path());
|
||||||
|
assert!(dto.contains("BackfillHttpRouteOptionDto"));
|
||||||
|
assert!(dto.contains("pub(crate) providers"));
|
||||||
|
assert!(dto.contains("pub(crate) role"));
|
||||||
|
for forbidden in ["endpoint_url", "pub(crate) url", "pub(crate) credential", "pub(crate) api_key", "pub(crate) authorization"] {
|
||||||
|
assert!(!dto.contains(forbidden), "route DTO leaks forbidden endpoint material marker {forbidden}");
|
||||||
|
}
|
||||||
|
let frontend = read_text(root.join("frontend/ts/main.ts").as_path());
|
||||||
|
for forbidden in ["http://", "https://", "apiKey", "authorization", "token"] {
|
||||||
|
assert!(!frontend.contains(forbidden), "frontend embeds forbidden provider material marker {forbidden}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// file: crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
|
// file: crates/ksp-app-backfill-desk/unit_tests/dto_common.rs
|
||||||
// version: 3
|
// version: 4
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
||||||
@@ -16,7 +16,7 @@ fn command_error_projection_excludes_arbitrary_context_and_source_values() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn transport_options_projection_contains_only_safe_transport_metadata() {
|
fn transport_options_projection_contains_only_safe_transport_metadata() {
|
||||||
let dto = crate::BackfillDeskOptionsDto {
|
let dto = crate::BackfillDeskOptionsDto {
|
||||||
compatible_roles: vec!["default".to_owned()],
|
http_routes: vec![crate::BackfillHttpRouteOptionDto { pooled: false, providers: vec!["solana-public".to_owned()], role: "default".to_owned() }],
|
||||||
composition_ready: true,
|
composition_ready: true,
|
||||||
configured_networks: vec!["devnet".to_owned()],
|
configured_networks: vec!["devnet".to_owned()],
|
||||||
network_coherent: true,
|
network_coherent: true,
|
||||||
@@ -32,7 +32,7 @@ fn transport_options_projection_contains_only_safe_transport_metadata() {
|
|||||||
let serialized = value.to_string();
|
let serialized = value.to_string();
|
||||||
assert!(serialized.contains("default"));
|
assert!(serialized.contains("default"));
|
||||||
assert!(serialized.contains("devnet"));
|
assert!(serialized.contains("devnet"));
|
||||||
assert!(!serialized.contains("provider"));
|
assert!(serialized.contains("solana-public"));
|
||||||
assert!(!serialized.contains("url"));
|
assert!(!serialized.contains("url"));
|
||||||
assert!(!serialized.contains("endpoint"));
|
assert!(!serialized.contains("endpoint"));
|
||||||
assert!(!serialized.contains("postgres"));
|
assert!(!serialized.contains("postgres"));
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ fn pool(endpoints: std::vec::Vec<ksp_onchain_transport_lib::HttpEndpointSettings
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compatible_roles_require_both_backfill_rpc_methods() {
|
fn http_routes_require_both_backfill_rpc_methods() {
|
||||||
let signatures = ksp_onchain_transport_lib::find_http_rpc_method("getSignaturesForAddress");
|
let signatures = ksp_onchain_transport_lib::find_http_rpc_method("getSignaturesForAddress");
|
||||||
let transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction");
|
let transaction = ksp_onchain_transport_lib::find_http_rpc_method("getTransaction");
|
||||||
assert!(signatures.is_some());
|
assert!(signatures.is_some());
|
||||||
@@ -76,10 +76,15 @@ fn compatible_roles_require_both_backfill_rpc_methods() {
|
|||||||
std::result::Result::Err(_) => return,
|
std::result::Result::Err(_) => return,
|
||||||
};
|
};
|
||||||
let snapshot = runtime_pool.snapshot();
|
let snapshot = runtime_pool.snapshot();
|
||||||
let roles = super::compatible_backfill_roles(&runtime_pool, &snapshot);
|
let roles = super::compatible_backfill_http_routes(&runtime_pool, &snapshot);
|
||||||
assert!(roles.is_ok());
|
assert!(roles.is_ok());
|
||||||
if let std::result::Result::Ok(roles) = roles {
|
if let std::result::Result::Ok(roles) = roles {
|
||||||
assert_eq!(roles, vec!["complete".to_owned()]);
|
assert_eq!(roles.len(), 1);
|
||||||
|
if let std::option::Option::Some(route) = roles.first() {
|
||||||
|
assert_eq!(route.role, "complete");
|
||||||
|
assert_eq!(route.providers, vec!["fixture".to_owned()]);
|
||||||
|
assert!(!route.pooled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"format_version": 1,
|
"format_version": 1,
|
||||||
"default_profile": "devnet",
|
"default_profile": "mainnet",
|
||||||
"profiles": [
|
"profiles": [
|
||||||
{
|
{
|
||||||
"profile_id": "devnet",
|
"profile_id": "devnet",
|
||||||
|
|||||||
66
deltas/0.3.7/pre.006.md
Normal file
66
deltas/0.3.7/pre.006.md
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# Delta `0.3.7-pre.006`
|
||||||
|
|
||||||
|
## Base requise
|
||||||
|
|
||||||
|
`0.3.7-pre.005-fix.001`.
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Faire de Mainnet le profil Backfill Desk par défaut et introduire une sélection HTTP opérateur entre pool multi-provider et provider ciblé, sans ouvrir encore le runtime Job/Start.
|
||||||
|
|
||||||
|
## Fichiers ajoutés
|
||||||
|
|
||||||
|
- `deltas/0.3.7/pre.006.md`
|
||||||
|
|
||||||
|
## Fichiers modifiés
|
||||||
|
|
||||||
|
- `Cargo.toml`
|
||||||
|
- `config/composite.ksp-app-backfill-desk.json`
|
||||||
|
- `config/std.transport.json`
|
||||||
|
- `crates/ksp-config-lib/unit_tests/fixtures/composite.ksp-app-backfill-desk.json`
|
||||||
|
- `crates/ksp-app-backfill-desk/src/app_state.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/src/dto_common.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/src/lib.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/src/transport_runtime.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/unit_tests/dto_common.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/unit_tests/transport_runtime.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/tests/config_composition.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/tests/desktop_contract.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/tests/desktop_security.rs`
|
||||||
|
- `crates/ksp-app-backfill-desk/frontend/main.html`
|
||||||
|
- `crates/ksp-app-backfill-desk/frontend/ts/main.ts`
|
||||||
|
- `docs/plans/028-V0_3_7_BACKFILL_DESK_PLAN.md`
|
||||||
|
- `docs/validation/024-V0_3_7_BACKFILL_DESK.md`
|
||||||
|
|
||||||
|
## Fichiers supprimés
|
||||||
|
|
||||||
|
Aucun.
|
||||||
|
|
||||||
|
## Décisions
|
||||||
|
|
||||||
|
- Mainnet devient le profil composite par défaut ; Devnet/Testnet restent configurables.
|
||||||
|
- Backfill reste HTTP-only en `0.3.7`.
|
||||||
|
- `backfill_pool` route Solana Public + PublicNode ; deux rôles dédiés permettent le ciblage d'un provider.
|
||||||
|
- Le frontend ne choisit jamais une URL : il choisit un rôle logique Transport.
|
||||||
|
- Helius HTTP peut être ajouté ultérieurement au même mécanisme de rôles via Config/Transport, sans modifier le contrat Job.
|
||||||
|
- Yellowstone gRPC est reporté à une version ultérieure (`0.3.12+` indicatif) ; WebSocket reste hors scope.
|
||||||
|
|
||||||
|
## Validations exécutées dans l'environnement d'assemblage
|
||||||
|
|
||||||
|
- audits Python Rust/workspace ;
|
||||||
|
- audit Markdown ;
|
||||||
|
- parsing JSON/TOML ;
|
||||||
|
- validation JSON Schema du Transport/composite ;
|
||||||
|
- contrôles statiques Mainnet/default/rôles HTTP ;
|
||||||
|
- contrôle TypeScript syntaxique avec bindings temporaires ;
|
||||||
|
- contrôle différentiel et reconstruction par delta.
|
||||||
|
|
||||||
|
## Validations non exécutées
|
||||||
|
|
||||||
|
`cargo`, `rustfmt`, Clippy et les tests Rust ne sont pas disponibles dans l'environnement d'assemblage. Ils restent obligatoires côté opérateur avant `pre.007`.
|
||||||
|
|
||||||
|
## Questions ouvertes
|
||||||
|
|
||||||
|
- admission et mapping complet `BackfillRequest` en `pre.007` ;
|
||||||
|
- Helius HTTP ne doit être activé qu'avec une configuration de secret réellement disponible ;
|
||||||
|
- smoke Mainnet lecture seule après intégration du Start, pas avant.
|
||||||
@@ -137,16 +137,16 @@ Aucun `BackfillCheckpoint`, `Store`, `HttpTransportPool`, sender/receiver Tokio
|
|||||||
Le composite cible est `config/composite.ksp-app-backfill-desk.json` avec trois profils cohérents :
|
Le composite cible est `config/composite.ksp-app-backfill-desk.json` avec trois profils cohérents :
|
||||||
|
|
||||||
| Profil composite | Logging | Transport | Store | Réseau |
|
| Profil composite | Logging | Transport | Store | Réseau |
|
||||||
|------------------|----------------|----------------------|-----------|----------------|
|
|------------------|----------------|-------------------------|-----------|----------------|
|
||||||
| `devnet` | `supertrace` | `devnet_public` | `devnet` | `devnet` |
|
| `devnet` | `supertrace` | `devnet_public` | `devnet` | `devnet` |
|
||||||
| `mainnet` | `console_info` | `mainnet_public` | `mainnet` | `mainnet-beta` |
|
| `mainnet` | `supertrace` | `mainnet_backfill_pool` | `mainnet` | `mainnet-beta` |
|
||||||
| `testnet` | `console_info` | `publicnode_testnet` | `testnet` | `testnet` |
|
| `testnet` | `console_info` | `publicnode_testnet` | `testnet` | `testnet` |
|
||||||
|
|
||||||
Le default V1 est `devnet`, afin de ne pas lancer implicitement une campagne mainnet. Aucun `std.job_backfill.json` n'est créé : les paramètres de campagne restent opérationnels et backend-validés.
|
Le default V1 est désormais `mainnet`, conformément à la finalité lecture seule du Backfill Desk. `devnet` et `testnet` restent sélectionnables par reconfiguration du composite. Pendant le développement de `0.3.7`, Mainnet conserve le profil Logging `supertrace`. Aucun `std.job_backfill.json` n'est créé : les paramètres de campagne restent opérationnels et backend-validés.
|
||||||
|
|
||||||
Au bootstrap, l'application charge le composite, résout Logging/Transport/Store via `ksp-config-lib`, construit `HttpTransportPool` et ouvre `ksp_store_lib::Store`. Elle compare le réseau Store au(x) cluster(s) HTTP activés et refuse le readiness si une composition mélange des réseaux.
|
Au bootstrap, l'application charge le composite, résout Logging/Transport/Store via `ksp-config-lib`, construit `HttpTransportPool` et ouvre `ksp_store_lib::Store`. Elle compare le réseau Store au(x) cluster(s) HTTP activés et refuse le readiness si une composition mélange des réseaux.
|
||||||
|
|
||||||
Les rôles présentés à l'UI sont dérivés des snapshots/settings Transport, dédupliqués, puis validés côté Rust comme capables de sélectionner à la fois `getSignaturesForAddress` et `getTransaction`. Le rôle `default` est actuellement le seul rôle des profils standard, mais il n'est pas codé en dur comme contrat du Desk.
|
Les routes HTTP présentées à l'UI sont dérivées des snapshots/settings Transport, dédupliquées, puis validées côté Rust comme capables de sélectionner à la fois `getSignaturesForAddress` et `getTransaction`. Sur Mainnet, `backfill_pool` regroupe Solana Public et PublicNode à priorité égale, tandis que `backfill_solana_public` et `backfill_publicnode` ciblent un provider unique. Le frontend ne reçoit que le rôle logique et les labels provider sûrs ; URL, credentials, rate-limit interne et retry restent possédés par Transport.
|
||||||
|
|
||||||
Le packaging Config suit le contrat atomique déjà détenu par `ksp-config-lib::prepare_packaged_runtime()` : il traverse l'intégralité de `ConfigFileRegistry::defaults()`. L'ajout du composite Backfill Desk fait donc passer le registre de 13 à 14 descriptors et impose que les quatre applications Desk qui utilisent ce packaging embarquent les 14 resources Config/schema du registre. Backfill Desk embarque ainsi également les documents Wallet/offchain sans les consommer au runtime ; leur présence satisfait le contrat de packaging partagé et n'ouvre aucune dépendance, permission frontend ou responsabilité métier supplémentaire.
|
Le packaging Config suit le contrat atomique déjà détenu par `ksp-config-lib::prepare_packaged_runtime()` : il traverse l'intégralité de `ConfigFileRegistry::defaults()`. L'ajout du composite Backfill Desk fait donc passer le registre de 13 à 14 descriptors et impose que les quatre applications Desk qui utilisent ce packaging embarquent les 14 resources Config/schema du registre. Backfill Desk embarque ainsi également les documents Wallet/offchain sans les consommer au runtime ; leur présence satisfait le contrat de packaging partagé et n'ouvre aucune dépendance, permission frontend ou responsabilité métier supplémentaire.
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ Aucun JSON, fichier ou table checkpoint n'est inventé. La reprise après crash/
|
|||||||
| Menace | Surface | Contrôle v0.3.7 |
|
| Menace | Surface | Contrôle v0.3.7 |
|
||||||
|------------------------------|------------------|----------------------------------------------------------------------------------------------|
|
|------------------------------|------------------|----------------------------------------------------------------------------------------------|
|
||||||
| fuite URI Store | Config/backend | jamais projetée en DTO/log frontend |
|
| fuite URI Store | Config/backend | jamais projetée en DTO/log frontend |
|
||||||
| fuite URL/token provider | Transport/Config | uniquement rôle/cluster/readiness sûrs ; aucune URL |
|
| fuite URL/token provider | Transport/Config | rôle + labels provider sûrs uniquement ; aucune URL/credential |
|
||||||
| fuite RAW transaction | snapshots/IPC | snapshot existant ne contient aucun payload ; aucun Store read général |
|
| fuite RAW transaction | snapshots/IPC | snapshot existant ne contient aucun payload ; aucun Store read général |
|
||||||
| fuite liste signatures | request/logging | input transmis au command, non journalisé ; DTO retour n'en contient pas |
|
| fuite liste signatures | request/logging | input transmis au command, non journalisé ; DTO retour n'en contient pas |
|
||||||
| fuite adresse | instrumentation | ne pas journaliser la valeur ; seulement scope kind/action code |
|
| fuite adresse | instrumentation | ne pas journaliser la valeur ; seulement scope kind/action code |
|
||||||
@@ -243,7 +243,7 @@ Le replay opérateur de `pre.003-fix.001` est ensuite intégralement propre : au
|
|||||||
|
|
||||||
### pre.004 — Transport readiness
|
### pre.004 — Transport readiness
|
||||||
|
|
||||||
Construire `HttpTransportPool`, dériver l'inventaire sûr des réseaux/rôles, vérifier le support simultané de `getSignaturesForAddress` et `getTransaction`, puis exposer `backfill_options()` sans provider, endpoint physique ni URL. `BackfillDeskOptionsDto` apparaît ici comme sous-contrat Transport seulement (`configured_networks`, rôles compatibles, diagnostic sûr, readiness) ; `pre.006` l'étendra avec commitments, scopes et bornes plutôt que d'ouvrir prématurément `ksp-job-backfill-lib`. Une composition Transport avec plusieurs clusters HTTP actifs ou sans rôle compatible reste non-ready. Une erreur de résolution/construction Transport est conservée comme diagnostic sûr afin que le shell puisse rester ouvrable.
|
Construire `HttpTransportPool`, dériver l'inventaire sûr des réseaux/rôles, vérifier le support simultané de `getSignaturesForAddress` et `getTransaction`, puis exposer `backfill_options()` sans provider, endpoint physique ni URL. `BackfillDeskOptionsDto` apparaît ici comme sous-contrat Transport seulement (`configured_networks`, rôles compatibles, diagnostic sûr, readiness) ; `pre.007` l'étendra avec commitments, scopes et bornes après stabilisation du choix HTTP de `pre.006`. Une composition Transport avec plusieurs clusters HTTP actifs ou sans rôle compatible reste non-ready. Une erreur de résolution/construction Transport est conservée comme diagnostic sûr afin que le shell puisse rester ouvrable.
|
||||||
|
|
||||||
Le replay opérateur de `pre.004` est acquis : audits, `cargo check --workspace`, Clippy, toutes les suites ciblées Backfill Desk et les deux arbres de dépendances passent. Le lancement `cargo tauri dev` confirme également le profil Logging `supertrace`, le profil Transport `devnet_public`, un réseau HTTP unique, un rôle compatible et `transport_ready = true`; les clics de tabs frontend apparaissent bien au niveau `DEBUG`.
|
Le replay opérateur de `pre.004` est acquis : audits, `cargo check --workspace`, Clippy, toutes les suites ciblées Backfill Desk et les deux arbres de dépendances passent. Le lancement `cargo tauri dev` confirme également le profil Logging `supertrace`, le profil Transport `devnet_public`, un réseau HTTP unique, un rôle compatible et `transport_ready = true`; les clics de tabs frontend apparaissent bien au niveau `DEBUG`.
|
||||||
|
|
||||||
@@ -253,45 +253,49 @@ Ouvrir uniquement `ksp-store-lib::Store` depuis le profil Store sélectionné pa
|
|||||||
|
|
||||||
Le `Store` ouvert reste détenu côté Rust et doit être fermé explicitement via `Store::close()` lors d'une demande de fermeture de la fenêtre principale. La Desk intercepte cette fermeture une seule fois, empêche la destruction immédiate, lance le close borné puis quitte l'application. Aucun `BackfillRequest`, `BackfillJobRuntime`, accès backend PostgreSQL direct ou capability Tauri supplémentaire n'est admis dans cette tranche.
|
Le `Store` ouvert reste détenu côté Rust et doit être fermé explicitement via `Store::close()` lors d'une demande de fermeture de la fenêtre principale. La Desk intercepte cette fermeture une seule fois, empêche la destruction immédiate, lance le close borné puis quitte l'application. Aucun `BackfillRequest`, `BackfillJobRuntime`, accès backend PostgreSQL direct ou capability Tauri supplémentaire n'est admis dans cette tranche.
|
||||||
|
|
||||||
### pre.006 — DTO/request mapping
|
### pre.006 — Mainnet par défaut + sélection route HTTP
|
||||||
|
|
||||||
Compléter les DTO TS-RS app-owned commencés par le sous-contrat Transport de `pre.004` : quatre scopes, commitments, min context slot, bornes backend-owned, signatures hostiles et validation de rôle/réseau.
|
Faire de `mainnet` le profil composite par défaut, conserver `supertrace` pendant le développement et ajouter un profil `mainnet_backfill_pool` HTTP-only. Exposer dans `backfill_options()` des routes sûres dérivées des rôles Transport : `backfill_pool` pour Solana Public + PublicNode, `backfill_solana_public` et `backfill_publicnode` pour un ciblage explicite. Le frontend rend ce choix avant Start et trace les changements ; aucune URL/clé ne traverse IPC et `ksp-job-backfill-lib` n'est pas encore ouvert par la Desk.
|
||||||
|
|
||||||
### pre.007 — runtime + Start
|
### pre.007 — DTO/request mapping
|
||||||
|
|
||||||
Single-active-run state, construction `BackfillJobRuntime`, spawn non bloquant, handle installé avant exécution et snapshot initial/terminal.
|
Ajouter `ksp-job-backfill-lib` et compléter les DTO TS-RS app-owned : quatre scopes HTTP existants, commitments, min context slot, bornes backend-owned, signatures explicites hostiles et rôle HTTP sélectionné. Mapper strictement vers `BackfillRequest`/`HttpRoleName` côté Rust sans Start effectif et refuser toute route qui n'appartient pas à l'inventaire courant.
|
||||||
|
|
||||||
### pre.008 — monitoring latest-value
|
### pre.008 — runtime + Start
|
||||||
|
|
||||||
|
Single-active-run state, construction `BackfillJobRuntime`, spawn non bloquant, handle installé avant exécution, admission atomique et snapshot initial/terminal.
|
||||||
|
|
||||||
|
### pre.009 — monitoring latest-value
|
||||||
|
|
||||||
Bridge de snapshots, status DTO, événements coalescés, compteurs complets, resynchronisation et absence de log parsing.
|
Bridge de snapshots, status DTO, événements coalescés, compteurs complets, resynchronisation et absence de log parsing.
|
||||||
|
|
||||||
### pre.009 — Cancel et races terminales
|
### pre.010 — Cancel et races terminales
|
||||||
|
|
||||||
Cancel, état cancelling, idempotence UX, concurrence Start/Cancel/terminal, sémantique de drain Store et fermeture app.
|
Cancel, état cancelling, idempotence UX, concurrence Start/Cancel/terminal, sémantique de drain Store et fermeture app.
|
||||||
|
|
||||||
### pre.010 — checkpoint/frontier et Resume
|
### pre.011 — checkpoint/frontier et Resume
|
||||||
|
|
||||||
Projection sûre, conservation Rust-only du checkpoint, reprise in-session et invariants par scope.
|
Projection sûre, conservation Rust-only du checkpoint, reprise in-session et invariants par scope.
|
||||||
|
|
||||||
### pre.011 — frontend fonctionnel et polish
|
### pre.012 — frontend fonctionnel et polish
|
||||||
|
|
||||||
Formulaire complet, états responsive, instrumentation sûre, summary terminal, erreurs, boutons contextuels, aucun secret/browser storage.
|
Formulaire complet, états responsive, instrumentation sûre, summary terminal, erreurs, boutons contextuels, aucun secret/browser storage.
|
||||||
|
|
||||||
### pre.012 — hardening et complétude
|
### pre.013 — hardening et complétude
|
||||||
|
|
||||||
Tests desktop/security/dependency/composition/release completeness, canaries DTO et scan des dépendances/interdictions.
|
Tests desktop/security/dependency/composition/release completeness, canaries DTO et scan des dépendances/interdictions.
|
||||||
|
|
||||||
### pre.013 — gate technique final
|
### pre.014 — gate technique final
|
||||||
|
|
||||||
`cargo fmt`, audits, check/clippy/tests workspace, arbres Cargo utiles, `cargo tauri build`, smoke opt-in si environnement sûr disponible.
|
`cargo fmt`, audits, check/clippy/tests workspace, arbres Cargo utiles, `cargo tauri build`, smoke Mainnet lecture seule opt-in si environnement sûr disponible.
|
||||||
|
|
||||||
### pre.014 — réconciliation documentaire
|
### pre.015 — réconciliation documentaire
|
||||||
|
|
||||||
README/USAGE/plan/validation et architecture seulement si la surface finale l'exige. Aucun nouveau runtime.
|
README/USAGE/plan/validation et architecture seulement si la surface finale l'exige. Aucun nouveau runtime.
|
||||||
|
|
||||||
### pre.015 — préparation publication
|
### pre.016 — préparation publication
|
||||||
|
|
||||||
Prompt 0.3.8, CHANGELOG et ROADMAP uniquement avec le bump prerelease/delta requis.
|
Prompt suivant + CHANGELOG + ROADMAP uniquement avec le bump prerelease/delta requis.
|
||||||
|
|
||||||
### rel.001 — publication stable
|
### rel.001 — publication stable
|
||||||
|
|
||||||
@@ -300,3 +304,7 @@ Mécanique de publication `v0.3.7`, sans rattrapage.
|
|||||||
## 14. Hors périmètre
|
## 14. Hors périmètre
|
||||||
|
|
||||||
Store Desk/navigation RAW, Worker API/service daemon, scheduler/registry générique Job, checkpoint durable, retry Job, sélection provider physique, nouveau protocole Transport, migration Store, decoding/materialization, application globale/control desk.
|
Store Desk/navigation RAW, Worker API/service daemon, scheduler/registry générique Job, checkpoint durable, retry Job, sélection provider physique, nouveau protocole Transport, migration Store, decoding/materialization, application globale/control desk.
|
||||||
|
|
||||||
|
## 15. Report transport gRPC
|
||||||
|
|
||||||
|
Le Backfill `0.3.7` reste HTTP-only. Une généralisation de `ksp-job-backfill-lib` et de Backfill Desk vers Yellowstone gRPC est reportée à une version ultérieure, avec `0.3.12+` comme cible indicative à réévaluer. WebSocket reste hors Backfill tant qu'un besoin historique concret ne le justifie pas.
|
||||||
|
|||||||
@@ -266,6 +266,25 @@ Le correctif ne modifie aucun runtime, aucun composite Config, aucun profil Tran
|
|||||||
- [X] aucune modification du composite de production ni des settings Transport/Store ;
|
- [X] aucune modification du composite de production ni des settings Transport/Store ;
|
||||||
- [X] aucun secret provider requis par le test déterministe de cohérence réseau ;
|
- [X] aucun secret provider requis par le test déterministe de cohérence réseau ;
|
||||||
- [X] audits statiques Rust/Markdown rejoués dans l'environnement d'assemblage ;
|
- [X] audits statiques Rust/Markdown rejoués dans l'environnement d'assemblage ;
|
||||||
- [ ] replay opérateur `cargo fmt/check/clippy/test` de `pre.005-fix.001` à exécuter.
|
- [X] replay opérateur `cargo fmt/check/clippy/test` de `pre.005-fix.001` propre.
|
||||||
|
|
||||||
La décision utilisateur de faire de Mainnet le profil Backfill par défaut et de tester plusieurs familles de transport Backfill (HTTP standard, HTTP provider tel que Helius, Yellowstone gRPC ; WebSocket exclu de V1 sauf besoin démontré) appartient à des couloirs Config/Transport antérieurs. Conformément à `VER-LIFECYCLE-010`, elle n'est pas introduite dans ce fix et doit ouvrir une prerelease dédiée après validation du correctif.
|
La décision utilisateur de faire de Mainnet le profil Backfill par défaut et de tester plusieurs familles de transport Backfill (HTTP standard, HTTP provider tel que Helius, Yellowstone gRPC ; WebSocket exclu de V1 sauf besoin démontré) appartient à des couloirs Config/Transport antérieurs. Conformément à `VER-LIFECYCLE-010`, elle n'est pas introduite dans ce fix et doit ouvrir une prerelease dédiée après validation du correctif.
|
||||||
|
|
||||||
|
## `0.3.7-pre.006` — Mainnet par défaut et routage HTTP opérateur
|
||||||
|
|
||||||
|
La décision post-`pre.005` est appliquée dans une nouvelle tranche dédiée : le composite Backfill Desk utilise `mainnet` par défaut, avec Logging `supertrace` pendant le développement et un profil Transport `mainnet_backfill_pool`. Ce profil expose deux endpoints HTTP sans secret obligatoire au démarrage : Solana Public et PublicNode.
|
||||||
|
|
||||||
|
Trois rôles logiques sont proposés : `backfill_pool` pour le pool multi-provider, `backfill_solana_public` et `backfill_publicnode` pour le ciblage explicite. L'IPC expose uniquement le rôle et les labels provider sûrs ; aucune URL ni credential. Le frontend charge `backfill_options()` au démarrage, rend le sélecteur et trace le changement de route. Aucun Start n'est ajouté dans cette tranche.
|
||||||
|
|
||||||
|
Le support Yellowstone gRPC de `ksp-job-backfill-lib`/Backfill Desk est retiré du périmètre `0.3.7` et reporté à une version ultérieure (`0.3.12+` comme cible indicative). WebSocket reste hors Backfill V1.
|
||||||
|
|
||||||
|
### Gate `pre.006`
|
||||||
|
|
||||||
|
- [X] Mainnet est le profil composite par défaut et conserve `supertrace` pendant le développement ;
|
||||||
|
- [X] le profil `mainnet_backfill_pool` expose Solana Public + PublicNode en HTTP avec rôles pool/ciblés ;
|
||||||
|
- [X] aucun endpoint gRPC n'est introduit dans ce profil ;
|
||||||
|
- [X] l'IPC expose uniquement rôle logique et labels provider sûrs ;
|
||||||
|
- [X] le frontend charge/rend le sélecteur et trace son changement ;
|
||||||
|
- [X] aucun Start ni dépendance `ksp-job-backfill-lib` n'est ouvert par la Desk ;
|
||||||
|
- [X] audits statiques Rust/Markdown, JSON Schema et syntaxe TypeScript propres dans l'environnement d'assemblage ;
|
||||||
|
- [ ] replay opérateur `cargo fmt/check/clippy/test` de `pre.006` à exécuter.
|
||||||
|
|||||||
Reference in New Issue
Block a user