v0.3.11-pre.002

This commit is contained in:
2026-09-08 09:10:57 +02:00
parent e2689d1b04
commit 984c327162
7 changed files with 402 additions and 5 deletions

View File

@@ -0,0 +1,20 @@
# file: crates/ksp-worker-raw-transaction-ingest-lib/Cargo.toml
# version: 1
[package]
name = "ksp-worker-raw-transaction-ingest-lib"
version.workspace = true
edition.workspace = true
repository.workspace = true
[dependencies]
ksp-core-lib = { path = "../ksp-core-lib" }
ksp-logging-lib = { path = "../ksp-logging-lib" }
ksp-raw-transaction-lib = { path = "../ksp-raw-transaction-lib" }
ksp-store-lib = { path = "../ksp-store-lib", default-features = false }
ksp-worker-api = { path = "../ksp-worker-api" }
sha2 = { workspace = true }
tokio = { workspace = true, features = ["macros", "rt", "sync", "time"] }
[lints]
workspace = true

View File

@@ -0,0 +1,12 @@
// file: crates/ksp-worker-raw-transaction-ingest-lib/src/lib.rs
// version: 1
#![warn(missing_docs)]
#![deny(unreachable_pub)]
#![forbid(unsafe_code)]
//! Source-neutral runtime foundation for continuous KSP RAW transaction ingestion.
//!
//! The crate is intentionally limited to its dependency skeleton in this tranche.
//! Worker identity, settings, lifecycle, tasks, admission, persistence and snapshots
//! are introduced only by their dedicated prereleases.

View File

@@ -0,0 +1,109 @@
// file: crates/ksp-worker-raw-transaction-ingest-lib/tests/dependency_boundary.rs
// version: 1
//! Dependency firewall canaries for the RAW transaction ingest Worker skeleton.
#[test]
fn pre_002_manifest_dependency_surface_is_exact() {
let manifest = include_str!("../Cargo.toml");
let dependencies = dependency_section(manifest);
let names = manifest_dependency_names(dependencies);
assert_eq!(names, vec!["ksp-core-lib", "ksp-logging-lib", "ksp-raw-transaction-lib", "ksp-store-lib", "ksp-worker-api", "sha2", "tokio",],);
for required in [
"ksp-core-lib = { path = \"../ksp-core-lib\" }",
"ksp-logging-lib = { path = \"../ksp-logging-lib\" }",
"ksp-raw-transaction-lib = { path = \"../ksp-raw-transaction-lib\" }",
"ksp-store-lib = { path = \"../ksp-store-lib\", default-features = false }",
"ksp-worker-api = { path = \"../ksp-worker-api\" }",
"sha2 = { workspace = true }",
"tokio = { workspace = true, features = [\"macros\", \"rt\", \"sync\", \"time\"] }",
] {
assert!(dependencies.contains(required), "required Worker dependency missing: {required}");
}
return;
}
#[test]
fn pre_002_manifest_keeps_forbidden_layers_and_live_sources_out() {
let manifest = include_str!("../Cargo.toml");
let dependencies = dependency_section(manifest);
for forbidden in [
"futures-util",
"ksp-config-lib",
"ksp-interface-lib",
"ksp-job-api",
"ksp-job-backfill-lib",
"ksp-onchain-transport-lib",
"ksp-program-api",
"ksp-store-api",
"ksp-store-postgres-lib",
"ksp-wallet-lib",
"reqwest",
"solana-",
"tokio-tungstenite",
"tonic",
"yellowstone-grpc-proto",
] {
assert!(!dependencies.contains(forbidden), "forbidden Worker dependency present: {forbidden}");
}
assert!(!manifest.contains("[dev-dependencies]"), "pre.002 requires no test-only dependency");
assert!(!manifest.contains("[build-dependencies]"), "pre.002 requires no build dependency");
return;
}
#[test]
fn pre_002_crate_root_contains_no_runtime_behavior_or_public_contract_yet() {
let root = include_str!("../src/lib.rs");
for forbidden in [
"pub mod ",
"pub struct ",
"pub enum ",
"pub trait ",
"pub fn ",
"tokio::",
"ksp_store_lib::",
"ksp_raw_transaction_lib::",
"ksp_worker_api::",
"start(",
"spawn(",
] {
assert!(!root.contains(forbidden), "pre.002 crate root opened behavior too early: {forbidden}");
}
return;
}
fn dependency_section(manifest: &str) -> &str {
let after_header = match manifest.split_once("[dependencies]") {
std::option::Option::Some((_, section)) => section,
std::option::Option::None => {
return "";
},
};
let end = match after_header.find("\n[") {
std::option::Option::Some(index) => index,
std::option::Option::None => after_header.len(),
};
return &after_header[..end];
}
fn manifest_dependency_names(section: &str) -> std::vec::Vec<&str> {
let mut names = std::vec::Vec::new();
for line in section.lines() {
let content = match line.split('#').next() {
std::option::Option::Some(value) => value.trim(),
std::option::Option::None => continue,
};
if content.is_empty() {
continue;
}
let name = match content.split('=').next() {
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
std::option::Option::None => continue,
};
if !name.is_empty() {
names.push(name);
}
}
names.sort_unstable();
return names;
}