v0.2.14-pre.002

This commit is contained in:
2026-08-28 11:07:16 +02:00
parent 5e5ed6d1ab
commit c1f61a380f
10 changed files with 605 additions and 9 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml # file: Cargo.toml
# version: 313 # version: 314
[workspace] [workspace]
resolver = "3" resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"] members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-wallet-lib"]
[workspace.package] [workspace.package]
version = "0.2.14-pre.1" version = "0.2.14-pre.2"
edition = "2024" edition = "2024"
license = "MIT" license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -0,0 +1,15 @@
# file: crates/ksp-program-api/Cargo.toml
# version: 1
[package]
name = "ksp-program-api"
version.workspace = true
edition.workspace = true
repository.workspace = true
[dependencies]
ksp-core-lib = { path = "../ksp-core-lib" }
ksp-interface-lib = { path = "../ksp-interface-lib" }
[lints]
workspace = true

View File

@@ -0,0 +1,92 @@
<!-- file: crates/ksp-program-api/README.md -->
<!-- version: 1 -->
# ksp-program-api
`ksp-program-api` est la façade publique ouverte du domaine Program KSP. Elle est destinée aux implémentations officielles futures comme aux crates Program externes et ne possède pas les implémentations concrètes.
La tranche initiale `0.2.14-pre.002` matérialise uniquement le scaffold et les types déjà possédés par les couches fondatrices. Aucun trait decoder n'est encore publié.
## Ownership
La crate dépend uniquement de :
```text
ksp-program-api
├── ksp-core-lib
└── ksp-interface-lib
└── ksp-core-lib
```
Core reste propriétaire de :
```text
Error
ErrorCode
ErrorContext
Result
Pubkey
```
Interface reste propriétaire de :
```text
ProgramAccountMeta
ProgramInstruction
```
`ksp-program-api` les réexporte depuis son crate-root pour offrir une façade de consommation stable sans dupliquer leurs types ni transférer leur ownership.
## Surface de scaffold
La façade `pre.002` expose exactement :
```text
Error
ErrorCode
ErrorContext
Result
Pubkey
ProgramAccountMeta
ProgramInstruction
```
Aucun module interne n'est public.
Les contrats suivants restent réservés aux tranches suivantes :
```text
ProgramInstructionRecognition pre.003
ProgramInstructionDecodeOutcome<T> pre.003
ProgramInstructionDecoder pre.004
```
## Frontières
La foundation ne contient pas :
```text
ksp-program-lib
registry runtime
identity/version/coverage de decoder
payload canonique D3
ProgramAccountDecoder
ProgramEventDecoder
ProgramReturnDataDecoder
ProgramExecutionPreparer
serde / serde_json
borsh / wincode / bincode
solana-instruction
network / async runtime
logging / tracing
Wallet / Transport / Store / Materializer / Config / Tauri
```
L'absence de ces surfaces est volontaire : `ksp-program-api` reste une API déclarative, ouverte et indépendante des implémentations/runtime supérieurs.
## Références
- [Usage public](USAGE.md)
- [Plan `0.2.14`](../../docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md)
- [Validation `0.2.14`](../../docs/validation/017-V0_2_14_PROGRAM_API.md)
- [Architecture Wire + Program](../../docs/architecture/006-WIRE_AND_PROGRAM.md)

View File

@@ -0,0 +1,55 @@
<!-- file: crates/ksp-program-api/USAGE.md -->
<!-- version: 1 -->
# Usage de ksp-program-api
Cette page décrit le scaffold public disponible à partir de `0.2.14-pre.002`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable.
## Construire un input Program avec la façade
```rust
let program_id = ksp_program_api::Pubkey::new_from_array([1_u8; 32]);
let account_id = ksp_program_api::Pubkey::new_from_array([2_u8; 32]);
let account = ksp_program_api::ProgramAccountMeta::readonly(account_id, true);
let instruction = ksp_program_api::ProgramInstruction::try_new(
program_id,
std::vec![account],
std::vec![0x01_u8, 0x02, 0x03],
);
assert!(instruction.is_ok());
```
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. Program API fournit seulement une façade cohérente aux futures implémentations de capability Program.
## Utiliser le contrat d'erreur commun
Les types d'erreur Core sont également disponibles depuis la façade :
```rust
fn forward_result(
value: ksp_program_api::Result<ksp_program_api::ProgramInstruction>,
) -> ksp_program_api::Result<ksp_program_api::ProgramInstruction> {
return value;
}
```
Aucun type d'erreur Program spécifique n'est nécessaire au scaffold.
## Ce que `pre.002` ne fournit pas
Il n'existe encore aucun :
```text
recognize(...)
decode(...)
ProgramInstructionRecognition
ProgramInstructionDecodeOutcome
ProgramInstructionDecoder
registry de decoders
payload générique JSON/Any
execution preparer
```
Ces éléments ne doivent pas être simulés côté consumer. Les contrats de recognition/outcome puis le trait decoder seront introduits dans leurs tranches dédiées.

