Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 033912fb2c | |||
| 11ca53ba48 | |||
| b01fb3fa53 | |||
| 4a86a76ca8 | |||
| 75e5ec047f | |||
| 81eda2e5ad | |||
| 72ddabd9f2 | |||
| 27a6715a3e | |||
| 37a1480c72 | |||
| ecc82f681d |
@@ -1,18 +1,21 @@
|
||||
# file: Cargo.toml
|
||||
# version: 17
|
||||
# version: 25
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/ksp-core-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.3"
|
||||
version = "0.1.1"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
authors = ["SinuS von SifriduS <sinus@sasedev.net>"]
|
||||
publish = false
|
||||
|
||||
[workspace.dependencies]
|
||||
solana-pubkey = { version = "^4.3", default-features = false }
|
||||
|
||||
[workspace.lints.rust]
|
||||
missing_docs = "warn"
|
||||
unreachable_pub = "deny"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 12 -->
|
||||
<!-- version: 13 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -31,7 +31,7 @@ Regrouper les releases consacrées aux fondations N1. Chaque release concrète e
|
||||
|
||||
### Releases concrètes
|
||||
|
||||
- [ ] `0.1.1` — Stabiliser `ksp-core-lib` : `Error`/`Result`, Program IDs fondamentaux et primitives réellement N1.
|
||||
- [X] `0.1.1` — Stabiliser `ksp-core-lib` : `Error`/`Result`, Program IDs fondamentaux et primitives réellement N1.
|
||||
- [ ] `0.1.2` — Introduire `ksp-logging-lib` comme façade KSP de `tracing`, `tracing-appender` et `tracing-subscriber`.
|
||||
- [ ] `0.1.3` — Introduire `ksp-config-lib` : documents, profils, résolution, validation et modifications autorisées.
|
||||
- [ ] `0.1.4` — Introduire `ksp-app-config-desk` pour valider réellement Config et la frontière Tauri.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# file: crates/ksp-core-lib/Cargo.toml
|
||||
# version: 1
|
||||
# version: 3
|
||||
|
||||
[package]
|
||||
name = "ksp-core-lib"
|
||||
@@ -7,5 +7,8 @@ version.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
solana-pubkey.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
130
crates/ksp-core-lib/src/error.rs
Normal file
130
crates/ksp-core-lib/src/error.rs
Normal file
@@ -0,0 +1,130 @@
|
||||
// file: crates/ksp-core-lib/src/error.rs
|
||||
// version: 1
|
||||
|
||||
/// Stable structured identifier for a KSP error.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct ErrorCode {
|
||||
domain: &'static str,
|
||||
code: &'static str,
|
||||
}
|
||||
|
||||
impl ErrorCode {
|
||||
/// Creates an error code from a stable domain and code identifier.
|
||||
#[must_use]
|
||||
pub const fn new(domain: &'static str, code: &'static str) -> Self {
|
||||
return Self { domain, code };
|
||||
}
|
||||
|
||||
/// Returns the stable error domain identifier.
|
||||
#[must_use]
|
||||
pub const fn domain(&self) -> &'static str {
|
||||
return self.domain;
|
||||
}
|
||||
|
||||
/// Returns the stable error code identifier within the domain.
|
||||
#[must_use]
|
||||
pub const fn code(&self) -> &'static str {
|
||||
return self.code;
|
||||
}
|
||||
}
|
||||
|
||||
/// Structured contextual field attached to a KSP error.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct ErrorContext {
|
||||
key: &'static str,
|
||||
value: std::string::String,
|
||||
}
|
||||
|
||||
impl ErrorContext {
|
||||
/// Creates one contextual field from a stable key and an owned value.
|
||||
#[must_use]
|
||||
pub fn new(key: &'static str, value: impl std::convert::Into<std::string::String>) -> Self {
|
||||
return Self { key, value: value.into() };
|
||||
}
|
||||
|
||||
/// Returns the stable contextual key.
|
||||
#[must_use]
|
||||
pub fn key(&self) -> &'static str {
|
||||
return self.key;
|
||||
}
|
||||
|
||||
/// Returns the contextual value.
|
||||
#[must_use]
|
||||
pub fn value(&self) -> &str {
|
||||
return self.value.as_str();
|
||||
}
|
||||
}
|
||||
|
||||
/// Common KSP error carrying a stable code, human-readable message, structured context and optional source.
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
code: crate::ErrorCode,
|
||||
message: std::string::String,
|
||||
context: std::vec::Vec<crate::ErrorContext>,
|
||||
source: std::option::Option<std::boxed::Box<dyn std::error::Error + std::marker::Send + std::marker::Sync + 'static>>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Creates a KSP error without context or external source.
|
||||
#[must_use]
|
||||
pub fn new(code: crate::ErrorCode, message: impl std::convert::Into<std::string::String>) -> Self {
|
||||
return Self { code, message: message.into(), context: std::vec::Vec::new(), source: std::option::Option::None };
|
||||
}
|
||||
|
||||
/// Returns the stable structured error code.
|
||||
#[must_use]
|
||||
pub const fn code(&self) -> crate::ErrorCode {
|
||||
return self.code;
|
||||
}
|
||||
|
||||
/// Returns the human-readable diagnostic message.
|
||||
#[must_use]
|
||||
pub fn message(&self) -> &str {
|
||||
return self.message.as_str();
|
||||
}
|
||||
|
||||
/// Returns the contextual fields in insertion order.
|
||||
#[must_use]
|
||||
pub fn context(&self) -> &[crate::ErrorContext] {
|
||||
return self.context.as_slice();
|
||||
}
|
||||
|
||||
/// Appends one contextual field and returns the enriched error.
|
||||
#[must_use]
|
||||
pub fn with_context(mut self, key: &'static str, value: impl std::convert::Into<std::string::String>) -> Self {
|
||||
self.context.push(crate::ErrorContext::new(key, value));
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Attaches an external error as the standard source and returns the enriched error.
|
||||
#[must_use]
|
||||
pub fn with_source<E>(mut self, source: E) -> Self
|
||||
where
|
||||
E: std::error::Error + std::marker::Send + std::marker::Sync + 'static,
|
||||
{
|
||||
self.source = std::option::Option::Some(std::boxed::Box::new(source));
|
||||
return self;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return write!(formatter, "{}.{}: {}", self.code.domain(), self.code.code(), self.message);
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> std::option::Option<&(dyn std::error::Error + 'static)> {
|
||||
return match self.source.as_deref() {
|
||||
std::option::Option::Some(source) => std::option::Option::Some(source),
|
||||
std::option::Option::None => std::option::Option::None,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// Common result type returned by KSP APIs using [`crate::Error`].
|
||||
pub type Result<T> = std::result::Result<T, crate::Error>;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/error.rs"]
|
||||
mod tests;
|
||||
@@ -1,7 +1,120 @@
|
||||
// file: crates/ksp-core-lib/src/lib.rs
|
||||
// version: 3
|
||||
// version: 6
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Minimal core-library skeleton for the KSP foundation phase.
|
||||
//! Core contracts shared by the foundational KSP layers.
|
||||
//!
|
||||
//! `ksp-core-lib` owns the common KSP error contract, the Solana [`Pubkey`]
|
||||
//! primitive used by the project, and the KSP-owned registry of fundamental
|
||||
//! Solana Program IDs. Higher-level domains extend these contracts without
|
||||
//! introducing reverse dependencies from Core.
|
||||
|
||||
mod error;
|
||||
mod program_ids;
|
||||
|
||||
/// Common KSP error type used by higher-level crates.
|
||||
pub use self::error::Error;
|
||||
/// Stable structured code identifying a KSP error category and condition.
|
||||
pub use self::error::ErrorCode;
|
||||
/// Structured contextual field attached to a KSP error.
|
||||
pub use self::error::ErrorContext;
|
||||
/// Common KSP result alias using [`Error`].
|
||||
pub use self::error::Result;
|
||||
/// Canonical Address Lookup Table Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_ADDRESS_LOOKUP_TABLE;
|
||||
/// Canonical Compute Budget Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_COMPUTE_BUDGET;
|
||||
/// Canonical Config Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_CONFIG;
|
||||
/// Canonical Feature Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_FEATURE;
|
||||
/// Canonical upgradeable BPF Loader Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_LOADER_BPF_UPGRADEABLE;
|
||||
/// Canonical deprecated BPF Loader Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_LOADER_BPF_V1;
|
||||
/// Canonical BPF Loader v2 Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_LOADER_BPF_V2;
|
||||
/// Canonical Native Loader Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_LOADER_NATIVE;
|
||||
/// Canonical Loader v4 Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_LOADER_V4;
|
||||
/// Canonical Ed25519 precompile Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_PRECOMPILE_ED25519;
|
||||
/// Canonical Secp256k1 precompile Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_PRECOMPILE_SECP256K1;
|
||||
/// Canonical Secp256r1 precompile Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_PRECOMPILE_SECP256R1;
|
||||
/// Canonical Slashing Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_SLASHING;
|
||||
/// Canonical Stake Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_STAKE;
|
||||
/// Canonical System Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_SYSTEM;
|
||||
/// Canonical Vote Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_VOTE;
|
||||
/// Canonical ZK ElGamal Proof Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_ZK_ELGAMAL_PROOF;
|
||||
/// Canonical ZK Token Proof Program ID as Base58 text.
|
||||
pub use self::program_ids::PRGID_SOLANA_ZK_TOKEN_PROOF;
|
||||
/// Canonical Address Lookup Table Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_ADDRESS_LOOKUP_TABLE;
|
||||
/// Canonical Compute Budget Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_COMPUTE_BUDGET;
|
||||
/// Canonical Config Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_CONFIG;
|
||||
/// Canonical Feature Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_FEATURE;
|
||||
/// Canonical upgradeable BPF Loader Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_LOADER_BPF_UPGRADEABLE;
|
||||
/// Canonical deprecated BPF Loader Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_LOADER_BPF_V1;
|
||||
/// Canonical BPF Loader v2 Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_LOADER_BPF_V2;
|
||||
/// Canonical Native Loader Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_LOADER_NATIVE;
|
||||
/// Canonical Loader v4 Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_LOADER_V4;
|
||||
/// Canonical Ed25519 precompile Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_PRECOMPILE_ED25519;
|
||||
/// Canonical Secp256k1 precompile Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_PRECOMPILE_SECP256K1;
|
||||
/// Canonical Secp256r1 precompile Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_PRECOMPILE_SECP256R1;
|
||||
/// Canonical Slashing Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_SLASHING;
|
||||
/// Canonical Stake Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_STAKE;
|
||||
/// Canonical System Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_SYSTEM;
|
||||
/// Canonical Vote Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_VOTE;
|
||||
/// Canonical ZK ElGamal Proof Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_ZK_ELGAMAL_PROOF;
|
||||
/// Canonical ZK Token Proof Program ID as a typed [`Pubkey`].
|
||||
pub use self::program_ids::PRGIDPK_SOLANA_ZK_TOKEN_PROOF;
|
||||
/// Immutable descriptor for one registered Program ID.
|
||||
pub use self::program_ids::ProgramIdEntry;
|
||||
/// Borrowed multi-axis filter for the canonical Program ID registry.
|
||||
pub use self::program_ids::ProgramIdFilter;
|
||||
/// Technical classification of one registered Program ID.
|
||||
pub use self::program_ids::ProgramIdKind;
|
||||
/// Returns the canonical Program ID registry.
|
||||
pub use self::program_ids::entries;
|
||||
/// Finds one registered Program ID by its Base58 representation.
|
||||
pub use self::program_ids::find_program_id;
|
||||
/// Finds one registered Program ID by its typed [`Pubkey`] representation.
|
||||
pub use self::program_ids::find_program_pubkey;
|
||||
/// Returns the Solana core/native Program ID view.
|
||||
pub use self::program_ids::native_program_ids;
|
||||
/// Returns Program IDs matching a multi-axis filter.
|
||||
pub use self::program_ids::program_ids;
|
||||
/// Returns Program IDs belonging to one domain.
|
||||
pub use self::program_ids::program_ids_by_domain;
|
||||
/// Returns Program IDs belonging to one family.
|
||||
pub use self::program_ids::program_ids_by_family;
|
||||
/// Returns Program IDs belonging to one protocol or project.
|
||||
pub use self::program_ids::program_ids_by_protocol;
|
||||
/// Solana account address primitive used by KSP Program IDs.
|
||||
pub use solana_pubkey::Pubkey;
|
||||
|
||||
492
crates/ksp-core-lib/src/program_ids.rs
Normal file
492
crates/ksp-core-lib/src/program_ids.rs
Normal file
@@ -0,0 +1,492 @@
|
||||
// file: crates/ksp-core-lib/src/program_ids.rs
|
||||
// version: 2
|
||||
|
||||
const DOMAIN_SOLANA: &str = "solana";
|
||||
const FAMILY_CONSENSUS: &str = "consensus";
|
||||
const FAMILY_LOADER: &str = "loader";
|
||||
const FAMILY_PRECOMPILE: &str = "precompile";
|
||||
const FAMILY_PROOF: &str = "proof";
|
||||
const FAMILY_RUNTIME: &str = "runtime";
|
||||
const PROTOCOL_SOLANA: &str = "solana";
|
||||
|
||||
/// Declares one KSP-owned Solana Program ID as matching Base58 and typed constants.
|
||||
///
|
||||
/// The Base58 literal is written once and decoded at compile time through [`crate::Pubkey`].
|
||||
#[macro_export]
|
||||
macro_rules! declare_program_id {
|
||||
($string_name:ident, $pubkey_name:ident, $value:literal) => {
|
||||
#[doc = concat!("Base58 Program ID declared as `", stringify!($string_name), "`.")]
|
||||
pub const $string_name: &str = $value;
|
||||
#[doc = concat!("Typed Program ID corresponding to `", stringify!($string_name), "`.")]
|
||||
pub const $pubkey_name: $crate::Pubkey = $crate::Pubkey::from_str_const($string_name);
|
||||
};
|
||||
}
|
||||
|
||||
crate::declare_program_id!(PRGID_SOLANA_ADDRESS_LOOKUP_TABLE, PRGIDPK_SOLANA_ADDRESS_LOOKUP_TABLE, "AddressLookupTab1e1111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_LOADER_BPF_V1, PRGIDPK_SOLANA_LOADER_BPF_V1, "BPFLoader1111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_LOADER_BPF_V2, PRGIDPK_SOLANA_LOADER_BPF_V2, "BPFLoader2111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_LOADER_BPF_UPGRADEABLE, PRGIDPK_SOLANA_LOADER_BPF_UPGRADEABLE, "BPFLoaderUpgradeab1e11111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_COMPUTE_BUDGET, PRGIDPK_SOLANA_COMPUTE_BUDGET, "ComputeBudget111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_CONFIG, PRGIDPK_SOLANA_CONFIG, "Config1111111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_PRECOMPILE_ED25519, PRGIDPK_SOLANA_PRECOMPILE_ED25519, "Ed25519SigVerify111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_FEATURE, PRGIDPK_SOLANA_FEATURE, "Feature111111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_LOADER_V4, PRGIDPK_SOLANA_LOADER_V4, "LoaderV411111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_LOADER_NATIVE, PRGIDPK_SOLANA_LOADER_NATIVE, "NativeLoader1111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_PRECOMPILE_SECP256K1, PRGIDPK_SOLANA_PRECOMPILE_SECP256K1, "KeccakSecp256k11111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_PRECOMPILE_SECP256R1, PRGIDPK_SOLANA_PRECOMPILE_SECP256R1, "Secp256r1SigVerify1111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_SLASHING, PRGIDPK_SOLANA_SLASHING, "S1ashing11111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_STAKE, PRGIDPK_SOLANA_STAKE, "Stake11111111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_SYSTEM, PRGIDPK_SOLANA_SYSTEM, "11111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_VOTE, PRGIDPK_SOLANA_VOTE, "Vote111111111111111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_ZK_ELGAMAL_PROOF, PRGIDPK_SOLANA_ZK_ELGAMAL_PROOF, "ZkE1Gama1Proof11111111111111111111111111111");
|
||||
crate::declare_program_id!(PRGID_SOLANA_ZK_TOKEN_PROOF, PRGIDPK_SOLANA_ZK_TOKEN_PROOF, "ZkTokenProof1111111111111111111111111111111");
|
||||
|
||||
/// Technical classification of a registered Program ID.
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ProgramIdKind {
|
||||
/// A regular executable program belonging to the registered protocol surface.
|
||||
Program,
|
||||
/// A Solana program loader.
|
||||
Loader,
|
||||
/// A runtime precompile exposed through a Program ID.
|
||||
Precompile,
|
||||
/// An enshrined on-chain program deployed as part of the Solana protocol.
|
||||
EnshrinedProgram,
|
||||
}
|
||||
|
||||
/// Immutable descriptor for one KSP-owned Program ID.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct ProgramIdEntry {
|
||||
code: &'static str,
|
||||
name: &'static str,
|
||||
program_id: &'static str,
|
||||
pubkey: crate::Pubkey,
|
||||
domain: &'static str,
|
||||
family: &'static str,
|
||||
protocol: &'static str,
|
||||
subfamily: std::option::Option<&'static str>,
|
||||
program_version: std::option::Option<&'static str>,
|
||||
kind: crate::ProgramIdKind,
|
||||
}
|
||||
|
||||
impl ProgramIdEntry {
|
||||
const fn new(code: &'static str, name: &'static str, program_id: &'static str, pubkey: crate::Pubkey) -> Self {
|
||||
return Self {
|
||||
code,
|
||||
name,
|
||||
program_id,
|
||||
pubkey,
|
||||
domain: "",
|
||||
family: "",
|
||||
protocol: "",
|
||||
subfamily: std::option::Option::None,
|
||||
program_version: std::option::Option::None,
|
||||
kind: crate::ProgramIdKind::Program,
|
||||
};
|
||||
}
|
||||
|
||||
const fn with_taxonomy(
|
||||
mut self,
|
||||
domain: &'static str,
|
||||
family: &'static str,
|
||||
protocol: &'static str,
|
||||
subfamily: std::option::Option<&'static str>,
|
||||
program_version: std::option::Option<&'static str>,
|
||||
kind: crate::ProgramIdKind,
|
||||
) -> Self {
|
||||
self.domain = domain;
|
||||
self.family = family;
|
||||
self.protocol = protocol;
|
||||
self.subfamily = subfamily;
|
||||
self.program_version = program_version;
|
||||
self.kind = kind;
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Returns the stable KSP machine-readable code of this entry.
|
||||
#[must_use]
|
||||
pub const fn code(&self) -> &'static str {
|
||||
return self.code;
|
||||
}
|
||||
|
||||
/// Returns the human-readable program name.
|
||||
#[must_use]
|
||||
pub const fn name(&self) -> &'static str {
|
||||
return self.name;
|
||||
}
|
||||
|
||||
/// Returns the canonical Base58 Program ID.
|
||||
#[must_use]
|
||||
pub const fn program_id(&self) -> &'static str {
|
||||
return self.program_id;
|
||||
}
|
||||
|
||||
/// Returns the typed Solana Program ID.
|
||||
#[must_use]
|
||||
pub const fn pubkey(&self) -> crate::Pubkey {
|
||||
return self.pubkey;
|
||||
}
|
||||
|
||||
/// Returns the broad functional domain.
|
||||
#[must_use]
|
||||
pub const fn domain(&self) -> &'static str {
|
||||
return self.domain;
|
||||
}
|
||||
|
||||
/// Returns the functional family within the domain.
|
||||
#[must_use]
|
||||
pub const fn family(&self) -> &'static str {
|
||||
return self.family;
|
||||
}
|
||||
|
||||
/// Returns the owning protocol or project identifier.
|
||||
#[must_use]
|
||||
pub const fn protocol(&self) -> &'static str {
|
||||
return self.protocol;
|
||||
}
|
||||
|
||||
/// Returns the optional architectural branch or product subfamily.
|
||||
#[must_use]
|
||||
pub const fn subfamily(&self) -> std::option::Option<&'static str> {
|
||||
return self.subfamily;
|
||||
}
|
||||
|
||||
/// Returns the optional public generation of this program lineage.
|
||||
#[must_use]
|
||||
pub const fn program_version(&self) -> std::option::Option<&'static str> {
|
||||
return self.program_version;
|
||||
}
|
||||
|
||||
/// Returns the technical Program ID classification.
|
||||
#[must_use]
|
||||
pub const fn kind(&self) -> crate::ProgramIdKind {
|
||||
return self.kind;
|
||||
}
|
||||
}
|
||||
|
||||
/// Borrowed filter used to select Program IDs from the canonical KSP registry.
|
||||
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
|
||||
pub struct ProgramIdFilter<'a> {
|
||||
domain: std::option::Option<&'a str>,
|
||||
family: std::option::Option<&'a str>,
|
||||
protocol: std::option::Option<&'a str>,
|
||||
subfamily: std::option::Option<&'a str>,
|
||||
program_version: std::option::Option<&'a str>,
|
||||
kind: std::option::Option<crate::ProgramIdKind>,
|
||||
}
|
||||
|
||||
impl<'a> ProgramIdFilter<'a> {
|
||||
/// Creates an empty filter matching every registered Program ID.
|
||||
#[must_use]
|
||||
pub const fn new() -> Self {
|
||||
return Self {
|
||||
domain: std::option::Option::None,
|
||||
family: std::option::Option::None,
|
||||
protocol: std::option::Option::None,
|
||||
subfamily: std::option::Option::None,
|
||||
program_version: std::option::Option::None,
|
||||
kind: std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
/// Restricts the filter to one functional domain.
|
||||
#[must_use]
|
||||
pub const fn with_domain(mut self, domain: &'a str) -> Self {
|
||||
self.domain = std::option::Option::Some(domain);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Restricts the filter to one functional family.
|
||||
#[must_use]
|
||||
pub const fn with_family(mut self, family: &'a str) -> Self {
|
||||
self.family = std::option::Option::Some(family);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Restricts the filter to one protocol or project.
|
||||
#[must_use]
|
||||
pub const fn with_protocol(mut self, protocol: &'a str) -> Self {
|
||||
self.protocol = std::option::Option::Some(protocol);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Restricts the filter to one architectural subfamily.
|
||||
#[must_use]
|
||||
pub const fn with_subfamily(mut self, subfamily: &'a str) -> Self {
|
||||
self.subfamily = std::option::Option::Some(subfamily);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Restricts the filter to one public program generation.
|
||||
#[must_use]
|
||||
pub const fn with_program_version(mut self, program_version: &'a str) -> Self {
|
||||
self.program_version = std::option::Option::Some(program_version);
|
||||
return self;
|
||||
}
|
||||
|
||||
/// Restricts the filter to one technical Program ID kind.
|
||||
#[must_use]
|
||||
pub const fn with_kind(mut self, kind: crate::ProgramIdKind) -> Self {
|
||||
self.kind = std::option::Option::Some(kind);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn matches(&self, entry: &crate::ProgramIdEntry) -> bool {
|
||||
if let std::option::Option::Some(domain) = self.domain
|
||||
&& entry.domain() != domain
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let std::option::Option::Some(family) = self.family
|
||||
&& entry.family() != family
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let std::option::Option::Some(protocol) = self.protocol
|
||||
&& entry.protocol() != protocol
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let std::option::Option::Some(subfamily) = self.subfamily
|
||||
&& entry.subfamily() != std::option::Option::Some(subfamily)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let std::option::Option::Some(program_version) = self.program_version
|
||||
&& entry.program_version() != std::option::Option::Some(program_version)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if let std::option::Option::Some(kind) = self.kind
|
||||
&& entry.kind() != kind
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const PROGRAM_ID_ENTRIES: &[crate::ProgramIdEntry] = &[
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.address_lookup_table",
|
||||
"Address Lookup Table Program",
|
||||
crate::PRGID_SOLANA_ADDRESS_LOOKUP_TABLE,
|
||||
crate::PRGIDPK_SOLANA_ADDRESS_LOOKUP_TABLE,
|
||||
)
|
||||
.with_taxonomy(DOMAIN_SOLANA, FAMILY_RUNTIME, PROTOCOL_SOLANA, std::option::Option::None, std::option::Option::None, crate::ProgramIdKind::Program),
|
||||
crate::ProgramIdEntry::new("solana.loader.bpf.v1", "Deprecated BPF Loader", crate::PRGID_SOLANA_LOADER_BPF_V1, crate::PRGIDPK_SOLANA_LOADER_BPF_V1)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_LOADER,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("bpf"),
|
||||
std::option::Option::Some("v1"),
|
||||
crate::ProgramIdKind::Loader,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.loader.bpf.v2", "BPF Loader v2", crate::PRGID_SOLANA_LOADER_BPF_V2, crate::PRGIDPK_SOLANA_LOADER_BPF_V2).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_LOADER,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("bpf"),
|
||||
std::option::Option::Some("v2"),
|
||||
crate::ProgramIdKind::Loader,
|
||||
),
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.loader.bpf_upgradeable",
|
||||
"Upgradeable BPF Loader",
|
||||
crate::PRGID_SOLANA_LOADER_BPF_UPGRADEABLE,
|
||||
crate::PRGIDPK_SOLANA_LOADER_BPF_UPGRADEABLE,
|
||||
)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_LOADER,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("bpf"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Loader,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.compute_budget", "Compute Budget Program", crate::PRGID_SOLANA_COMPUTE_BUDGET, crate::PRGIDPK_SOLANA_COMPUTE_BUDGET)
|
||||
.with_taxonomy(DOMAIN_SOLANA, FAMILY_RUNTIME, PROTOCOL_SOLANA, std::option::Option::None, std::option::Option::None, crate::ProgramIdKind::Program),
|
||||
crate::ProgramIdEntry::new("solana.config", "Config Program", crate::PRGID_SOLANA_CONFIG, crate::PRGIDPK_SOLANA_CONFIG).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_RUNTIME,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.precompile.ed25519",
|
||||
"Ed25519 Signature Verification Precompile",
|
||||
crate::PRGID_SOLANA_PRECOMPILE_ED25519,
|
||||
crate::PRGIDPK_SOLANA_PRECOMPILE_ED25519,
|
||||
)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_PRECOMPILE,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("ed25519"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Precompile,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.feature", "Feature Program", crate::PRGID_SOLANA_FEATURE, crate::PRGIDPK_SOLANA_FEATURE).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_RUNTIME,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.loader.v4", "Loader v4", crate::PRGID_SOLANA_LOADER_V4, crate::PRGIDPK_SOLANA_LOADER_V4).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_LOADER,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::Some("v4"),
|
||||
crate::ProgramIdKind::Loader,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.loader.native", "Native Loader", crate::PRGID_SOLANA_LOADER_NATIVE, crate::PRGIDPK_SOLANA_LOADER_NATIVE).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_LOADER,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("native"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Loader,
|
||||
),
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.precompile.secp256k1",
|
||||
"Secp256k1 Signature Verification Precompile",
|
||||
crate::PRGID_SOLANA_PRECOMPILE_SECP256K1,
|
||||
crate::PRGIDPK_SOLANA_PRECOMPILE_SECP256K1,
|
||||
)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_PRECOMPILE,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("secp256k1"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Precompile,
|
||||
),
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.precompile.secp256r1",
|
||||
"Secp256r1 Signature Verification Precompile",
|
||||
crate::PRGID_SOLANA_PRECOMPILE_SECP256R1,
|
||||
crate::PRGIDPK_SOLANA_PRECOMPILE_SECP256R1,
|
||||
)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_PRECOMPILE,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("secp256r1"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Precompile,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.slashing", "Slashing Program", crate::PRGID_SOLANA_SLASHING, crate::PRGIDPK_SOLANA_SLASHING).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_CONSENSUS,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::EnshrinedProgram,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.stake", "Stake Program", crate::PRGID_SOLANA_STAKE, crate::PRGIDPK_SOLANA_STAKE).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_CONSENSUS,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.system", "System Program", crate::PRGID_SOLANA_SYSTEM, crate::PRGIDPK_SOLANA_SYSTEM).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_RUNTIME,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.vote", "Vote Program", crate::PRGID_SOLANA_VOTE, crate::PRGIDPK_SOLANA_VOTE).with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_CONSENSUS,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::None,
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new(
|
||||
"solana.proof.zk_elgamal",
|
||||
"ZK ElGamal Proof Program",
|
||||
crate::PRGID_SOLANA_ZK_ELGAMAL_PROOF,
|
||||
crate::PRGIDPK_SOLANA_ZK_ELGAMAL_PROOF,
|
||||
)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_PROOF,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("zk_elgamal"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
crate::ProgramIdEntry::new("solana.proof.zk_token", "ZK Token Proof Program", crate::PRGID_SOLANA_ZK_TOKEN_PROOF, crate::PRGIDPK_SOLANA_ZK_TOKEN_PROOF)
|
||||
.with_taxonomy(
|
||||
DOMAIN_SOLANA,
|
||||
FAMILY_PROOF,
|
||||
PROTOCOL_SOLANA,
|
||||
std::option::Option::Some("zk_token"),
|
||||
std::option::Option::None,
|
||||
crate::ProgramIdKind::Program,
|
||||
),
|
||||
];
|
||||
|
||||
/// Returns the canonical KSP Program ID registry.
|
||||
#[must_use]
|
||||
pub const fn entries() -> &'static [crate::ProgramIdEntry] {
|
||||
return PROGRAM_ID_ENTRIES;
|
||||
}
|
||||
|
||||
/// Returns a lazy view of Program IDs matching all configured filter axes.
|
||||
pub fn program_ids<'a>(filter: crate::ProgramIdFilter<'a>) -> impl std::iter::Iterator<Item = &'static crate::ProgramIdEntry> + 'a {
|
||||
return PROGRAM_ID_ENTRIES.iter().filter(move |entry| {
|
||||
return filter.matches(entry);
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns all Solana core/native Program IDs, including loaders, precompiles and enshrined programs.
|
||||
pub fn native_program_ids() -> impl std::iter::Iterator<Item = &'static crate::ProgramIdEntry> {
|
||||
return crate::program_ids(crate::ProgramIdFilter::new().with_domain(DOMAIN_SOLANA).with_protocol(PROTOCOL_SOLANA));
|
||||
}
|
||||
|
||||
/// Returns a lazy view of Program IDs belonging to one functional domain.
|
||||
pub fn program_ids_by_domain<'a>(domain: &'a str) -> impl std::iter::Iterator<Item = &'static crate::ProgramIdEntry> + 'a {
|
||||
return crate::program_ids(crate::ProgramIdFilter::new().with_domain(domain));
|
||||
}
|
||||
|
||||
/// Returns a lazy view of Program IDs belonging to one functional family.
|
||||
pub fn program_ids_by_family<'a>(family: &'a str) -> impl std::iter::Iterator<Item = &'static crate::ProgramIdEntry> + 'a {
|
||||
return crate::program_ids(crate::ProgramIdFilter::new().with_family(family));
|
||||
}
|
||||
|
||||
/// Returns a lazy view of Program IDs belonging to one protocol or project.
|
||||
pub fn program_ids_by_protocol<'a>(protocol: &'a str) -> impl std::iter::Iterator<Item = &'static crate::ProgramIdEntry> + 'a {
|
||||
return crate::program_ids(crate::ProgramIdFilter::new().with_protocol(protocol));
|
||||
}
|
||||
|
||||
/// Finds one registered Program ID by its canonical Base58 representation.
|
||||
#[must_use]
|
||||
pub fn find_program_id(program_id: &str) -> std::option::Option<&'static crate::ProgramIdEntry> {
|
||||
return PROGRAM_ID_ENTRIES.iter().find(|entry| {
|
||||
return entry.program_id() == program_id;
|
||||
});
|
||||
}
|
||||
|
||||
/// Finds one registered Program ID by its typed Solana representation.
|
||||
#[must_use]
|
||||
pub fn find_program_pubkey(program_id: &crate::Pubkey) -> std::option::Option<&'static crate::ProgramIdEntry> {
|
||||
return PROGRAM_ID_ENTRIES.iter().find(|entry| {
|
||||
return entry.pubkey() == *program_id;
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/program_ids.rs"]
|
||||
mod tests;
|
||||
67
crates/ksp-core-lib/tests/public_api.rs
Normal file
67
crates/ksp-core-lib/tests/public_api.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
// file: crates/ksp-core-lib/tests/public_api.rs
|
||||
// version: 4
|
||||
|
||||
//! Integration tests for the public `ksp-core-lib` contracts.
|
||||
|
||||
ksp_core_lib::declare_program_id!(TEST_PRGID_SYSTEM, TEST_PRGIDPK_SYSTEM, "11111111111111111111111111111111");
|
||||
|
||||
const TEST_ERROR_CODE: ksp_core_lib::ErrorCode = ksp_core_lib::ErrorCode::new("consumer", "failed");
|
||||
|
||||
fn public_result() -> ksp_core_lib::Result<()> {
|
||||
let error = ksp_core_lib::Error::new(TEST_ERROR_CODE, "consumer failure").with_context("operation", "public_api");
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_contract_is_consumable_from_crate_root() {
|
||||
let result = public_result();
|
||||
assert!(result.is_err());
|
||||
let error = match result {
|
||||
std::result::Result::Ok(()) => return,
|
||||
std::result::Result::Err(error) => error,
|
||||
};
|
||||
assert_eq!(error.code(), TEST_ERROR_CODE);
|
||||
assert_eq!(error.message(), "consumer failure");
|
||||
assert_eq!(error.context(), &[ksp_core_lib::ErrorContext::new("operation", "public_api")]);
|
||||
assert_eq!(std::string::ToString::to_string(&error), "consumer.failed: consumer failure");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn program_id_contract_is_consumable_from_crate_root() {
|
||||
assert_eq!(TEST_PRGID_SYSTEM, ksp_core_lib::PRGID_SOLANA_SYSTEM);
|
||||
assert_eq!(TEST_PRGIDPK_SYSTEM, ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
|
||||
assert_eq!(ksp_core_lib::entries().len(), 18);
|
||||
assert_eq!(ksp_core_lib::native_program_ids().count(), 18);
|
||||
let system = ksp_core_lib::find_program_id(ksp_core_lib::PRGID_SOLANA_SYSTEM);
|
||||
let system = match system {
|
||||
std::option::Option::Some(entry) => entry,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert_eq!(system.code(), "solana.system");
|
||||
assert_eq!(system.domain(), "solana");
|
||||
assert_eq!(system.family(), "runtime");
|
||||
assert_eq!(system.protocol(), "solana");
|
||||
assert_eq!(system.pubkey(), ksp_core_lib::PRGIDPK_SOLANA_SYSTEM);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn program_id_registry_supports_public_taxonomy_filters() {
|
||||
let loader_count = ksp_core_lib::program_ids_by_family("loader").count();
|
||||
let precompile_count = ksp_core_lib::program_ids_by_family("precompile").count();
|
||||
let bpf_v2_count = ksp_core_lib::program_ids(
|
||||
ksp_core_lib::ProgramIdFilter::new()
|
||||
.with_domain("solana")
|
||||
.with_family("loader")
|
||||
.with_protocol("solana")
|
||||
.with_subfamily("bpf")
|
||||
.with_program_version("v2")
|
||||
.with_kind(ksp_core_lib::ProgramIdKind::Loader),
|
||||
)
|
||||
.count();
|
||||
assert_eq!(loader_count, 5);
|
||||
assert_eq!(precompile_count, 3);
|
||||
assert_eq!(bpf_v2_count, 1);
|
||||
return;
|
||||
}
|
||||
78
crates/ksp-core-lib/unit_tests/error.rs
Normal file
78
crates/ksp-core-lib/unit_tests/error.rs
Normal file
@@ -0,0 +1,78 @@
|
||||
// file: crates/ksp-core-lib/unit_tests/error.rs
|
||||
// version: 2
|
||||
|
||||
#[derive(Debug)]
|
||||
struct TestSource;
|
||||
|
||||
impl std::fmt::Display for TestSource {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter.write_str("source failure");
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for TestSource {}
|
||||
|
||||
fn assert_send_sync<T>(_: std::marker::PhantomData<T>)
|
||||
where
|
||||
T: std::marker::Send + std::marker::Sync,
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_code_preserves_domain_and_code() {
|
||||
const CODE: crate::ErrorCode = crate::ErrorCode::new("core", "sample_failure");
|
||||
assert_eq!(CODE.domain(), "core");
|
||||
assert_eq!(CODE.code(), "sample_failure");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_context_preserves_key_and_value() {
|
||||
let context = crate::ErrorContext::new("operation", "sample");
|
||||
assert_eq!(context.key(), "operation");
|
||||
assert_eq!(context.value(), "sample");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_preserves_code_message_and_context_order() {
|
||||
let code = crate::ErrorCode::new("core", "sample_failure");
|
||||
let error = crate::Error::new(code, "sample message").with_context("first", "one").with_context("second", "two");
|
||||
assert_eq!(error.code(), code);
|
||||
assert_eq!(error.message(), "sample message");
|
||||
assert_eq!(error.context().len(), 2);
|
||||
assert_eq!(error.context()[0].key(), "first");
|
||||
assert_eq!(error.context()[0].value(), "one");
|
||||
assert_eq!(error.context()[1].key(), "second");
|
||||
assert_eq!(error.context()[1].value(), "two");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_contains_only_qualified_code_and_message() {
|
||||
let error = crate::Error::new(crate::ErrorCode::new("core", "sample_failure"), "sample message")
|
||||
.with_context("secret_free_context", "not rendered")
|
||||
.with_source(TestSource);
|
||||
assert_eq!(std::string::ToString::to_string(&error), "core.sample_failure: sample message");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn standard_source_is_preserved() {
|
||||
let error = crate::Error::new(crate::ErrorCode::new("core", "sample_failure"), "sample message").with_source(TestSource);
|
||||
let source = std::error::Error::source(&error);
|
||||
assert!(source.is_some());
|
||||
let source_message = match source {
|
||||
std::option::Option::Some(value) => std::string::ToString::to_string(value),
|
||||
std::option::Option::None => std::string::String::new(),
|
||||
};
|
||||
assert_eq!(source_message, "source failure");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn common_error_is_send_and_sync() {
|
||||
assert_send_sync(std::marker::PhantomData::<crate::Error>);
|
||||
return;
|
||||
}
|
||||
89
crates/ksp-core-lib/unit_tests/program_ids.rs
Normal file
89
crates/ksp-core-lib/unit_tests/program_ids.rs
Normal file
@@ -0,0 +1,89 @@
|
||||
// file: crates/ksp-core-lib/unit_tests/program_ids.rs
|
||||
// version: 1
|
||||
|
||||
fn assert_program_id_types(program_id: &'static str, pubkey: crate::Pubkey) {
|
||||
assert_eq!(pubkey, crate::Pubkey::from_str_const(program_id));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn declared_program_ids_have_matching_text_and_pubkey_forms() {
|
||||
assert_program_id_types(crate::PRGID_SOLANA_SYSTEM, crate::PRGIDPK_SOLANA_SYSTEM);
|
||||
assert_program_id_types(crate::PRGID_SOLANA_STAKE, crate::PRGIDPK_SOLANA_STAKE);
|
||||
assert_program_id_types(crate::PRGID_SOLANA_VOTE, crate::PRGIDPK_SOLANA_VOTE);
|
||||
assert_program_id_types(crate::PRGID_SOLANA_SLASHING, crate::PRGIDPK_SOLANA_SLASHING);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_contains_the_eighteen_core_program_ids() {
|
||||
assert_eq!(crate::entries().len(), 18);
|
||||
assert_eq!(crate::native_program_ids().count(), 18);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_codes_program_ids_and_pubkeys_are_unique() {
|
||||
for left_index in 0..crate::entries().len() {
|
||||
for right_index in (left_index + 1)..crate::entries().len() {
|
||||
let left = &crate::entries()[left_index];
|
||||
let right = &crate::entries()[right_index];
|
||||
assert_ne!(left.code(), right.code());
|
||||
assert_ne!(left.program_id(), right.program_id());
|
||||
assert_ne!(left.pubkey(), right.pubkey());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn registry_pubkeys_match_their_owned_base58_values() {
|
||||
for entry in crate::entries() {
|
||||
assert_eq!(entry.pubkey(), crate::Pubkey::from_str_const(entry.program_id()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn filters_combine_domain_family_protocol_subfamily_version_and_kind() {
|
||||
let bpf_v2 = crate::program_ids(
|
||||
crate::ProgramIdFilter::new()
|
||||
.with_domain("solana")
|
||||
.with_family("loader")
|
||||
.with_protocol("solana")
|
||||
.with_subfamily("bpf")
|
||||
.with_program_version("v2")
|
||||
.with_kind(crate::ProgramIdKind::Loader),
|
||||
)
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
assert_eq!(bpf_v2.len(), 1);
|
||||
assert_eq!(bpf_v2[0].program_id(), crate::PRGID_SOLANA_LOADER_BPF_V2);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn family_views_cover_expected_core_groups() {
|
||||
assert_eq!(crate::program_ids_by_family("runtime").count(), 5);
|
||||
assert_eq!(crate::program_ids_by_family("consensus").count(), 3);
|
||||
assert_eq!(crate::program_ids_by_family("loader").count(), 5);
|
||||
assert_eq!(crate::program_ids_by_family("precompile").count(), 3);
|
||||
assert_eq!(crate::program_ids_by_family("proof").count(), 2);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn direct_lookup_supports_text_and_typed_program_ids() {
|
||||
let by_text = crate::find_program_id(crate::PRGID_SOLANA_SLASHING);
|
||||
let by_pubkey = crate::find_program_pubkey(&crate::PRGIDPK_SOLANA_SLASHING);
|
||||
assert_eq!(by_text.map(crate::ProgramIdEntry::code), std::option::Option::Some("solana.slashing"));
|
||||
assert_eq!(by_pubkey.map(crate::ProgramIdEntry::code), std::option::Option::Some("solana.slashing"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn non_program_well_known_accounts_are_absent() {
|
||||
assert!(crate::find_program_id("1nc1nerator11111111111111111111111111111111").is_none());
|
||||
assert!(crate::find_program_id("StakeConfig11111111111111111111111111111111").is_none());
|
||||
assert!(crate::find_program_id("SysvarC1ock11111111111111111111111111111111").is_none());
|
||||
return;
|
||||
}
|
||||
285
deltas/0.1.1/pre.001-fix.001.md
Normal file
285
deltas/0.1.1/pre.001-fix.001.md
Normal file
@@ -0,0 +1,285 @@
|
||||
<!-- file: deltas/0.1.1/pre.001-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.1-pre.001-fix.001
|
||||
|
||||
## Base requise
|
||||
|
||||
Livraison précédente appliquée et commitée :
|
||||
|
||||
```text
|
||||
0.1.1-pre.001
|
||||
```
|
||||
|
||||
La base stable initiale `khadhroony-solana-project-v0.0.3.zip` provient directement de Gitea depuis le tag `v0.0.3`. L'absence de `.git` dans cette archive n'impose donc aucune vérification supplémentaire du tag pour le cadrage de cette session.
|
||||
|
||||
## Type de livraison
|
||||
|
||||
```text
|
||||
ksp-doc-0.1.1-pre.001-fix.001.zip
|
||||
```
|
||||
|
||||
## Objectif
|
||||
|
||||
Corriger le plan de `0.1.1-pre.001` après validation du brainstorming Program IDs, sans ouvrir `pre.002` et sans modifier de code/runtime.
|
||||
|
||||
Ce correctif :
|
||||
|
||||
- confirme `solana-pubkey` comme dépendance Solana fondamentale candidate de Core ;
|
||||
- interdit `solana-sdk-ids` comme dépendance KSP, y compris de développement ;
|
||||
- fait posséder à KSP ses chaînes Base58 et représentations `Pubkey` de Program IDs ;
|
||||
- fixe les préfixes `PRGID_` et `PRGIDPK_` ;
|
||||
- fixe la structure générale de nomenclature `<PREFIX>_<DOMAIN>_<SUBDOMAIN?>_<NAME>_<VERSION?>` ;
|
||||
- prévoit une macro KSP `declare_program_id!` produisant les deux représentations depuis une déclaration unique ;
|
||||
- réintroduit et améliore le concept de registre descriptif enumerable inspiré de l'ancien `ks-program-ids` ;
|
||||
- supprime le nombre arbitrairement figé de 17 Program IDs avant l'inventaire final de `pre.003` ;
|
||||
- maintient la séparation stricte entre Program IDs et well-known accounts.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
Aucun fichier participant au code, build, runtime, à la configuration exécutable ou aux migrations n'est modifié.
|
||||
|
||||
Conformément à `VER-ID-008`, `workspace.package.version` reste donc :
|
||||
|
||||
```text
|
||||
0.1.1-pre.1
|
||||
```
|
||||
|
||||
Le correctif possède néanmoins son identifiant de livraison/commit propre :
|
||||
|
||||
```text
|
||||
0.1.1-pre.001-fix.001
|
||||
```
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `deltas/0.1.1/pre.001-fix.001.md`
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` — version documentaire 1 -> 2.
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Corrections et décisions incorporées
|
||||
|
||||
### Provenance de la base stable
|
||||
|
||||
La réserve de `pre.001` liée à l'absence de `.git` dans l'archive Gitea est retirée du plan actif.
|
||||
|
||||
Dans le workflow KSP fourni, une archive nommée `khadhroony-solana-project-vX.Y.Z.zip` est produite directement par Gitea depuis le tag correspondant. `khadhroony-solana-project-v0.0.3.zip` est donc acceptée comme base stable/taguée `v0.0.3`.
|
||||
|
||||
Le delta `pre.001` déjà livré n'est pas réécrit ; ce correctif trace explicitement la correction.
|
||||
|
||||
### Dépendances Solana/Anza
|
||||
|
||||
Direction acquise :
|
||||
|
||||
```text
|
||||
ksp-core-lib -> solana-pubkey
|
||||
```
|
||||
|
||||
lorsque `pre.003` implémentera réellement la surface Program IDs.
|
||||
|
||||
En revanche :
|
||||
|
||||
```text
|
||||
ksp-core-lib -X-> solana-sdk-ids
|
||||
```
|
||||
|
||||
s'applique aux dépendances runtime **et** de développement.
|
||||
|
||||
`solana-sdk-ids` peut être consultée comme source officielle externe lors des audits, mais elle ne doit pas entrer dans le graphe Cargo KSP.
|
||||
|
||||
### Ownership et représentations des Program IDs
|
||||
|
||||
KSP possède la valeur Base58 canonique de chaque Program ID retenu.
|
||||
|
||||
Chaque ID expose deux représentations publiques liées :
|
||||
|
||||
```text
|
||||
PRGID_<SUFFIXE> : &'static str
|
||||
PRGIDPK_<SUFFIXE> : Pubkey
|
||||
```
|
||||
|
||||
Le suffixe doit être strictement identique entre les deux formes.
|
||||
|
||||
La nomenclature générale est :
|
||||
|
||||
```text
|
||||
<PREFIX>_<DOMAIN>_<SUBDOMAIN?>_<NAME>_<VERSION?>
|
||||
```
|
||||
|
||||
Exemples de convention :
|
||||
|
||||
```text
|
||||
PRGID_SOLANA_SYSTEM
|
||||
PRGIDPK_SOLANA_SYSTEM
|
||||
|
||||
PRGID_SOLANA_LOADER_BPF_V2
|
||||
PRGIDPK_SOLANA_LOADER_BPF_V2
|
||||
|
||||
PRGID_SOLANA_PRECOMPILE_ED25519
|
||||
PRGIDPK_SOLANA_PRECOMPILE_ED25519
|
||||
|
||||
PRGID_SPL_MEMO_V3
|
||||
PRGIDPK_SPL_MEMO_V3
|
||||
```
|
||||
|
||||
L'exemple SPL Memo définit uniquement la convention future ; il n'ouvre pas SPL dans le périmètre fonctionnel de `0.1.1`.
|
||||
|
||||
### Macro de déclaration
|
||||
|
||||
Le plan prévoit une macro publique KSP initialement nommée :
|
||||
|
||||
```text
|
||||
declare_program_id!
|
||||
```
|
||||
|
||||
Elle doit prendre une seule valeur Base58 canonique et produire les deux constantes `PRGID_*` et `PRGIDPK_*` correspondantes à la compilation.
|
||||
|
||||
La macro doit s'inspirer de la mécanique compile-time de `solana_address::declare_id!`/des primitives accessibles via la génération retenue de `solana-pubkey`, tout en conservant une API KSP adaptée à plusieurs Program IDs dans la même crate.
|
||||
|
||||
Elle ne doit notamment pas imposer des symboles génériques `ID`, `id()` ou `check_id()` qui entreraient en collision entre plusieurs déclarations.
|
||||
|
||||
### Registre descriptif enumerable
|
||||
|
||||
Le rejet initial d'un `ProgramIdEntry` enumerable est annulé.
|
||||
|
||||
L'ancien `ks-program-ids` fournissait notamment :
|
||||
|
||||
```text
|
||||
ProgramIdEntry
|
||||
entries()
|
||||
registered_program_ids()
|
||||
native_program_ids()
|
||||
native_well_known_account_ids()
|
||||
find_registered_program_id()
|
||||
```
|
||||
|
||||
La surface KSP doit reprendre/améliorer les capacités utiles sans reprendre les redondances historiques.
|
||||
|
||||
Direction de `pre.003` :
|
||||
|
||||
```text
|
||||
ProgramIdEntry
|
||||
entries()
|
||||
native_program_ids()
|
||||
find_program_id()
|
||||
```
|
||||
|
||||
Une recherche typée par `Pubkey` reste autorisée si son utilité est démontrée pendant l'implémentation.
|
||||
|
||||
`registered_program_ids()` n'est pas repris automatiquement s'il ne fait que dupliquer `entries()`.
|
||||
|
||||
`ProgramIdEntry` doit pouvoir exposer au minimum un code KSP stable, les formes `PRGID_*`/`PRGIDPK_*` et une classification descriptive minimale permettant les sous-ensembles utiles sans dupliquer plusieurs registres.
|
||||
|
||||
### Program IDs fondamentaux
|
||||
|
||||
La liste de `pre.001` n'est plus figée à 17 entrées.
|
||||
|
||||
L'inventaire final sera confirmé dans `pre.003` contre les sources officielles actuelles, en couvrant notamment :
|
||||
|
||||
- System, Stake, Vote, Config, Feature et Compute Budget ;
|
||||
- Address Lookup Table ;
|
||||
- loaders BPF historiques/actuels, Loader v4 et Native Loader ;
|
||||
- précompiles Ed25519, Secp256k1 et Secp256r1 ;
|
||||
- programmes ZK fondamentaux encore pertinents ;
|
||||
- toute surface native/historique supplémentaire réellement justifiée.
|
||||
|
||||
L'ancien `ks-program-ids` reste un inventaire historique utile. Son entrée `slashing` doit par exemple être réévaluée selon son statut officiel actuel plutôt que retenue ou rejetée uniquement parce qu'elle figurait dans bot3.
|
||||
|
||||
### Program IDs et well-known accounts
|
||||
|
||||
Les Program IDs exécutables et les well-known account IDs restent deux concepts distincts.
|
||||
|
||||
`PRGID_*` / `PRGIDPK_*` ne doivent jamais nommer un compte connu non exécutable.
|
||||
|
||||
Le concept historique `native_well_known_account_ids()` est conservé comme direction architecturale possible, mais `0.1.1` ne crée pas une API vide pour ce domaine si aucun well-known account n'est retenu dans sa surface réelle.
|
||||
|
||||
## Impact sur les prereleases suivantes
|
||||
|
||||
`pre.002` ne change pas :
|
||||
|
||||
```text
|
||||
Error / Result
|
||||
```
|
||||
|
||||
`pre.003` est précisé :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
+ declare_program_id!
|
||||
+ PRGID_* / PRGIDPK_*
|
||||
+ inventaire final des Program IDs fondamentaux
|
||||
+ ProgramIdEntry / entries() / native_program_ids() / find_program_id()
|
||||
+ tests de conformité/unicité
|
||||
```
|
||||
|
||||
Aucune dépendance `solana-sdk-ids` ne doit y être ajoutée.
|
||||
|
||||
## Hors scope inchangé
|
||||
|
||||
Le correctif n'ouvre toujours pas :
|
||||
|
||||
- Logging ;
|
||||
- Config ;
|
||||
- Tauri ;
|
||||
- Wallet/signing ;
|
||||
- codecs wire ;
|
||||
- Interface ;
|
||||
- Program decoding/dispatch registry/`ProgramExecutionPreparer` ;
|
||||
- execution policy/orchestration ;
|
||||
- Transport ;
|
||||
- Store ;
|
||||
- Materializer ;
|
||||
- workers/jobs/pipelines ;
|
||||
- scenarios ;
|
||||
- trading/ML.
|
||||
|
||||
## Validations exécutées
|
||||
|
||||
- relecture des règles `VERSION_WORKFLOW.md` et `FILE_CONTRACTS.md` de la base stable ;
|
||||
- confirmation qu'un fix purement documentaire ne modifie pas la version Cargo ;
|
||||
- réaudit ciblé de l'ancien `ks-program-ids` fourni dans l'archive bot3 de référence : `ProgramIdEntry`, `entries()`, `registered_program_ids()`, `native_program_ids()`, `native_well_known_account_ids()` et `find_registered_program_id()` ;
|
||||
- relecture du plan `003-V0_1_1_CORE_FOUNDATION_PLAN.md` après correction ;
|
||||
- contrôle statique du header/version des fichiers livrés ;
|
||||
- contrôle des fins de fichiers ;
|
||||
- contrôle de la structure et du contenu de l'archive ;
|
||||
- vérification de l'absence de fichier Cargo/code/runtime dans ce correctif.
|
||||
|
||||
## Validations non exécutées
|
||||
|
||||
Aucune validation Cargo n'est déclarée pour ce correctif documentaire.
|
||||
|
||||
Les commandes suivantes ne sont pas nécessaires pour démontrer le contenu de ce delta, qui ne modifie aucun artefact compilé :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Elles restent les validations attendues dès la prochaine tranche Rust applicable.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Les décisions nécessaires pour quitter `pre.001` sont considérées validées.
|
||||
|
||||
Les points d'implémentation suivants sont volontairement reportés à leur tranche propriétaire sans bloquer `pre.002` :
|
||||
|
||||
- structure Rust exacte et classification minimale de `ProgramIdEntry` en `pre.003` ;
|
||||
- présence éventuelle d'une recherche dédiée par `Pubkey` ;
|
||||
- inventaire final des IDs natifs/historiques à partir des sources officielles actuelles ;
|
||||
- détail d'expansion de `declare_program_id!` selon l'API exacte de la version `solana-pubkey` retenue.
|
||||
|
||||
## Suite
|
||||
|
||||
Après validation/commit de ce correctif :
|
||||
|
||||
```text
|
||||
0.1.1-pre.002 — Error/Result et fondation API
|
||||
```
|
||||
277
deltas/0.1.1/pre.001-fix.002.md
Normal file
277
deltas/0.1.1/pre.001-fix.002.md
Normal file
@@ -0,0 +1,277 @@
|
||||
<!-- file: deltas/0.1.1/pre.001-fix.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.1-pre.001-fix.002
|
||||
|
||||
## Base requise
|
||||
|
||||
Livraison précédente appliquée et commitée :
|
||||
|
||||
```text
|
||||
0.1.1-pre.001-fix.001
|
||||
```
|
||||
|
||||
## Type de livraison
|
||||
|
||||
```text
|
||||
ksp-doc-0.1.1-pre.001-fix.002.zip
|
||||
```
|
||||
|
||||
## Objectif
|
||||
|
||||
Compléter le cadrage Program IDs de `pre.001` avant ouverture de `pre.002`, après réaudit de l'ancien registre/IDLs bot3 et confrontation à des Program IDs publics actuels.
|
||||
|
||||
Ce correctif reste purement documentaire. Il fixe l'architecture de classification/recherche nécessaire pour que le registre KSP puisse ultérieurement retrouver les programmes par domaine, famille, protocole, sous-famille et génération sans dupliquer plusieurs registres statiques.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
Aucun fichier de code/build/runtime n'est modifié.
|
||||
|
||||
`workspace.package.version` reste donc :
|
||||
|
||||
```text
|
||||
0.1.1-pre.1
|
||||
```
|
||||
|
||||
Identifiant de livraison/commit :
|
||||
|
||||
```text
|
||||
0.1.1-pre.001-fix.002
|
||||
```
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `deltas/0.1.1/pre.001-fix.002.md`
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` — version documentaire 2 -> 3.
|
||||
|
||||
## Décisions acquises
|
||||
|
||||
### Registre canonique unique
|
||||
|
||||
KSP ne doit pas maintenir des tableaux indépendants pour chaque vue (`native`, `amm`, protocole, etc.).
|
||||
|
||||
`entries()` reste la source canonique et les vues/recherches sont dérivées de la classification de chaque `ProgramIdEntry`.
|
||||
|
||||
### Taxonomie minimale
|
||||
|
||||
`ProgramIdEntry` doit être conçu pour porter au minimum les axes descriptifs suivants :
|
||||
|
||||
```text
|
||||
domain
|
||||
family
|
||||
protocol
|
||||
subfamily?
|
||||
program_version?
|
||||
kind
|
||||
```
|
||||
|
||||
auxquels s'ajoutent le code KSP unique, la chaîne Base58 `PRGID_*` et le `Pubkey` `PRGIDPK_*`.
|
||||
|
||||
Les vocabulaires de classification restent extensibles. Core ne doit pas posséder une enum fermée de tous les protocoles/familles futurs.
|
||||
|
||||
### AMM comme famille agrégatrice
|
||||
|
||||
Le réaudit de bot3 montre que les anciens préfixes `AMM`, `CPMM`, `CLMM`, `DLMM`, `STABLE_SWAP` et `WEIGHTED_SWAP` représentent plusieurs spécialisations d'une même grande famille utile pour la recherche.
|
||||
|
||||
La direction KSP devient donc :
|
||||
|
||||
```text
|
||||
family = amm
|
||||
```
|
||||
|
||||
avec des `subfamily` optionnelles telles que :
|
||||
|
||||
```text
|
||||
cpmm
|
||||
clmm
|
||||
dlmm
|
||||
damm
|
||||
stable_swap
|
||||
weighted_swap
|
||||
gamma
|
||||
ssl
|
||||
```
|
||||
|
||||
lorsqu'elles correspondent réellement à une branche/architecture reconnue.
|
||||
|
||||
Une future `amm_program_ids()` doit filtrer le registre canonique sur cette famille et inclure toutes ces sous-familles.
|
||||
|
||||
### `subfamily` et `program_version` sont deux axes indépendants
|
||||
|
||||
La version ne doit pas être détournée en sous-famille.
|
||||
|
||||
Cas audités :
|
||||
|
||||
- SPL Memo : trois Program IDs v1/v3/v4, même lignée fonctionnelle ;
|
||||
- Aldrin AMM : v1/v2, même famille/protocole ;
|
||||
- Meteora DAMM : sous-famille `damm`, versions v1/v2 ;
|
||||
- Meteora DLMM : sous-famille `dlmm` distincte de DAMM ;
|
||||
- Jupiter Aggregator : même lignée, versions v4/v6 ;
|
||||
- GooseFX : GAMMA et SSL sont des branches distinctes ; `SSL v2` possède une version, tandis qu'aucun `v1` ne doit être inventé pour GAMMA.
|
||||
|
||||
### Nom du champ de version
|
||||
|
||||
Le champ retenu conceptuellement est :
|
||||
|
||||
```text
|
||||
program_version
|
||||
```
|
||||
|
||||
et non `protocol_version`.
|
||||
|
||||
Raison : un protocole peut posséder simultanément plusieurs programmes/composants dont les versions évoluent indépendamment. La version doit être attachée à la lignée du Program ID concerné, pas au protocole entier.
|
||||
|
||||
`program_version` est un label de génération reconnu (`v1`, `v2`, `v4`, `v6`, `v0.5`, etc.), pas nécessairement un SemVer.
|
||||
|
||||
### Version d'IDL explicitement distincte
|
||||
|
||||
Une version d'IDL/schema n'est pas une version de Program ID.
|
||||
|
||||
Exemples observés dans les IDLs archivées bot3 :
|
||||
|
||||
- Jupiter V6 : IDL `0.1.0` ;
|
||||
- GooseFX SSL V2 : IDL `0.3.0` ;
|
||||
- GooseFX GAMMA : IDL/schema `0.2.0` ;
|
||||
- Meteora DAMM V2 : IDL/schema distinct de la génération publique `v2`.
|
||||
|
||||
La provenance/version des IDLs appartiendra à la couche Interface/decoder lorsqu'elle sera ouverte ; elle n'entre pas dans `ProgramIdEntry` de Core en `0.1.1`.
|
||||
|
||||
### Nomenclature des constantes
|
||||
|
||||
La nomenclature Rust est séparée de la taxonomie fonctionnelle.
|
||||
|
||||
Le premier segment après `PRGID_`/`PRGIDPK_` est désormais nommé `NAMESPACE`, afin de ne pas confondre le nom public stable avec le champ taxonomique `domain` :
|
||||
|
||||
```text
|
||||
PRGID_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?>
|
||||
PRGIDPK_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?>
|
||||
```
|
||||
|
||||
Exemples :
|
||||
|
||||
```text
|
||||
PRGID_SPL_MEMO_V3
|
||||
PRGIDPK_SPL_MEMO_V3
|
||||
|
||||
PRGID_METEORA_DAMM_V2
|
||||
PRGIDPK_METEORA_DAMM_V2
|
||||
|
||||
PRGID_GOOSEFX_GAMMA
|
||||
PRGIDPK_GOOSEFX_GAMMA
|
||||
|
||||
PRGID_GOOSEFX_SSL_V2
|
||||
PRGIDPK_GOOSEFX_SSL_V2
|
||||
```
|
||||
|
||||
Le symbole public ne doit pas être renommé uniquement parce qu'une classification fonctionnelle est affinée plus tard.
|
||||
|
||||
### Recherches et vues prévues
|
||||
|
||||
Direction conceptuelle :
|
||||
|
||||
```text
|
||||
ProgramIdEntry
|
||||
ProgramIdFilter
|
||||
entries()
|
||||
program_ids(filter)
|
||||
native_program_ids()
|
||||
find_program_id()
|
||||
```
|
||||
|
||||
Le filtre doit pouvoir combiner plusieurs critères.
|
||||
|
||||
Des helpers de recherche peuvent être proposés :
|
||||
|
||||
```text
|
||||
program_ids_by_domain(...)
|
||||
program_ids_by_family(...)
|
||||
program_ids_by_protocol(...)
|
||||
```
|
||||
|
||||
`native_program_ids()` reste une vue Core réelle de `0.1.1`.
|
||||
|
||||
`amm_program_ids()` est explicitement prévue pour la surface future possédant des IDs AMM, mais n'est pas créée vide pendant `0.1.1` puisque les AMM sont hors scope fonctionnel de la release.
|
||||
|
||||
Les vues doivent pouvoir être des iterators/views du registre canonique afin d'éviter la duplication de tableaux statiques.
|
||||
|
||||
## Réaudit effectué
|
||||
|
||||
### Archive bot3
|
||||
|
||||
Le réaudit a porté sur :
|
||||
|
||||
- `ks-program-ids` et ses 137 entrées historiques ;
|
||||
- `ProgramIdEntry`, `entries()`, `native_program_ids()` et la recherche historique ;
|
||||
- les familles historiques AMM/CLMM/CPMM/DLMM/router/orderbook/etc. ;
|
||||
- les IDLs archivées, notamment GooseFX GAMMA/V2, Meteora DAMM/DLMM, Jupiter v4/v6, CCTP v1/v2, Raydium CLMM/CPMM, OpenBook v2 et Marginfi v2.
|
||||
|
||||
L'inventaire montre également qu'un même protocole traverse plusieurs familles : Jupiter, Raydium, Meteora, Kamino, MetaDAO, Pump, Metaplex, Orca, etc. `protocol` doit donc être un axe séparé de `family`.
|
||||
|
||||
### Sources externes actuelles
|
||||
|
||||
Contrôles représentatifs effectués le 2026-08-14 :
|
||||
|
||||
- Agave runtime `fetch-spl.sh` : Memo 1.0.0, 3.0.0 et 4.0.0 sont associés à trois Program IDs distincts ;
|
||||
- `spl-memo-interface` actuel : modules `v1`, `v3`, `v4` distincts ;
|
||||
- Solana Explorer et Solscan : présence/identification des Program IDs Memo et de programmes DEX audités ;
|
||||
- GooseFX officiel : GAMMA est une lignée AMM distincte ; l'écosystème publie également la lignée SSL ;
|
||||
- Meteora officiel : DAMM v1, DAMM v2 et DLMM sont des surfaces distinctes ;
|
||||
- Jupiter officiel : plusieurs générations du Swap Aggregator sont distinguées par Program ID.
|
||||
|
||||
Ces contrôles sont utilisés comme validation de taxonomie, pas comme dépendances KSP.
|
||||
|
||||
## Impact sur `pre.003`
|
||||
|
||||
`pre.003` devra désormais :
|
||||
|
||||
- implémenter `ProgramIdEntry` avec une taxonomie compatible avec les axes acquis ;
|
||||
- implémenter `ProgramIdFilter` ou une forme équivalente permettant les intersections ;
|
||||
- dériver `native_program_ids()` du registre canonique ;
|
||||
- tester les filtres par domaine/famille/protocole/sous-famille/version/kind ;
|
||||
- ne jamais confondre génération du programme et version d'IDL ;
|
||||
- préserver la possibilité d'ajouter plus tard `amm_program_ids()` sans modifier la structure fondamentale du registre.
|
||||
|
||||
## Hors scope inchangé
|
||||
|
||||
Ce correctif n'ajoute aucun Program ID SPL/DEX au code de `0.1.1` et n'ouvre toujours pas :
|
||||
|
||||
- Logging ;
|
||||
- Config ;
|
||||
- Tauri ;
|
||||
- Wallet/signing ;
|
||||
- codecs wire ;
|
||||
- Interface/IDL runtime ;
|
||||
- Program decoding/dispatch ;
|
||||
- execution ;
|
||||
- Transport ;
|
||||
- Store ;
|
||||
- Materializer ;
|
||||
- workers/jobs/pipelines ;
|
||||
- scenarios ;
|
||||
- trading/ML.
|
||||
|
||||
## Validations exécutées
|
||||
|
||||
- réaudit du registre `ks-program-ids` de l'archive bot3 ;
|
||||
- inventaire des Program IDs versionnés et des protocoles présents dans plusieurs familles ;
|
||||
- inspection ciblée des IDLs multi-version/à plusieurs sous-familles ;
|
||||
- confrontation représentative avec Agave/SPL, Solana Explorer, Solscan, GooseFX, Meteora et Jupiter ;
|
||||
- relecture du plan après modification ;
|
||||
- contrôle statique des headers/version documentaire ;
|
||||
- contrôle des fins de fichiers ;
|
||||
- contrôle de l'absence de modification Cargo/code/runtime dans ce fix.
|
||||
|
||||
## Validations non exécutées
|
||||
|
||||
Aucune validation Cargo n'est requise pour ce fix exclusivement documentaire et aucune n'est déclarée réussie.
|
||||
|
||||
## Suite
|
||||
|
||||
Après application et commit de ce correctif, le cadrage `pre.001` peut être considéré comme clôturé et la session peut passer à :
|
||||
|
||||
```text
|
||||
0.1.1-pre.002 — Error/Result et fondation API
|
||||
```
|
||||
219
deltas/0.1.1/pre.001.md
Normal file
219
deltas/0.1.1/pre.001.md
Normal file
@@ -0,0 +1,219 @@
|
||||
<!-- file: deltas/0.1.1/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.1-pre.001
|
||||
|
||||
## Base requise
|
||||
|
||||
Release stable/taguée attendue :
|
||||
|
||||
```text
|
||||
v0.0.3
|
||||
```
|
||||
|
||||
L'archive de base fournie contient bien la version Cargo stable `0.0.3` et le delta final `deltas/0.0.3/rel.001.md`.
|
||||
|
||||
Elle ne contient pas `.git` : le working tree réel, le commit et le tag `v0.0.3` doivent être vérifiés sur le dépôt cible avant commit de ce delta.
|
||||
|
||||
## Objectif
|
||||
|
||||
Ouvrir `0.1.1` par la prerelease obligatoire de brainstorming, audit et planification, sans développement fonctionnel Core.
|
||||
|
||||
Cette tranche :
|
||||
|
||||
- inventorie la surface réelle de `ksp-core-lib` ;
|
||||
- borne les contrats N1 de la release ;
|
||||
- propose le contrat ouvert `Error` / `Result` ;
|
||||
- borne les Program IDs fondamentaux ;
|
||||
- audite les primitives Solana/Anza actuelles nécessaires ;
|
||||
- fixe la stratégie d'API, tests et dépendances ;
|
||||
- dimensionne `pre.002` à `pre.005` ;
|
||||
- confirme les hors-scope.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
`workspace.package.version` passe de :
|
||||
|
||||
```text
|
||||
0.0.3
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.1.1-pre.1
|
||||
```
|
||||
|
||||
L'identifiant Cargo respecte SemVer sans zéro initial ; l'identifiant de livraison reste `0.1.1-pre.001`.
|
||||
|
||||
Le header de `Cargo.toml` passe de version 17 à 18.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`
|
||||
- `deltas/0.1.1/pre.001.md`
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `Cargo.toml`
|
||||
- `ROADMAP.md`
|
||||
- `docs/plans/000-README.md`
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Inventaire Core
|
||||
|
||||
`ksp-core-lib` est encore un squelette volontairement minimal :
|
||||
|
||||
- aucun module fonctionnel ;
|
||||
- aucune dépendance externe ;
|
||||
- aucun type public autre que la documentation de crate ;
|
||||
- aucun test ;
|
||||
- aucune surface Error/Result ou Program IDs existante à préserver pour compatibilité.
|
||||
|
||||
Cette situation permet de définir le contrat sans dette de compatibilité interne KSP.
|
||||
|
||||
## Décisions de planification
|
||||
|
||||
### Error/Result
|
||||
|
||||
Le modèle historique bot3 avec enum centrale de domaines n'est pas migré.
|
||||
|
||||
La direction retenue pour `pre.002` est :
|
||||
|
||||
- `Error` structuré ;
|
||||
- `ErrorCode` ouvert avec domaine/code statiques ;
|
||||
- `ErrorContext` structuré ;
|
||||
- message lisible ;
|
||||
- cause standard optionnelle `Send + Sync` ;
|
||||
- alias `Result<T>` ;
|
||||
- aucune connaissance dans Core des futurs domaines Config/Logging/Wallet/Transport/Store/Tauri/protocoles ;
|
||||
- aucune liste centrale de conversions d'erreurs externes.
|
||||
|
||||
Le détail complet et les invariants figurent dans `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`.
|
||||
|
||||
### Solana/Anza
|
||||
|
||||
Sources officielles consultées le 2026-08-14 : dépôt `anza-xyz/solana-sdk`, notamment la crate Pubkey, la primitive Address, `sdk-ids` et le manifest workspace.
|
||||
|
||||
État vérifié :
|
||||
|
||||
```text
|
||||
solana-pubkey 4.3.0
|
||||
solana-address 2.7.0
|
||||
solana-sdk-ids 3.1.0 package
|
||||
Solana SDK workspace MSRV 1.89.0
|
||||
```
|
||||
|
||||
Direction retenue :
|
||||
|
||||
- runtime Core : `solana-pubkey` seulement, lorsque `pre.003` implémentera réellement les Program IDs ;
|
||||
- `default-features = false` tant qu'aucune feature supplémentaire n'est démontrée nécessaire ;
|
||||
- `Pubkey` réexporté depuis `ksp_core_lib` ;
|
||||
- pas de dépendance directe KSP à `solana-address` ;
|
||||
- `solana-sdk-ids` seulement comme dev-dependency candidate pour les tests de conformité, pas comme dépendance runtime ;
|
||||
- aucune autre primitive Solana autorisée n'est ajoutée par anticipation.
|
||||
|
||||
Les versions seront revérifiées juste avant leur ajout réel au manifeste.
|
||||
|
||||
### Program IDs
|
||||
|
||||
Première surface proposée : 17 Program IDs fondamentaux exposés par la source officielle Solana SDK, incluant les loaders et précompiles de la frontière runtime :
|
||||
|
||||
- Address Lookup Table ;
|
||||
- BPF Loader ;
|
||||
- BPF Loader deprecated ;
|
||||
- BPF Loader Upgradeable ;
|
||||
- Compute Budget ;
|
||||
- Config ;
|
||||
- Ed25519 precompile ;
|
||||
- Feature ;
|
||||
- Loader v4 ;
|
||||
- Native Loader ;
|
||||
- Secp256k1 precompile ;
|
||||
- Secp256r1 precompile ;
|
||||
- Stake ;
|
||||
- System ;
|
||||
- Vote ;
|
||||
- ZK ElGamal Proof ;
|
||||
- ZK Token Proof.
|
||||
|
||||
Sont exclus : sysvars, incinerator, stake config account, SPL/protocoles, registre enumerable et alias bot3 historiques.
|
||||
|
||||
### Autres primitives
|
||||
|
||||
Aucune autre primitive commune n'est justifiée maintenant.
|
||||
|
||||
`Hash`, `Nonce`, Keypair, Signer, identité/version de module et provenance restent reportés jusqu'à un besoin concret.
|
||||
|
||||
## Prereleases prévues
|
||||
|
||||
```text
|
||||
pre.001 audit + brainstorming + plan
|
||||
pre.002 Error/Result + tests publics
|
||||
pre.003 Pubkey + Program IDs + conformité Solana
|
||||
pre.004 intégration Core + audits + compléments strictement justifiés
|
||||
pre.005 validations finales + docs/cleanup + prompt 0.1.2
|
||||
```
|
||||
|
||||
Le découpage reste souple ; une tranche trop large sera scindée plutôt que surchargée.
|
||||
|
||||
## Hors scope confirmé
|
||||
|
||||
- Logging ;
|
||||
- Config ;
|
||||
- Tauri ;
|
||||
- Wallet/signing ;
|
||||
- codecs wire ;
|
||||
- Interface ;
|
||||
- Program decoding/registry/preparation ;
|
||||
- Execution ;
|
||||
- Transport ;
|
||||
- Store ;
|
||||
- Materializer ;
|
||||
- workers/jobs/pipelines ;
|
||||
- scenarios ;
|
||||
- trading/ML.
|
||||
|
||||
## Validations exécutées
|
||||
|
||||
Dans l'environnement de préparation de ce delta :
|
||||
|
||||
- lecture/audit de l'archive complète `0.0.3` fournie ;
|
||||
- vérification de la version stable `0.0.3` dans le manifest ;
|
||||
- vérification de la présence du delta `0.0.3/rel.001` et du prompt final `0.1.1` ;
|
||||
- inventaire de `ksp-core-lib` ;
|
||||
- lecture des règles, plans et documents d'architecture requis par le prompt ;
|
||||
- audit de l'ancien `ks-core` / `ks-program-ids` de l'archive bot3 fournie comme référence historique, sans le traiter comme source de vérité KSP ;
|
||||
- vérification des versions et surfaces actuelles sur les sources officielles Anza/Solana ;
|
||||
- parsing TOML statique du manifest modifié ;
|
||||
- contrôle statique des headers `file:` / `version:` des fichiers ajoutés/modifiés ;
|
||||
- contrôle statique des liens Markdown locaux après modification.
|
||||
|
||||
## Validations non exécutées
|
||||
|
||||
L'environnement de préparation ne contient ni `cargo` ni `rustc`.
|
||||
|
||||
Les commandes suivantes n'ont donc pas pu être exécutées ici :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Elles doivent être exécutées sur le dépôt réel après application du delta. Aucun succès Cargo n'est déclaré par ce delta.
|
||||
|
||||
Le tag Git et le working tree ne peuvent pas non plus être vérifiés depuis l'archive fournie, qui ne contient pas `.git`.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
- validation par le user du modèle Error/Result proposé avant `pre.002` ;
|
||||
- choix exact des méthodes ergonomiques de contexte et du format `Display`, à stabiliser par tests en `pre.002` ;
|
||||
- revérification de la version Solana et du MSRV juste avant `pre.003` ;
|
||||
- confirmation de l'utilité de `solana-sdk-ids` comme dev-dependency de conformité au moment où les tests sont écrits.
|
||||
|
||||
Aucune question ouverte ne justifie de commencer le développement fonctionnel avant validation de ce plan.
|
||||
127
deltas/0.1.1/pre.002-fix.001.md
Normal file
127
deltas/0.1.1/pre.002-fix.001.md
Normal file
@@ -0,0 +1,127 @@
|
||||
<!-- file: deltas/0.1.1/pre.002-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.1-pre.002-fix.001
|
||||
|
||||
## Base requise
|
||||
|
||||
Commit de livraison attendu :
|
||||
|
||||
```text
|
||||
v0.1.1-pre.002
|
||||
```
|
||||
|
||||
La version Cargo reste :
|
||||
|
||||
```text
|
||||
0.1.1-pre.2
|
||||
```
|
||||
|
||||
Ce correctif ne modifie aucun contrat public de `ksp-core-lib` et ne justifie donc aucune nouvelle prerelease Cargo.
|
||||
|
||||
## Objectif
|
||||
|
||||
Corriger les deux warnings remontés par les validations réelles de `0.1.1-pre.002` avant d'ouvrir `0.1.1-pre.003`.
|
||||
|
||||
Les validations exécutées sur le dépôt cible ont confirmé que :
|
||||
|
||||
- `cargo fmt --all` réussit ;
|
||||
- `cargo check --workspace` réussit ;
|
||||
- `cargo test --workspace` réussit avec 6 tests unitaires, 1 test d'intégration et 0 échec ;
|
||||
- `cargo clippy --workspace --all-targets` termine sans erreur mais remonte deux warnings à corriger.
|
||||
|
||||
Warnings observés :
|
||||
|
||||
1. `clippy::extra_unused_type_parameters` sur le helper de vérification `Send + Sync` ;
|
||||
2. `missing_docs` sur la crate de test d'intégration `tests/public_api.rs`.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `crates/ksp-core-lib/unit_tests/error.rs`
|
||||
- `crates/ksp-core-lib/tests/public_api.rs`
|
||||
|
||||
## Fichier ajouté
|
||||
|
||||
- `deltas/0.1.1/pre.002-fix.001.md`
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Correction `Send + Sync`
|
||||
|
||||
Le helper de test :
|
||||
|
||||
```text
|
||||
assert_send_sync<T>()
|
||||
```
|
||||
|
||||
utilisait `T` uniquement dans ses bornes de trait. Clippy considère alors le paramètre de type comme inutilisé avec `extra_unused_type_parameters`.
|
||||
|
||||
Le helper reçoit désormais un `std::marker::PhantomData<T>` :
|
||||
|
||||
```text
|
||||
assert_send_sync<T>(PhantomData<T>)
|
||||
```
|
||||
|
||||
et le test fournit `PhantomData<crate::Error>`.
|
||||
|
||||
Cette forme conserve exactement l'objectif du test de compilation : l'appel ne compile que si `crate::Error` satisfait `Send + Sync`, tout en utilisant réellement le paramètre générique et sans ajouter de dépendance, d'import ou de logique runtime significative.
|
||||
|
||||
## Correction `missing_docs`
|
||||
|
||||
Le test d'intégration `crates/ksp-core-lib/tests/public_api.rs` constitue une crate Rust indépendante lors de sa compilation.
|
||||
|
||||
Une rustdoc crate-level est ajoutée :
|
||||
|
||||
```text
|
||||
//! Integration tests for the public `ksp-core-lib` error contract.
|
||||
```
|
||||
|
||||
Cela satisfait le lint workspace `missing_docs = warn` sans désactiver le lint et sans documenter artificiellement les helpers privés du test.
|
||||
|
||||
## Headers de fichiers
|
||||
|
||||
Les deux fichiers Rust modifiés passent de :
|
||||
|
||||
```text
|
||||
version: 1
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
version: 2
|
||||
```
|
||||
|
||||
## Contrat public
|
||||
|
||||
Aucun changement.
|
||||
|
||||
Les éléments suivants restent strictement identiques à `0.1.1-pre.002` :
|
||||
|
||||
```text
|
||||
ksp_core_lib::Error
|
||||
ksp_core_lib::ErrorCode
|
||||
ksp_core_lib::ErrorContext
|
||||
ksp_core_lib::Result<T>
|
||||
```
|
||||
|
||||
Le plan `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` reste en version documentaire 5 : aucune décision d'architecture ou d'API n'est modifiée par ce correctif.
|
||||
|
||||
## Dépendances
|
||||
|
||||
Aucune dépendance ajoutée ou modifiée.
|
||||
|
||||
## Validations à exécuter après application
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Le résultat attendu de ce correctif est l'absence des deux warnings qui ont motivé `pre.002-fix.001`.
|
||||
|
||||
Aucune validation du correctif lui-même n'est déclarée réussie tant que ces commandes n'ont pas été exécutées sur le dépôt cible.
|
||||
215
deltas/0.1.1/pre.002.md
Normal file
215
deltas/0.1.1/pre.002.md
Normal file
@@ -0,0 +1,215 @@
|
||||
<!-- file: deltas/0.1.1/pre.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta 0.1.1-pre.002
|
||||
|
||||
## Base requise
|
||||
|
||||
Commit de livraison attendu :
|
||||
|
||||
```text
|
||||
v0.1.1-pre.001-fix.002
|
||||
```
|
||||
|
||||
Le plan actif est `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` version documentaire 4, incluant le réalignement du tableau des cas représentatifs effectué avant le commit du correctif précédent.
|
||||
|
||||
## Objectif
|
||||
|
||||
Implémenter la première surface fonctionnelle de `ksp-core-lib` : le contrat commun ouvert `Error` / `Result` validé pendant `pre.001`.
|
||||
|
||||
Cette tranche reste strictement bornée à l'erreur commune et n'ouvre aucune dépendance Solana ni aucun Program ID.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
`workspace.package.version` passe de :
|
||||
|
||||
```text
|
||||
0.1.1-pre.1
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.1.1-pre.2
|
||||
```
|
||||
|
||||
L'identifiant Cargo respecte SemVer sans zéro initial ; l'identifiant de livraison reste `0.1.1-pre.002`.
|
||||
|
||||
Le header de `Cargo.toml` passe de version 18 à 19.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
- `crates/ksp-core-lib/src/error.rs`
|
||||
- `crates/ksp-core-lib/unit_tests/error.rs`
|
||||
- `crates/ksp-core-lib/tests/public_api.rs`
|
||||
- `deltas/0.1.1/pre.002.md`
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
- `Cargo.toml`
|
||||
- `crates/ksp-core-lib/src/lib.rs`
|
||||
- `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Contrat implémenté
|
||||
|
||||
### `ErrorCode`
|
||||
|
||||
`ErrorCode` contient uniquement :
|
||||
|
||||
```text
|
||||
domain: &'static str
|
||||
code: &'static str
|
||||
```
|
||||
|
||||
Décisions :
|
||||
|
||||
- `ErrorCode::new(...)` est `const` afin que chaque crate supérieure puisse définir ses propres codes statiques ;
|
||||
- Core ne possède aucune enum centrale des domaines ;
|
||||
- `domain()` et `code()` exposent les deux identifiants stables ;
|
||||
- `ErrorCode` est `Copy`, `Clone`, `Eq`, `PartialEq`, `Hash` et `Debug` parce qu'il ne contient que deux chaînes statiques.
|
||||
|
||||
### `ErrorContext`
|
||||
|
||||
`ErrorContext` contient :
|
||||
|
||||
```text
|
||||
key: &'static str
|
||||
value: String
|
||||
```
|
||||
|
||||
Le contexte conserve son ordre d'insertion dans `Error`.
|
||||
|
||||
L'API publique expose `ErrorContext::new(...)`, `key()` et `value()`.
|
||||
|
||||
### `Error`
|
||||
|
||||
`Error` contient :
|
||||
|
||||
```text
|
||||
code: ErrorCode
|
||||
message: String
|
||||
context: Vec<ErrorContext>
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>
|
||||
```
|
||||
|
||||
Décisions stabilisées :
|
||||
|
||||
- `Error::new(...)` construit l'erreur minimale ;
|
||||
- `with_context(...)` consomme `self`, ajoute un champ puis retourne l'erreur enrichie ;
|
||||
- `with_source(...)` suit le même modèle pour une cause externe ;
|
||||
- aucune méthode mutable publique parallèle n'est ajoutée ;
|
||||
- aucune conversion générique `From<ExternalError>` n'est introduite ;
|
||||
- `Error` ne dérive pas `Clone`, `Eq` ou `PartialEq`, afin de ne pas affaiblir le support d'une vraie cause externe ;
|
||||
- `Error` implémente `std::fmt::Display` et `std::error::Error` ;
|
||||
- le rendu `Display` est exactement :
|
||||
|
||||
```text
|
||||
<domain>.<code>: <message>
|
||||
```
|
||||
|
||||
Le contexte et la chaîne de causes ne sont pas injectés automatiquement dans ce rendu.
|
||||
|
||||
### `Result<T>`
|
||||
|
||||
La façade expose :
|
||||
|
||||
```text
|
||||
ksp_core_lib::Result<T> = std::result::Result<T, ksp_core_lib::Error>
|
||||
```
|
||||
|
||||
## Façade Core
|
||||
|
||||
`crates/ksp-core-lib/src/lib.rs` ouvre le module d'implémentation en privé puis réexporte explicitement :
|
||||
|
||||
```text
|
||||
ksp_core_lib::Error
|
||||
ksp_core_lib::ErrorCode
|
||||
ksp_core_lib::ErrorContext
|
||||
ksp_core_lib::Result
|
||||
```
|
||||
|
||||
Aucun `pub mod` n'est introduit.
|
||||
|
||||
## Dépendances
|
||||
|
||||
Aucune dépendance n'est ajoutée à `ksp-core-lib` pendant cette tranche.
|
||||
|
||||
En particulier, `pre.002` n'introduit ni `thiserror`, ni `anyhow`, ni crate Solana, ni codec wire.
|
||||
|
||||
## Tests ajoutés
|
||||
|
||||
### Tests unitaires externes
|
||||
|
||||
`crates/ksp-core-lib/unit_tests/error.rs` vérifie :
|
||||
|
||||
- conservation de `domain` et `code` ;
|
||||
- possibilité de déclarer un `ErrorCode` constant ;
|
||||
- conservation des champs `ErrorContext` ;
|
||||
- conservation du message et de l'ordre du contexte ;
|
||||
- rendu exact de `Display` ;
|
||||
- absence du contexte et de la cause dans le rendu ;
|
||||
- conservation de la cause via `std::error::Error::source()` ;
|
||||
- propriété `Send + Sync` de l'erreur commune.
|
||||
|
||||
Le fichier est rattaché au module privé de production via `#[cfg(test)]` et `#[path = "../unit_tests/error.rs"]`.
|
||||
|
||||
### Test d'intégration
|
||||
|
||||
`crates/ksp-core-lib/tests/public_api.rs` consomme exclusivement la façade crate-root et vérifie que `Error`, `ErrorCode`, `ErrorContext` et `Result` sont utilisables depuis une crate externe.
|
||||
|
||||
## Documentation de plan
|
||||
|
||||
Le plan passe de version documentaire 4 à 5 afin de remplacer les deux questions désormais résolues par les décisions réellement implémentées :
|
||||
|
||||
- `with_context(...)` consomme `self` ;
|
||||
- `Display` utilise la forme stable `<domain>.<code>: <message>`.
|
||||
|
||||
Les questions `pre.003` concernant `solana-pubkey` restent ouvertes et inchangées.
|
||||
|
||||
## Validations exécutées
|
||||
|
||||
Dans l'environnement de préparation :
|
||||
|
||||
- reconstruction de la base `0.1.1-pre.001-fix.002` depuis la release `0.0.3` et les deltas successifs ;
|
||||
- prise en compte de la version 4 du plan fournie après réalignement manuel du tableau ;
|
||||
- contrôle du périmètre des fichiers modifiés/ajoutés ;
|
||||
- parsing TOML statique du manifest racine ;
|
||||
- contrôle des headers `file:` / `version:` et des fins de ligne des fichiers livrés ;
|
||||
- recherche statique des usages interdits `unsafe`, `unwrap`, `expect`, `panic` et opérateur `?` dans le code de production ajouté ;
|
||||
- contrôle de l'absence de `use` dans le code Rust ajouté ;
|
||||
- contrôle de l'absence de nouvelle dépendance Cargo.
|
||||
|
||||
## Validations non exécutées
|
||||
|
||||
L'environnement de préparation ne contient ni `cargo` ni `rustc`.
|
||||
|
||||
Les commandes suivantes n'ont donc pas pu être exécutées ici :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Elles doivent être exécutées sur le dépôt réel avant validation du commit. Aucun succès Cargo n'est déclaré par ce delta.
|
||||
|
||||
## Décisions prises
|
||||
|
||||
- Le contrat Error/Result ouvert de `pre.001` est retenu sans enum centrale de domaines.
|
||||
- `ErrorCode::new(...)` est `const`.
|
||||
- Les champs des types publics restent privés et sont accessibles par API explicite.
|
||||
- Le contexte est ordonné et enrichi par consommation de `self`.
|
||||
- La cause standard est conservée avec les bornes `Error + Send + Sync + 'static`.
|
||||
- `Display` est volontairement court et stable ; Logging décidera plus tard comment exploiter contexte et causes.
|
||||
- Core ne possède aucune conversion vers les erreurs des domaines supérieurs.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question bloquante pour `pre.002`.
|
||||
|
||||
Les questions relatives à `Pubkey`, aux Program IDs et à leur registre restent réservées à `0.1.1-pre.003` conformément au plan actif.
|
||||
120
deltas/0.1.1/pre.003-fix.001.md
Normal file
120
deltas/0.1.1/pre.003-fix.001.md
Normal file
@@ -0,0 +1,120 @@
|
||||
<!-- file: deltas/0.1.1/pre.003-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.1.1-pre.003-fix.001` — Cargo workspace + Clippy
|
||||
|
||||
## Statut
|
||||
|
||||
Correctif de `0.1.1-pre.003` après application et validation partielle de la tranche par le user.
|
||||
|
||||
Version technique du correctif :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.3.fix.1"
|
||||
```
|
||||
|
||||
Le périmètre fonctionnel de `pre.003` ne change pas.
|
||||
|
||||
## Base et validations reçues
|
||||
|
||||
Sur `0.1.1-pre.3`, le user a exécuté avec succès :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
```
|
||||
|
||||
Résultats communiqués :
|
||||
|
||||
- 14 tests unitaires passent ;
|
||||
- 3 tests d'intégration `public_api` passent ;
|
||||
- `cargo tree` résout `solana-pubkey 4.3.0` puis `solana-address 2.7.0` ;
|
||||
- `cargo tree -d` ne rapporte aucun doublon.
|
||||
|
||||
`cargo clippy --workspace --all-targets` échoue sur trois closures de `program_ids.rs` à cause de la règle workspace `clippy::implicit_return = deny`.
|
||||
|
||||
## Correction Cargo
|
||||
|
||||
La déclaration directe suivante dans `crates/ksp-core-lib/Cargo.toml` est supprimée :
|
||||
|
||||
```toml
|
||||
solana-pubkey = { version = "4.3.0", default-features = false }
|
||||
```
|
||||
|
||||
La dépendance appartient désormais au manifeste workspace :
|
||||
|
||||
```toml
|
||||
[workspace.dependencies]
|
||||
solana-pubkey = { version = "^4.3", default-features = false }
|
||||
```
|
||||
|
||||
La crate propriétaire la consomme uniquement par héritage :
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
solana-pubkey.workspace = true
|
||||
```
|
||||
|
||||
La contrainte `^4.3` exprime la génération compatible voulue par KSP ; le patch concret reste résolu par Cargo/lockfile.
|
||||
|
||||
## Règles ajoutées
|
||||
|
||||
`docs/rules/RULES_DEPENDENCIES.md` ajoute `DEP-CARGO-001` à `DEP-CARGO-005` afin de rendre obligatoire :
|
||||
|
||||
- la centralisation des dépendances externes sous `[workspace.dependencies]` ;
|
||||
- l'usage de `.workspace = true` dans les crates membres ;
|
||||
- la centralisation des contraintes de version et options communes ;
|
||||
- la convention de contrainte caret `^M.m` pour une génération majeure/mineure compatible ;
|
||||
- la distinction entre contrainte de manifeste et résolution concrète du lockfile.
|
||||
|
||||
## Correction Clippy
|
||||
|
||||
Les trois closures signalées utilisent maintenant un `return` explicite dans leur corps :
|
||||
|
||||
- filtre générique de `program_ids(...)` ;
|
||||
- recherche texte `find_program_id(...)` ;
|
||||
- recherche typée `find_program_pubkey(...)`.
|
||||
|
||||
Aucune signature ni sémantique de l'API publique ne change.
|
||||
|
||||
## Documentation
|
||||
|
||||
`docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` est aligné sur la nouvelle règle Cargo et documente la contrainte workspace `^4.3` au lieu d'une déclaration locale `4.3.0`.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-core-lib/Cargo.toml
|
||||
crates/ksp-core-lib/src/program_ids.rs
|
||||
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
|
||||
docs/rules/RULES_DEPENDENCIES.md
|
||||
```
|
||||
|
||||
## Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.1.1/pre.003-fix.001.md
|
||||
```
|
||||
|
||||
## Validations de ce correctif
|
||||
|
||||
Non exécutées dans l'environnement de préparation du delta, qui ne fournit pas la toolchain Cargo/Rust du dépôt.
|
||||
|
||||
À exécuter après application :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
```
|
||||
|
||||
## Hors scope
|
||||
|
||||
Ce correctif n'ajoute ni Program ID, ni dépendance, ni primitive Core supplémentaire et ne démarre pas `0.1.1-pre.004`.
|
||||
284
deltas/0.1.1/pre.003.md
Normal file
284
deltas/0.1.1/pre.003.md
Normal file
@@ -0,0 +1,284 @@
|
||||
<!-- file: deltas/0.1.1/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.1.1-pre.003` — Pubkey + Program IDs
|
||||
|
||||
## Statut
|
||||
|
||||
Tranche fonctionnelle `0.1.1-pre.003` préparée après validation réussie par le user de `0.1.1-pre.002-fix.001`.
|
||||
|
||||
La base utilisateur observée avant ce delta utilise :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.2.fix.1"
|
||||
```
|
||||
|
||||
Le présent delta ouvre :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.3"
|
||||
```
|
||||
|
||||
## Validation de la base précédente
|
||||
|
||||
Le user a exécuté avec succès avant ce delta :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Les six tests unitaires Error et le test d'intégration public Error passent sans warning dans cette validation.
|
||||
|
||||
## Audit Solana/Anza revérifié
|
||||
|
||||
Au 2026-08-14 :
|
||||
|
||||
- `solana-pubkey 4.3.0` est la version publiée courante observée sur crates.io ;
|
||||
- son MSRV publié est Rust `1.89.0` ;
|
||||
- la validation précédente du user expose une génération Clippy `rust-1.94.0`, donc la toolchain observée satisfait ce MSRV ;
|
||||
- `Pubkey` reste la façade de compatibilité officielle sur l'`Address` Solana actuel ;
|
||||
- `Pubkey::from_str_const` permet le décodage Base58 compile-time nécessaire à la macro KSP ;
|
||||
- `solana-sdk-ids` est consulté uniquement comme source d'audit et n'entre pas dans le graphe Cargo KSP.
|
||||
|
||||
Sources externes revérifiées pendant cette tranche :
|
||||
|
||||
- crates.io / docs.rs pour `solana-pubkey 4.3.0` ;
|
||||
- `anza-xyz/solana-sdk`, `sdk-ids/src/lib.rs`, pour les identifiants fondamentaux actuellement publiés ;
|
||||
- SIMD-0204 et la documentation Anza pour le Slashing Program `S1ashing11111111111111111111111111111111111`.
|
||||
|
||||
## Dépendance Core
|
||||
|
||||
`crates/ksp-core-lib/Cargo.toml` ajoute uniquement :
|
||||
|
||||
```toml
|
||||
solana-pubkey = { version = "4.3.0", default-features = false }
|
||||
```
|
||||
|
||||
Aucun codec wire, client RPC, umbrella SDK ou registre `solana-sdk-ids` n'est ajouté.
|
||||
|
||||
`ksp_core_lib::Pubkey` réexporte `solana_pubkey::Pubkey` depuis la façade Core.
|
||||
|
||||
## Macro KSP de Program ID
|
||||
|
||||
La macro publique :
|
||||
|
||||
```text
|
||||
ksp_core_lib::declare_program_id!
|
||||
```
|
||||
|
||||
possède la chaîne Base58 une seule fois et produit simultanément :
|
||||
|
||||
```text
|
||||
PRGID_* : &'static str
|
||||
PRGIDPK_* : Pubkey
|
||||
```
|
||||
|
||||
La représentation typée est construite avec `Pubkey::from_str_const`, sans parsing runtime, `unwrap`, `expect`, `panic` ni opérateur `?`.
|
||||
|
||||
La macro ne génère pas de symboles génériques `ID`, `id()` ou `check_id()` et peut donc être utilisée plusieurs fois dans une même crate/module.
|
||||
|
||||
## Première surface Program IDs Core
|
||||
|
||||
La tranche fixe le premier registre à 18 Program IDs.
|
||||
|
||||
Les 17 valeurs de la surface officielle actuelle Anza `solana-sdk-ids` sont possédées localement par KSP :
|
||||
|
||||
1. Address Lookup Table ;
|
||||
2. BPF Loader historique v1 ;
|
||||
3. BPF Loader v2 ;
|
||||
4. BPF Loader Upgradeable ;
|
||||
5. Compute Budget ;
|
||||
6. Config ;
|
||||
7. Ed25519 precompile ;
|
||||
8. Feature ;
|
||||
9. Loader v4 ;
|
||||
10. Native Loader ;
|
||||
11. Secp256k1 precompile ;
|
||||
12. Secp256r1 precompile ;
|
||||
13. Stake ;
|
||||
14. System ;
|
||||
15. Vote ;
|
||||
16. ZK ElGamal Proof ;
|
||||
17. ZK Token Proof.
|
||||
|
||||
Le dix-huitième identifiant est :
|
||||
|
||||
```text
|
||||
PRGID_SOLANA_SLASHING = "S1ashing11111111111111111111111111111111111"
|
||||
```
|
||||
|
||||
Son statut de programme enshrined et son adresse sont confirmés séparément par SIMD-0204/Anza ; sa présence ne dépend donc pas de l'ancien registre bot3.
|
||||
|
||||
Les sysvars, `StakeConfig`, l'incinerator et les autres well-known accounts restent exclus du registre Program IDs.
|
||||
|
||||
## Nomenclature publique
|
||||
|
||||
Chaque entrée possède une paire `PRGID_*` / `PRGIDPK_*` au crate-root.
|
||||
|
||||
Exemples :
|
||||
|
||||
```text
|
||||
PRGID_SOLANA_SYSTEM
|
||||
PRGIDPK_SOLANA_SYSTEM
|
||||
|
||||
PRGID_SOLANA_LOADER_BPF_V1
|
||||
PRGIDPK_SOLANA_LOADER_BPF_V1
|
||||
|
||||
PRGID_SOLANA_PRECOMPILE_ED25519
|
||||
PRGIDPK_SOLANA_PRECOMPILE_ED25519
|
||||
|
||||
PRGID_SOLANA_SLASHING
|
||||
PRGIDPK_SOLANA_SLASHING
|
||||
```
|
||||
|
||||
Le suffixe est strictement identique entre les deux représentations.
|
||||
|
||||
## Registre canonique
|
||||
|
||||
`ProgramIdEntry` porte :
|
||||
|
||||
```text
|
||||
code
|
||||
name
|
||||
program_id
|
||||
pubkey
|
||||
domain
|
||||
family
|
||||
protocol
|
||||
subfamily
|
||||
program_version
|
||||
kind
|
||||
```
|
||||
|
||||
Les axes fonctionnels restent extensibles sous forme de chaînes. Aucun enum central fermé des domaines, familles ou protocoles futurs n'est créé.
|
||||
|
||||
`ProgramIdKind` est limité à la classification technique :
|
||||
|
||||
```text
|
||||
Program
|
||||
Loader
|
||||
Precompile
|
||||
EnshrinedProgram
|
||||
```
|
||||
|
||||
La première taxonomie Core utilise :
|
||||
|
||||
```text
|
||||
domain = solana
|
||||
protocol = solana
|
||||
|
||||
family = runtime
|
||||
family = consensus
|
||||
family = loader
|
||||
family = precompile
|
||||
family = proof
|
||||
```
|
||||
|
||||
`program_version` reste distinct de `subfamily`. Les BPF loaders v1/v2 et Loader v4 utilisent l'axe version ; la branche BPF utilise séparément `subfamily = bpf`.
|
||||
|
||||
## API de recherche et vues
|
||||
|
||||
La façade expose :
|
||||
|
||||
```text
|
||||
entries()
|
||||
program_ids(filter)
|
||||
native_program_ids()
|
||||
program_ids_by_domain(...)
|
||||
program_ids_by_family(...)
|
||||
program_ids_by_protocol(...)
|
||||
find_program_id(...)
|
||||
find_program_pubkey(...)
|
||||
```
|
||||
|
||||
`ProgramIdFilter` peut combiner :
|
||||
|
||||
```text
|
||||
domain
|
||||
family
|
||||
protocol
|
||||
subfamily
|
||||
program_version
|
||||
kind
|
||||
```
|
||||
|
||||
Toutes les vues sont construites à partir du registre canonique unique. Elles retournent des iterators paresseux sans dupliquer un tableau statique par catégorie.
|
||||
|
||||
Une future fonction `amm_program_ids()` pourra donc devenir une vue `family = amm` sans changement structurel de `ProgramIdEntry`.
|
||||
|
||||
## Tests ajoutés
|
||||
|
||||
`unit_tests/program_ids.rs` vérifie notamment :
|
||||
|
||||
- cohérence texte/`Pubkey` des déclarations ;
|
||||
- présence exacte des 18 Program IDs Core ;
|
||||
- unicité des codes, Base58 et `Pubkey` ;
|
||||
- correspondance de chaque `Pubkey` avec la Base58 KSP ;
|
||||
- intersection des six axes de filtre ;
|
||||
- tailles attendues des familles Core actuelles ;
|
||||
- recherche texte et `Pubkey` ;
|
||||
- absence de l'incinerator, `StakeConfig` et du Clock sysvar.
|
||||
|
||||
`tests/public_api.rs` vérifie en consommateur externe :
|
||||
|
||||
- la macro `declare_program_id!` ;
|
||||
- les constantes `PRGID_*` / `PRGIDPK_*` ;
|
||||
- `Pubkey` ;
|
||||
- les vues du registre ;
|
||||
- les getters de `ProgramIdEntry` ;
|
||||
- le filtrage public combiné.
|
||||
|
||||
## Documentation
|
||||
|
||||
`docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` passe en version documentaire 6 afin de :
|
||||
|
||||
- fixer l'inventaire Core à 18 IDs ;
|
||||
- tracer la vérification du Slashing Program ;
|
||||
- enregistrer `solana-pubkey 4.3.0` comme dépendance effectivement introduite ;
|
||||
- fermer la question de MSRV de `pre.003` ;
|
||||
- fixer `ProgramIdKind` et les retours iterator des vues ;
|
||||
- compléter l'API publique réellement implémentée.
|
||||
|
||||
## Hors scope préservé
|
||||
|
||||
Cette tranche n'ajoute toujours pas :
|
||||
|
||||
- SPL Token/Token-2022/ATA/Memo ;
|
||||
- Metaplex ou DEX ;
|
||||
- well-known accounts ;
|
||||
- codecs Borsh/Wincode ;
|
||||
- decoder/executor/IDL ;
|
||||
- RPC/WS ;
|
||||
- Wallet ;
|
||||
- Logging ;
|
||||
- Config ;
|
||||
- Store ;
|
||||
- applications.
|
||||
|
||||
## Validations à exécuter sur le dépôt cible
|
||||
|
||||
Cette livraison ne déclare aucune validation Cargo non exécutée dans l'environnement de génération.
|
||||
|
||||
Après application :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
```
|
||||
|
||||
Les deux commandes `cargo tree` doivent notamment confirmer l'absence de `solana-sdk-ids` et permettre de contrôler le graphe/features réellement résolus.
|
||||
|
||||
## Suite
|
||||
|
||||
Si les validations sont propres, la tranche suivante reste :
|
||||
|
||||
```text
|
||||
0.1.1-pre.004 — intégration Core + audits
|
||||
```
|
||||
120
deltas/0.1.1/pre.004.md
Normal file
120
deltas/0.1.1/pre.004.md
Normal file
@@ -0,0 +1,120 @@
|
||||
<!-- file: deltas/0.1.1/pre.004.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.1.1-pre.004` — intégration Core + audits
|
||||
|
||||
## Statut
|
||||
|
||||
Tranche d'intégration préparée après validation réussie par le user de `0.1.1-pre.003-fix.001`.
|
||||
|
||||
La base validée utilise :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.3.fix.1"
|
||||
```
|
||||
|
||||
Le présent delta ouvre :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.4"
|
||||
```
|
||||
|
||||
## Validation de la base précédente
|
||||
|
||||
Le user a exécuté avec succès :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
```
|
||||
|
||||
Résultats communiqués :
|
||||
|
||||
- 14 tests unitaires passent ;
|
||||
- 3 tests d'intégration publics passent ;
|
||||
- Clippy ne rapporte plus de warning ou d'erreur ;
|
||||
- `cargo tree` résout `solana-pubkey 4.3.0` puis `solana-address 2.7.0` et leurs dépendances fondamentales ;
|
||||
- `cargo tree -d` ne rapporte aucun doublon.
|
||||
|
||||
## Audit d'intégration Core
|
||||
|
||||
L'audit conjoint de `Error` / `Result`, `Pubkey` et Program IDs ne démontre aucun besoin de primitive N1 supplémentaire dans `0.1.1`.
|
||||
|
||||
La façade conserve les propriétés attendues :
|
||||
|
||||
- les modules d'implémentation restent privés ;
|
||||
- les contrats consommables sont réexportés explicitement au crate-root ;
|
||||
- `ksp-core-lib` ne dépend d'aucune couche KSP supérieure ;
|
||||
- `solana-pubkey` reste l'unique dépendance externe directe de Core ;
|
||||
- aucun codec wire, RPC/client, signer/keypair, store, logging ou configuration n'est introduit ;
|
||||
- le registre Program IDs reste descriptif et distinct de tout registry de decoder/executor.
|
||||
|
||||
## Rustdocs
|
||||
|
||||
La rustdoc crate-level de `ksp-core-lib` est complétée afin de rendre explicites :
|
||||
|
||||
- le contrat d'erreur commun ;
|
||||
- la propriété de `Pubkey` dans la façade Core ;
|
||||
- la propriété KSP du registre de Program IDs fondamentaux ;
|
||||
- l'absence de dépendance inverse vers les domaines supérieurs.
|
||||
|
||||
## Test public renforcé
|
||||
|
||||
`tests/public_api.rs` déclare désormais :
|
||||
|
||||
```text
|
||||
const TEST_ERROR_CODE: ksp_core_lib::ErrorCode = ...
|
||||
```
|
||||
|
||||
Le test confirme ainsi depuis une crate consommatrice que `ErrorCode::new(...)` est réellement utilisable en contexte `const`, ce qui permettra aux futures crates de domaine de posséder leurs codes sans faire connaître leurs domaines à Core.
|
||||
|
||||
Aucune signature publique n'est modifiée.
|
||||
|
||||
## Documentation du plan
|
||||
|
||||
`docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` passe en version documentaire 8 pour enregistrer le résultat de l'audit `pre.004` et ajouter le contrôle explicite des features résolues :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-core-lib/src/lib.rs
|
||||
crates/ksp-core-lib/tests/public_api.rs
|
||||
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
|
||||
```
|
||||
|
||||
## Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.1.1/pre.004.md
|
||||
```
|
||||
|
||||
## Validations à exécuter sur le dépôt cible
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
Aucune validation non exécutée dans l'environnement de préparation n'est déclarée réussie pour ce delta.
|
||||
|
||||
## Suite
|
||||
|
||||
Si cette tranche est propre, la suite prévue est :
|
||||
|
||||
```text
|
||||
0.1.1-pre.005 — clôture, documentation finale et prompt 0.1.2
|
||||
```
|
||||
191
deltas/0.1.1/pre.005.md
Normal file
191
deltas/0.1.1/pre.005.md
Normal file
@@ -0,0 +1,191 @@
|
||||
<!-- file: deltas/0.1.1/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.1.1-pre.005` — clôture Core et prompt Logging
|
||||
|
||||
## Base requise
|
||||
|
||||
`v0.1.1-pre.004` au sens du commit de livraison correspondant, avec :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.4"
|
||||
```
|
||||
|
||||
Le présent delta ouvre :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.5"
|
||||
```
|
||||
|
||||
## Objectif
|
||||
|
||||
Clôturer la phase de développement `0.1.1` sans élargir la surface Core : enregistrer les validations finales de `pre.004`, confirmer la politique de features `solana-pubkey`, réaligner les documents de référence et produire le prompt final de démarrage `0.1.2`.
|
||||
|
||||
La publication stable reste un delta `0.1.1-rel.001` séparé après validation de cette prerelease.
|
||||
|
||||
## Validation de la base précédente
|
||||
|
||||
Le user a exécuté avec succès le 2026-08-14 :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
Résultats communiqués :
|
||||
|
||||
- 14 tests unitaires passent ;
|
||||
- 3 tests d'intégration publics passent ;
|
||||
- Clippy passe sans warning communiqué ;
|
||||
- `cargo tree` conserve `solana-pubkey 4.3.0` comme unique dépendance externe directe de `ksp-core-lib` ;
|
||||
- `solana-pubkey` résout `solana-address 2.7.0` puis ses dépendances fondamentales ;
|
||||
- `cargo tree -d` ne rapporte aucun doublon ;
|
||||
- `cargo tree -e features` a été inspecté.
|
||||
|
||||
## Décision finale sur les features `solana-pubkey`
|
||||
|
||||
Aucune feature optionnelle supplémentaire n'est activée dans `0.1.1`.
|
||||
|
||||
La déclaration workspace reste :
|
||||
|
||||
```toml
|
||||
solana-pubkey = { version = "^4.3", default-features = false }
|
||||
```
|
||||
|
||||
Les features optionnelles `alloc`, `borsh`, `bytemuck`, `curve25519`, `rand`, `serde`, `sha2`, `std` et `wincode` ne correspondent à aucun besoin du contrat Core actuellement livré.
|
||||
|
||||
Les features `solana-address` visibles dans le graphe résolu (`copy`, `decode`, `error`, `sanitize`, `syscalls`, `default`) appartiennent à la composition interne de la génération actuelle de `solana-pubkey`/`solana-address`. Elles ne justifient pas une activation KSP supplémentaire.
|
||||
|
||||
Les futures releases activent une feature uniquement lorsque leur propriétaire fonctionnel démontre un besoin concret. En particulier, `borsh`/`wincode` ne sont pas activées dans Core par anticipation d'une future surface wire.
|
||||
|
||||
## Documentation finale
|
||||
|
||||
Le plan `0.1.1` est consolidé pour :
|
||||
|
||||
- refléter la surface réellement implémentée ;
|
||||
- enregistrer les validations réussies de `pre.004` ;
|
||||
- fermer la question des features `solana-pubkey` ;
|
||||
- confirmer qu'aucune primitive N1 supplémentaire n'est nécessaire ;
|
||||
- confirmer qu'aucun `README.md`/`USAGE.md` spécifique à la crate n'est nécessaire pour cette petite surface ;
|
||||
- confirmer que le dépôt ne possède actuellement aucun changelog général à synchroniser.
|
||||
|
||||
La séquence fonctionnelle est mise à jour pour remplacer le périmètre candidat de `0.1.1` par la surface effectivement stabilisée et son lifecycle réellement suivi.
|
||||
|
||||
Les index de documentation/plans/prompts sont réalignés avec les fichiers présents.
|
||||
|
||||
## Prompt `0.1.2`
|
||||
|
||||
Ajout :
|
||||
|
||||
```text
|
||||
prompts/002-V0_1_2_START_PROMPT.md
|
||||
```
|
||||
|
||||
Ce prompt ouvre :
|
||||
|
||||
```text
|
||||
0.1.2 — Logging foundation
|
||||
```
|
||||
|
||||
après publication stable de `0.1.1`.
|
||||
|
||||
Il conserve notamment les décisions suivantes :
|
||||
|
||||
- `ksp-logging-lib` est la façade KSP unique de logging/tracing runtime ;
|
||||
- Logging peut dépendre de `ksp-core-lib`, jamais l'inverse ;
|
||||
- `pre.001` de Logging reste une phase d'audit/brainstorming/planification ;
|
||||
- la stack `tracing` et ses features sont revérifiées depuis les sources officielles avant ajout ;
|
||||
- l'API doit préserver les callsites réels ;
|
||||
- Logging possède ses settings runtime sans dépendre de Config ;
|
||||
- les secrets ne sont jamais loggés automatiquement ;
|
||||
- les dépendances externes restent centralisées sous `[workspace.dependencies]`.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.1.1/pre.005.md
|
||||
prompts/002-V0_1_2_START_PROMPT.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
|
||||
prompts/000-README.md
|
||||
```
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Nettoyage/archivage
|
||||
|
||||
Aucun fichier temporaire ou obsolète supplémentaire n'est identifié comme devant être supprimé dans cette tranche.
|
||||
|
||||
Les deltas historiques et le prompt `0.1.1` restent conservés comme historique utile.
|
||||
|
||||
## Validations exécutées pendant la préparation
|
||||
|
||||
Contrôles statiques hors Cargo :
|
||||
|
||||
- parsing TOML ;
|
||||
- headers `file:` / `version:` des fichiers modifiés/ajoutés ;
|
||||
- terminaison EOF ;
|
||||
- liens Markdown locaux ;
|
||||
- cohérence des index documentaires ;
|
||||
- cohérence de la version `0.1.1-pre.5` ;
|
||||
- absence d'ajout de feature `solana-pubkey` ;
|
||||
- intégrité de l'archive delta.
|
||||
|
||||
## Validations non exécutées pendant la préparation
|
||||
|
||||
L'environnement de préparation ne fournit pas `cargo`/`rustc`.
|
||||
|
||||
Après application du delta, exécuter sur le dépôt cible :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
Aucune de ces validations de `pre.005` n'est déclarée réussie avant exécution par le user.
|
||||
|
||||
## Publication suivante
|
||||
|
||||
Si `pre.005` est propre, préparer :
|
||||
|
||||
```text
|
||||
0.1.1-rel.001
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1"
|
||||
```
|
||||
|
||||
Le commit de `rel.001` validé comme stable reçoit ensuite le tag :
|
||||
|
||||
```text
|
||||
v0.1.1
|
||||
```
|
||||
|
||||
La session suivante peut alors démarrer avec :
|
||||
|
||||
```text
|
||||
prompts/002-V0_1_2_START_PROMPT.md
|
||||
```
|
||||
150
deltas/0.1.1/rel.001.md
Normal file
150
deltas/0.1.1/rel.001.md
Normal file
@@ -0,0 +1,150 @@
|
||||
<!-- file: deltas/0.1.1/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.1.1-rel.001` — publication stable Core
|
||||
|
||||
## Base requise
|
||||
|
||||
`v0.1.1-pre.005` au sens du commit de livraison correspondant, avec :
|
||||
|
||||
```text
|
||||
workspace.package.version = "0.1.1-pre.5"
|
||||
```
|
||||
|
||||
## Objectif
|
||||
|
||||
Publier la release stable `0.1.1`, clôturer `Core foundation` et préparer l'ouverture de `0.1.2 — Logging foundation` sans modifier la surface fonctionnelle de `ksp-core-lib`.
|
||||
|
||||
## Version Cargo
|
||||
|
||||
`workspace.package.version` passe de :
|
||||
|
||||
```text
|
||||
0.1.1-pre.5
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.1.1
|
||||
```
|
||||
|
||||
Le header de `Cargo.toml` passe de version 24 à 25.
|
||||
|
||||
La politique de dépendance reste inchangée :
|
||||
|
||||
```toml
|
||||
[workspace.dependencies]
|
||||
solana-pubkey = { version = "^4.3", default-features = false }
|
||||
```
|
||||
|
||||
Aucune feature optionnelle supplémentaire n'est activée.
|
||||
|
||||
## Validations finales exécutées par le user
|
||||
|
||||
Commandes exécutées avec succès le 2026-08-14 sur `0.1.1-pre.5` :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
Résultats communiqués :
|
||||
|
||||
- `cargo check --workspace` : succès ;
|
||||
- `cargo test --workspace` : 14 tests unitaires réussis, 3 tests d'intégration publics réussis, doc-tests réussis ;
|
||||
- `cargo clippy --workspace --all-targets` : succès sans warning communiqué ;
|
||||
- `cargo tree -p ksp-core-lib` : dépendance externe directe unique `solana-pubkey 4.3.0`, résolvant `solana-address 2.7.0` ;
|
||||
- `cargo tree -p ksp-core-lib -d` : aucun doublon ;
|
||||
- `cargo tree -p ksp-core-lib -e features` : graphe inspecté, sans besoin d'activer une feature optionnelle `solana-pubkey` supplémentaire.
|
||||
|
||||
## Surface stable publiée
|
||||
|
||||
`0.1.1` stabilise notamment :
|
||||
|
||||
- `ksp_core_lib::ErrorCode`, `ErrorContext`, `Error` et `Result<T>` ;
|
||||
- `ksp_core_lib::Pubkey` ;
|
||||
- les 18 Program IDs fondamentaux possédés par KSP et leurs paires `PRGID_*` / `PRGIDPK_*` ;
|
||||
- `declare_program_id!` ;
|
||||
- `ProgramIdEntry`, `ProgramIdFilter`, `ProgramIdKind` ;
|
||||
- le registre canonique enumerable/recherchable et ses vues par taxonomie ;
|
||||
- `native_program_ids()`, recherches texte/`Pubkey` et filtres combinables ;
|
||||
- la séparation `subfamily` / `program_version` ;
|
||||
- les règles Cargo workspace introduites pendant la release.
|
||||
|
||||
Aucune nouvelle primitive ou API n'est ajoutée par le présent delta de publication.
|
||||
|
||||
## Documentation de clôture
|
||||
|
||||
Le présent delta :
|
||||
|
||||
- marque `0.1.1` réalisée dans `ROADMAP.md` ;
|
||||
- conserve `003-V0_1_1_CORE_FOUNDATION_PLAN.md` comme plan historique clôturé ;
|
||||
- réaligne la séquence fonctionnelle sur la publication stable ;
|
||||
- réaligne les index de documentation/plans ;
|
||||
- conserve `prompts/002-V0_1_2_START_PROMPT.md` comme prompt de démarrage de la release suivante.
|
||||
|
||||
Aucun changelog général n'existe dans la base actuelle ; aucun changelog artificiel n'est créé.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.1.1/rel.001.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
ROADMAP.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
|
||||
```
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Décisions
|
||||
|
||||
Aucune nouvelle décision architecturale.
|
||||
|
||||
La publication stable confirme les décisions et contrats stabilisés pendant les prereleases `0.1.1` et leurs fixes.
|
||||
|
||||
## Publication Git
|
||||
|
||||
Après application de ce delta :
|
||||
|
||||
1. vérifier que le working tree ne contient que les modifications attendues ;
|
||||
2. exécuter au minimum un `cargo check --workspace` final sur la version Cargo stable `0.1.1` ;
|
||||
3. créer le commit de release `v0.1.1-rel.001` ;
|
||||
4. marquer ce commit comme release stable avec le tag :
|
||||
|
||||
```text
|
||||
v0.1.1
|
||||
```
|
||||
|
||||
Aucun autre tag n'est requis pour les prereleases/fixes historiques.
|
||||
|
||||
## Suite
|
||||
|
||||
Après le tag stable `v0.1.1`, ouvrir :
|
||||
|
||||
```text
|
||||
0.1.2-pre.001
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
prompts/002-V0_1_2_START_PROMPT.md
|
||||
```
|
||||
|
||||
La première prerelease de `0.1.2` reste une phase de brainstorming, audit et planification avant développement fonctionnel de `ksp-logging-lib`.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/000-README.md -->
|
||||
<!-- version: 8 -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Documentation KSP
|
||||
|
||||
@@ -34,7 +34,8 @@ docs/
|
||||
├── plans/
|
||||
│ ├── 000-README.md
|
||||
│ ├── 001-V0_0_3_PLAN.md
|
||||
│ └── 002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
│ ├── 002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
│ └── 003-V0_1_1_CORE_FOUNDATION_PLAN.md
|
||||
└── rules/
|
||||
├── FILE_CONTRACTS.md
|
||||
├── PROMPT_STRUCTURE.md
|
||||
@@ -51,7 +52,7 @@ D'autres sous-répertoires seront ajoutés uniquement lorsque leur rôle aura é
|
||||
|
||||
## Documents de planification
|
||||
|
||||
Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md).
|
||||
Le plan historique de la phase fondatrice clôturée est conservé dans [`plans/001-V0_0_3_PLAN.md`](plans/001-V0_0_3_PLAN.md). La séquence active des premières releases fonctionnelles est définie dans [`plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md`](plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md). Le plan détaillé de la release stable `0.1.1` est conservé comme historique clôturé dans [`plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md`](plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md).
|
||||
|
||||
`IDEAS.md` conserve les pistes et questions qui ne sont pas encore des engagements du roadmap ni des décisions architecturales.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 6 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -10,7 +10,8 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
## Plans de référence
|
||||
|
||||
- [`001-V0_0_3_PLAN.md`](001-V0_0_3_PLAN.md) — plan historique de la phase fondatrice `0.0.3`, clôturée ;
|
||||
- [`002-FUNCTIONAL_RELEASE_SEQUENCE.md`](002-FUNCTIONAL_RELEASE_SEQUENCE.md) — séquence active de référence des premières releases fonctionnelles, dont `0.1.1`.
|
||||
- [`002-FUNCTIONAL_RELEASE_SEQUENCE.md`](002-FUNCTIONAL_RELEASE_SEQUENCE.md) — séquence active de référence des premières releases fonctionnelles ;
|
||||
- [`003-V0_1_1_CORE_FOUNDATION_PLAN.md`](003-V0_1_1_CORE_FOUNDATION_PLAN.md) — plan historique clôturé de la release stable `0.1.1`, établi par `0.1.1-pre.001` puis consolidé jusqu'à `0.1.1-rel.001`.
|
||||
|
||||
Le `pre.001` de chaque release fonctionnelle peut introduire son propre plan détaillé lorsque la release s'ouvre.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -48,27 +48,24 @@ Stabiliser `ksp-core-lib` comme fondation N1 minimale et durable.
|
||||
|
||||
Le Core possède uniquement les contrats réellement transversaux nécessaires aux couches supérieures.
|
||||
|
||||
### Périmètre initial
|
||||
### Surface stabilisée
|
||||
|
||||
À auditer précisément dans `0.1.1-pre.001`, avec comme candidats acquis :
|
||||
`0.1.1` stabilise :
|
||||
|
||||
- type public commun `ksp_core_lib::Error` ;
|
||||
- alias public commun `Result<T>` ou forme équivalente validée ;
|
||||
- architecture d'erreur permettant aux domaines supérieurs d'ajouter du contexte sans faire connaître tous les futurs domaines à Core ;
|
||||
- Program IDs fondamentaux appartenant à KSP Core ;
|
||||
- primitives/identités réellement communes et déjà justifiées ;
|
||||
- conventions de version/provenance N1 uniquement si un besoin concret existe ;
|
||||
- exports crate-root et documentation publique ;
|
||||
- tests unitaires/integration appropriés ;
|
||||
- respect complet des règles Rust/workspace.
|
||||
- `ksp_core_lib::ErrorCode`, `ErrorContext`, `Error` et `Result<T>` comme contrat d'erreur ouvert aux domaines supérieurs ;
|
||||
- `ksp_core_lib::Pubkey` comme primitive Solana réexportée par Core ;
|
||||
- 18 Program IDs fondamentaux possédés par KSP avec paires `PRGID_*` / `PRGIDPK_*` ;
|
||||
- `declare_program_id!` pour construire la représentation texte et `Pubkey` depuis une déclaration canonique unique ;
|
||||
- `ProgramIdEntry`, `ProgramIdFilter`, `ProgramIdKind` et le registre enumerable/recherchable ;
|
||||
- des vues par domaine/famille/protocole et `native_program_ids()` sans registres secondaires ;
|
||||
- une taxonomie extensible séparant notamment `subfamily` et `program_version` ;
|
||||
- les réexports crate-root, rustdocs et tests publics correspondants.
|
||||
|
||||
### Dépendances
|
||||
|
||||
Core ne dépend pas de `ksp-logging-lib`, Config, Wallet, Store, Transport, Program ou Materializer.
|
||||
|
||||
Une primitive Solana/Anza officiellement stable peut être ajoutée seulement lorsqu'un item Core concret en a besoin.
|
||||
|
||||
`solana-pubkey` est un candidat naturel pour les Program IDs ; les autres primitives autorisées ne sont pas ajoutées par anticipation.
|
||||
La seule dépendance externe directe de `ksp-core-lib` à la clôture est `solana-pubkey`, déclarée au workspace avec la génération `^4.3`, `default-features = false`, puis héritée par la crate avec `.workspace = true`. Aucune feature optionnelle supplémentaire n'est activée dans `0.1.1`.
|
||||
|
||||
### Hors scope
|
||||
|
||||
@@ -87,20 +84,20 @@ Une primitive Solana/Anza officiellement stable peut être ajoutée seulement lo
|
||||
|
||||
### Lifecycle de la release
|
||||
|
||||
Le nombre de prereleases n'est pas figé avant `pre.001`.
|
||||
|
||||
Trajectoire candidate :
|
||||
Trajectoire réellement suivie :
|
||||
|
||||
```text
|
||||
pre.001 brainstorming + audit + plan détaillé
|
||||
pre.002 Error/Result + fondation API
|
||||
pre.003 primitives/Program IDs réellement retenus
|
||||
pre.004 compléments/tests/audits
|
||||
pre.005 validation finale/docs/cleanup/prompt 0.1.2
|
||||
pre.001 brainstorming + audit + plan détaillé
|
||||
pre.001-fix.001/.002 corrections de cadrage Program IDs/taxonomie
|
||||
pre.002 Error/Result + fondation API
|
||||
pre.002-fix.001 corrections de tests/lints
|
||||
pre.003 Pubkey + Program IDs
|
||||
pre.003-fix.001 politique Cargo workspace + corrections Clippy
|
||||
pre.004 intégration Core + audits
|
||||
pre.005 validation finale/docs/cleanup/prompt 0.1.2
|
||||
rel.001 publication stable validée de 0.1.1
|
||||
```
|
||||
|
||||
Cette séquence est indicative. `pre.001` peut la modifier.
|
||||
|
||||
## `0.1.2` — Logging foundation
|
||||
|
||||
### Dépendances
|
||||
@@ -325,7 +322,7 @@ Les directions restent celles du roadmap :
|
||||
|
||||
Ces séries sont des objectifs fonctionnels, pas un calendrier contractuel.
|
||||
|
||||
# Sélection de la première release
|
||||
# Progression de la série `0.1.x`
|
||||
|
||||
La première release fonctionnelle est :
|
||||
|
||||
@@ -333,10 +330,15 @@ La première release fonctionnelle est :
|
||||
0.1.1 — Core foundation
|
||||
```
|
||||
|
||||
Le prompt de démarrage associé est :
|
||||
Son prompt historique d'ouverture reste :
|
||||
|
||||
```text
|
||||
prompts/001-V0_1_1_START_PROMPT.md
|
||||
```
|
||||
|
||||
`0.0.3` est désormais la base fondatrice stable. La prochaine phase ouvre `0.1.1-pre.001` à partir du prompt final `prompts/001-V0_1_1_START_PROMPT.md`.
|
||||
`0.1.1-rel.001` publie la surface Core stable après validation complète de `pre.005`. Le commit de release reçoit le tag `v0.1.1`. La release suivante s'ouvre avec :
|
||||
|
||||
```text
|
||||
0.1.2 — Logging foundation
|
||||
prompts/002-V0_1_2_START_PROMPT.md
|
||||
```
|
||||
|
||||
699
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
Normal file
699
docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md
Normal file
@@ -0,0 +1,699 @@
|
||||
<!-- file: docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md -->
|
||||
<!-- version: 10 -->
|
||||
|
||||
# Plan KSP 0.1.1 — Core foundation
|
||||
|
||||
## Statut
|
||||
|
||||
Plan historique clôturé de `0.1.1`, établi par `0.1.1-pre.001`, consolidé jusqu'à `0.1.1-pre.005` puis fermé par `0.1.1-rel.001`.
|
||||
|
||||
La surface fonctionnelle Core prévue par ce plan est implémentée et validée. Le delta `rel.001` publie `workspace.package.version = "0.1.1"`; son commit doit recevoir le tag stable `v0.1.1` avant ouverture de `0.1.2`.
|
||||
|
||||
## Base auditée
|
||||
|
||||
Base fournie :
|
||||
|
||||
```text
|
||||
0.0.3 stable
|
||||
```
|
||||
|
||||
Constats sur l'archive reçue :
|
||||
|
||||
- `workspace.package.version = "0.0.3"` ;
|
||||
- seul `crates/ksp-core-lib` est membre du workspace ;
|
||||
- `ksp-core-lib` ne possède encore aucune dépendance ;
|
||||
- `crates/ksp-core-lib/src/lib.rs` contient uniquement la façade/squelette minimal et les lints de crate ;
|
||||
- le delta final `deltas/0.0.3/rel.001.md` indique que les validations Cargo de publication ont été exécutées avec succès par le user avant stabilisation ;
|
||||
- le prompt `prompts/001-V0_1_1_START_PROMPT.md` présent dans l'archive correspond au prompt final attendu pour cette session.
|
||||
|
||||
Dans le workflow KSP, l'archive `khadhroony-solana-project-v0.0.3.zip` est produite directement par Gitea depuis le tag correspondant. Cette provenance suffit à considérer la base fournie comme la release stable/taguée `v0.0.3` attendue ; l'absence normale de `.git` dans l'archive n'ajoute pas de vérification Git supplémentaire à cette session.
|
||||
|
||||
## Mission bornée
|
||||
|
||||
`0.1.1` doit rendre `ksp-core-lib` immédiatement consommable par les prochaines fondations N1 sans lui faire absorber leurs responsabilités.
|
||||
|
||||
La surface retenue pour cette release est limitée à :
|
||||
|
||||
1. un contrat commun `Error` / `Result` ouvert aux domaines supérieurs ;
|
||||
2. la primitive Solana d'adresse publique nécessaire aux Program IDs ;
|
||||
3. les Program IDs fondamentaux du runtime Solana, leurs deux représentations canonique texte/`Pubkey` et un petit registre descriptif enumerable ;
|
||||
4. les réexports crate-root, rustdocs et tests nécessaires à ces contrats.
|
||||
|
||||
Aucune autre primitive n'est ajoutée sans usage concret découvert pendant la release.
|
||||
|
||||
## Inventaire des contrats Core nécessaires maintenant
|
||||
|
||||
### `Error` / `Result`
|
||||
|
||||
Besoin concret immédiat : `0.1.2` Logging puis les autres crates KSP doivent pouvoir retourner une erreur KSP commune sans obliger leurs consommateurs à adopter une erreur propre à chaque couche.
|
||||
|
||||
Le modèle historique de bot3 fondé sur une enum centrale comportant des variantes telles que Config, Tracing, Tauri, HTTP ou DB n'est pas repris : une telle enum fait connaître à Core les domaines supérieurs et doit être modifiée à chaque nouveau domaine.
|
||||
|
||||
### `Pubkey`
|
||||
|
||||
Les Program IDs ont besoin d'une représentation Solana typée et commune. Core doit posséder cette dépendance fondamentale et peut réexporter le type afin que les crates KSP supérieures n'aient pas à importer directement la crate Solana correspondante uniquement pour manipuler un Program ID.
|
||||
|
||||
### Program IDs fondamentaux
|
||||
|
||||
Core doit posséder les identifiants fondamentaux du runtime Solana qui ne relèvent d'aucun protocole supérieur.
|
||||
|
||||
Cette propriété inclut les valeurs canoniques KSP, leur représentation `Pubkey`, leur nomenclature et un registre descriptif enumerable permettant de les inventorier/rechercher. Ce registre de constantes n'est pas le registry de dispatch de `ksp-program-lib` : il ne sélectionne aucun decoder, executor ou implémentation de programme et ne crée aucune enum fermée des protocoles.
|
||||
|
||||
## Contrat d'erreur retenu
|
||||
|
||||
### Forme générale
|
||||
|
||||
`pre.002` stabilise un type structuré et extensible plutôt qu'une enum fermée.
|
||||
|
||||
Surface conceptuelle :
|
||||
|
||||
```text
|
||||
ErrorCode
|
||||
domain: &'static str
|
||||
code: &'static str
|
||||
|
||||
ErrorContext
|
||||
key: &'static str
|
||||
value: String
|
||||
|
||||
Error
|
||||
code: ErrorCode
|
||||
message: String
|
||||
context: Vec<ErrorContext>
|
||||
source: Option<Box<dyn std::error::Error + Send + Sync + 'static>>
|
||||
|
||||
Result<T> = std::result::Result<T, Error>
|
||||
```
|
||||
|
||||
La surface Rust de `pre.002` retient les constructeurs/getters explicites ainsi que des enrichissements consommant `self` : `Error::with_context(...)` et `Error::with_source(...)`. `ErrorCode::new(...)` est `const` afin que les crates supérieures puissent déclarer leurs codes sous forme de constantes. Les invariants suivants font partie du contrat.
|
||||
|
||||
### Invariants
|
||||
|
||||
- `Error` est le seul type d'erreur KSP commun exposé par Core.
|
||||
- `Result<T>` est un alias public vers `std::result::Result<T, Error>`.
|
||||
- `ErrorCode` sépare explicitement un domaine stable et un code stable sans enum centrale des domaines.
|
||||
- Les domaines supérieurs définissent leurs propres constantes `ErrorCode` ; Core ne connaît pas Config, Logging, Wallet, Transport, Store, Tauri ou les protocoles.
|
||||
- Les identifiants de domaine/code sont des chaînes statiques afin de favoriser des codes définis au code source et stables, pas des catégories dynamiques construites au runtime.
|
||||
- `message` reste un diagnostic lisible par un humain.
|
||||
- `ErrorContext` permet d'ajouter du contexte structuré sans étendre le type `Error` à chaque besoin métier.
|
||||
- Les clés de contexte sont statiques ; les valeurs sont possédées.
|
||||
- Le contexte d'erreur ne doit pas contenir de secret. Logging décidera plus tard quels champs sont effectivement émis.
|
||||
- Une cause externe peut être conservée par `source` lorsqu'elle implémente `std::error::Error + Send + Sync + 'static`.
|
||||
- Une erreur externe qui ne respecte pas ces bornes peut toujours être transformée explicitement en message/contexte sans être conservée comme `source`.
|
||||
- `Error` implémente `std::fmt::Display` et `std::error::Error`.
|
||||
- `Display` utilise exactement la forme `<domain>.<code>: <message>` ; il ne concatène pas automatiquement le contexte ou la chaîne de causes.
|
||||
- Aucun `From<ExternalError>` générique ou inventaire de conversions propres aux futurs domaines n'est ajouté dans Core. Les crates propriétaires enveloppent explicitement leur cause avec leur propre `ErrorCode`.
|
||||
- Aucun besoin de `Clone`, `Eq` ou `PartialEq` n'est imposé à `Error` : préserver une vraie cause d'erreur est prioritaire sur ces dérivations.
|
||||
|
||||
Exemple conceptuel de code qualifié :
|
||||
|
||||
```text
|
||||
config.profile_missing
|
||||
logging.initialization_failed
|
||||
transport.http_request_failed
|
||||
```
|
||||
|
||||
Ces exemples illustrent le contrat ouvert ; ils ne créent aucune connaissance de ces domaines dans Core.
|
||||
|
||||
## API publique Core prévue
|
||||
|
||||
La façade crate-root doit exposer directement les contrats consommables :
|
||||
|
||||
```text
|
||||
ksp_core_lib::Error
|
||||
ksp_core_lib::ErrorCode
|
||||
ksp_core_lib::ErrorContext
|
||||
ksp_core_lib::Result
|
||||
ksp_core_lib::Pubkey
|
||||
ksp_core_lib::ProgramIdEntry
|
||||
ksp_core_lib::ProgramIdFilter
|
||||
ksp_core_lib::ProgramIdKind
|
||||
ksp_core_lib::entries
|
||||
ksp_core_lib::program_ids
|
||||
ksp_core_lib::program_ids_by_domain
|
||||
ksp_core_lib::program_ids_by_family
|
||||
ksp_core_lib::program_ids_by_protocol
|
||||
ksp_core_lib::native_program_ids
|
||||
ksp_core_lib::find_program_id
|
||||
ksp_core_lib::find_program_pubkey
|
||||
ksp_core_lib::declare_program_id!
|
||||
ksp_core_lib::PRGID_*
|
||||
ksp_core_lib::PRGIDPK_*
|
||||
```
|
||||
|
||||
Les modules d'implémentation restent privés conformément aux règles Rust du dépôt.
|
||||
|
||||
Arborescence candidate après développement :
|
||||
|
||||
```text
|
||||
crates/ksp-core-lib/
|
||||
├── Cargo.toml
|
||||
├── src/
|
||||
│ ├── lib.rs
|
||||
│ ├── error.rs
|
||||
│ └── program_ids.rs
|
||||
├── unit_tests/
|
||||
│ ├── error.rs
|
||||
│ └── program_ids.rs
|
||||
└── tests/
|
||||
└── public_api.rs
|
||||
```
|
||||
|
||||
Cette arborescence peut être ajustée si l'implémentation révèle une séparation plus simple, sans introduire `mod.rs` ni `pub mod`.
|
||||
|
||||
## Audit Solana/Anza actuel
|
||||
|
||||
Audit effectué le 2026-08-14 sur les sources officielles actuelles du dépôt `anza-xyz/solana-sdk` et les métadonnées de publication correspondantes.
|
||||
|
||||
### `solana-pubkey`
|
||||
|
||||
État observé :
|
||||
|
||||
```text
|
||||
solana-pubkey 4.3.0
|
||||
MSRV officiel du workspace Solana SDK : Rust 1.89.0
|
||||
```
|
||||
|
||||
La génération actuelle de `solana-pubkey` est une façade de compatibilité officielle sur `solana-address` : elle réexporte notamment `solana_address::Address` sous le nom `Pubkey`.
|
||||
|
||||
Décision pour `0.1.1` :
|
||||
|
||||
- conserver le vocabulaire/API KSP `Pubkey` déjà prévu par l'architecture ;
|
||||
- utiliser directement `solana-pubkey` comme dépendance propriétaire de `ksp-core-lib` ;
|
||||
- déclarer la génération retenue sous `[workspace.dependencies]` avec la contrainte explicite `^4.3`, la résolution auditée actuelle étant `4.3.0` ;
|
||||
- définir `default-features = false` au niveau workspace puis consommer la dépendance dans `ksp-core-lib` avec `solana-pubkey.workspace = true` ;
|
||||
- n'activer ni Borsh, ni Wincode, ni Serde, ni Rand, ni feature cryptographique par anticipation ;
|
||||
- réexporter le type `Pubkey` depuis `ksp_core_lib` afin que son utilisation fasse partie intentionnellement du contrat Core.
|
||||
|
||||
L'audit final `pre.005` confirme qu'aucune feature optionnelle de `solana-pubkey` ne doit être activée dans `0.1.1`. La surface Core actuelle utilise uniquement l'identité `Pubkey`, la construction compile-time des Program IDs et les opérations déjà disponibles avec la dépendance retenue. Les features `alloc`, `borsh`, `bytemuck`, `curve25519`, `rand`, `serde`, `sha2`, `std` et `wincode` restent need-driven et seront activées uniquement dans la crate propriétaire lorsqu'un contrat réel l'exigera.
|
||||
|
||||
Le `cargo tree -p ksp-core-lib -e features` exécuté par le user montre des features de `solana-address` telles que `copy`, `decode`, `error`, `sanitize`, `syscalls` et `default`. Elles proviennent de la composition interne résolue de `solana-pubkey`/`solana-address` et ne justifient pas d'activer une feature optionnelle KSP supplémentaire sur `solana-pubkey`.
|
||||
|
||||
Depuis `pre.003-fix.001`, la règle générale KSP impose la centralisation des dépendances externes sous `[workspace.dependencies]` et l'héritage `.workspace = true` dans les crates membres. La résolution Cargo observée pour la contrainte `^4.3` reste `solana-pubkey 4.3.0` au moment de cette tranche.
|
||||
|
||||
### `solana-address`
|
||||
|
||||
`solana-address 2.7.0` est la primitive interne actuelle derrière `solana-pubkey`.
|
||||
|
||||
Elle n'est pas ajoutée directement à KSP en `0.1.1` : l'ajouter en parallèle n'apporte aucun besoin Core supplémentaire et multiplierait les points d'entrée publics pour la même identité Solana.
|
||||
|
||||
### `solana-sdk-ids`
|
||||
|
||||
La source officielle `solana-sdk-ids` reste utile comme référence d'audit des identifiants publiés par Anza/Solana.
|
||||
|
||||
État du package observé pendant `pre.001` :
|
||||
|
||||
```text
|
||||
solana-sdk-ids 3.1.0
|
||||
```
|
||||
|
||||
Décision acquise : **ne pas ajouter `solana-sdk-ids` à KSP**, ni comme dépendance runtime, ni comme dev-dependency.
|
||||
|
||||
KSP possède ses propres constantes et registres de Program IDs. Les sources officielles Anza/Solana sont consultées pour vérifier les valeurs et l'évolution de la surface, mais cette vérification ne doit pas créer une dépendance Cargo à leur crate d'IDs.
|
||||
|
||||
### Crates explicitement non nécessaires à `0.1.1`
|
||||
|
||||
Ne pas ajouter :
|
||||
|
||||
- `solana-sdk` umbrella ;
|
||||
- `solana-keypair` ;
|
||||
- `solana-signer` ;
|
||||
- `solana-hash` ;
|
||||
- `solana-nonce` ;
|
||||
- crates transaction/message/instruction ;
|
||||
- crates RPC/client ;
|
||||
- Borsh/Wincode/Serde pour une hypothétique future surface wire.
|
||||
|
||||
La génération retenue de `solana-pubkey` requiert Rust 1.89.0. La validation `pre.002-fix.001` a été exécutée avec une génération Clippy Rust 1.94.0, donc la toolchain observée satisfait ce MSRV. Une future révision ne devra pas revenir silencieusement à une vieille génération Solana uniquement pour contourner une exigence de toolchain.
|
||||
|
||||
## Program IDs retenus pour la première surface Core
|
||||
|
||||
`pre.003` fixe la première surface Core à **18 Program IDs**.
|
||||
|
||||
Les 17 identifiants fondamentaux exposés par la surface officielle actuelle `solana-sdk-ids` sont recopiés comme valeurs KSP sans créer de dépendance Cargo vers cette crate :
|
||||
|
||||
- System ;
|
||||
- Stake ;
|
||||
- Vote ;
|
||||
- Config ;
|
||||
- Feature ;
|
||||
- Compute Budget ;
|
||||
- Address Lookup Table ;
|
||||
- BPF Loader historique v1 ;
|
||||
- BPF Loader v2 ;
|
||||
- BPF Loader Upgradeable ;
|
||||
- Loader v4 ;
|
||||
- Native Loader ;
|
||||
- précompiles Ed25519, Secp256k1 et Secp256r1 ;
|
||||
- ZK ElGamal Proof ;
|
||||
- ZK Token Proof.
|
||||
|
||||
Le dix-huitième identifiant est le Slashing Program `S1ashing11111111111111111111111111111111111`. Il n'est pas encore publié dans `solana-sdk-ids`, mais son statut de programme enshrined et son adresse sont confirmés par SIMD-0204 et la documentation Anza. L'ancien `ks-program-ids` de bot3 avait déjà cette entrée ; `pre.003` ne la conserve toutefois qu'après cette revérification officielle indépendante.
|
||||
|
||||
### Exclusions volontaires de `0.1.1`
|
||||
|
||||
Ne pas ajouter fonctionnellement pendant cette release :
|
||||
|
||||
- SPL Token, Token-2022, ATA, Memo ou tout autre protocole SPL ;
|
||||
- Metaplex et autres protocoles ;
|
||||
- `incinerator`, qui est une adresse spéciale et non un Program ID exécutable ;
|
||||
- les sysvar account IDs ;
|
||||
- les autres well-known accounts non exécutables uniquement pour agrandir la première surface.
|
||||
|
||||
Les exemples SPL/protocoles utilisés pour définir la nomenclature ci-dessous illustrent la convention future et ne modifient pas le hors-scope de `0.1.1`.
|
||||
|
||||
Les well-known account IDs doivent rester explicitement séparés des Program IDs. L'ancien `native_well_known_account_ids()` constitue une bonne direction conceptuelle ; aucune API vide n'est toutefois créée en `0.1.1` tant qu'aucun well-known account n'est réellement retenu dans la surface de la release.
|
||||
|
||||
## Nomenclature des Program IDs
|
||||
|
||||
La nomenclature des symboles et la taxonomie du registre sont deux contrats liés mais distincts.
|
||||
|
||||
Le nom Rust d'une constante doit privilégier une **identité stable** et ne doit pas embarquer toute la classification fonctionnelle, car une reclassification future ne doit pas obliger à renommer un symbole public.
|
||||
|
||||
La forme générale devient :
|
||||
|
||||
```text
|
||||
PRGID_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?> -> &'static str Base58
|
||||
PRGIDPK_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?> -> Pubkey
|
||||
```
|
||||
|
||||
Règles :
|
||||
|
||||
- `PRGID_` identifie toujours la représentation texte Base58 ;
|
||||
- `PRGIDPK_` identifie toujours la représentation `Pubkey` ;
|
||||
- le suffixe après le préfixe doit être identique entre les deux formes ;
|
||||
- `NAMESPACE` identifie le namespace/propriétaire stable de l'identité, par exemple `SOLANA`, `SPL`, `METAPLEX`, `RAYDIUM`, `METEORA`, `GOOSEFX` ou `JUPITER` ;
|
||||
- `PROGRAM_OR_FAMILY` et `VARIANT` décrivent l'identité publique utile du programme sans tenter de recopier mécaniquement tous les champs de `ProgramIdEntry` ;
|
||||
- `VERSION` n'est ajoutée que lorsque le projet/protocole distingue réellement plusieurs générations d'une même lignée de programme ;
|
||||
- un suffixe ressemblant à une année ou une version dans un nom officiel n'est pas automatiquement interprété comme `program_version` : `Token-2022` reste par exemple une identité de programme distincte et non une déduction automatique de version ;
|
||||
- la valeur de version est un label KSP normalisé à partir de la génération publiquement reconnue (`V1`, `V2`, `V3`, `V4`, `V6`, `V0_5`, etc.), pas la version d'une crate ou d'une IDL.
|
||||
|
||||
Exemples de convention :
|
||||
|
||||
```text
|
||||
PRGID_SOLANA_SYSTEM
|
||||
PRGIDPK_SOLANA_SYSTEM
|
||||
|
||||
PRGID_SOLANA_LOADER_BPF_V2
|
||||
PRGIDPK_SOLANA_LOADER_BPF_V2
|
||||
|
||||
PRGID_SOLANA_PRECOMPILE_ED25519
|
||||
PRGIDPK_SOLANA_PRECOMPILE_ED25519
|
||||
|
||||
PRGID_SPL_MEMO_V1
|
||||
PRGIDPK_SPL_MEMO_V1
|
||||
PRGID_SPL_MEMO_V3
|
||||
PRGIDPK_SPL_MEMO_V3
|
||||
PRGID_SPL_MEMO_V4
|
||||
PRGIDPK_SPL_MEMO_V4
|
||||
|
||||
PRGID_METEORA_DAMM_V2
|
||||
PRGIDPK_METEORA_DAMM_V2
|
||||
|
||||
PRGID_GOOSEFX_GAMMA
|
||||
PRGIDPK_GOOSEFX_GAMMA
|
||||
PRGID_GOOSEFX_SSL_V2
|
||||
PRGIDPK_GOOSEFX_SSL_V2
|
||||
```
|
||||
|
||||
Les exemples SPL/DEX définissent uniquement la convention future pendant `0.1.1` ; ces protocoles restent hors scope fonctionnel de cette release.
|
||||
|
||||
### Pourquoi `NAMESPACE` et non `DOMAIN` dans le symbole
|
||||
|
||||
Le mot `domain` est réservé à la taxonomie fonctionnelle du registre décrite plus bas. Une constante doit rester stable si la classification fonctionnelle d'un programme est affinée.
|
||||
|
||||
Par exemple, `PRGID_GOOSEFX_GAMMA` reste un bon identifiant public même si KSP affine plus tard sa classification AMM. Le nom de symbole ne doit donc pas être une sérialisation complète de `domain/family/protocol/subfamily`.
|
||||
|
||||
## Construction et ownership des constantes
|
||||
|
||||
KSP possède la chaîne Base58 canonique de chaque Program ID et ne dépend pas d'un registre runtime externe pour la fournir.
|
||||
|
||||
La chaîne Base58 ne doit être écrite qu'une seule fois dans la déclaration KSP. Une macro publique KSP, nommée initialement `declare_program_id!`, doit produire les deux représentations à partir d'une déclaration unique, selon une forme conceptuelle de ce type :
|
||||
|
||||
```text
|
||||
declare_program_id!(
|
||||
PRGID_SOLANA_SYSTEM,
|
||||
PRGIDPK_SOLANA_SYSTEM,
|
||||
"11111111111111111111111111111111"
|
||||
);
|
||||
```
|
||||
|
||||
Le résultat conceptuel est :
|
||||
|
||||
```text
|
||||
PRGID_SOLANA_SYSTEM : &'static str
|
||||
PRGIDPK_SOLANA_SYSTEM : Pubkey
|
||||
```
|
||||
|
||||
La macro doit s'inspirer de la mécanique compile-time de `solana_address::declare_id!`/des primitives correspondantes exposées via la génération `solana-pubkey`, mais KSP possède son API et sa nomenclature. L'implémentation exacte sera vérifiée en `pre.003` contre la version réellement retenue de `solana-pubkey`.
|
||||
|
||||
Invariants :
|
||||
|
||||
- aucune seconde copie manuelle de la valeur Base58 ;
|
||||
- aucune conversion runtime inutile ;
|
||||
- aucun `unwrap`, `expect`, `panic` ou opérateur `?` ;
|
||||
- les deux constantes sont disponibles au crate-root ;
|
||||
- la macro n'impose pas les symboles génériques `ID`, `id()` ou `check_id()` qui entreraient en collision lorsque plusieurs Program IDs sont déclarés dans Core.
|
||||
|
||||
Les sources officielles Solana/Anza servent :
|
||||
|
||||
1. de source de vérité externe pour vérifier la valeur Base58 ;
|
||||
2. de contrôle de l'évolution des IDs/runtime ;
|
||||
3. de référence d'audit ponctuelle sans dépendance Cargo.
|
||||
|
||||
## Registre descriptif des Program IDs
|
||||
|
||||
L'ancien `ks-program-ids` fournissait notamment :
|
||||
|
||||
```text
|
||||
ProgramIdEntry
|
||||
entries()
|
||||
registered_program_ids()
|
||||
native_program_ids()
|
||||
native_well_known_account_ids()
|
||||
find_registered_program_id()
|
||||
```
|
||||
|
||||
Cette fonctionnalité doit être reprise et améliorée autour d'un **registre canonique unique**. Les vues spécialisées ne doivent pas maintenir des listes indépendantes et dupliquer les mêmes Program IDs.
|
||||
|
||||
### Axes de classification retenus
|
||||
|
||||
L'audit de l'ancien registre bot3 et des IDLs archivées montre qu'un seul axe hiérarchique ne suffit pas. La taxonomie KSP doit séparer au minimum :
|
||||
|
||||
- `domain` : domaine fonctionnel large ;
|
||||
- `family` : famille fonctionnelle dans ce domaine ;
|
||||
- `protocol` : protocole/projet auquel appartient le programme ;
|
||||
- `subfamily` : branche, architecture ou produit interne optionnel dans une même famille/protocole ;
|
||||
- `program_version` : génération publique optionnelle de la **lignée du programme on-chain** ;
|
||||
- `kind` : classification technique nécessaire aux vues Core telles que les programmes natifs/loaders/précompiles ;
|
||||
- le code KSP unique, la chaîne Base58 `PRGID_*` et le `Pubkey` `PRGIDPK_*` restent les identités de l'entrée.
|
||||
|
||||
Les vocabulaires de `domain`, `family`, `protocol`, `subfamily` et `program_version` restent des chaînes extensibles : Core ne crée aucune enum fermée des futurs protocoles Solana. `kind` est volontairement une petite enum technique `ProgramIdKind` (`Program`, `Loader`, `Precompile`, `EnshrinedProgram`) parce qu'elle décrit la nature de l'entrée plutôt qu'un catalogue de protocoles.
|
||||
|
||||
`family = amm` est retenu comme famille agrégatrice future pour les modèles AMM. Les variantes `cpmm`, `clmm`, `dlmm`, `damm`, `stable_swap`, `weighted_swap`, `gamma`, `ssl` ou équivalentes appartiennent au niveau `subfamily` lorsqu'elles représentent réellement une branche architecturale du protocole. Cela permettra à une future vue `amm_program_ids()` de retrouver l'ensemble de ces programmes au lieu de limiter la recherche à l'ancien préfixe bot3 `AMM_*`.
|
||||
|
||||
`subfamily` reste optionnelle : un programme unique peut supporter plusieurs courbes/mécanismes et ne doit pas être forcé artificiellement dans une seule sous-famille. L'AMM Aldrin constitue notamment un cas où le programme peut couvrir plusieurs types de courbes ; la famille `amm` suffit alors si aucune sous-famille unique n'est normative.
|
||||
|
||||
### `program_version` est distinct de `subfamily`
|
||||
|
||||
La version est un axe indépendant. Elle ne doit jamais être encodée comme une `subfamily` uniquement pour distinguer deux Program IDs.
|
||||
|
||||
Cas représentatifs audités :
|
||||
|
||||
| Cas | `domain`/`family`/`protocol` | `subfamily` | `program_version` |
|
||||
|----------------------------|-------------------------------------------------------------------|-------------------|-------------------------------------------------------------|
|
||||
| SPL Memo v1 / v3 / v4 | identiques entre les trois entrées | identique/absente | `v1` / `v3` / `v4` |
|
||||
| Aldrin AMM v1 / v2 | identiques | identique/absente | `v1` / `v2` |
|
||||
| Meteora DAMM v1 / v2 | identiques | `damm` | `v1` / `v2` |
|
||||
| Meteora DLMM | même domaine/protocole AMM | `dlmm` | aucune si aucune génération normative n'est attachée à l'ID |
|
||||
| GooseFX GAMMA | même domaine/famille/protocole GooseFX que les autres AMM GooseFX | `gamma` | aucune génération `v1` ne doit être inventée |
|
||||
| GooseFX SSL v2 | même domaine/famille/protocole GooseFX | `ssl` | `v2` |
|
||||
| Jupiter Aggregator v4 / v6 | identiques pour la lignée Aggregator | `aggregator` | `v4` / `v6` |
|
||||
|
||||
Cette séparation évite notamment de traiter GooseFX `GAMMA` comme « V1 » de GooseFX `SSL V2`, ce que les sources/IDLs ne justifient pas.
|
||||
|
||||
### Version du programme versus version d'IDL
|
||||
|
||||
`program_version` ne représente **jamais** la version de l'IDL, de la crate cliente, du SDK ou du schéma Anchor.
|
||||
|
||||
L'audit des IDLs archivées de bot3 démontre que ces nombres évoluent indépendamment du Program ID :
|
||||
|
||||
- l'IDL `jupiter_v6` porte une version d'IDL `0.1.0` alors que la génération publique du programme est `v6` ;
|
||||
- l'IDL `goosefx_v2` porte une version d'IDL `0.3.0` alors que la génération publique est `v2` ;
|
||||
- l'IDL GooseFX `gamma` porte une version de schéma `0.2.0` sans faire de GAMMA une hypothétique « v0.2 » du protocole ;
|
||||
- l'IDL Meteora DAMM v2 peut porter une version de schéma différente de `v2`.
|
||||
|
||||
Une éventuelle provenance/version d'IDL appartient plus tard à la couche d'interface/decoder ou à ses métadonnées, pas à l'identité `ProgramIdEntry` de Core.
|
||||
|
||||
Le nom `protocol_version` n'est pas retenu : un même protocole peut posséder simultanément plusieurs composants/lignées versionnés indépendamment (par exemple un aggregator, un limit-order program, un vault ou un lending program). `program_version` borne correctement la version à l'entrée/lignée concernée.
|
||||
|
||||
### Recherches et vues
|
||||
|
||||
Direction de l'API :
|
||||
|
||||
```text
|
||||
ProgramIdEntry
|
||||
ProgramIdFilter
|
||||
entries()
|
||||
program_ids(filter)
|
||||
native_program_ids()
|
||||
find_program_id()
|
||||
```
|
||||
|
||||
Le filtre générique doit pouvoir combiner les axes, au minimum :
|
||||
|
||||
```text
|
||||
domain
|
||||
family
|
||||
protocol
|
||||
subfamily
|
||||
program_version
|
||||
kind
|
||||
```
|
||||
|
||||
Des helpers lisibles peuvent être exposés lorsque leur usage est réel :
|
||||
|
||||
```text
|
||||
program_ids_by_domain(...)
|
||||
program_ids_by_family(...)
|
||||
program_ids_by_protocol(...)
|
||||
native_program_ids()
|
||||
```
|
||||
|
||||
Une future surface possédant des Program IDs AMM pourra ajouter :
|
||||
|
||||
```text
|
||||
amm_program_ids()
|
||||
```
|
||||
|
||||
Cette fonction devra être une vue de la classification canonique (`family = amm`) et non un second registre manuel. `0.1.1` ne crée pas un helper AMM vide puisque les Program IDs AMM restent hors scope de la release, mais son ajout futur ne doit nécessiter aucune refonte de `ProgramIdEntry`.
|
||||
|
||||
Les vues filtrées retournent des iterators paresseux sur le registre canonique et n'allouent pas de collection intermédiaire. `entries()` reste la vue exhaustive sous forme de slice statique. `native_program_ids()` et les helpers `program_ids_by_domain(...)`, `program_ids_by_family(...)` et `program_ids_by_protocol(...)` sont des vues de cette même source.
|
||||
|
||||
`registered_program_ids()` de bot3 reste considéré comme un alias redondant de `entries()` et n'est pas repris automatiquement. Les well-known accounts suivent un registre/naming distinct lorsqu'ils deviennent nécessaires.
|
||||
|
||||
### Invariants du registre
|
||||
|
||||
`ProgramIdEntry` doit permettre :
|
||||
|
||||
- recherche exacte par chaîne Base58 et, si utile, par `Pubkey` ;
|
||||
- recherche par domaine ;
|
||||
- recherche par famille ;
|
||||
- recherche par protocole ;
|
||||
- recherche par sous-famille lorsqu'elle existe ;
|
||||
- recherche par génération de programme lorsqu'elle existe ;
|
||||
- intersections de plusieurs critères sans créer un registre secondaire par combinaison ;
|
||||
- production des vues spécialisées telles que `native_program_ids()` et, plus tard, `amm_program_ids()` ;
|
||||
- unicité des codes et Program IDs canoniques.
|
||||
|
||||
La classification est descriptive. Elle ne porte aucun decoder, executor, IDL ou capability de dispatch et ne devient pas le registry fonctionnel de `ksp-program-lib`.
|
||||
|
||||
### Validation externe de la taxonomie pendant `pre.001-fix.002`
|
||||
|
||||
Le réaudit a confronté l'inventaire bot3 et ses IDLs à plusieurs sources externes actuelles :
|
||||
|
||||
- la source officielle Agave de chargement SPL distingue explicitement les Memo `1.0.0`, `3.0.0` et `4.0.0` avec trois Program IDs distincts ;
|
||||
- l'interface SPL Memo actuelle expose séparément les modules `v1`, `v3` et `v4` ;
|
||||
- Solana Explorer/Solscan exposent encore les Program IDs correspondants ;
|
||||
- les sources GooseFX distinguent le programme GAMMA et la lignée SSL/V2 ;
|
||||
- les sources Meteora distinguent DAMM v1, DAMM v2 et DLMM ;
|
||||
- les sources Jupiter distinguent les générations de son Swap Aggregator, notamment v4 et v6.
|
||||
|
||||
Ces cas valident la séparation `family` / `subfamily` / `program_version` et invalident l'utilisation de `subfamily` comme simple conteneur de version.
|
||||
|
||||
## Primitives communes supplémentaires
|
||||
|
||||
Aucune primitive supplémentaire n'est démontrée nécessaire pendant `pre.001`.
|
||||
|
||||
Sont donc explicitement reportés :
|
||||
|
||||
- identité/version de module générique ;
|
||||
- provenance/processor version ;
|
||||
- `Hash` ;
|
||||
- `Nonce` ;
|
||||
- temps/slot ;
|
||||
- identifiants de transport/provider ;
|
||||
- types de transaction/instruction/account ;
|
||||
- traits de module ou de composant.
|
||||
|
||||
L'ancien `ks-core::ModuleKind` / `ModuleName` / `ModuleVersion` de bot3 n'est pas migré par défaut. Une convention de provenance ne sera ajoutée que lorsqu'un consommateur réel l'exigera.
|
||||
|
||||
## Stratégie de tests
|
||||
|
||||
### `pre.002` — Error
|
||||
|
||||
Tests unitaires externes sous `unit_tests/` pour vérifier au minimum :
|
||||
|
||||
- conservation du domaine/code ;
|
||||
- message ;
|
||||
- ajout et ordre du contexte ;
|
||||
- format `Display` ;
|
||||
- absence du contexte/source dans le rendu si ce choix est conservé ;
|
||||
- conservation de `source()` ;
|
||||
- `Send + Sync` du type commun au moyen d'un test de compilation approprié.
|
||||
|
||||
Test d'intégration sous `tests/` pour vérifier que `Error`, `ErrorCode`, `ErrorContext` et `Result` sont réellement consommables depuis le crate-root.
|
||||
|
||||
### `pre.003` — Pubkey et Program IDs
|
||||
|
||||
Tests unitaires externes pour vérifier les invariants internes éventuels.
|
||||
|
||||
Tests d'intégration pour vérifier :
|
||||
|
||||
- `ksp_core_lib::Pubkey` consommable depuis la façade ;
|
||||
- type exact des constantes `PRGID_*` et `PRGIDPK_*` ;
|
||||
- égalité entre chaque chaîne Base58 possédée par KSP et sa représentation `Pubkey` compile-time ;
|
||||
- unicité des codes, chaînes Base58 et `Pubkey` du registre ;
|
||||
- cohérence de `entries()`, `program_ids(...)`, `native_program_ids()` et `find_program_id()` ;
|
||||
- filtres par `domain`, `family`, `protocol`, `subfamily`, `program_version` et `kind`, y compris leurs intersections ;
|
||||
- absence de duplication des entrées entre registre canonique et vues spécialisées ;
|
||||
- séparation entre Program IDs et well-known accounts ;
|
||||
- conformité des valeurs avec les sources officielles Anza/Solana consultées par l'audit, sans dépendance `solana-sdk-ids`.
|
||||
|
||||
L'ordre de `entries()` ne devient un contrat public que s'il est explicitement documenté comme tel ; sinon les tests doivent vérifier les invariants sans imposer arbitrairement un ordre.
|
||||
|
||||
## Validations prévues
|
||||
|
||||
Après chaque modification Rust applicable :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Audits complémentaires prévus lorsque la dépendance Solana existe :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-core-lib
|
||||
cargo tree -p ksp-core-lib -d
|
||||
cargo tree -p ksp-core-lib -e features
|
||||
```
|
||||
|
||||
Objectifs :
|
||||
|
||||
- confirmer que Core ne tire aucune couche KSP supérieure ;
|
||||
- confirmer l'absence de codecs wire ajoutés par KSP ;
|
||||
- examiner toute duplication de génération fondamentale ;
|
||||
- vérifier que seules les features Solana nécessaires sont actives.
|
||||
|
||||
Les scripts/audits propres au dépôt seront exécutés s'ils existent réellement au moment de chaque tranche. Aucun script de ce type n'est présent dans l'archive `0.0.3` auditée.
|
||||
|
||||
## Découpage des prereleases
|
||||
|
||||
### `0.1.1-pre.001` — audit + brainstorming + plan
|
||||
|
||||
Objectifs :
|
||||
|
||||
- inventorier Core ;
|
||||
- fixer la direction Error/Result ;
|
||||
- borner les Program IDs ;
|
||||
- vérifier la génération Solana actuelle ;
|
||||
- décider les dépendances réellement candidates ;
|
||||
- fixer tests, API et hors-scope ;
|
||||
- ouvrir le plan `003-V0_1_1_CORE_FOUNDATION_PLAN.md`.
|
||||
|
||||
Pas de développement fonctionnel Core.
|
||||
|
||||
### `0.1.1-pre.002` — Error/Result
|
||||
|
||||
Objectifs :
|
||||
|
||||
- implémenter `ErrorCode`, `ErrorContext`, `Error` et `Result<T>` ;
|
||||
- mettre en place les modules privés et réexports crate-root associés ;
|
||||
- ajouter les tests unitaires externes et tests d'intégration de cette surface ;
|
||||
- valider l'absence de connaissance des domaines supérieurs.
|
||||
|
||||
Aucune dépendance Solana n'est nécessaire à cette tranche.
|
||||
|
||||
### `0.1.1-pre.003` — Pubkey + Program IDs
|
||||
|
||||
Objectifs :
|
||||
|
||||
- revérifier les versions Solana/Anza au jour de l'implémentation ;
|
||||
- vérifier la toolchain observée par rapport au MSRV de la génération retenue ;
|
||||
- déclarer `solana-pubkey = { version = "^4.3", default-features = false }` sous `[workspace.dependencies]` et la consommer uniquement dans le propriétaire `ksp-core-lib` avec `solana-pubkey.workspace = true` ;
|
||||
- réexporter `Pubkey` ;
|
||||
- implémenter `declare_program_id!` et la paire `PRGID_*` / `PRGIDPK_*` ;
|
||||
- finaliser à 18 l'inventaire des Program IDs fondamentaux à partir des sources officielles actuelles ;
|
||||
- implémenter `ProgramIdEntry`, `ProgramIdFilter`, `ProgramIdKind`, `entries()`, `program_ids(...)`, les vues domain/family/protocol, `native_program_ids()`, `find_program_id()` et `find_program_pubkey()` ;
|
||||
- implémenter la taxonomie extensible `domain` / `family` / `protocol` / `subfamily` / `program_version` / `kind` sans enum centrale fermée des protocoles ;
|
||||
- garantir que les futurs helpers spécialisés comme `amm_program_ids()` puissent être des vues du registre canonique sans duplication ;
|
||||
- ajouter les tests de conformité, d'unicité, de filtrage et de façade publique ;
|
||||
- confirmer l'absence totale de dépendance `solana-sdk-ids` ;
|
||||
- auditer le graphe/features réels après validation Cargo par le user.
|
||||
|
||||
### `0.1.1-pre.004` — intégration Core + audits
|
||||
|
||||
Résultat de l'audit d'intégration :
|
||||
|
||||
- `Error` / `Result`, `Pubkey` et le registre Program IDs composent une façade Core cohérente sans dépendance vers une couche KSP supérieure ;
|
||||
- aucune primitive N1 supplémentaire n'est démontrée nécessaire ;
|
||||
- les modules d'implémentation restent privés et les contrats consommables sont réexportés explicitement au crate-root ;
|
||||
- le test d'intégration public vérifie aussi qu'un consommateur peut déclarer un `const ErrorCode`, usage requis par les futures crates propriétaires de domaines ;
|
||||
- la rustdoc crate-level est complétée pour expliciter la frontière Core.
|
||||
|
||||
Validations `pre.004` exécutées avec succès par le user le 2026-08-14 :
|
||||
|
||||
- `cargo fmt --all` ;
|
||||
- `cargo check --workspace` ;
|
||||
- `cargo test --workspace` : 14 tests unitaires et 3 tests d'intégration publics réussis ;
|
||||
- `cargo clippy --workspace --all-targets` : succès sans warning communiqué ;
|
||||
- `cargo tree -p ksp-core-lib` : dépendance directe unique `solana-pubkey 4.3.0`, résolvant `solana-address 2.7.0` ;
|
||||
- `cargo tree -p ksp-core-lib -d` : aucun doublon ;
|
||||
- `cargo tree -p ksp-core-lib -e features` : graphe des features inspecté, sans besoin d'activer une feature optionnelle `solana-pubkey` supplémentaire pour le contrat Core actuel.
|
||||
|
||||
La tranche ne change ni le contrat Error, ni la taxonomie, ni l'inventaire des 18 Program IDs.
|
||||
|
||||
### `0.1.1-pre.005` — clôture
|
||||
|
||||
Résultat de clôture validé :
|
||||
|
||||
- aucune nouvelle primitive Core et aucune nouvelle feature `solana-pubkey` ne sont ajoutées ;
|
||||
- les documents de référence de `0.1.1` sont réalignés avec la surface effectivement livrée ;
|
||||
- aucun `README.md`/`USAGE.md` spécifique à la crate n'est ajouté : la rustdoc crate-level et les tests publics couvrent suffisamment la petite surface actuelle ;
|
||||
- aucun changelog général n'existe dans la base actuelle, donc aucun fichier de changelog artificiel n'est créé uniquement pour cette release ;
|
||||
- le prompt final `prompts/002-V0_1_2_START_PROMPT.md` est créé pour ouvrir Logging après publication stable de `0.1.1` ;
|
||||
- la publication stable est réalisée séparément par `0.1.1-rel.001`, conformément au workflow de versionnement.
|
||||
|
||||
### `0.1.1-rel.001` — publication stable
|
||||
|
||||
La publication stable :
|
||||
|
||||
- passe `workspace.package.version` de `0.1.1-pre.5` à `0.1.1` ;
|
||||
- enregistre les validations finales de `pre.005` exécutées avec succès par le user le 2026-08-14 ;
|
||||
- confirme 14 tests unitaires et 3 tests d'intégration publics réussis ;
|
||||
- confirme Clippy sans warning communiqué ;
|
||||
- confirme `solana-pubkey 4.3.0` comme unique dépendance externe directe de `ksp-core-lib` ;
|
||||
- confirme l'absence de doublons dans `cargo tree -d` ;
|
||||
- confirme que le graphe de features ne justifie aucune feature optionnelle `solana-pubkey` supplémentaire ;
|
||||
- marque `0.1.1` comme réalisée dans le roadmap et conserve le présent plan comme historique clôturé ;
|
||||
- prépare le commit de release puis le tag stable `v0.1.1`.
|
||||
|
||||
Aucun contrat public, Program ID, dépendance ou feature n'est modifié par `rel.001`.
|
||||
|
||||
Un `pre.NNN-fix.NNN` corrige la tranche correspondante sans réécrire son historique.
|
||||
|
||||
## Hors scope confirmé
|
||||
|
||||
`0.1.1` n'ouvre pas :
|
||||
|
||||
- `ksp-logging-lib` ;
|
||||
- `ksp-config-lib` ;
|
||||
- Tauri ;
|
||||
- wallet/keypair/signer ;
|
||||
- Borsh/Wincode et autres codecs wire ;
|
||||
- `ksp-interface-lib` ;
|
||||
- Program decoder/registry/`ProgramExecutionPreparer` ;
|
||||
- execution policy/orchestration ;
|
||||
- transport RPC/WS/Helius/Yellowstone ;
|
||||
- Store/PostgreSQL ;
|
||||
- materializers ;
|
||||
- workers/jobs/pipelines ;
|
||||
- scenarios ;
|
||||
- trading/ML.
|
||||
|
||||
## Questions ouvertes non bloquantes
|
||||
|
||||
Aucune question ouverte ne bloque la publication de `0.1.1`. Les capacités volontairement différées restent soumises à la règle need-driven des releases futures plutôt qu'à des placeholders Core.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/rules/RULES_DEPENDENCIES.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Règles des dépendances KSP
|
||||
|
||||
@@ -23,6 +23,14 @@ Elles complètent les règles Rust générales et le graphe de `docs/architectur
|
||||
- **DEP-KSP-004** — Aucun `ksp-data-api` global n'est introduit uniquement pour éviter des conversions explicites entre modèles appartenant à des responsabilités différentes.
|
||||
- **DEP-KSP-005** — Une dépendance autorisée par le graphe n'est ajoutée au manifeste que lorsqu'un usage réel la justifie.
|
||||
|
||||
## Déclaration Cargo et centralisation workspace
|
||||
|
||||
- **DEP-CARGO-001** — Toute dépendance externe utilisée par une crate membre du workspace est déclarée une seule fois dans le `Cargo.toml` racine sous `[workspace.dependencies]`.
|
||||
- **DEP-CARGO-002** — Une crate membre consomme une dépendance centralisée avec `<dependency>.workspace = true` et ne redéclare pas localement sa version.
|
||||
- **DEP-CARGO-003** — Les options communes de résolution telles que `default-features` et la contrainte de version sont définies au niveau `[workspace.dependencies]`. Une crate membre n'ajoute localement que des features réellement propres à son usage lorsqu'elles sont nécessaires et compatibles avec l'héritage Cargo.
|
||||
- **DEP-CARGO-004** — Lorsqu'une génération majeure/mineure compatible est retenue, KSP exprime explicitement l'intention sous forme caret `^M.m` (par exemple `^4.3`) plutôt qu'avec une écriture patch telle que `4.3.0`. Même si Cargo interprète aussi par défaut cette dernière comme une contrainte compatible caret, KSP normalise la syntaxe pour rendre l'intention manifeste. Un pin exact `=M.m.p` ou un bornage différent requiert une justification explicite.
|
||||
- **DEP-CARGO-005** — Le `Cargo.lock` résout la version patch concrète à l'intérieur de la contrainte du workspace ; cette résolution ne remplace pas la politique de version déclarée dans le manifeste racine.
|
||||
|
||||
## Codecs wire et cohérence des versions
|
||||
|
||||
- **DEP-WIRE-001** — Pour les surfaces wire officielles KSP, les dépendances directes vers `borsh`, `wincode` ou codecs équivalents appartiennent normalement à `ksp-interface-lib`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: prompts/000-README.md -->
|
||||
<!-- version: 3 -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Prompts KSP
|
||||
|
||||
@@ -21,4 +21,5 @@ Le prompt générique `0.1.x` a été affiné pendant `0.0.3` puis remplacé par
|
||||
|
||||
## Documents
|
||||
|
||||
- [`001-V0_1_1_START_PROMPT.md`](001-V0_1_1_START_PROMPT.md) — prompt final ouvrant la première release fonctionnelle `0.1.1` après publication stable de `0.0.3`.
|
||||
- [`001-V0_1_1_START_PROMPT.md`](001-V0_1_1_START_PROMPT.md) — prompt historique ouvrant la première release fonctionnelle `0.1.1` après publication stable de `0.0.3` ;
|
||||
- [`002-V0_1_2_START_PROMPT.md`](002-V0_1_2_START_PROMPT.md) — prompt final destiné à ouvrir `0.1.2 — Logging foundation` après publication stable de `0.1.1`.
|
||||
|
||||
335
prompts/002-V0_1_2_START_PROMPT.md
Normal file
335
prompts/002-V0_1_2_START_PROMPT.md
Normal file
@@ -0,0 +1,335 @@
|
||||
<!-- file: prompts/002-V0_1_2_START_PROMPT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Prompt de démarrage KSP 0.1.2
|
||||
|
||||
**Statut : Final — à utiliser après validation et publication stable de `0.1.1`.**
|
||||
|
||||
## 1. Identité
|
||||
|
||||
Release fonctionnelle :
|
||||
|
||||
```text
|
||||
0.1.2 — Logging foundation
|
||||
```
|
||||
|
||||
Deuxième release fonctionnelle de Khadhroony Solana Project.
|
||||
|
||||
## 2. Mission
|
||||
|
||||
Introduire et stabiliser `ksp-logging-lib` comme façade KSP commune et propriétaire du logging/tracing runtime.
|
||||
|
||||
Cette crate doit être la seule crate KSP qui importe directement et configure la stack `tracing` nécessaire à la politique générale de logs. Les autres crates comportementales KSP doivent consommer la façade de `ksp-logging-lib` plutôt que définir chacune leur propre initialisation ou leur propre politique de tracing.
|
||||
|
||||
La release doit établir une surface assez générale pour Logging lui-même et pour les prochaines crates N1, sans ouvrir `ksp-config-lib`, Tauri, Transport, Wallet, Program, Store ou les autres couches supérieures.
|
||||
|
||||
## 3. Base requise
|
||||
|
||||
Base attendue :
|
||||
|
||||
```text
|
||||
0.1.1 stable
|
||||
```
|
||||
|
||||
La session commence uniquement après validation de la dernière prerelease de `0.1.1`, publication du delta final `rel.001` et tag stable :
|
||||
|
||||
```text
|
||||
v0.1.1
|
||||
```
|
||||
|
||||
Dans le workflow KSP, une archive Gitea nommée `khadhroony-solana-project-v0.1.1.zip` provient directement du tag correspondant et constitue une base stable suffisante pour la session.
|
||||
|
||||
## 4. État validé à préserver
|
||||
|
||||
`ksp-core-lib` fournit désormais la fondation N1 commune, notamment :
|
||||
|
||||
```text
|
||||
ksp_core_lib::ErrorCode
|
||||
ksp_core_lib::ErrorContext
|
||||
ksp_core_lib::Error
|
||||
ksp_core_lib::Result<T>
|
||||
ksp_core_lib::Pubkey
|
||||
```
|
||||
|
||||
ainsi que la propriété KSP des Program IDs fondamentaux et leur registre descriptif.
|
||||
|
||||
Logging peut dépendre de `ksp-core-lib` pour `Error` / `Result`. La relation inverse reste interdite : Core ne dépend pas de Logging.
|
||||
|
||||
La politique Cargo établie dans `0.1.1` doit être conservée :
|
||||
|
||||
- toute dépendance externe est déclarée au `Cargo.toml` racine sous `[workspace.dependencies]` ;
|
||||
- une crate membre consomme ces dépendances avec `<crate>.workspace = true` ;
|
||||
- les versions sont exprimées avec une génération compatible explicite telle que `^M.m`, sauf pin justifié ;
|
||||
- les features et `default-features` sont activées uniquement lorsqu'un besoin concret le démontre.
|
||||
|
||||
## 5. Sources de vérité internes
|
||||
|
||||
Relire en priorité les fichiers réellement présents dans la base, notamment :
|
||||
|
||||
- `ROADMAP.md` ;
|
||||
- `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` ;
|
||||
- `docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md` ;
|
||||
- `docs/architecture/002-LAYERS_AND_DEPENDENCIES.md` ;
|
||||
- `docs/architecture/003-COMPONENT_CONTRACTS.md` ;
|
||||
- `docs/architecture/004-COMPONENT_INVENTORY.md` ;
|
||||
- `docs/architecture/005-DEPENDENCY_GRAPH.md` ;
|
||||
- `docs/rules/RULES_DEPENDENCIES.md` ;
|
||||
- `docs/rules/RULES_KSP.md` ;
|
||||
- `docs/rules/RULES_RUST.md` ;
|
||||
- `docs/rules/VERSION_WORKFLOW.md` ;
|
||||
- `docs/IDEAS.md` ;
|
||||
- les deltas `deltas/0.1.1/*`.
|
||||
|
||||
Relire aussi les règles/index racine supplémentaires présents au moment de la session. Ne jamais inventer un document absent de la base.
|
||||
|
||||
## 6. Sources externes normatives
|
||||
|
||||
Avant d'ajouter `tracing`, `tracing-subscriber`, `tracing-appender` ou toute crate liée :
|
||||
|
||||
- vérifier les versions publiées actuelles depuis les sources officielles Tokio/tracing et crates.io/docs.rs ;
|
||||
- examiner leurs features et dépendances réelles ;
|
||||
- identifier le MSRV/toolchain pertinent ;
|
||||
- éviter d'activer les default features ou features optionnelles uniquement par commodité ;
|
||||
- examiner `cargo tree` et `cargo tree -e features` après intégration.
|
||||
|
||||
La première prerelease doit choisir les dépendances réellement nécessaires à l'API retenue ; la présence architecturale d'une crate candidate n'oblige pas à l'ajouter si la surface finale n'en a pas besoin.
|
||||
|
||||
## 7. Première prerelease obligatoire : `0.1.2-pre.001`
|
||||
|
||||
`pre.001` est d'abord une prerelease de **brainstorming, audit et planification**.
|
||||
|
||||
Elle doit au minimum :
|
||||
|
||||
1. inventorier l'état réel du workspace et confirmer la création/absence actuelle de `ksp-logging-lib` ;
|
||||
2. auditer la stack `tracing` officielle actuelle, ses versions, features et dépendances ;
|
||||
3. définir précisément la frontière entre façade KSP, initialisation et backend/subscriber ;
|
||||
4. déterminer si l'API publique principale doit utiliser des macros, des fonctions ou une combinaison ;
|
||||
5. préserver les callsites/source locations réels pour les événements de logging ;
|
||||
6. définir les niveaux KSP `error`, `warn`, `info`, `debug`, `trace` ;
|
||||
7. définir les champs structurés communs utiles maintenant, notamment `target`, `domain`, `component` ou équivalents sans inventer une taxonomie trop rigide ;
|
||||
8. définir le contrat de settings runtime de Logging sans dépendre de Config ;
|
||||
9. définir le lifecycle d'initialisation, les erreurs d'initialisation et le comportement d'une initialisation répétée ;
|
||||
10. étudier console, fichiers, filtering, appender non bloquant et rotation uniquement selon les besoins de la première surface ;
|
||||
11. traiter explicitement la durée de vie/ownership des guards nécessaires aux writers non bloquants si cette voie est retenue ;
|
||||
12. définir la stratégie de prévention des secrets dans les logs ;
|
||||
13. proposer l'API publique et les crate-root reexports ;
|
||||
14. proposer les tests unitaires/intégration et audits de dépendances ;
|
||||
15. dimensionner les prereleases suivantes ;
|
||||
16. confirmer les hors-scope.
|
||||
|
||||
Ne pas transformer `pre.001` en une grosse phase de développement avant validation du plan.
|
||||
|
||||
## 8. Responsabilité de `ksp-logging-lib`
|
||||
|
||||
La direction acquise est :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
-> ksp-core-lib
|
||||
-> tracing stack réellement retenue
|
||||
```
|
||||
|
||||
`ksp-logging-lib` doit être la façade commune de logging/tracing du projet et le propriétaire de la politique runtime correspondante.
|
||||
|
||||
Les crates comportementales KSP pourront dépendre directement de `ksp-logging-lib` et utiliser sa surface KSP pour :
|
||||
|
||||
```text
|
||||
error
|
||||
warn
|
||||
info
|
||||
debug
|
||||
trace
|
||||
```
|
||||
|
||||
avec les champs structurés réellement retenus par `pre.001`.
|
||||
|
||||
Les crates `*-api` purement déclaratives restent sans dépendance logging par défaut lorsqu'elles n'ont aucun comportement réel à tracer.
|
||||
|
||||
## 9. Callsite et macros
|
||||
|
||||
L'audit doit porter une attention particulière à la préservation du callsite réel.
|
||||
|
||||
Une simple fonction wrapper autour d'une macro `tracing::*` peut enregistrer le fichier/module/ligne du wrapper plutôt que ceux de l'appelant. La surface KSP doit donc être conçue pour préserver correctement les métadonnées de callsite, quitte à exposer des macros KSP qui délèguent aux macros `tracing` au point d'appel.
|
||||
|
||||
Le design exact des macros/fonctions et leurs noms sont décidés dans `pre.001`, puis testés avant stabilisation.
|
||||
|
||||
## 10. Settings et Config
|
||||
|
||||
`ksp-logging-lib` ne dépend pas de `ksp-config-lib`.
|
||||
|
||||
Logging possède les settings runtime strictement nécessaires à son initialisation. `ksp-config-lib`, lorsqu'il sera développé en `0.1.3`, pourra lire/résoudre ses documents puis convertir explicitement la configuration obtenue vers les settings publics de Logging.
|
||||
|
||||
Ne pas introduire de document JSON/TOML de configuration global dans Logging uniquement pour anticiper Config.
|
||||
|
||||
## 11. Sorties et lifecycle
|
||||
|
||||
Le `pre.001` doit déterminer la première surface réellement utile parmi :
|
||||
|
||||
- console/stdout/stderr ;
|
||||
- fichiers ;
|
||||
- filtrage global et/ou par target/domain ;
|
||||
- format lisible et/ou structuré ;
|
||||
- rotation ;
|
||||
- writer non bloquant ;
|
||||
- flush/shutdown propre.
|
||||
|
||||
Lorsque `tracing-appender::non_blocking` ou un mécanisme équivalent est retenu, la durée de vie du guard doit être possédée par un objet/lifecycle KSP explicite afin d'éviter une perte silencieuse de logs à la fin du scope d'initialisation.
|
||||
|
||||
Une capacité non nécessaire à la première validation n'est pas ajoutée par anticipation.
|
||||
|
||||
## 12. Erreurs
|
||||
|
||||
Les erreurs Logging utilisent le contrat Core :
|
||||
|
||||
```text
|
||||
ksp_core_lib::Error
|
||||
ksp_core_lib::Result<T>
|
||||
```
|
||||
|
||||
`ksp-logging-lib` définit ses propres constantes `ErrorCode` dans son domaine sans ajouter de variante ou de connaissance Logging à `ksp-core-lib`.
|
||||
|
||||
Les causes externes utiles sont conservées via le contrat `source` Core lorsqu'elles satisfont les bornes prévues.
|
||||
|
||||
Aucun `unwrap`, `expect`, `panic` production ou opérateur `?` n'est utilisé.
|
||||
|
||||
## 13. Secrets et données sensibles
|
||||
|
||||
Logging ne doit pas devenir un canal de fuite de secrets.
|
||||
|
||||
`pre.001` doit au minimum définir :
|
||||
|
||||
- quels champs sont interdits par politique ;
|
||||
- comment les settings sensibles sont exclus ;
|
||||
- quelles données doivent être explicitement redacted/omises par les appelants ;
|
||||
- si des helpers de redaction génériques sont réellement nécessaires maintenant.
|
||||
|
||||
Ne pas logger automatiquement les contenus de clés privées, seeds, passwords, tokens d'API ou autres secrets.
|
||||
|
||||
## 14. Dépendances et propriété
|
||||
|
||||
Interdictions :
|
||||
|
||||
```text
|
||||
ksp-core-lib -X-> ksp-logging-lib
|
||||
ksp-logging-lib -X-> ksp-config-lib
|
||||
ksp-logging-lib -X-> wallet/transport/program/store/workers/jobs/apps
|
||||
```
|
||||
|
||||
`ksp-logging-lib` est la seule crate KSP qui doit normalement importer directement `tracing` et réaliser la configuration du subscriber/appender retenu.
|
||||
|
||||
Une application Tauri future peut exceptionnellement devoir intégrer une crate/plugin tracing imposée par son framework. Cette exception reste au niveau adaptateur/application et ne crée pas une seconde politique de logging parallèle à `ksp-logging-lib`.
|
||||
|
||||
## 15. Hors scope strict de `0.1.2`
|
||||
|
||||
- `ksp-config-lib` et documents/profils Config ;
|
||||
- application Tauri ;
|
||||
- wallet/keypair/signer ;
|
||||
- RPC/WS/providers ;
|
||||
- Program decoding/execution ;
|
||||
- Store/PostgreSQL ;
|
||||
- materializers ;
|
||||
- workers/jobs/pipelines ;
|
||||
- scenarios ;
|
||||
- trading/ML ;
|
||||
- OpenTelemetry ou export réseau de traces, sauf besoin concret explicitement revalidé et borné ;
|
||||
- observability distribuée complète.
|
||||
|
||||
## 16. Règles Rust et Cargo
|
||||
|
||||
Préserver les règles workspace, notamment :
|
||||
|
||||
- Rust 2024 ;
|
||||
- async-first pour les I/O futures lorsque pertinent, sans rendre artificiellement async les appels de logging synchrones ;
|
||||
- `unsafe` interdit ;
|
||||
- `unwrap` / `expect` interdits ;
|
||||
- `panic` interdit en production ;
|
||||
- opérateur `?` interdit ;
|
||||
- returns explicites, y compris dans les closures lorsque Clippy l'exige ;
|
||||
- `unreachable_pub = deny` ;
|
||||
- `missing_docs = warn` ;
|
||||
- imports de traits seulement lorsque nécessaire ;
|
||||
- réexports crate-root explicites ;
|
||||
- pas de `mod.rs` ;
|
||||
- pas de `pub(super)` / `pub(in ...)` ;
|
||||
- code/Rustdoc en anglais ;
|
||||
- tests unitaires externes au `src` selon la convention du dépôt ;
|
||||
- dépendances externes centralisées sous `[workspace.dependencies]`.
|
||||
|
||||
## 17. Git et deltas
|
||||
|
||||
À partir de `0.1.x`, chaque delta est commité :
|
||||
|
||||
```text
|
||||
pre.NNN
|
||||
pre.NNN-fix.NNN
|
||||
rel.NNN
|
||||
```
|
||||
|
||||
Une erreur est corrigée par le delta suivant ; l'historique n'est pas réécrit.
|
||||
|
||||
Seul le commit final validé comme stable reçoit :
|
||||
|
||||
```text
|
||||
v0.1.2
|
||||
```
|
||||
|
||||
## 18. Dimensionnement indicatif
|
||||
|
||||
Le nombre réel de prereleases est décidé dans `pre.001`.
|
||||
|
||||
Trajectoire candidate uniquement :
|
||||
|
||||
```text
|
||||
pre.001 audit + brainstorming + plan
|
||||
pre.002 crate/settings + façade levels/callsites
|
||||
pre.003 initialisation + console/filtering
|
||||
pre.004 fichiers/appender/rotation/lifecycle si retenus
|
||||
pre.005 intégration/tests/audits
|
||||
pre.006 validation finale/docs/cleanup/prompt 0.1.3
|
||||
```
|
||||
|
||||
Scinder une tranche si son périmètre devient trop large. Supprimer/réorganiser une tranche si le `pre.001` démontre qu'une capacité candidate n'est pas nécessaire.
|
||||
|
||||
## 19. Validations attendues
|
||||
|
||||
Lorsque les commandes sont applicables :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo tree -p ksp-logging-lib
|
||||
cargo tree -p ksp-logging-lib -d
|
||||
cargo tree -p ksp-logging-lib -e features
|
||||
```
|
||||
|
||||
Exécuter également les scripts/audits réellement présents dans le dépôt.
|
||||
|
||||
Aucune validation non exécutée ne doit être déclarée réussie.
|
||||
|
||||
## 20. Critères de sortie
|
||||
|
||||
`0.1.2` peut être publiée stable lorsque :
|
||||
|
||||
- la façade Logging et son ownership sont clairs ;
|
||||
- les callsites sont préservés par tests ;
|
||||
- les cinq niveaux KSP nécessaires sont utilisables ;
|
||||
- l'initialisation choisie est déterministe et testée ;
|
||||
- console/fichiers/filtering/lifecycle retenus sont validés ;
|
||||
- les erreurs utilisent Core sans dépendance inverse ;
|
||||
- aucune dépendance Config ou domaine supérieur n'a été introduite ;
|
||||
- les secrets sont protégés par une politique documentée/testable ;
|
||||
- le graphe de dépendances/features est audité ;
|
||||
- les validations workspace sont propres ;
|
||||
- la documentation finale et le prompt de la release suivante sont prêts.
|
||||
|
||||
## 21. Release suivante
|
||||
|
||||
La release suivante prévue est :
|
||||
|
||||
```text
|
||||
0.1.3 — ksp-config-lib
|
||||
```
|
||||
|
||||
Son périmètre concret reste soumis au `pre.001` correspondant et peut être scindé si Config s'avère trop large pour une seule release.
|
||||
Reference in New Issue
Block a user