View File

@@ -0,0 +1,28 @@
// file: crates/ksp-program-api/src/lib.rs
// version: 1
#![warn(missing_docs)]
#![deny(unreachable_pub)]
#![forbid(unsafe_code)]
//! Open Program contracts shared by KSP and external Program implementations.
//!
//! This initial scaffold exposes only the Core and Interface types selected by
//! the `0.2.14` API model. Decoder behavior, recognition, decode outcomes,
//! registries, codecs, runtime logging and execution preparation are added only
//! by later contracts when their ownership is justified.
/// Common KSP error type used by Program-facing contracts.
pub use ksp_core_lib::Error;
/// Stable structured code identifying a KSP error category and condition.
pub use ksp_core_lib::ErrorCode;
/// Structured contextual field attached to a KSP error.
pub use ksp_core_lib::ErrorContext;
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
pub use ksp_core_lib::Pubkey;
/// Common KSP result alias using [`Error`].
pub use ksp_core_lib::Result;
/// Passive account metadata attached to one Program instruction.
pub use ksp_interface_lib::ProgramAccountMeta;
/// Passive, bounded Program instruction wire contract.
pub use ksp_interface_lib::ProgramInstruction;

View File

@@ -0,0 +1,91 @@
// file: crates/ksp-program-api/tests/dependency_boundary.rs
// version: 1
//! Dependency and declarative-surface canaries for the Program API scaffold.
#[test]
fn pre_002_manifest_has_exact_core_and_interface_runtime_dependencies() {
let manifest = include_str!("../Cargo.toml");
let dependencies_tail = manifest.split("[dependencies]").nth(1);
assert!(dependencies_tail.is_some(), "Program API dependencies section must exist");
let dependencies_tail = match dependencies_tail {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let dependencies = match dependencies_tail.split("[lints]").next() {
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
assert_eq!(manifest_dependency_names(dependencies), std::vec!["ksp-core-lib", "ksp-interface-lib"]);
for forbidden in [
"ksp-config-lib",
"ksp-logging-lib",
"ksp-materializer-api",
"ksp-materializer-lib",
"ksp-offchain-transport-lib",
"ksp-onchain-transport-lib",
"ksp-program-lib",
"ksp-store-api",
"ksp-store-lib",
"ksp-wallet-lib",
"borsh",
"bincode",
"reqwest",
"serde",
"serde_json",
"solana-instruction",
"tauri",
"tokio",
"tonic",
"tracing",
"wincode",
] {
assert!(!dependencies.contains(forbidden), "forbidden Program API dependency detected: {forbidden}");
}
return;
}
#[test]
fn pre_002_crate_root_is_facade_only_without_decoder_runtime_surface() {
let crate_root = include_str!("../src/lib.rs");
for required in ["Error", "ErrorCode", "ErrorContext", "Pubkey", "Result", "ProgramAccountMeta", "ProgramInstruction"] {
assert!(crate_root.contains(required), "required Program API facade export missing: {required}");
}
for forbidden in [
"pub mod ",
"ProgramInstructionRecognition",
"ProgramInstructionDecodeOutcome",
"ProgramInstructionDecoder",
"ProgramExecutionPreparer",
"TRACING_TARGET",
"ksp_logging_lib",
"serde",
"Any",
] {
assert!(!crate_root.contains(forbidden), "forbidden pre.002 Program API surface detected: {forbidden}");
}
assert!(!std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/constants.rs").exists());
return;
}
fn manifest_dependency_names(section: &str) -> std::vec::Vec<&str> {
let mut names = std::vec::Vec::new();
for line in section.lines() {
let content = match line.split('#').next() {
std::option::Option::Some(value) => value.trim(),
std::option::Option::None => continue,
};
if content.is_empty() {
continue;
}
let name = match content.split('=').next() {
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
std::option::Option::None => continue,
};
if !name.is_empty() {
names.push(name);
}
}
names.sort_unstable();
return names;
}

View File

@@ -0,0 +1,33 @@
// file: crates/ksp-program-api/tests/public_api.rs
// version: 1
//! Integration canaries for the public `ksp-program-api` scaffold.
fn consume_result(value: ksp_program_api::Result<ksp_program_api::Pubkey>) -> ksp_program_api::Result<ksp_program_api::Pubkey> {
return value;
}
#[test]
fn public_pre_002_core_and_interface_facade_is_available_from_crate_root() {
let program_id = ksp_program_api::Pubkey::new_from_array([0xA1_u8; 32]);
let account_id = ksp_program_api::Pubkey::new_from_array([0xA2_u8; 32]);
let account = ksp_program_api::ProgramAccountMeta::readonly(account_id, true);
let instruction = ksp_program_api::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xA3_u8]);
assert!(instruction.is_ok());
let forwarded = consume_result(std::result::Result::Ok(program_id));
assert!(forwarded.is_ok());
let error_code_type: std::option::Option<ksp_program_api::ErrorCode> = std::option::Option::None;
let error_context_type: std::option::Option<ksp_program_api::ErrorContext> = std::option::Option::None;
let error_type: std::option::Option<ksp_program_api::Error> = std::option::Option::None;
assert!(error_code_type.is_none());
assert!(error_context_type.is_none());
assert!(error_type.is_none());
return;
}
#[test]
fn public_pre_002_scaffold_does_not_require_private_modules() {
let source = include_str!("../src/lib.rs");
assert!(!source.contains("pub mod "));
return;
}

235
deltas/0.2.14/pre.002.md Normal file
View File

@@ -0,0 +1,235 @@
<!-- file: deltas/0.2.14/pre.002.md -->
<!-- version: 1 -->
# Delta `0.2.14-pre.002` — scaffold `ksp-program-api` + façade + firewall
## 1. Base requise
Cette tranche s'applique exclusivement sur :
```text
v0.2.13
+ 0.2.14-pre.001
```
Le gate opérateur fourni pour `pre.001` est vert :
```text
cargo fmt --all PASS
python3 scripts/audit_rust_workspace_rules.py PASS
python3 scripts/audit_markdown_tables.py ... PASS — 170 tables / 116 fichiers
cargo check --workspace PASS
cargo clippy --workspace --all-targets PASS sans warning
```
La version workspace passe de :
```text
0.2.14-pre.1
```
à :
```text
0.2.14-pre.2
```
Commit attendu :
```text
v0.2.14-pre.002
```
## 2. Objectif
Matérialiser uniquement le scaffold de `ksp-program-api` et verrouiller sa façade/dependency firewall avant toute capability de décodage.
La tranche ajoute :
```text
nouveau membre workspace ksp-program-api
manifest Core + Interface uniquement
façade crate-root explicite
réexports Core retenus
réexports Interface retenus
README/USAGE initiaux
canari public API
canari dependency firewall
```
Elle n'ajoute pas :
```text
ProgramInstructionRecognition
ProgramInstructionDecodeOutcome
ProgramInstructionDecoder
ProgramExecutionPreparer
registry runtime
identity/version/coverage
payload canonique D3
serde / JSON / Any
codec
runtime logging
network / async runtime
```
## 3. Façade publique de scaffold
Le crate-root réexporte explicitement :
```text
ksp-core-lib
Error
ErrorCode
ErrorContext
Result
Pubkey
ksp-interface-lib
ProgramAccountMeta
ProgramInstruction
```
Ces réexports ne changent pas l'ownership des types. Ils fournissent la façade retenue par le plan afin qu'une future implémentation externe puisse dépendre du contrat Program sans reconstruire les types Core/Interface ni accéder à leurs modules privés.
Aucun `pub mod` n'est exposé.
## 4. Dependency firewall
Le manifest membre possède exactement :
```text
[dependencies]
ksp-core-lib
ksp-interface-lib
```
Le canari `tests/dependency_boundary.rs` verrouille notamment l'absence de :
```text
ksp-program-lib
ksp-logging-lib
Transport / Config / Wallet / Store / Materializer
serde / serde_json
borsh / bincode / wincode
solana-instruction
reqwest / tokio / tonic / tauri / tracing
```
Il verrouille aussi l'absence de `src/constants.rs`, `TRACING_TARGET`, recognition/outcome/decoder/preparer et de module public pendant `pre.002`.
## 5. Logging
La crate reste une API déclarative sans comportement runtime. Aucun span/event n'est émis et aucun logging n'est nécessaire.
Restent donc volontairement absents :
```text
ksp-logging-lib
src/constants.rs
TRACING_TARGET
tracing direct
```
Si une future surface Program comportementale nécessite réellement une instrumentation, elle devra respecter les règles Logging KSP dans la crate qui possède ce comportement. Le scaffold API ne doit pas tirer un runtime logging par anticipation.
## 6. Tests ajoutés
`tests/public_api.rs` vérifie que la façade crate-root permet de construire `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction`, et que les types d'erreur Core sont adressables sans module privé.
`tests/dependency_boundary.rs` vérifie :
```text
dépendances normales exactes = Core + Interface
absence des dépendances interdites
absence de pub mod
absence des contrats réservés à pre.003/pre.004
absence de logging/runtime/codec
```
Aucun unit test métier n'est ajouté : la crate ne possède encore aucun comportement propre.
## 7. Fichiers ajoutés
```text
crates/ksp-program-api/Cargo.toml
crates/ksp-program-api/README.md
crates/ksp-program-api/USAGE.md
crates/ksp-program-api/src/lib.rs
crates/ksp-program-api/tests/dependency_boundary.rs
crates/ksp-program-api/tests/public_api.rs
deltas/0.2.14/pre.002.md
```
## 8. Fichiers modifiés
```text
Cargo.toml
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
docs/validation/017-V0_2_14_PROGRAM_API.md
```
## 9. Fichiers volontairement inchangés
```text
README.md
RULES.md
ROADMAP.md
CHANGELOG.md
docs/architecture/**
docs/rules/**
crates/ksp-core-lib/**
crates/ksp-interface-lib/**
crates/ksp-logging-lib/**
crates/ksp-*-transport-lib/**
crates/ksp-config-lib/**
crates/ksp-wallet-lib/**
crates/ksp-app-*/**
prompts/**
```
Aucune architecture durable n'est rouverte : la direction `Program API -> Core + Interface` est déjà normative.
## 10. Validations de génération
Les audits Python sont rejoués sur l'arbre matérialisé avant livraison. L'environnement de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`; aucun PASS Cargo nouveau n'est revendiqué localement.
## 11. Gate opérateur attendu
Après application :
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
cargo check --workspace
cargo clippy --workspace --all-targets
cargo test -p ksp-program-api
cargo test --workspace
cargo tree -p ksp-program-api --edges normal
cargo tree --duplicates
```
Le graphe normal doit confirmer :
```text
ksp-program-api
├── ksp-core-lib
└── ksp-interface-lib
└── ksp-core-lib
```
Une correction découverte par ce gate reste un `0.2.14-pre.002-fix.NNN` et n'avance pas `pre.003`.
## 12. Suite
Après gate vert, `pre.003` pourra matérialiser uniquement :
```text
ProgramInstructionRecognition
ProgramInstructionDecodeOutcome<Decoded>
invariants / Debug sûr associés
unit/public canaries correspondants
```
`ProgramInstructionDecoder` et l'implémentation externe restent réservés à `pre.004`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md --> <!-- file: docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Plan `0.2.14` — Program API foundation # Plan `0.2.14` — Program API foundation
@@ -535,11 +535,17 @@ Ce périmètre reste compatible avec une release clôturable dans une session et
### `pre.001` — Audit KSP + kbot3 + API model + sizing ### `pre.001` — Audit KSP + kbot3 + API model + sizing
Présente tranche : baseline, règles/architecture, héritage, ownership, API candidate, dependency graph, threat model, tests et scope réduit. Aucun code Program. **Statut : réalisé ; gate opérateur intégralement PASS.**
Baseline, règles/architecture, héritage, ownership, API candidate, dependency graph, threat model, tests et scope réduit. Aucun code Program.
### `pre.002` — Scaffold `ksp-program-api` + façade + firewall ### `pre.002` — Scaffold `ksp-program-api` + façade + firewall
Créer la crate, l'ajouter au workspace, poser les réexports Core/Interface retenus, README/USAGE initiaux minimaux et canaris de dépendances/public facade. Aucun trait decoder encore. **Statut : matérialisé ; gate opérateur à confirmer.**
La crate est membre du workspace avec exactement `ksp-core-lib` et `ksp-interface-lib` comme dépendances normales. Le crate-root réexporte `Error`, `ErrorCode`, `ErrorContext`, `Result`, `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction`. README/USAGE initiaux et canaris `public_api` / `dependency_boundary` sont présents.
Aucun trait decoder, recognition, outcome, registry, codec, runtime logging ou execution preparer n'est avancé.
### `pre.003` — Recognition + outcome minimal ### `pre.003` — Recognition + outcome minimal
@@ -571,6 +577,28 @@ Mécanique de publication uniquement.
La numérotation reste souple : une anomalie peut insérer une tranche dédiée, mais les couloirs `gate technique -> réconciliation documentaire -> publication minimale` restent séparés. La numérotation reste souple : une anomalie peut insérer une tranche dédiée, mais les couloirs `gate technique -> réconciliation documentaire -> publication minimale` restent séparés.
## 13.1 État préparé après `pre.002`
Le scaffold strict attendu pour ouvrir `pre.003` est :
```text
ksp-program-api membre workspace
normal dependencies ksp-core-lib + ksp-interface-lib uniquement
crate-root facade Core/Interface réexportés explicitement
public modules aucun
ProgramInstructionRecognition absent par contrat pre.002
ProgramInstructionDecodeOutcome absent par contrat pre.002
ProgramInstructionDecoder absent par contrat pre.002
ProgramExecutionPreparer absent
serde / JSON / codecs absents
ksp-logging-lib / tracing absents
README / USAGE initiaux
public API canary présent
dependency firewall canary présent
```
`pre.003` reste limité à `ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome<Decoded>` avec leur sémantique et leur Debug sûr. Le trait decoder reste réservé à `pre.004`.
## 14. Hors périmètre confirmé ## 14. Hors périmètre confirmé
```text ```text

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/017-V0_2_14_PROGRAM_API.md --> <!-- file: docs/validation/017-V0_2_14_PROGRAM_API.md -->
<!-- version: 1 --> <!-- version: 2 -->
# Validation `0.2.14` — Program API foundation # Validation `0.2.14` — Program API foundation
@@ -157,6 +157,25 @@ prompt de démarrage 0.3.1
delta de la prerelease delta de la prerelease
``` ```
## 8. Statut courant ## 8. État préparé `pre.002`
`0.2.14-pre.001` ne matérialise aucune crate Program et n'exécute aucun decoder. Le gate de design est considéré cohérent lorsque les validations statiques de l'overlay passent; toutes les preuves fonctionnelles restent `PENDING` jusqu'aux tranches correspondantes. Le scaffold matérialisé est :
```text
workspace member PASS structurel
normal dependencies ksp-core-lib + ksp-interface-lib uniquement
crate-root facade Error/ErrorCode/ErrorContext/Result/Pubkey + Interface instruction types
public modules aucun
README / USAGE présents
public API canary présent
dependency firewall canary présent
ProgramInstructionRecognition absent par contrat pre.002
ProgramInstructionDecodeOutcome absent par contrat pre.002
ProgramInstructionDecoder absent par contrat pre.002
registry / canonical payload / preparer absents
serde / codecs / runtime logging absents
```
Le gate opérateur `pre.001` fourni le 28 août 2026 est vert pour `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace` et Clippy workspace.
Le passage à `pre.003` reste conditionné au gate opérateur de cet overlay. Les preuves recognition/outcome restent `PENDING` jusqu'à leur tranche dédiée.