Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31461cf9be | |||
| 8c8b7ee986 | |||
| 5bfe6f0820 | |||
| 8c4e835fdd | |||
| 695d1080bd | |||
| e774a065b4 | |||
| 29f27ae109 | |||
| 0ee28eeb95 | |||
| 900444bff5 | |||
| 99477d0d2b | |||
| 9148920f42 |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,8 +1,16 @@
|
||||
<!-- file: CHANGELOG.md -->
|
||||
<!-- version: 16 -->
|
||||
<!-- version: 17 -->
|
||||
|
||||
# Changelog KSP
|
||||
|
||||
## 0.2.13 — Interface / wire foundation — 2026-08-28
|
||||
|
||||
`0.2.13` introduit `ksp-interface-lib` comme première façade wire officielle KSP, volontairement passive et Program-facing. La surface stable réexporte le `Pubkey` canonique de Core, ajoute `ProgramAccountMeta` et `ProgramInstruction` à champs privés avec accessors explicites, conserve l’ordre et les doublons des account metas, accepte les Program Pubkeys opaques et borne l’admission à **255 account metas** et **10 240 octets** de data. Les deux bornes sont des limites d’admission Interface et ne prétendent pas garantir à elles seules le fit d’une transaction Solana top-level. Les erreurs réutilisent le contrat Core `Error/Result` avec uniquement `field`, `actual_len` et `maximum_len`, tandis que le `Debug` de l’instruction n’expose que `program_id`, `account_count` et `data_len`.
|
||||
|
||||
La dependency direction finale reste strictement `ksp-interface-lib -> ksp-core-lib -> solana-pubkey`. Aucun `serde`, codec générique (`borsh`, `wincode`, `bincode`), `solana-instruction`, runtime réseau ou logging n’est ajouté à cette foundation. Les canaris public API, consumer externe, dependency firewall et release completeness verrouillent les six exports crate-root, les quatre modules de production, l’absence de narrowing/codec caché, le transfert des `Vec` admis sans réallocation interne et la non-répétition de matériel hostile dans les erreurs. `pre.005-fix.001` corrige uniquement un faux positif du scanner Logging provoqué par le littéral de test `tracing::`, sans changement de production ni de dépendance. Les gates `pre.006` et `pre.007` passent ensuite audits Rust/Markdown, `cargo check`, Clippy, tests Interface, ownership Logging, workspace complet et graphes Cargo avant la réconciliation documentaire finale.
|
||||
|
||||
`prompts/019-V0_2_14_START_PROMPT.md` ouvre `0.2.14 — Program API foundation` exclusivement depuis le tag stable `v0.2.13`. Le gate `pre.001` de cette prochaine release exige aussi l’archive historique `khadhroony-bot3_v0.5.3-pre.005-fix010.zip` afin d’auditer les anciens contrats decoder/executor sous une matrice `REPRENDRE / REDESSINER / REPORTER / REJETER`, sans faire de kbot3 une autorité architecturale ni recréer son monolithe `ks-lib`.
|
||||
|
||||
## 0.2.12 — SOL Prices Desk + projection prix Wallet — 2026-08-27
|
||||
|
||||
`0.2.12` ajoute `ksp-app-solprices-desk`, troisième Desk Tauri spécialisé de KSP, comme HID strictement provider-neutral au-dessus de `ksp-offchain-transport-lib`. Son composite dédié sélectionne `std.logging` et `std.offchain_transport`; la vue Prices expose l’inventaire des huit providers SOL/USD, disponibilité, sémantique, auth, prix exact sous forme de chaîne, timestamps provider/KSP distincts et retry deadline sans inventer de fraîcheur. Les refresh manuel individuel, sélectionné et global passent exclusivement par `MarketPriceService`; les batchs sont bornés à `1..=64`, les états `in_flight` restent backend-owned et aucun polling, scheduler, fallback, moyenne ou prix canonique n’est introduit dans le Desk. Le frontend conserve l’absence de réseau/persistence navigateur et journalise les interactions sans prix, credential, URL, header ou payload provider.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 302
|
||||
# version: 312
|
||||
|
||||
[workspace]
|
||||
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-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-wallet-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.12"
|
||||
version = "0.2.13"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 90 -->
|
||||
<!-- version: 91 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -57,8 +57,8 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
|
||||
- [X] `0.2.10` — OrbitFlare Yellowstone gRPC stable : profil Config V3 Devnet, License Key injectée comme metadata secrète `x-token`, smoke live `Subscribe -> Slot + Ping` validé deux fois, sans modification du moteur N1/N2 ni heartbeat provider.
|
||||
- [X] `0.2.11` — Off-chain price transport stable : `ksp-offchain-transport-lib` expose SOL/USD via huit adapters REST `reqwest` sans SDK provider, décimal exact, sémantiques/provenance explicites, registry/availability/rate limits et refresh single/many/all génériques ; Config `std.offchain_transport` construit le service sans dépendance inverse, DexScreener reste lié à une paire explicite sans discovery, aucun consensus/fallback automatique n’est introduit, et le smoke live keyless final passe 7/7 après correction CoinMarketCap V2.
|
||||
- [X] `0.2.12` — SOL Prices Desk + projection prix Wallet stables : HID provider-neutral avec refresh row/selected/all et batch `1..=64`, observations/timestamps exacts sans polling/consensus, puis refresh balance Wallet enrichi d’une moyenne SOL/USD consumer-owned et d’un équivalent USD exact best-effort ; smoke live de composition, workspace complet et bundles Tauri Linux validés.
|
||||
- [ ] `0.2.13` — Introduire la première surface de `ksp-interface-lib`, façade wire KSP publique et passive utilisable par les implémentations officielles et externes ; `pre.001` doit confronter l’architecture actuelle aux contrats utiles de l’ancien `khadhroony-bot3` sans recréer son monolithe `ks-lib`, et séparer explicitement données wire, comportement Program et implémentations.
|
||||
- [ ] `0.2.14` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet ; les traits de reconnaissance/decode/build et autres comportements ne doivent pas être aspirés prématurément dans `ksp-interface-lib`.
|
||||
- [X] `0.2.13` — Interface / wire foundation stable : `ksp-interface-lib` expose `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` passifs, admission bornée à 255 account metas / 10 240 bytes, erreurs et `Debug` sans payload hostile, façade crate-root et consumer externe canaris ; graphe strict `Interface -> Core`, sans serde/codec générique, `solana-instruction`, réseau ni logging runtime.
|
||||
- [ ] `0.2.14` — Introduire `ksp-program-api` comme premier contrat Program extensible, sans imposer encore `ksp-program-lib` complet ; `pre.001` doit auditer la base stable `v0.2.13` et l’archive historique `khadhroony-bot3_v0.5.3-pre.005-fix010.zip`, puis classer reconnaissance/decode/outcomes/proofs/préparation sous `REPRENDRE / REDESSINER / REPORTER / REJETER` avant de figer la surface.
|
||||
|
||||
### TODO/IDEAS — providers Yellowstone non planifiés
|
||||
|
||||
|
||||
14
crates/ksp-interface-lib/Cargo.toml
Normal file
14
crates/ksp-interface-lib/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
# file: crates/ksp-interface-lib/Cargo.toml
|
||||
# version: 1
|
||||
|
||||
[package]
|
||||
name = "ksp-interface-lib"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
131
crates/ksp-interface-lib/README.md
Normal file
131
crates/ksp-interface-lib/README.md
Normal file
@@ -0,0 +1,131 @@
|
||||
<!-- file: crates/ksp-interface-lib/README.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# ksp-interface-lib
|
||||
|
||||
`ksp-interface-lib` est la façade wire officielle KSP destinée aux contrats passifs partagés par les implémentations Program Solana officielles ou externes. La crate expose uniquement des structures de représentation/admission ; elle ne possède ni transport, ni exécution, ni persistence, ni comportement métier Program.
|
||||
|
||||
## Ownership
|
||||
|
||||
La crate réutilise les primitives fondamentales déjà possédées par `ksp-core-lib` :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
Error / ErrorCode / Result
|
||||
Program IDs fondamentaux
|
||||
```
|
||||
|
||||
`Pubkey` est réexporté depuis le crate-root Interface afin qu'un consumer wire n'introduise aucun wrapper d'identité parallèle. Les Program IDs restent possédés et répertoriés par Core.
|
||||
|
||||
La dependency direction candidate `0.2.13` reste strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey
|
||||
```
|
||||
|
||||
## Surface publique `0.2.13`
|
||||
|
||||
La façade crate-root expose exactement :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
ProgramAccountMeta
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
Aucun module interne n'est public.
|
||||
|
||||
### `ProgramAccountMeta`
|
||||
|
||||
`ProgramAccountMeta` représente un compte ordonné d'une instruction avec :
|
||||
|
||||
```text
|
||||
pubkey
|
||||
is_signer
|
||||
is_writable
|
||||
```
|
||||
|
||||
Les champs restent privés. Les constructeurs publics sont `readonly(pubkey, is_signer)` et `writable(pubkey, is_signer)`, complétés par les accessors `pubkey()`, `is_signer()` et `is_writable()`.
|
||||
|
||||
La structure n'applique aucune sémantique spécifique à un programme et n'exige pas que la `Pubkey` appartienne au registry des Program IDs Core.
|
||||
|
||||
### `ProgramInstruction`
|
||||
|
||||
`ProgramInstruction` représente un contrat passif borné :
|
||||
|
||||
```text
|
||||
program_id
|
||||
accounts: Vec<ProgramAccountMeta>
|
||||
data: Vec<u8>
|
||||
```
|
||||
|
||||
`ProgramInstruction::try_new` consomme directement les deux `Vec`, conserve l'ordre et les doublons des accounts et préserve les octets opaques de `data` sans décodage.
|
||||
|
||||
Les cas vides sont valides et une `program_id` inconnue du registry KSP reste admissible.
|
||||
|
||||
## Bornes d'admission
|
||||
|
||||
Interface applique deux limites locales :
|
||||
|
||||
| Limite | Valeur |
|
||||
|------------------------------------|----------|
|
||||
| `MAX_PROGRAM_INSTRUCTION_ACCOUNTS` | `255` |
|
||||
| `MAX_PROGRAM_INSTRUCTION_DATA_LEN` | `10_240` |
|
||||
|
||||
Ces valeurs sont des **bornes d'admission Interface**. Elles ne constituent pas une garantie qu'une instruction donnée tient dans toutes les contraintes d'une transaction Solana top-level. La limite CPI de comptes uniques n'est notamment pas transformée en règle artificielle sur la liste d'account metas.
|
||||
|
||||
Un dépassement utilise le code commun :
|
||||
|
||||
```text
|
||||
interface.program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
Le contexte d'erreur est limité aux métadonnées sûres `field`, `actual_len` et `maximum_len`. Aucun payload arbitraire ni account meta hostile n'est recopié dans l'erreur.
|
||||
|
||||
Le `Debug` de `ProgramInstruction` est volontairement borné : il affiche `program_id`, `account_count` et `data_len`, jamais les accounts complets ni les octets du payload.
|
||||
|
||||
## Codecs et runtime
|
||||
|
||||
La foundation `0.2.13` n'ajoute aucun codec par réflexe :
|
||||
|
||||
```text
|
||||
serde / serde_json absents
|
||||
borsh absent
|
||||
wincode absent
|
||||
bincode absent
|
||||
solana-instruction absent
|
||||
```
|
||||
|
||||
Des codecs/layouts/discriminants spécifiques pourront être ajoutés ultérieurement uniquement lorsqu'un vertical Program réel en démontre le besoin et que leur ownership wire appartient bien à Interface.
|
||||
|
||||
La crate ne produit aucun événement runtime. Elle ne dépend donc pas de `ksp-logging-lib` et ne possède ni `constants.rs` ni `TRACING_TARGET`. Si un futur comportement Interface exige réellement du logging, le runtime devra passer par la façade Logging KSP plutôt que par une dépendance directe à Tracing.
|
||||
|
||||
## Frontières
|
||||
|
||||
`ksp-interface-lib` ne possède pas :
|
||||
|
||||
```text
|
||||
RPC / WebSocket / gRPC
|
||||
provider DTOs Transport
|
||||
wallet / signature
|
||||
Config / environnement
|
||||
persistence / Store
|
||||
Program decoding / recognition / proofs
|
||||
execution policy / signers
|
||||
transaction replay / CPI path / runtime logs
|
||||
lifecycle réseau
|
||||
```
|
||||
|
||||
La foundation Program API est reportée à `0.2.14`. Les wires génériques d'acquisition/CORE restent reportés à `0.3.2+`.
|
||||
|
||||
## Références
|
||||
|
||||
- [Usage public](USAGE.md)
|
||||
- [Plan `0.2.13`](../../docs/plans/020-V0_2_13_INTERFACE_PLAN.md)
|
||||
- [Validation `0.2.13`](../../docs/validation/016-V0_2_13_INTERFACE.md)
|
||||
- [Architecture Wire + Program](../../docs/architecture/006-WIRE_AND_PROGRAM.md)
|
||||
122
crates/ksp-interface-lib/USAGE.md
Normal file
122
crates/ksp-interface-lib/USAGE.md
Normal file
@@ -0,0 +1,122 @@
|
||||
<!-- file: crates/ksp-interface-lib/USAGE.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Usage de ksp-interface-lib
|
||||
|
||||
Cette page décrit la façade publique matérialisée par `0.2.13`. Les modules internes ne font pas partie du contrat consommable : utiliser uniquement les exports du crate-root.
|
||||
|
||||
## Construire des account metas
|
||||
|
||||
```rust
|
||||
let readonly_account = ksp_interface_lib::Pubkey::new_from_array([1_u8; 32]);
|
||||
let writable_account = ksp_interface_lib::Pubkey::new_from_array([2_u8; 32]);
|
||||
|
||||
let readonly = ksp_interface_lib::ProgramAccountMeta::readonly(readonly_account, true);
|
||||
let writable = ksp_interface_lib::ProgramAccountMeta::writable(writable_account, false);
|
||||
|
||||
assert_eq!(readonly.pubkey(), &readonly_account);
|
||||
assert!(readonly.is_signer());
|
||||
assert!(!readonly.is_writable());
|
||||
|
||||
assert_eq!(writable.pubkey(), &writable_account);
|
||||
assert!(!writable.is_signer());
|
||||
assert!(writable.is_writable());
|
||||
```
|
||||
|
||||
`readonly`/`writable` décrivent uniquement les flags wire de l'account meta. Interface ne valide pas l'identité du compte contre un registry Program.
|
||||
|
||||
## Construire une instruction passive
|
||||
|
||||
```rust
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([3_u8; 32]);
|
||||
let account_id = ksp_interface_lib::Pubkey::new_from_array([4_u8; 32]);
|
||||
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::writable(account_id, true);
|
||||
let result = ksp_interface_lib::ProgramInstruction::try_new(
|
||||
program_id,
|
||||
std::vec![account, account],
|
||||
std::vec![7_u8, 8, 9],
|
||||
);
|
||||
|
||||
match result {
|
||||
std::result::Result::Ok(instruction) => {
|
||||
assert_eq!(instruction.program_id(), &program_id);
|
||||
assert_eq!(instruction.accounts(), &[account, account]);
|
||||
assert_eq!(instruction.data(), &[7_u8, 8, 9]);
|
||||
}
|
||||
std::result::Result::Err(error) => {
|
||||
eprintln!("{error}");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
L'ordre et les doublons des accounts sont conservés. Les octets `data` restent opaques : `ProgramInstruction` ne les sérialise, désérialise ni interprète.
|
||||
|
||||
Les `Vec` fournis à `try_new` sont consommés par la structure après validation des bornes ; aucun clone ou reformatage interne n'est requis par le contrat actuel.
|
||||
|
||||
## Bornes
|
||||
|
||||
Les limites publiques sont :
|
||||
|
||||
```rust
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
```
|
||||
|
||||
`255` account metas et `10_240` bytes de data sont admis. `256` account metas ou `10_241` bytes sont refusés par `try_new` avant création d'un `ProgramInstruction` valide.
|
||||
|
||||
Ces limites sont des bornes locales Interface et ne promettent pas qu'une instruction admise respecte à elle seule toutes les contraintes de taille/account-set d'une transaction Solana complète.
|
||||
|
||||
## Observer une erreur de limite
|
||||
|
||||
Le code public est :
|
||||
|
||||
```rust
|
||||
assert_eq!(
|
||||
ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(),
|
||||
"interface",
|
||||
);
|
||||
assert_eq!(
|
||||
ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(),
|
||||
"program_instruction_limit_exceeded",
|
||||
);
|
||||
```
|
||||
|
||||
Une erreur de dépassement expose uniquement un contexte structurel sûr :
|
||||
|
||||
```text
|
||||
field
|
||||
actual_len
|
||||
maximum_len
|
||||
```
|
||||
|
||||
Le contenu du payload et les account metas arbitraires ne sont pas projetés dans le diagnostic.
|
||||
|
||||
## Debug borné
|
||||
|
||||
Le `Debug` de `ProgramInstruction` contient uniquement :
|
||||
|
||||
```text
|
||||
program_id
|
||||
account_count
|
||||
data_len
|
||||
```
|
||||
|
||||
Il ne faut donc pas attendre de ce rendu une sérialisation wire ou un dump du payload.
|
||||
|
||||
## Dépendances à ne pas ajouter côté consumer
|
||||
|
||||
Un consumer de la façade Interface n'a pas besoin d'ajouter un SDK Program Solana uniquement pour reconstruire `ProgramInstruction`. La crate utilise le `Pubkey` canonique partagé avec Core et conserve son propre contrat passif.
|
||||
|
||||
La foundation ne fournit volontairement pas :
|
||||
|
||||
```text
|
||||
serde générique
|
||||
Borsh / Wincode générique
|
||||
solana-instruction interop automatique
|
||||
transport réseau
|
||||
Program decoder/preparer
|
||||
signing/execution
|
||||
```
|
||||
|
||||
Ces surfaces doivent être introduites dans leur owner respectif lorsqu'un cas réel le justifie, pas comme dépendances implicites d'un consumer Interface.
|
||||
6
crates/ksp-interface-lib/src/error.rs
Normal file
6
crates/ksp-interface-lib/src/error.rs
Normal file
@@ -0,0 +1,6 @@
|
||||
// file: crates/ksp-interface-lib/src/error.rs
|
||||
// version: 1
|
||||
|
||||
/// Error code used when a bounded passive Program instruction contract exceeds one of its Interface-owned admission limits.
|
||||
pub const ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED: ksp_core_lib::ErrorCode =
|
||||
ksp_core_lib::ErrorCode::new("interface", "program_instruction_limit_exceeded");
|
||||
30
crates/ksp-interface-lib/src/lib.rs
Normal file
30
crates/ksp-interface-lib/src/lib.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// file: crates/ksp-interface-lib/src/lib.rs
|
||||
// version: 3
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Passive wire contracts shared by KSP Program implementations.
|
||||
//!
|
||||
//! The foundation reuses the canonical Solana [`Pubkey`] owned by
|
||||
//! `ksp-core-lib` and exposes only bounded, passive Program-facing structures.
|
||||
//! Runtime, transport, persistence and Program behavior remain outside this
|
||||
//! crate.
|
||||
|
||||
mod error;
|
||||
mod program_account_meta;
|
||||
mod program_instruction;
|
||||
|
||||
/// Error code used when an Interface-owned Program instruction admission limit is exceeded.
|
||||
pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;
|
||||
/// Maximum number of account metas admitted by one passive Program instruction contract.
|
||||
pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;
|
||||
/// Passive account metadata attached to one Program instruction.
|
||||
pub use self::program_account_meta::ProgramAccountMeta;
|
||||
/// Maximum opaque data payload admitted by one passive Program instruction contract.
|
||||
pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;
|
||||
/// Passive, bounded Program instruction wire contract.
|
||||
pub use self::program_instruction::ProgramInstruction;
|
||||
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
|
||||
pub use ksp_core_lib::Pubkey;
|
||||
52
crates/ksp-interface-lib/src/program_account_meta.rs
Normal file
52
crates/ksp-interface-lib/src/program_account_meta.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
// file: crates/ksp-interface-lib/src/program_account_meta.rs
|
||||
// version: 1
|
||||
|
||||
/// Maximum number of account metas admitted by one passive Program instruction contract.
|
||||
pub const MAX_PROGRAM_INSTRUCTION_ACCOUNTS: usize = 255;
|
||||
|
||||
/// Passive account metadata attached to one Program instruction.
|
||||
///
|
||||
/// Account metas preserve the caller-provided Solana account identity and the
|
||||
/// signer/writable flags without applying Program-specific semantics.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct ProgramAccountMeta {
|
||||
pubkey: crate::Pubkey,
|
||||
is_signer: bool,
|
||||
is_writable: bool,
|
||||
}
|
||||
|
||||
impl ProgramAccountMeta {
|
||||
/// Creates one read-only account meta.
|
||||
#[must_use]
|
||||
pub const fn readonly(pubkey: crate::Pubkey, is_signer: bool) -> Self {
|
||||
return Self { pubkey, is_signer, is_writable: false };
|
||||
}
|
||||
|
||||
/// Creates one writable account meta.
|
||||
#[must_use]
|
||||
pub const fn writable(pubkey: crate::Pubkey, is_signer: bool) -> Self {
|
||||
return Self { pubkey, is_signer, is_writable: true };
|
||||
}
|
||||
|
||||
/// Returns whether this account must sign the containing instruction.
|
||||
#[must_use]
|
||||
pub const fn is_signer(&self) -> bool {
|
||||
return self.is_signer;
|
||||
}
|
||||
|
||||
/// Returns whether this account may be written by the containing instruction.
|
||||
#[must_use]
|
||||
pub const fn is_writable(&self) -> bool {
|
||||
return self.is_writable;
|
||||
}
|
||||
|
||||
/// Returns the canonical account address.
|
||||
#[must_use]
|
||||
pub const fn pubkey(&self) -> &crate::Pubkey {
|
||||
return &self.pubkey;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/program_account_meta.rs"]
|
||||
mod tests;
|
||||
81
crates/ksp-interface-lib/src/program_instruction.rs
Normal file
81
crates/ksp-interface-lib/src/program_instruction.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
// file: crates/ksp-interface-lib/src/program_instruction.rs
|
||||
// version: 1
|
||||
|
||||
/// Maximum opaque data payload admitted by one passive Program instruction contract.
|
||||
pub const MAX_PROGRAM_INSTRUCTION_DATA_LEN: usize = 10 * 1024;
|
||||
|
||||
/// Passive, bounded Program instruction wire contract.
|
||||
///
|
||||
/// The instruction preserves the caller-provided Program identity, ordered
|
||||
/// account metas and opaque data bytes without applying Program-specific
|
||||
/// semantics. Construction enforces only the Interface-owned admission bounds.
|
||||
pub struct ProgramInstruction {
|
||||
program_id: crate::Pubkey,
|
||||
accounts: std::vec::Vec<crate::ProgramAccountMeta>,
|
||||
data: std::vec::Vec<u8>,
|
||||
}
|
||||
|
||||
impl ProgramInstruction {
|
||||
/// Creates one passive Program instruction after enforcing Interface admission bounds.
|
||||
///
|
||||
/// The provided vectors are consumed directly. Their account order and duplicates
|
||||
/// are preserved exactly when construction succeeds.
|
||||
pub fn try_new(program_id: crate::Pubkey, accounts: std::vec::Vec<crate::ProgramAccountMeta>, data: std::vec::Vec<u8>) -> ksp_core_lib::Result<Self> {
|
||||
if accounts.len() > crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED,
|
||||
"Program instruction account count exceeds the Interface admission limit",
|
||||
)
|
||||
.with_context("field", "accounts")
|
||||
.with_context("actual_len", accounts.len().to_string())
|
||||
.with_context("maximum_len", crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS.to_string()),
|
||||
);
|
||||
}
|
||||
if data.len() > crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN {
|
||||
return std::result::Result::Err(
|
||||
ksp_core_lib::Error::new(
|
||||
crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED,
|
||||
"Program instruction data length exceeds the Interface admission limit",
|
||||
)
|
||||
.with_context("field", "data")
|
||||
.with_context("actual_len", data.len().to_string())
|
||||
.with_context("maximum_len", crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN.to_string()),
|
||||
);
|
||||
}
|
||||
return std::result::Result::Ok(Self { program_id, accounts, data });
|
||||
}
|
||||
|
||||
/// Returns the ordered account metas exactly as admitted at construction.
|
||||
#[must_use]
|
||||
pub fn accounts(&self) -> &[crate::ProgramAccountMeta] {
|
||||
return self.accounts.as_slice();
|
||||
}
|
||||
|
||||
/// Returns the opaque Program instruction data bytes.
|
||||
#[must_use]
|
||||
pub fn data(&self) -> &[u8] {
|
||||
return self.data.as_slice();
|
||||
}
|
||||
|
||||
/// Returns the Program identity.
|
||||
#[must_use]
|
||||
pub const fn program_id(&self) -> &crate::Pubkey {
|
||||
return &self.program_id;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for ProgramInstruction {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("ProgramInstruction")
|
||||
.field("program_id", &self.program_id)
|
||||
.field("account_count", &self.accounts.len())
|
||||
.field("data_len", &self.data.len())
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/program_instruction.rs"]
|
||||
mod tests;
|
||||
131
crates/ksp-interface-lib/tests/dependency_boundary.rs
Normal file
131
crates/ksp-interface-lib/tests/dependency_boundary.rs
Normal file
@@ -0,0 +1,131 @@
|
||||
// file: crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
// version: 5
|
||||
|
||||
//! Dependency and passive-surface canaries for the Interface foundation.
|
||||
|
||||
#[test]
|
||||
fn pre_002_manifest_has_exact_core_only_runtime_dependency() {
|
||||
let manifest = include_str!("../Cargo.toml");
|
||||
let dependencies_tail = manifest.split("[dependencies]").nth(1);
|
||||
assert!(dependencies_tail.is_some(), "Interface 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"]);
|
||||
for forbidden in [
|
||||
"ksp-config-lib",
|
||||
"ksp-logging-lib",
|
||||
"ksp-offchain-transport-lib",
|
||||
"ksp-onchain-transport-lib",
|
||||
"ksp-program-api",
|
||||
"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 Interface dependency detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_surface_remains_passive_without_codecs_or_runtime_logging() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
assert!(crate_root.contains("ProgramAccountMeta"));
|
||||
assert!(crate_root.contains("MAX_PROGRAM_INSTRUCTION_ACCOUNTS"));
|
||||
assert!(crate_root.contains("ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED"));
|
||||
assert!(crate_root.contains("ProgramInstruction"));
|
||||
assert!(crate_root.contains("MAX_PROGRAM_INSTRUCTION_DATA_LEN"));
|
||||
assert!(!crate_root.contains("TRACING_TARGET"));
|
||||
assert!(!crate_root.contains("ksp_logging_lib"));
|
||||
assert!(!std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/constants.rs").exists());
|
||||
let instruction_source = include_str!("../src/program_instruction.rs");
|
||||
for forbidden in ["serde", "borsh", "bincode", "wincode", "solana_instruction", "ksp_logging_lib", "TRACING_TARGET"] {
|
||||
assert!(!instruction_source.contains(forbidden), "forbidden Interface surface detected: {forbidden}");
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_all_production_sources_preserve_the_dependency_firewall() {
|
||||
let production_sources = [
|
||||
include_str!("../src/error.rs"),
|
||||
include_str!("../src/lib.rs"),
|
||||
include_str!("../src/program_account_meta.rs"),
|
||||
include_str!("../src/program_instruction.rs"),
|
||||
];
|
||||
for source in production_sources {
|
||||
for forbidden in [
|
||||
"borsh::",
|
||||
"bincode::",
|
||||
"ksp_config_lib::",
|
||||
"ksp_logging_lib::",
|
||||
"ksp_offchain_transport_lib::",
|
||||
"ksp_onchain_transport_lib::",
|
||||
"ksp_program_api::",
|
||||
"ksp_program_lib::",
|
||||
"ksp_store_api::",
|
||||
"ksp_store_lib::",
|
||||
"ksp_wallet_lib::",
|
||||
"reqwest::",
|
||||
"serde::",
|
||||
"serde_json::",
|
||||
"solana_instruction::",
|
||||
"tauri::",
|
||||
"tokio::",
|
||||
"tonic::",
|
||||
concat!("tracing", "::"),
|
||||
"wincode::",
|
||||
] {
|
||||
assert!(!source.contains(forbidden), "forbidden production dependency path detected: {forbidden}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_instruction_source_has_no_narrowing_cast_or_hidden_codec_entry_point() {
|
||||
let instruction_source = include_str!("../src/program_instruction.rs");
|
||||
for forbidden in [" as u8", " as u16", " as u32", " as u64", "serialize", "deserialize", "encode", "decode"] {
|
||||
assert!(!instruction_source.contains(forbidden), "forbidden instruction implementation pattern detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
27
crates/ksp-interface-lib/tests/external_consumer.rs
Normal file
27
crates/ksp-interface-lib/tests/external_consumer.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
// file: crates/ksp-interface-lib/tests/external_consumer.rs
|
||||
// version: 1
|
||||
|
||||
//! Downstream-style consumer canary for the public Interface facade.
|
||||
|
||||
fn consume_instruction(instruction: ksp_interface_lib::ProgramInstruction) -> (ksp_interface_lib::Pubkey, usize, usize) {
|
||||
return (*instruction.program_id(), instruction.accounts().len(), instruction.data().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_external_consumer_uses_only_the_crate_root_facade() {
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xA1_u8; 32]);
|
||||
let account_id = ksp_interface_lib::Pubkey::new_from_array([0xA2_u8; 32]);
|
||||
let readonly = ksp_interface_lib::ProgramAccountMeta::readonly(account_id, true);
|
||||
let writable = ksp_interface_lib::ProgramAccountMeta::writable(account_id, false);
|
||||
let instruction = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![readonly, writable, readonly], std::vec![7_u8, 8, 9]);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(consume_instruction(instruction), (program_id, 3, 3));
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
||||
return;
|
||||
}
|
||||
79
crates/ksp-interface-lib/tests/public_api.rs
Normal file
79
crates/ksp-interface-lib/tests/public_api.rs
Normal file
@@ -0,0 +1,79 @@
|
||||
// file: crates/ksp-interface-lib/tests/public_api.rs
|
||||
// version: 4
|
||||
|
||||
//! Integration canaries for the public `ksp-interface-lib` foundation.
|
||||
|
||||
fn consume_pubkey(pubkey: ksp_interface_lib::Pubkey) -> [u8; 32] {
|
||||
return pubkey.to_bytes();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_002_pubkey_contract_is_available_from_crate_root() {
|
||||
let pubkey = ksp_interface_lib::Pubkey::default();
|
||||
assert_eq!(consume_pubkey(pubkey), [0_u8; 32]);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_003_account_meta_and_limit_contracts_are_available_from_crate_root() {
|
||||
let pubkey = ksp_interface_lib::Pubkey::new_from_array([3_u8; 32]);
|
||||
let readonly = ksp_interface_lib::ProgramAccountMeta::readonly(pubkey, true);
|
||||
let writable = ksp_interface_lib::ProgramAccountMeta::writable(pubkey, false);
|
||||
assert_eq!(readonly.pubkey(), &pubkey);
|
||||
assert!(readonly.is_signer());
|
||||
assert!(!readonly.is_writable());
|
||||
assert_eq!(writable.pubkey(), &pubkey);
|
||||
assert!(!writable.is_signer());
|
||||
assert!(writable.is_writable());
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_003_interface_error_code_is_stable_and_core_owned() {
|
||||
let code: ksp_core_lib::ErrorCode = ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;
|
||||
assert_eq!(code.domain(), "interface");
|
||||
assert_eq!(code.code(), "program_instruction_limit_exceeded");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_004_program_instruction_contract_is_available_from_crate_root() {
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([4_u8; 32]);
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([5_u8; 32]), true);
|
||||
let instruction = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![1_u8, 2, 3]);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(instruction.program_id(), &program_id);
|
||||
assert_eq!(instruction.accounts(), &[account]);
|
||||
assert_eq!(instruction.data(), &[1_u8, 2, 3]);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_005_limit_error_is_observable_without_private_module_access() {
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xC1_u8; 32]);
|
||||
let rejected = ksp_interface_lib::ProgramInstruction::try_new(
|
||||
program_id,
|
||||
std::vec::Vec::new(),
|
||||
std::vec![0xC2_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1],
|
||||
);
|
||||
assert!(rejected.is_err());
|
||||
let error = match rejected {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED);
|
||||
assert_eq!(error.context().len(), 3);
|
||||
assert_eq!(error.context()[0].key(), "field");
|
||||
assert_eq!(error.context()[0].value(), "data");
|
||||
assert_eq!(error.context()[1].key(), "actual_len");
|
||||
assert_eq!(error.context()[1].value(), "10241");
|
||||
assert_eq!(error.context()[2].key(), "maximum_len");
|
||||
assert_eq!(error.context()[2].value(), "10240");
|
||||
return;
|
||||
}
|
||||
75
crates/ksp-interface-lib/tests/release_completeness.rs
Normal file
75
crates/ksp-interface-lib/tests/release_completeness.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
// file: crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
// version: 1
|
||||
|
||||
//! Release-level completeness canaries for the `0.2.13` Interface foundation.
|
||||
|
||||
#[test]
|
||||
fn pre_005_exact_crate_root_export_inventory_is_stable() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
let mut actual = std::vec::Vec::new();
|
||||
for line in crate_root.lines() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with("pub use ") {
|
||||
actual.push(trimmed);
|
||||
}
|
||||
}
|
||||
actual.sort_unstable();
|
||||
let mut expected = std::vec![
|
||||
"pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;",
|
||||
"pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;",
|
||||
"pub use self::program_account_meta::ProgramAccountMeta;",
|
||||
"pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;",
|
||||
"pub use self::program_instruction::ProgramInstruction;",
|
||||
"pub use ksp_core_lib::Pubkey;",
|
||||
];
|
||||
expected.sort_unstable();
|
||||
assert_eq!(actual, expected);
|
||||
assert!(!crate_root.contains("pub mod "));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_production_module_inventory_contains_no_second_wire_domain() -> std::io::Result<()> {
|
||||
let source_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
|
||||
let entries = match std::fs::read_dir(source_root) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let mut names = std::vec::Vec::new();
|
||||
for entry in entries {
|
||||
let entry = match entry {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let file_type = match entry.file_type() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
if !file_type.is_file() {
|
||||
continue;
|
||||
}
|
||||
let name = match entry.file_name().into_string() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => continue,
|
||||
};
|
||||
if name.ends_with(".rs") {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
assert_eq!(names, std::vec!["error.rs", "lib.rs", "program_account_meta.rs", "program_instruction.rs"]);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_foundation_has_one_error_code_and_two_bounded_passive_types() {
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(), "program_instruction_limit_exceeded");
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xB1_u8; 32]);
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xB2_u8; 32]), false);
|
||||
let instruction = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xB3_u8]);
|
||||
assert!(instruction.is_ok());
|
||||
return;
|
||||
}
|
||||
31
crates/ksp-interface-lib/unit_tests/program_account_meta.rs
Normal file
31
crates/ksp-interface-lib/unit_tests/program_account_meta.rs
Normal file
@@ -0,0 +1,31 @@
|
||||
// file: crates/ksp-interface-lib/unit_tests/program_account_meta.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn readonly_and_writable_constructors_preserve_identity_signer_and_writable_flags() {
|
||||
let readonly_pubkey = crate::Pubkey::new_from_array([7_u8; 32]);
|
||||
let writable_pubkey = crate::Pubkey::new_from_array([9_u8; 32]);
|
||||
let readonly = crate::ProgramAccountMeta::readonly(readonly_pubkey, true);
|
||||
assert_eq!(readonly.pubkey(), &readonly_pubkey);
|
||||
assert!(readonly.is_signer());
|
||||
assert!(!readonly.is_writable());
|
||||
let writable = crate::ProgramAccountMeta::writable(writable_pubkey, false);
|
||||
assert_eq!(writable.pubkey(), &writable_pubkey);
|
||||
assert!(!writable.is_signer());
|
||||
assert!(writable.is_writable());
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_meta_accepts_opaque_pubkeys_without_program_registry_validation() {
|
||||
let opaque_pubkey = crate::Pubkey::new_from_array([0xA5_u8; 32]);
|
||||
let meta = crate::ProgramAccountMeta::readonly(opaque_pubkey, false);
|
||||
assert_eq!(meta.pubkey(), &opaque_pubkey);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn account_limit_constant_matches_the_interface_admission_contract() {
|
||||
assert_eq!(crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
return;
|
||||
}
|
||||
162
crates/ksp-interface-lib/unit_tests/program_instruction.rs
Normal file
162
crates/ksp-interface-lib/unit_tests/program_instruction.rs
Normal file
@@ -0,0 +1,162 @@
|
||||
// file: crates/ksp-interface-lib/unit_tests/program_instruction.rs
|
||||
// version: 2
|
||||
|
||||
fn meta(byte: u8, writable: bool) -> crate::ProgramAccountMeta {
|
||||
let pubkey = crate::Pubkey::new_from_array([byte; 32]);
|
||||
if writable {
|
||||
return crate::ProgramAccountMeta::writable(pubkey, false);
|
||||
}
|
||||
return crate::ProgramAccountMeta::readonly(pubkey, false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_accepts_empty_accounts_and_data_with_opaque_program_id() {
|
||||
let program_id = crate::Pubkey::new_from_array([0xD3_u8; 32]);
|
||||
let instruction = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec::Vec::new());
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(instruction.program_id(), &program_id);
|
||||
assert!(instruction.accounts().is_empty());
|
||||
assert!(instruction.data().is_empty());
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_preserves_account_order_duplicates_and_opaque_data() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x41_u8; 32]);
|
||||
let first = meta(1, false);
|
||||
let duplicate = meta(2, true);
|
||||
let accounts = std::vec![first, duplicate, first];
|
||||
let data = std::vec![0_u8, 1, 2, 0xFF];
|
||||
let instruction = crate::ProgramInstruction::try_new(program_id, accounts, data.clone());
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(instruction.accounts(), &[first, duplicate, first]);
|
||||
assert_eq!(instruction.data(), data.as_slice());
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_accepts_account_limit_and_rejects_one_above_it() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x51_u8; 32]);
|
||||
let account = meta(7, false);
|
||||
let accepted = crate::ProgramInstruction::try_new(program_id, std::vec![account; crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS], std::vec::Vec::new());
|
||||
assert!(accepted.is_ok());
|
||||
let rejected = crate::ProgramInstruction::try_new(program_id, std::vec![account; crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS + 1], std::vec::Vec::new());
|
||||
assert!(rejected.is_err());
|
||||
let error = match rejected {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED);
|
||||
assert_eq!(error.message(), "Program instruction account count exceeds the Interface admission limit");
|
||||
assert_eq!(error.context().len(), 3);
|
||||
assert_eq!(error.context()[0].key(), "field");
|
||||
assert_eq!(error.context()[0].value(), "accounts");
|
||||
assert_eq!(error.context()[1].key(), "actual_len");
|
||||
assert_eq!(error.context()[1].value(), "256");
|
||||
assert_eq!(error.context()[2].key(), "maximum_len");
|
||||
assert_eq!(error.context()[2].value(), "255");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_accepts_data_limit_and_rejects_one_byte_above_it() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x61_u8; 32]);
|
||||
let accepted = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec![0xA5_u8; crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN]);
|
||||
assert!(accepted.is_ok());
|
||||
let rejected = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec![0x5A_u8; crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1]);
|
||||
assert!(rejected.is_err());
|
||||
let error = match rejected {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code(), crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED);
|
||||
assert_eq!(error.message(), "Program instruction data length exceeds the Interface admission limit");
|
||||
assert_eq!(error.context().len(), 3);
|
||||
assert_eq!(error.context()[0].value(), "data");
|
||||
assert_eq!(error.context()[1].value(), "10241");
|
||||
assert_eq!(error.context()[2].value(), "10240");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_debug_is_bounded_and_omits_accounts_and_payload_bytes() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x71_u8; 32]);
|
||||
let payload = b"PAYLOAD_SENTINEL_NEVER_RENDER".to_vec();
|
||||
let instruction = crate::ProgramInstruction::try_new(program_id, std::vec![meta(8, false), meta(9, true)], payload);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let rendered = std::format!("{instruction:?}");
|
||||
assert!(rendered.contains("ProgramInstruction"));
|
||||
assert!(rendered.contains("account_count: 2"));
|
||||
assert!(rendered.contains("data_len: 29"));
|
||||
assert!(!rendered.contains("PAYLOAD_SENTINEL_NEVER_RENDER"));
|
||||
assert!(!rendered.contains("is_signer"));
|
||||
assert!(!rendered.contains("is_writable"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_preserves_owned_vector_allocations_without_internal_reallocation() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x81_u8; 32]);
|
||||
let accounts = std::vec![meta(10, false), meta(11, true), meta(12, false)];
|
||||
let accounts_ptr = accounts.as_ptr();
|
||||
let data = std::vec![0x10_u8, 0x20, 0x30, 0x40];
|
||||
let data_ptr = data.as_ptr();
|
||||
let instruction = crate::ProgramInstruction::try_new(program_id, accounts, data);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(instruction.accounts().as_ptr(), accounts_ptr);
|
||||
assert_eq!(instruction.data().as_ptr(), data_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn instruction_limit_errors_do_not_echo_hostile_payload_or_account_material() {
|
||||
let program_id = crate::Pubkey::new_from_array([0x91_u8; 32]);
|
||||
let hostile_marker = b"HOSTILE_INTERFACE_PAYLOAD_SENTINEL";
|
||||
let mut hostile_data = hostile_marker.to_vec();
|
||||
hostile_data.resize(crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1, 0xA5_u8);
|
||||
let data_error = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), hostile_data);
|
||||
assert!(data_error.is_err());
|
||||
let data_error = match data_error {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
let data_display = std::format!("{data_error}");
|
||||
let data_debug = std::format!("{data_error:?}");
|
||||
assert!(!data_display.contains("HOSTILE_INTERFACE_PAYLOAD_SENTINEL"));
|
||||
assert!(!data_debug.contains("HOSTILE_INTERFACE_PAYLOAD_SENTINEL"));
|
||||
for context in data_error.context() {
|
||||
assert!(!context.value().contains("HOSTILE_INTERFACE_PAYLOAD_SENTINEL"));
|
||||
}
|
||||
let hostile_account = meta(0xE1, true);
|
||||
let hostile_account_debug = std::format!("{hostile_account:?}");
|
||||
let account_error =
|
||||
crate::ProgramInstruction::try_new(program_id, std::vec![hostile_account; crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS + 1], std::vec::Vec::new());
|
||||
assert!(account_error.is_err());
|
||||
let account_error = match account_error {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
let account_debug = std::format!("{account_error:?}");
|
||||
assert!(!account_debug.contains(hostile_account_debug.as_str()));
|
||||
assert_eq!(account_error.context().len(), 3);
|
||||
assert_eq!(account_error.context()[0].value(), "accounts");
|
||||
assert_eq!(account_error.context()[1].value(), "256");
|
||||
assert_eq!(account_error.context()[2].value(), "255");
|
||||
return;
|
||||
}
|
||||
276
deltas/0.2.13/pre.001.md
Normal file
276
deltas/0.2.13/pre.001.md
Normal file
@@ -0,0 +1,276 @@
|
||||
<!-- file: deltas/0.2.13/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.001` — audit/sizing Interface / wire foundation
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
```text
|
||||
v0.2.12
|
||||
```
|
||||
|
||||
Archive opérateur utilisée : `khadhroony-solana-project-v0.2.12.zip`, annoncée comme issue du tag Gitea stable.
|
||||
|
||||
Vérifications d'identité :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.12 PASS à l'entrée
|
||||
deltas/0.2.12/rel.001.md présent
|
||||
prompts/018-V0_2_13_START_PROMPT.md présent
|
||||
crates/ksp-interface-lib absent
|
||||
crates/ksp-program-api absent
|
||||
.git absent de l'archive
|
||||
```
|
||||
|
||||
Le tag stable n'est donc pas revérifiable localement par Git. L'archive opérateur, le delta stable et la preuve opérateur fournie constituent l'autorité de reprise.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Exécuter le gate obligatoire `pre.001` sans ouvrir encore la crate : relire règles/architecture, auditer Core/Transport, auditer l'héritage kbot3, vérifier les candidates externes actuelles, décider le premier lot wire, fixer ownership/bornes/threat model/dependency graph/tests, produire plan/validation et recalibrer la release.
|
||||
|
||||
## 3. Décisions prises
|
||||
|
||||
```text
|
||||
crate cible ksp-interface-lib
|
||||
premier lot ProgramAccountMeta + ProgramInstruction
|
||||
orientation Program-facing passive
|
||||
Pubkey ksp-core-lib::Pubkey, aucun wrapper parallèle
|
||||
Program IDs fondamentaux restent ksp-core-lib
|
||||
account metas ordre + doublons préservés
|
||||
borne account metas 255
|
||||
borne instruction data 10_240 octets
|
||||
fields privés pour préserver les invariants
|
||||
serde OUT pour la foundation
|
||||
borsh/bincode/wincode OUT sans protocole concret
|
||||
solana-instruction référence normative, pas dépendance runtime
|
||||
solana-loader-v3-interface reporté au vertical loader-v3 réel
|
||||
Transport DTO refactor OUT
|
||||
Program traits/decode/recognition 0.2.14, OUT de Interface
|
||||
replay/CPI/logs/return-data/Core 0.3.2+, OUT de 0.2.13
|
||||
nouvelle dépendance externe aucune
|
||||
network/logging runtime aucun
|
||||
```
|
||||
|
||||
Les plafonds 255/10 KiB sont des bornes d'admission Interface dérivées des limites runtime Solana actuelles. Ils ne garantissent pas qu'une instruction donnée rentre dans une transaction top-level complète ; l'assembly transactionnel reste hors scope.
|
||||
|
||||
## 4. Héritage kbot3
|
||||
|
||||
Archive auditée : `khadhroony-bot3_v0.5.3-pre.005-fix010.zip`.
|
||||
|
||||
Verdict synthétique :
|
||||
|
||||
```text
|
||||
REPRENDRE ordered account meta; instruction program_id/accounts/data
|
||||
REDESSINER wrappers String Pubkey/ProgramId; payload non borné
|
||||
REPORTER decoder traits; recognition/proofs; replay/CPI/logs/return data;
|
||||
canonical transaction; prepared execution/signers/policies
|
||||
REJETER monolithe ks-lib; JSON/version/hash génériques par réflexe;
|
||||
operation_code dans le contrat d'instruction passive
|
||||
```
|
||||
|
||||
Aucun code kbot3 n'est porté par ce delta.
|
||||
|
||||
## 5. Audit externe ciblé
|
||||
|
||||
État observé le 27 août 2026 :
|
||||
|
||||
```text
|
||||
solana-instruction 3.5.0
|
||||
Instruction = program_id: Pubkey + Vec<AccountMeta> + Vec<u8>
|
||||
solana-pubkey ^4.3.0
|
||||
serde/borsh/bincode/wincode optionnels
|
||||
licence Anza SDK Apache-2.0
|
||||
|
||||
solana-program 4.1.0
|
||||
MAX_CPI_INSTRUCTION_ACCOUNTS = 255
|
||||
MAX_CPI_INSTRUCTION_DATA_LEN = 10 * 1024
|
||||
MAX_CPI_ACCOUNT_INFOS = 128 (unique account infos; non appliqué aux metas)
|
||||
|
||||
solana-loader-v3-interface 8.1.1
|
||||
compatible avec solana-instruction ^3.5.0 / solana-pubkey ^4.3.0 observés
|
||||
hors premier lot
|
||||
```
|
||||
|
||||
Aucune nouvelle dépendance n'est justifiée par `pre.001`.
|
||||
|
||||
## 6. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
deltas/0.2.13/pre.001.md
|
||||
```
|
||||
|
||||
## 7. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/validation/000-README.md
|
||||
```
|
||||
|
||||
`workspace.package.version` passe à `0.2.13-pre.1` conformément au workflow des prereleases non-fix.
|
||||
|
||||
## 8. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 9. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
prompts/018-V0_2_13_START_PROMPT.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/architecture/**
|
||||
crates/**
|
||||
config/**
|
||||
.env.example
|
||||
```
|
||||
|
||||
La roadmap/séquence/architecture possèdent déjà les frontières `0.2.13` / `0.2.14` / `0.3.2`. `pre.001` les confronte à la base réelle dans le nouveau plan sans les réécrire par duplication. `ROADMAP.md` et `CHANGELOG.md` restent hors du couloir de cette tranche.
|
||||
|
||||
## 10. Audit interne exécuté
|
||||
|
||||
Points confirmés :
|
||||
|
||||
```text
|
||||
Core réexporte Pubkey et possède les Program IDs fondamentaux
|
||||
Core possède Error/Result communs
|
||||
Transport possède encore les projections HTTP/WS/Yellowstone concrètes
|
||||
aucun besoin de déplacer ces DTOs vers Interface en 0.2.13
|
||||
Interface ne doit pas dépendre de Program/Transport/Store/Wallet/Config
|
||||
Program API pourra dépendre de Core + Interface en 0.2.14
|
||||
wires d'acquisition/CORE génériques restent réservés à 0.3.2+
|
||||
workspace n'a pas solana-instruction/borsh/wincode comme besoin Interface actuel
|
||||
```
|
||||
|
||||
## 11. Threat model et tests décidés
|
||||
|
||||
```text
|
||||
accounts 255 accepté
|
||||
accounts 256 refusé
|
||||
data 10_240 accepté
|
||||
data 10_241 refusé
|
||||
empty accounts/data accepté
|
||||
ordre + doublons préservés
|
||||
unknown Program Pubkey accepté
|
||||
Debug instruction résumé borné
|
||||
payload hostile dans Debug/Error absent
|
||||
serde hostile éliminé par absence de serde
|
||||
malformed/discriminant N/A tant qu'aucun codec n'est retenu
|
||||
panic/unwrap/expect/? audits/lints KSP
|
||||
network smoke non requis
|
||||
public API / external consumer requis
|
||||
cargo tree / dependency firewall requis dès scaffold
|
||||
```
|
||||
|
||||
## 12. Validations exécutées dans le sandbox
|
||||
|
||||
Avant modification, sur l'archive stable extraite :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... deltas/0.2.13 PASS
|
||||
```
|
||||
|
||||
La preuve opérateur fournie sur le checkout stable `0.2.12` établit :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
Rust rules audit PASS
|
||||
Markdown table audit PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Après génération du présent overlay :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
KSP workspace Rust rule audit clean
|
||||
python3 scripts/audit_markdown_tables.py ... deltas/0.2.13 PASS
|
||||
tables / files 160 / 111
|
||||
```
|
||||
|
||||
## 13. Validations non exécutées dans ce sandbox
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Cause : executable `cargo` absent du sandbox de préparation. `ksp-interface-lib` n'existe pas encore par contrat de `pre.001`, donc les graphes propres à la crate commenceront avec `pre.002`.
|
||||
|
||||
Aucune commande non exécutée localement n'est déclarée PASS.
|
||||
|
||||
## 14. Forecast souple recalibré
|
||||
|
||||
### pre.001 — audit + héritage + frontières + sizing
|
||||
|
||||
**Statut : livré par le présent delta.**
|
||||
|
||||
### pre.002 — scaffold `ksp-interface-lib` + façade + firewall
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.003 — `ProgramAccountMeta` + bornes communes
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.004 — `ProgramInstruction` passif borné
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.005 — adversarial + consumer externe + API/dependency hardening
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.006 — gate technique final
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.007 — réconciliation documentaire finale
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### pre.008 — préparation de publication minimale
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
### rel.001 — publication stable
|
||||
|
||||
**Statut : prévu.**
|
||||
|
||||
Le second lot wire optionnel du forecast initial est supprimé : aucun second domaine ne justifie une tranche dans cette foundation. Le scope reste compatible avec une release/session.
|
||||
|
||||
## 15. Questions ouvertes
|
||||
|
||||
Aucune question bloquante pour `pre.002`.
|
||||
|
||||
Les noms exacts des codes d'erreur et le détail final des accessors peuvent encore être ajustés dans `pre.003`/`pre.004` sans rouvrir l'ownership, les bornes ou le scope de release.
|
||||
|
||||
## 16. Validation opérateur après application
|
||||
|
||||
Exécuter :
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
`pre.002` ne commence qu'après retour du gate appliqué.
|
||||
205
deltas/0.2.13/pre.002.md
Normal file
205
deltas/0.2.13/pre.002.md
Normal file
@@ -0,0 +1,205 @@
|
||||
<!-- file: deltas/0.2.13/pre.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.002` — scaffold `ksp-interface-lib`
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.12
|
||||
+ 0.2.13-pre.001
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour `pre.001` est intégralement vert : `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace`, Clippy workspace et `cargo test --workspace` passent.
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.13-pre.1
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.13-pre.2
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Créer uniquement le scaffold de `ksp-interface-lib` et verrouiller sa frontière avant les types wire fonctionnels.
|
||||
|
||||
La tranche matérialise :
|
||||
|
||||
```text
|
||||
nouveau membre workspace ksp-interface-lib
|
||||
manifest avec ksp-core-lib comme seule dépendance normale
|
||||
façade crate-root explicite
|
||||
réexport contrôlé de ksp_core_lib::Pubkey
|
||||
README/USAGE initiaux
|
||||
canari public API minimal
|
||||
canari dependency firewall
|
||||
```
|
||||
|
||||
Elle ne matérialise pas encore :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
bornes instruction
|
||||
codes d'erreur Interface
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
network/runtime
|
||||
Program behavior
|
||||
```
|
||||
|
||||
## 3. Décision Logging
|
||||
|
||||
`0.2.13` reste une foundation de contrats passifs. Aucun comportement runtime n'est actuellement prévu dans `ksp-interface-lib`, donc aucun événement/span n'a besoin d'être émis.
|
||||
|
||||
En conséquence, la tranche maintient explicitement absents :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
src/constants.rs
|
||||
TRACING_TARGET
|
||||
tracing direct
|
||||
```
|
||||
|
||||
Cette absence est volontaire et couverte par le canari de dépendances. Si un comportement runtime réel apparaît dans une future évolution d'Interface, l'instrumentation devra être ajoutée via `ksp-logging-lib`; `DEP-LOG-010` imposera alors un `pub(crate) const TRACING_TARGET: &str` possédé par `src/constants.rs`.
|
||||
|
||||
Les futures validations de bornes de `pre.003`/`pre.004` doivent retourner des erreurs structurées ; elles ne justifient pas à elles seules des logs runtime.
|
||||
|
||||
## 4. Surface publique de scaffold
|
||||
|
||||
La seule primitive publique nouvellement exposée est :
|
||||
|
||||
```rust
|
||||
pub use ksp_core_lib::Pubkey;
|
||||
```
|
||||
|
||||
Ce réexport confirme l'ownership décidé : Interface n'introduit aucun wrapper `ProgramId`/`Pubkey` parallèle et utilisera la primitive Core dans ses futurs contrats wire.
|
||||
|
||||
La façade ne contient aucun `pub mod`. Les types d'instruction restent absents pour éviter d'avancer `pre.003`/`pre.004`.
|
||||
|
||||
## 5. Dependency firewall
|
||||
|
||||
Le manifest membre possède exactement :
|
||||
|
||||
```text
|
||||
[dependencies]
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
```
|
||||
|
||||
Le canari `tests/dependency_boundary.rs` vérifie notamment l'absence de :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
ksp-program-*
|
||||
ksp-*-transport-lib
|
||||
ksp-config-lib
|
||||
ksp-store-*
|
||||
ksp-wallet-lib
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
reqwest / tokio / tonic / tauri / tracing
|
||||
```
|
||||
|
||||
Il verrouille aussi l'absence de `src/constants.rs` et `TRACING_TARGET` tant que la crate reste passive.
|
||||
|
||||
## 6. Tests ajoutés
|
||||
|
||||
`tests/public_api.rs` vérifie que le `Pubkey` canonique est consommable uniquement depuis le crate-root Interface.
|
||||
|
||||
`tests/dependency_boundary.rs` vérifie :
|
||||
|
||||
```text
|
||||
dépendance normale exacte = ksp-core-lib
|
||||
absence des dépendances interdites
|
||||
absence de ProgramAccountMeta/ProgramInstruction en pre.002
|
||||
absence de surface Logging runtime
|
||||
```
|
||||
|
||||
Aucun unit test métier n'est ajouté : aucune primitive fonctionnelle n'existe encore.
|
||||
|
||||
## 7. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-interface-lib/tests/public_api.rs
|
||||
deltas/0.2.13/pre.002.md
|
||||
```
|
||||
|
||||
## 8. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
## 9. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
.env.example
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-offchain-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
Aucune architecture durable n'est rouverte : le graphe `Interface -> Core`, avec Logging uniquement lorsqu'un runtime logging réel existe, est déjà documenté.
|
||||
|
||||
## 10. Validations de génération
|
||||
|
||||
Les audits Python sont rejoués sur l'arbre matérialisé avant livraison. Le sandbox de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`; aucun PASS Cargo nouveau n'est donc 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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le `cargo tree -p ksp-interface-lib --edges normal` doit montrer Core comme unique dépendance KSP directe et ne doit pas révéler de codec/runtime ajouté par Interface.
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.13-pre.002-fix.NNN` et n'avance pas `pre.003`.
|
||||
|
||||
## 12. Suite
|
||||
|
||||
Après gate vert, `pre.003` pourra matérialiser uniquement :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
constante de borne account metas
|
||||
modèle d'erreur Interface minimal nécessaire
|
||||
unit/public canaries correspondants
|
||||
```
|
||||
|
||||
`ProgramInstruction`, sa data bound et son Debug résumé restent réservés à `pre.004`.
|
||||
272
deltas/0.2.13/pre.003.md
Normal file
272
deltas/0.2.13/pre.003.md
Normal file
@@ -0,0 +1,272 @@
|
||||
<!-- file: deltas/0.2.13/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.003` — `ProgramAccountMeta` + borne accounts
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.12
|
||||
+ 0.2.13-pre.001
|
||||
+ 0.2.13-pre.002
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour `pre.002` est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal inspecté
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Le graphe ciblé confirme :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey 4.3.0
|
||||
```
|
||||
|
||||
Aucune dépendance codec/runtime n'est introduite par Interface et les doublons workspace observés sont préexistants à cette crate.
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.13-pre.2
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.13-pre.3
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Matérialiser uniquement la primitive passive représentant un account meta d'instruction Program, figer la borne publique du nombre d'account metas et introduire le code d'erreur Interface minimal nécessaire à la future admission de `ProgramInstruction`.
|
||||
|
||||
La tranche ajoute :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS = 255
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
unit tests de la primitive
|
||||
public API canaries correspondants
|
||||
```
|
||||
|
||||
Elle n'ajoute pas encore :
|
||||
|
||||
```text
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
enforcement de collection 255/256
|
||||
data payload
|
||||
Debug résumé d'instruction
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
logging/runtime
|
||||
Program behavior
|
||||
```
|
||||
|
||||
## 3. `ProgramAccountMeta`
|
||||
|
||||
La primitive possède trois champs privés :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
is_signer
|
||||
is_writable
|
||||
```
|
||||
|
||||
Les constructeurs publics sont :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta::readonly(pubkey, is_signer)
|
||||
ProgramAccountMeta::writable(pubkey, is_signer)
|
||||
```
|
||||
|
||||
Les accessors publics sont :
|
||||
|
||||
```text
|
||||
pubkey()
|
||||
is_signer()
|
||||
is_writable()
|
||||
```
|
||||
|
||||
Le type reste strictement passif :
|
||||
|
||||
- aucune validation de registry Program n'est appliquée au `Pubkey` ;
|
||||
- aucune policy signer/writable n'est inventée ;
|
||||
- aucune sérialisation ou conversion vers `solana-instruction::AccountMeta` n'est ajoutée ;
|
||||
- les champs privés empêchent une dérive future de représentation sans passer par l'API possédée par Interface.
|
||||
|
||||
## 4. Borne accounts
|
||||
|
||||
La façade expose :
|
||||
|
||||
```rust
|
||||
pub const MAX_PROGRAM_INSTRUCTION_ACCOUNTS: usize = 255;
|
||||
```
|
||||
|
||||
Cette constante fixe le plafond d'admission retenu par le plan `0.2.13`.
|
||||
|
||||
`pre.003` ne crée volontairement aucune collection artificielle autour de `ProgramAccountMeta` uniquement pour tester `255/256`. L'enforcement concret sera réalisé dans `ProgramInstruction::try_new` à `pre.004`, lorsque la collection existera réellement.
|
||||
|
||||
La borne data `10_240` reste également réservée à `pre.004` avec le payload qu'elle protège.
|
||||
|
||||
## 5. Modèle d'erreur minimal
|
||||
|
||||
Interface continue d'utiliser `ksp_core_lib::Error`, `ErrorCode` et `Result`; aucun second type d'erreur n'est introduit.
|
||||
|
||||
La seule catégorie matérialisée est :
|
||||
|
||||
```text
|
||||
interface.program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
via :
|
||||
|
||||
```text
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
Le code `invalid_program_instruction` n'est pas ajouté : aucun invariant de forme distinct des bornes n'existe encore dans la foundation. Le créer uniquement par symétrie serait prématuré.
|
||||
|
||||
À `pre.004`, les erreurs de borne devront limiter leur contexte aux longueurs et plafonds sûrs ; aucun payload ni compte arbitraire ne devra être copié dans les diagnostics.
|
||||
|
||||
## 6. Logging
|
||||
|
||||
La décision de `pre.002` reste inchangée. Interface est toujours une crate de contrats passifs et n'émet aucun événement/span runtime.
|
||||
|
||||
Restent donc absents :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
src/constants.rs
|
||||
TRACING_TARGET
|
||||
tracing direct
|
||||
```
|
||||
|
||||
## 7. Tests
|
||||
|
||||
Les unit tests de `ProgramAccountMeta` couvrent :
|
||||
|
||||
```text
|
||||
readonly -> identité/signature conservées, writable=false
|
||||
writable -> identité/signature conservées, writable=true
|
||||
Pubkey opaque/non registry accepté
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS == 255
|
||||
```
|
||||
|
||||
`tests/public_api.rs` prouve depuis le crate-root :
|
||||
|
||||
```text
|
||||
construction readonly/writable
|
||||
accessors publics
|
||||
borne accounts publique
|
||||
code d'erreur stable et typé par ksp_core_lib::ErrorCode
|
||||
```
|
||||
|
||||
`tests/dependency_boundary.rs` conserve le firewall `pre.002` et vérifie désormais que :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta est présent
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS est présent
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED est présent
|
||||
ProgramInstruction reste absent
|
||||
logging/runtime restent absents
|
||||
```
|
||||
|
||||
## 8. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/error.rs
|
||||
crates/ksp-interface-lib/src/program_account_meta.rs
|
||||
crates/ksp-interface-lib/unit_tests/program_account_meta.rs
|
||||
deltas/0.2.13/pre.003.md
|
||||
```
|
||||
|
||||
## 9. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-interface-lib/tests/public_api.rs
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
## 10. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
.env.example
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-offchain-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
README/USAGE restent dans leur lane de réconciliation finale `pre.007`; aucune documentation durable hors plan/validation n'est rouverte pour cette petite tranche fonctionnelle.
|
||||
|
||||
## 11. Validations de génération
|
||||
|
||||
Les audits Python sont rejoués sur l'arbre matérialisé avant livraison. Le sandbox de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`; aucun nouveau PASS Cargo n'est donc revendiqué localement.
|
||||
|
||||
## 12. 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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.13-pre.003-fix.NNN` et n'avance pas `pre.004`.
|
||||
|
||||
## 13. Suite
|
||||
|
||||
Après gate vert, `pre.004` pourra matérialiser uniquement :
|
||||
|
||||
```text
|
||||
ProgramInstruction { program_id, accounts, data }
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN = 10_240
|
||||
try_new borné
|
||||
accessors
|
||||
Debug résumé sans payload
|
||||
acceptation 0/255 accounts et 0/10_240 data
|
||||
rejet 256 accounts et 10_241 data
|
||||
ordre et doublons conservés
|
||||
contextes d'erreur sûrs
|
||||
```
|
||||
|
||||
Aucun serde/codec ou comportement Program ne doit être ajouté dans cette tranche suivante.
|
||||
295
deltas/0.2.13/pre.004.md
Normal file
295
deltas/0.2.13/pre.004.md
Normal file
@@ -0,0 +1,295 @@
|
||||
<!-- file: deltas/0.2.13/pre.004.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.004` — `ProgramInstruction` passif borné
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.12
|
||||
+ 0.2.13-pre.001
|
||||
+ 0.2.13-pre.002
|
||||
+ 0.2.13-pre.003
|
||||
```
|
||||
|
||||
La preuve opérateur fournie pour `pre.003` confirme :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal inspecté
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
`cargo test --workspace` n'apparaît pas dans cette preuve opérateur. La présente préparation n'en invente donc pas le résultat ; ce test devra être rejoué avec le gate de `pre.004` avant de déclarer la continuité workspace complète.
|
||||
|
||||
Le graphe ciblé reste strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey 4.3.0
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.13-pre.3
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.13-pre.4
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Matérialiser le second type du premier lot wire générique décidé en `pre.001` : une instruction Program passive `{ program_id, accounts, data }`, bornée à l'admission et sans comportement Program.
|
||||
|
||||
La tranche ajoute :
|
||||
|
||||
```text
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN = 10_240
|
||||
ProgramInstruction::try_new(...)
|
||||
accessors program_id/accounts/data
|
||||
Debug résumé
|
||||
unit/public canaries de limites, ordre et doublons
|
||||
```
|
||||
|
||||
Elle n'ajoute pas :
|
||||
|
||||
```text
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
codec ou discriminant Program spécifique
|
||||
Program API / Program behavior
|
||||
Transport / Store / Config / Wallet
|
||||
ksp-logging-lib / constants.rs / TRACING_TARGET
|
||||
runtime réseau
|
||||
```
|
||||
|
||||
## 3. `ProgramInstruction`
|
||||
|
||||
Le type possède trois champs privés :
|
||||
|
||||
```text
|
||||
program_id : Pubkey
|
||||
accounts : Vec<ProgramAccountMeta>
|
||||
data : Vec<u8>
|
||||
```
|
||||
|
||||
Le constructeur public est :
|
||||
|
||||
```text
|
||||
ProgramInstruction::try_new(program_id, accounts, data)
|
||||
-> ksp_core_lib::Result<ProgramInstruction>
|
||||
```
|
||||
|
||||
Les accessors publics sont :
|
||||
|
||||
```text
|
||||
program_id() -> &Pubkey
|
||||
accounts() -> &[ProgramAccountMeta]
|
||||
data() -> &[u8]
|
||||
```
|
||||
|
||||
La construction consomme directement les `Vec` fournis. Aucun clone interne, conversion vers `solana-instruction` ou sérialisation n'est ajouté.
|
||||
|
||||
## 4. Bornes d'admission
|
||||
|
||||
Les deux plafonds sont désormais matérialisés :
|
||||
|
||||
```text
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS = 255
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN = 10_240
|
||||
```
|
||||
|
||||
`try_new` vérifie en `usize` :
|
||||
|
||||
```text
|
||||
accounts.len() <= 255
|
||||
data.len() <= 10_240
|
||||
```
|
||||
|
||||
Canaris exacts :
|
||||
|
||||
```text
|
||||
255 accounts accepté
|
||||
256 accounts refusé
|
||||
10_240 octets data accepté
|
||||
10_241 octets data refusé
|
||||
```
|
||||
|
||||
Ces valeurs restent des bornes d'admission Interface fondées sur les plafonds Solana CPI audités en `pre.001`. Elles ne garantissent pas qu'une instruction rentre dans une transaction top-level complète.
|
||||
|
||||
## 5. Sémantique passive
|
||||
|
||||
Restent valides :
|
||||
|
||||
```text
|
||||
accounts vides
|
||||
data vide
|
||||
Program Pubkey inconnu du registry Core
|
||||
doublons d'accounts
|
||||
ordre arbitraire des account metas
|
||||
payload opaque quelconque sous la borne
|
||||
```
|
||||
|
||||
Interface n'ajoute aucune politique signer/writable, aucun lookup de Program ID, aucune déduplication et aucune interprétation du payload.
|
||||
|
||||
## 6. Erreurs
|
||||
|
||||
Les deux violations de borne réutilisent :
|
||||
|
||||
```text
|
||||
interface.program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
via `ksp_core_lib::Error/Result`.
|
||||
|
||||
Le contexte d'erreur est limité à :
|
||||
|
||||
```text
|
||||
field
|
||||
actual_len
|
||||
maximum_len
|
||||
```
|
||||
|
||||
Aucun octet `data`, aucun account arbitraire et aucun payload externe n'est copié dans l'erreur.
|
||||
|
||||
Le code conceptuel `invalid_program_instruction` reste absent : la foundation ne possède toujours aucun invariant de forme distinct des deux limites.
|
||||
|
||||
## 7. Debug borné
|
||||
|
||||
`ProgramInstruction` n'utilise pas un `derive(Debug)` qui imprimerait les deux `Vec`.
|
||||
|
||||
Son `Debug` manuel expose uniquement :
|
||||
|
||||
```text
|
||||
program_id
|
||||
account_count
|
||||
data_len
|
||||
```
|
||||
|
||||
Les account metas et le payload sont volontairement absents du rendu.
|
||||
|
||||
## 8. Logging
|
||||
|
||||
La décision de `pre.002` reste inchangée : cette crate est passive.
|
||||
|
||||
Restent absents :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
src/constants.rs
|
||||
TRACING_TARGET
|
||||
tracing direct
|
||||
```
|
||||
|
||||
Une erreur de validation de borne est une valeur retournée au caller, pas un événement runtime à logger depuis Interface.
|
||||
|
||||
## 9. Tests
|
||||
|
||||
Les unit tests de `ProgramInstruction` couvrent :
|
||||
|
||||
```text
|
||||
accounts/data vides acceptés
|
||||
Program Pubkey opaque accepté
|
||||
ordre et doublons préservés
|
||||
payload opaque préservé
|
||||
255 / 256 accounts
|
||||
10_240 / 10_241 octets data
|
||||
code/message/contexte d'erreur sûr
|
||||
Debug résumé sans payload ni account flags
|
||||
```
|
||||
|
||||
`tests/public_api.rs` ajoute un canari de consommation crate-root de `ProgramInstruction` et de `MAX_PROGRAM_INSTRUCTION_DATA_LEN`.
|
||||
|
||||
`tests/dependency_boundary.rs` est avancé à `pre.004` et confirme toujours :
|
||||
|
||||
```text
|
||||
ksp-core-lib seule dépendance normale
|
||||
aucun serde/borsh/bincode/wincode
|
||||
aucun solana-instruction
|
||||
aucun logging/runtime
|
||||
ProgramInstruction présent via façade explicite
|
||||
```
|
||||
|
||||
## 10. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/program_instruction.rs
|
||||
crates/ksp-interface-lib/unit_tests/program_instruction.rs
|
||||
deltas/0.2.13/pre.004.md
|
||||
```
|
||||
|
||||
## 11. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-interface-lib/tests/public_api.rs
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
## 12. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
.env.example
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
crates/ksp-interface-lib/src/error.rs
|
||||
crates/ksp-interface-lib/src/program_account_meta.rs
|
||||
crates/ksp-interface-lib/unit_tests/program_account_meta.rs
|
||||
docs/architecture/**
|
||||
prompts/**
|
||||
config/**
|
||||
```
|
||||
|
||||
## 13. Gate attendu
|
||||
|
||||
Après application de l'overlay :
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le `cargo test --workspace` est particulièrement requis ici puisqu'il n'était pas présent dans la preuve opérateur fournie pour `pre.003`.
|
||||
|
||||
## 14. Suite autorisée
|
||||
|
||||
Après gate vert, `pre.005` doit rester une tranche de hardening :
|
||||
|
||||
```text
|
||||
cas adversariaux complémentaires
|
||||
consumer externe
|
||||
surface crate-root
|
||||
firewall source/manifest
|
||||
graphes Cargo
|
||||
canari de complétude du premier lot
|
||||
```
|
||||
|
||||
Aucun second domaine wire, codec générique ou comportement Program ne doit être ajouté opportunément.
|
||||
137
deltas/0.2.13/pre.005-fix.001.md
Normal file
137
deltas/0.2.13/pre.005-fix.001.md
Normal file
@@ -0,0 +1,137 @@
|
||||
<!-- file: deltas/0.2.13/pre.005-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.005-fix.001` — faux positif du scanner Logging
|
||||
|
||||
## 1. Déclencheur
|
||||
|
||||
Le gate opérateur de `pre.005` confirme :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS / clean
|
||||
python3 scripts/audit_markdown_tables.py ... PASS / clean
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace FAIL
|
||||
cargo tree -p ksp-interface-lib --edges normal Core-only confirmé
|
||||
cargo tree --duplicates fourni
|
||||
```
|
||||
|
||||
Le test ciblé Interface est entièrement vert :
|
||||
|
||||
```text
|
||||
unit tests 10/10
|
||||
manifest/source firewall 4/4
|
||||
external consumer 1/1
|
||||
public API 5/5
|
||||
release completeness 3/3
|
||||
```
|
||||
|
||||
Le workspace échoue uniquement ici :
|
||||
|
||||
```text
|
||||
ksp-logging-lib/tests/ownership.rs
|
||||
workspace_crates_do_not_bypass_ksp_logging_facade
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs bypasses ksp-logging-lib via tracing
|
||||
```
|
||||
|
||||
## 2. Cause exacte
|
||||
|
||||
Le scanner Logging recherche le chemin littéral :
|
||||
|
||||
```text
|
||||
tracing::
|
||||
```
|
||||
|
||||
sur le texte brut de tous les fichiers Rust des crates KSP, tests compris.
|
||||
|
||||
Le hardening `pre.005` a ajouté ce même littéral dans `tests/dependency_boundary.rs` comme **pattern interdit à rechercher dans les sources de production**. Il ne s'agit donc ni d'un import, ni d'un appel runtime, ni d'une dépendance Interface vers Tracing : le scanner transversal détecte simplement la donnée de son canari voisin.
|
||||
|
||||
Le graphe Cargo opérateur confirme toujours :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey 4.3.0
|
||||
```
|
||||
|
||||
## 3. Correction
|
||||
|
||||
Le firewall Interface conserve strictement la même vérification, mais le token est écrit sans matérialiser `tracing::` contigu dans le source du test :
|
||||
|
||||
```rust
|
||||
concat!("tracing", "::")
|
||||
```
|
||||
|
||||
La valeur produite à la compilation reste exactement `tracing::`. Le test Interface continue donc d'échouer si un module de production utilise directement ce chemin.
|
||||
|
||||
Aucun `allow`, aucune exclusion de fichier et aucun affaiblissement du scanner Logging ne sont introduits.
|
||||
|
||||
## 4. Version
|
||||
|
||||
Le fix modifie un test Rust ; la version workspace devient :
|
||||
|
||||
```text
|
||||
0.2.13-pre.5.fix.1
|
||||
```
|
||||
|
||||
Commit attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.13-pre.005-fix.001
|
||||
```
|
||||
|
||||
Aucun tag prerelease.
|
||||
|
||||
## 5. Frontières
|
||||
|
||||
Inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
surface publique Interface
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
bornes 255 / 10_240
|
||||
Error/Result Core
|
||||
ksp-logging-lib absent d'Interface
|
||||
constants.rs absent
|
||||
TRACING_TARGET absent
|
||||
serde/borsh/bincode/wincode absents
|
||||
solana-instruction absent
|
||||
```
|
||||
|
||||
## 6. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
deltas/0.2.13/pre.005-fix.001.md
|
||||
```
|
||||
|
||||
## 7. Gate opérateur
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
`pre.006` reste interdit tant que ce gate n'est pas intégralement vert.
|
||||
213
deltas/0.2.13/pre.005.md
Normal file
213
deltas/0.2.13/pre.005.md
Normal file
@@ -0,0 +1,213 @@
|
||||
<!-- file: deltas/0.2.13/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.005` — hardening adversarial + consumer externe + complétude
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.12
|
||||
+ 0.2.13-pre.001
|
||||
+ 0.2.13-pre.002
|
||||
+ 0.2.13-pre.003
|
||||
+ 0.2.13-pre.004
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour `pre.004` est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal inspecté
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Le graphe ciblé reste strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey 4.3.0
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.13-pre.4
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.13-pre.5
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Fermer le hardening du premier lot wire générique sans ajouter de capacité fonctionnelle ni de second domaine wire.
|
||||
|
||||
La tranche ajoute uniquement des preuves :
|
||||
|
||||
```text
|
||||
consumer externe crate-root
|
||||
inventaire exact de complétude release
|
||||
firewall source/manifest renforcé
|
||||
absence de narrowing/codec caché
|
||||
transfert sans réallocation des Vec admis
|
||||
absence de contenu hostile dans les erreurs de limite
|
||||
public API boundary canary
|
||||
```
|
||||
|
||||
Aucun fichier `src/` de production n'est modifié.
|
||||
|
||||
## 3. Consumer externe
|
||||
|
||||
`tests/external_consumer.rs` constitue le canari downstream. Comme tout integration test Rust, il est compilé comme un crate distinct de la bibliothèque et utilise exclusivement :
|
||||
|
||||
```text
|
||||
ksp_interface_lib::Pubkey
|
||||
ksp_interface_lib::ProgramAccountMeta
|
||||
ksp_interface_lib::ProgramInstruction
|
||||
ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
Aucun chemin vers un module privé n'est requis.
|
||||
|
||||
## 4. Complétude de release
|
||||
|
||||
`tests/release_completeness.rs` verrouille exactement les six exports crate-root retenus pour `0.2.13` et refuse une façade `pub mod`.
|
||||
|
||||
Il verrouille également l'inventaire des fichiers Rust de production :
|
||||
|
||||
```text
|
||||
error.rs
|
||||
lib.rs
|
||||
program_account_meta.rs
|
||||
program_instruction.rs
|
||||
```
|
||||
|
||||
Ce canari rend explicite qu'un second lot wire, un codec générique, un runtime ou un nouveau domaine ne peut pas être ajouté silencieusement dans cette release.
|
||||
|
||||
## 5. Hardening adversarial
|
||||
|
||||
Les unit tests de `ProgramInstruction` sont renforcés sur deux propriétés.
|
||||
|
||||
Premièrement, les pointeurs des `Vec<ProgramAccountMeta>` et `Vec<u8>` sont capturés avant `try_new` puis comparés aux slices exposés après construction. Le canari prouve que l'implémentation courante transfère les allocations admises sans clone/réallocation interne.
|
||||
|
||||
Deuxièmement, les deux branches d'erreur de limite sont confrontées à du matériel hostile : payload avec marqueur explicite et account meta arbitraire. Les rendus/contextes d'erreur doivent rester bornés aux champs sûrs déjà définis :
|
||||
|
||||
```text
|
||||
field
|
||||
actual_len
|
||||
maximum_len
|
||||
```
|
||||
|
||||
Aucun payload ni account meta n'est recopié dans l'erreur.
|
||||
|
||||
## 6. Dependency/API firewall
|
||||
|
||||
`tests/dependency_boundary.rs` conserve l'exigence manifeste :
|
||||
|
||||
```text
|
||||
ksp-core-lib = seule dépendance normale
|
||||
```
|
||||
|
||||
et étend le scan à tous les fichiers Rust de production pour interdire les chemins directs vers :
|
||||
|
||||
```text
|
||||
Program/Store/Transport/Config/Wallet
|
||||
serde/serde_json
|
||||
borsh/bincode/wincode
|
||||
solana-instruction
|
||||
reqwest/tokio/tonic/tauri
|
||||
tracing/ksp-logging-lib
|
||||
```
|
||||
|
||||
Un canari dédié refuse également les casts étroits et les points d'entrée génériques `serialize/deserialize/encode/decode` dans `program_instruction.rs`.
|
||||
|
||||
## 7. Public API
|
||||
|
||||
`tests/public_api.rs` ajoute un test de rejet `10_241` bytes depuis un consumer externe au module privé et vérifie que le caller reçoit le code Core commun ainsi que les trois contextes sûrs attendus.
|
||||
|
||||
Aucune nouvelle API publique n'est créée par `pre.005`.
|
||||
|
||||
## 8. Logging et codecs
|
||||
|
||||
La décision reste inchangée : Interface est passive.
|
||||
|
||||
Toujours absents :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
constants.rs
|
||||
TRACING_TARGET
|
||||
tracing direct
|
||||
serde
|
||||
borsh
|
||||
bincode
|
||||
wincode
|
||||
solana-instruction
|
||||
```
|
||||
|
||||
## 9. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/tests/external_consumer.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
deltas/0.2.13/pre.005.md
|
||||
```
|
||||
|
||||
## 10. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-interface-lib/tests/public_api.rs
|
||||
crates/ksp-interface-lib/unit_tests/program_instruction.rs
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
## 11. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
.env.example
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/unit_tests/program_account_meta.rs
|
||||
docs/architecture/**
|
||||
prompts/**
|
||||
config/**
|
||||
```
|
||||
|
||||
## 12. Gate attendu
|
||||
|
||||
Après application de l'overlay :
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Si ce gate est vert, `pre.006` doit rester un gate technique final sans nouveau développement fonctionnel.
|
||||
141
deltas/0.2.13/pre.006.md
Normal file
141
deltas/0.2.13/pre.006.md
Normal file
@@ -0,0 +1,141 @@
|
||||
<!-- file: deltas/0.2.13/pre.006.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.006` — gate technique final Interface
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement après `0.2.13-pre.005-fix.001`.
|
||||
|
||||
Le gate opérateur du fix est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS / clean
|
||||
python3 scripts/audit_markdown_tables.py ... PASS / clean
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal Core-only confirmé
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Le faux positif `tracing::` de `pre.005` est donc fermé sans changement de production ni de dépendances.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Préparer le gate technique final de `0.2.13` sans rouvrir la surface fonctionnelle.
|
||||
|
||||
Aucun nouveau type wire, aucun codec, aucun test métier, aucune dépendance et aucun comportement runtime ne sont ajoutés. Les canaris existants suffisent déjà à vérifier :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
bornes 255 / 10_240
|
||||
ordre et doublons
|
||||
Pubkey opaque
|
||||
Debug borné
|
||||
erreurs sans payload hostile
|
||||
consumer externe
|
||||
façade crate-root
|
||||
inventaire exact de production
|
||||
firewall source / manifest
|
||||
Core-only dependency graph
|
||||
```
|
||||
|
||||
## 3. Décision de tranche
|
||||
|
||||
`pre.006` reste un gate pur. Ajouter un nouveau test uniquement pour matérialiser le numéro de prerelease augmenterait la surface de changement sans renforcer une propriété non couverte. La tranche modifie donc seulement la version workspace, le plan, la validation et le présent delta.
|
||||
|
||||
## 4. Version
|
||||
|
||||
La prerelease non-fix synchronise la version Cargo conformément à `VER-ID-009` :
|
||||
|
||||
```text
|
||||
0.2.13-pre.5.fix.1
|
||||
→
|
||||
0.2.13-pre.6
|
||||
```
|
||||
|
||||
Commit attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.13-pre.006
|
||||
```
|
||||
|
||||
Aucun tag prerelease.
|
||||
|
||||
## 5. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.2.13/pre.006.md
|
||||
```
|
||||
|
||||
## 6. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
## 7. Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## 8. Surface explicitement inchangée
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/tests/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/**
|
||||
architectures / règles
|
||||
```
|
||||
|
||||
La réconciliation README/USAGE et des documents durables reste réservée à `pre.007`. La préparation du prompt suivant, du CHANGELOG et du ROADMAP reste réservée à `pre.008`.
|
||||
|
||||
## 9. Validations exécutées à la génération
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS / clean
|
||||
python3 scripts/audit_markdown_tables.py ... PASS / clean (162 tables, 119 files)
|
||||
contrôle du diff PASS / 3 modifiés + 1 ajouté
|
||||
```
|
||||
|
||||
Aucun `cargo` n'est disponible dans l'environnement de génération ; aucun PASS Cargo local n'est revendiqué.
|
||||
|
||||
## 10. Gate opérateur
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
## 11. Décisions prises
|
||||
|
||||
- le scope fonctionnel `0.2.13` est figé ;
|
||||
- aucun codec générique n'est introduit ;
|
||||
- Interface reste passive et sans logging runtime ;
|
||||
- `ksp-core-lib` reste l'unique dépendance normale directe ;
|
||||
- aucun smoke réseau n'est pertinent pour cette crate wire pure ;
|
||||
- `pre.007` ne commence qu'après gate `pre.006` intégralement vert.
|
||||
|
||||
## 12. Questions ouvertes
|
||||
|
||||
Aucune question technique bloquante pour `0.2.13`. La seule étape suivante après gate vert est la réconciliation documentaire finale.
|
||||
192
deltas/0.2.13/pre.007.md
Normal file
192
deltas/0.2.13/pre.007.md
Normal file
@@ -0,0 +1,192 @@
|
||||
<!-- file: deltas/0.2.13/pre.007.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.007` — réconciliation documentaire finale Interface
|
||||
|
||||
## 1. Base
|
||||
|
||||
```text
|
||||
0.2.13-pre.006
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.006`, exécuté le **28 août 2026**, est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audits Rust / export completeness / workspace PASS
|
||||
audit Markdown PASS — 162 tables / 119 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal Core-only confirmé
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
La lane technique est donc fermée avant cette tranche.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
`pre.007` est exclusivement le couloir de réconciliation documentaire finale de `0.2.13`. Aucun fichier Rust, test, manifest de crate, dépendance, codec ou comportement n'est modifié.
|
||||
|
||||
La tranche transforme les README/USAGE initiaux d'Interface en références durables et aligne plan, validation, séquence fonctionnelle et index documentaires sur la surface réellement validée.
|
||||
|
||||
## 3. Version technique
|
||||
|
||||
```text
|
||||
0.2.13-pre.6
|
||||
->
|
||||
0.2.13-pre.7
|
||||
```
|
||||
|
||||
Le bump est mécanique pour une prerelease non-fix. Aucun autre manifest/version applicative n'est synchronisé artificiellement.
|
||||
|
||||
## 4. Surface finale candidate documentée
|
||||
|
||||
```text
|
||||
Pubkey réexport Core
|
||||
ProgramAccountMeta passif, champs privés
|
||||
ProgramInstruction passif, champs privés
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS 255
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN 10_240
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED interface.program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
Les propriétés réconciliées sont :
|
||||
|
||||
```text
|
||||
accounts ordonnés préservés
|
||||
doublons accounts préservés
|
||||
accounts/data vides acceptés
|
||||
Program Pubkey hors registry accepté
|
||||
Vec accounts/data consommés sans reformatage interne
|
||||
Debug ProgramInstruction program_id/account_count/data_len uniquement
|
||||
erreur de borne field/actual_len/maximum_len uniquement
|
||||
```
|
||||
|
||||
Les limites `255` et `10_240` restent explicitement des bornes d'admission Interface et non une garantie complète de fit transaction Solana top-level.
|
||||
|
||||
## 5. Dependency firewall final
|
||||
|
||||
Le graphe normal confirmé par l'opérateur reste :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey
|
||||
```
|
||||
|
||||
La foundation ne dépend pas de :
|
||||
|
||||
```text
|
||||
serde / serde_json
|
||||
borsh / wincode / bincode
|
||||
solana-instruction
|
||||
Transport / Config / Store / Wallet / Program
|
||||
reqwest / tonic / tokio / Tauri
|
||||
ksp-logging-lib / tracing runtime
|
||||
```
|
||||
|
||||
L'absence de runtime logging est volontaire : la surface actuelle est purement passive.
|
||||
|
||||
## 6. Références durables réconciliées
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
Le README Interface fixe l'ownership, la surface publique, les bornes, le modèle d'erreur, le Debug borné, le graphe et les frontières de responsabilité.
|
||||
|
||||
`USAGE.md` documente l'usage crate-root de `ProgramAccountMeta` et `ProgramInstruction`, les accessors, les limites et l'observation des erreurs sans accès aux modules privés.
|
||||
|
||||
La séquence fonctionnelle enregistre le contenu effectivement livré par `0.2.13`, tout en maintenant :
|
||||
|
||||
```text
|
||||
0.2.14 Program API foundation
|
||||
0.3.2+ wires génériques acquisition/CORE
|
||||
```
|
||||
|
||||
## 7. Fichiers ajoutés/modifiés
|
||||
|
||||
Ajouté :
|
||||
|
||||
```text
|
||||
deltas/0.2.13/pre.007.md
|
||||
```
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
Aucun fichier supprimé.
|
||||
|
||||
## 8. Surfaces volontairement inchangées
|
||||
|
||||
Cette tranche ne touche pas :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/tests/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
docs/architecture/**
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/**
|
||||
```
|
||||
|
||||
Les architectures existantes sont déjà compatibles avec la foundation réellement livrée et ne nécessitent aucune réécriture de clôture.
|
||||
|
||||
## 9. Gate opérateur
|
||||
|
||||
La tranche étant documentaire hors bump workspace, le gate demandé reste déterministe :
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke réseau/live ni nouveau `cargo tree` n'est requis si l'overlay est appliqué exactement : ces preuves appartiennent à la lane technique fermée par `pre.006`.
|
||||
|
||||
## 10. Suite
|
||||
|
||||
Si le gate est vert :
|
||||
|
||||
```text
|
||||
0.2.13-pre.008 — préparation minimale de publication
|
||||
```
|
||||
|
||||
`pre.008` reste limitée à :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
deltas/0.2.13/pre.008.md
|
||||
```
|
||||
|
||||
Aucun code, test, README/USAGE, plan, validation ou architecture ne doit être rouvert dans cette lane de publication minimale sauf défaut réel découvert au gate.
|
||||
233
deltas/0.2.13/pre.008.md
Normal file
233
deltas/0.2.13/pre.008.md
Normal file
@@ -0,0 +1,233 @@
|
||||
<!-- file: deltas/0.2.13/pre.008.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-pre.008` — préparation minimale de publication
|
||||
|
||||
## 1. Base
|
||||
|
||||
```text
|
||||
0.2.13-pre.007
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.007`, exécuté le **28 août 2026**, est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audits Rust / export completeness / workspace PASS
|
||||
audit Markdown PASS — 164 tables / 120 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
La réconciliation documentaire finale est donc fermée avant cette tranche.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
`pre.008` est exclusivement la lane minimale de préparation de publication de `0.2.13` imposée par `VER-LIFECYCLE-003` et `PROMPT_STRUCTURE.md`.
|
||||
|
||||
Elle ne rouvre aucun code, test, README/USAGE, plan, validation, architecture, règle ou configuration.
|
||||
|
||||
Elle :
|
||||
|
||||
```text
|
||||
bump la prerelease Cargo vers pre.8
|
||||
prépare l'entrée CHANGELOG stable 0.2.13
|
||||
synchronise le statut global ROADMAP
|
||||
ajoute le prompt autonome 0.2.14
|
||||
trace cette préparation dans le delta
|
||||
```
|
||||
|
||||
## 3. Version technique
|
||||
|
||||
```text
|
||||
0.2.13-pre.7
|
||||
->
|
||||
0.2.13-pre.8
|
||||
```
|
||||
|
||||
Le bump est mécanique pour une prerelease non-fix.
|
||||
|
||||
## 4. Changelog / Roadmap
|
||||
|
||||
`CHANGELOG.md` prépare l'entrée stable :
|
||||
|
||||
```text
|
||||
0.2.13 — Interface / wire foundation — 2026-08-28
|
||||
```
|
||||
|
||||
Le résumé conserve les faits de clôture réellement prouvés :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta + ProgramInstruction passifs
|
||||
255 account metas / 10_240 bytes
|
||||
Error/Debug sans payload hostile
|
||||
graphe Interface -> Core uniquement
|
||||
aucun serde/codec générique/solana-instruction/network/logging
|
||||
canaris public API / external consumer / dependency firewall / completeness
|
||||
pre.005-fix.001 limité au faux positif scanner Logging
|
||||
gates techniques et documentaires finaux verts
|
||||
```
|
||||
|
||||
`ROADMAP.md` marque `0.2.13` comme terminé et maintient `0.2.14` comme prochaine release active.
|
||||
|
||||
## 5. Prompt `0.2.14`
|
||||
|
||||
Ajout :
|
||||
|
||||
```text
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
```
|
||||
|
||||
Le prompt ouvre :
|
||||
|
||||
```text
|
||||
0.2.14 — Program API foundation
|
||||
```
|
||||
|
||||
exclusivement depuis :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
```
|
||||
|
||||
Le démarrage exige explicitement **deux archives** :
|
||||
|
||||
```text
|
||||
archive opérateur KSP v0.2.13
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
Ordre d'autorité fixé :
|
||||
|
||||
```text
|
||||
v0.2.13 + règles/architecture KSP autorité actuelle
|
||||
kbot3 historique audit/héritage uniquement
|
||||
```
|
||||
|
||||
L'archive kbot3 est obligatoire pour le gate `pre.001` afin d'auditer réellement les anciens contrats :
|
||||
|
||||
```text
|
||||
ks-lib/src/decoder/api/contracts.rs
|
||||
ks-lib/src/decoder/api/decoder.rs
|
||||
ks-lib/src/model/decoded.rs
|
||||
ks-lib/src/model/replay.rs
|
||||
ks-lib/src/model/solana.rs
|
||||
ks-lib/src/executor/api/execution.rs
|
||||
ks-lib/src/executor/api/executor.rs
|
||||
```
|
||||
|
||||
Le prompt impose la matrice :
|
||||
|
||||
```text
|
||||
REPRENDRE
|
||||
REDESSINER
|
||||
REPORTER
|
||||
REJETER
|
||||
```
|
||||
|
||||
et protège notamment les frontières :
|
||||
|
||||
```text
|
||||
Core = Pubkey / Program IDs / Error
|
||||
Interface = wire passif
|
||||
Program API = comportements/contracts extensibles
|
||||
Program Lib = implémentations officielles futures
|
||||
CORE futur = replay/context transaction/CPI/logs/return data/balance deltas
|
||||
Execution futur = policy/wallet/network/simulation/send/confirmation
|
||||
```
|
||||
|
||||
La prévision souple initiale réserve distinctement audit/sizing, scaffold, contracts, hardening, gate technique, réconciliation documentaire et préparation de publication.
|
||||
|
||||
## 6. Fichiers ajoutés/modifiés
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
deltas/0.2.13/pre.008.md
|
||||
```
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
```
|
||||
|
||||
Aucun fichier supprimé.
|
||||
|
||||
## 7. Surfaces volontairement inchangées
|
||||
|
||||
Cette tranche ne touche pas :
|
||||
|
||||
```text
|
||||
README.md
|
||||
RULES.md
|
||||
.env.example
|
||||
config/**
|
||||
crates/**
|
||||
docs/**
|
||||
prompts/001..018
|
||||
```
|
||||
|
||||
En particulier :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/tests/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
docs/architecture/**
|
||||
```
|
||||
|
||||
## 8. Validations de préparation
|
||||
|
||||
À exécuter dans l'environnement de préparation :
|
||||
|
||||
```text
|
||||
audit Rust workspace
|
||||
audit Markdown
|
||||
contrôle exact du payload overlay
|
||||
contrôle des versions/file headers
|
||||
```
|
||||
|
||||
Aucun résultat Cargo nouveau n'est revendiqué tant qu'il n'a pas été exécuté par l'opérateur sur `pre.008`.
|
||||
|
||||
## 9. Gate opérateur
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke réseau/live ni nouveau graphe Cargo n'est requis puisque cette lane ne modifie ni code ni dépendances.
|
||||
|
||||
## 10. Suite
|
||||
|
||||
Si le gate est vert :
|
||||
|
||||
```text
|
||||
0.2.13-rel.001
|
||||
```
|
||||
|
||||
La release finale effectue uniquement la mécanique de publication stable :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.13
|
||||
delta rel.001
|
||||
commit de publication
|
||||
tag stable v0.2.13 après validation opérateur
|
||||
```
|
||||
|
||||
`rel.001` ne doit contenir aucun rattrapage fonctionnel ou documentaire.
|
||||
285
deltas/0.2.13/rel.001.md
Normal file
285
deltas/0.2.13/rel.001.md
Normal file
@@ -0,0 +1,285 @@
|
||||
<!-- file: deltas/0.2.13/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.13-rel.001` — publication stable Interface / wire foundation
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Base directe attendue :
|
||||
|
||||
```text
|
||||
0.2.13-pre.008
|
||||
workspace.package.version = 0.2.13-pre.8
|
||||
```
|
||||
|
||||
Commit attendu pour cette livraison :
|
||||
|
||||
```text
|
||||
v0.2.13-rel.001
|
||||
```
|
||||
|
||||
Tag stable attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
```
|
||||
|
||||
## 2. Responsabilité de `rel.001`
|
||||
|
||||
Cette livraison effectue uniquement la mécanique de publication stable définie par le cycle KSP et `VER-LIFECYCLE-012`.
|
||||
|
||||
Elle :
|
||||
|
||||
- passe `workspace.package.version` de `0.2.13-pre.8` à `0.2.13` ;
|
||||
- ajoute le présent delta `rel.001` ;
|
||||
- ne corrige ni code, ni test, ni manifest de crate, ni README/USAGE, ni plan/validation, ni architecture/règle, ni prompt, ni `CHANGELOG.md`, ni `ROADMAP.md`.
|
||||
|
||||
Tout défaut appartenant à un couloir antérieur doit renvoyer vers une prerelease appropriée ; `rel.001` n'est jamais une tranche de rattrapage.
|
||||
|
||||
## 3. Preuves acquises avant publication
|
||||
|
||||
Le gate opérateur du gate technique final `0.2.13-pre.006`, exécuté le **28 août 2026**, a validé :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
KSP workspace Rust rule audit clean
|
||||
python3 scripts/audit_markdown_tables.py PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal PASS / inspecté
|
||||
cargo tree --duplicates PASS / inspecté
|
||||
```
|
||||
|
||||
Le graphe ciblé est resté strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey
|
||||
```
|
||||
|
||||
Le gate opérateur de la réconciliation documentaire `0.2.13-pre.007`, exécuté le **28 août 2026**, a ensuite validé :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
KSP workspace Rust rule audit clean
|
||||
python3 scripts/audit_markdown_tables.py PASS — 164 tables / 120 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Enfin, le gate opérateur de la préparation minimale de publication `0.2.13-pre.008`, exécuté le **28 août 2026**, a validé :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
KSP workspace Rust rule audit clean
|
||||
python3 scripts/audit_markdown_tables.py PASS — 164 tables / 122 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
`pre.008` n'a rouvert aucun code, test, README/USAGE, plan, validation ou architecture. Elle a préparé uniquement `Cargo.toml`, `CHANGELOG.md`, `ROADMAP.md`, le prompt suivant et son delta.
|
||||
|
||||
## 4. Version stable publiée
|
||||
|
||||
La version Cargo devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.13
|
||||
```
|
||||
|
||||
La release stable publiée est :
|
||||
|
||||
```text
|
||||
0.2.13 — Interface / wire foundation
|
||||
```
|
||||
|
||||
La surface stable comprend :
|
||||
|
||||
```text
|
||||
Pubkey canonique réexporté depuis ksp-core-lib
|
||||
ProgramAccountMeta passif à champs privés
|
||||
ProgramInstruction passif à champs privés
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS = 255
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN = 10_240
|
||||
ordre et doublons des account metas conservés
|
||||
Program Pubkeys opaques acceptés
|
||||
Error/Result Core pour les violations de bornes
|
||||
contextes d'erreur limités à field / actual_len / maximum_len
|
||||
Debug borné sans account material ni payload data
|
||||
six exports crate-root exacts
|
||||
quatre modules Rust de production exacts
|
||||
consumer externe canari
|
||||
firewall de dépendances canari
|
||||
release completeness canari
|
||||
```
|
||||
|
||||
La dependency direction stable reste :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
-> ksp-core-lib
|
||||
-> solana-pubkey
|
||||
```
|
||||
|
||||
Sont volontairement absents de cette foundation :
|
||||
|
||||
```text
|
||||
serde / serde_json
|
||||
borsh / wincode / bincode
|
||||
solana-instruction
|
||||
ksp-logging-lib / tracing runtime Interface
|
||||
reqwest / tonic / tokio / réseau
|
||||
Program API / Program Lib
|
||||
Store / Config / Wallet / Tauri
|
||||
```
|
||||
|
||||
## 5. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.2.13/rel.001.md
|
||||
```
|
||||
|
||||
## 6. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
```
|
||||
|
||||
## 7. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 8. Validations exécutées pour préparer le delta
|
||||
|
||||
Contrôles statiques de l'overlay :
|
||||
|
||||
```text
|
||||
Cargo.toml version 0.2.13
|
||||
Cargo.toml header version 312
|
||||
payload rel.001 2 fichiers exactement
|
||||
CHANGELOG.md non rouvert
|
||||
ROADMAP.md non rouvert
|
||||
prompt 019 non rouvert
|
||||
README/USAGE non rouverts
|
||||
plan / validation non rouverts
|
||||
code / tests non rouverts
|
||||
aucun fichier de rattrapage présent
|
||||
```
|
||||
|
||||
La préparation de l'archive ne rejoue aucun test Cargo dans l'environnement de génération. Le gate stable final reste à exécuter après application du delta et avant commit/tag.
|
||||
|
||||
## 9. Validations non exécutées pendant la préparation
|
||||
|
||||
Ne sont volontairement pas rejoués pour construire l'overlay :
|
||||
|
||||
```text
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
smokes réseau/live
|
||||
```
|
||||
|
||||
Le changement est limité au signal de version Cargo et au présent delta ; ces contrôles doivent uniquement être rejoués dans le gate stable défini ci-dessous lorsque requis.
|
||||
|
||||
## 10. Validation stable après application
|
||||
|
||||
Exécuter avant publication :
|
||||
|
||||
```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.13
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke réseau/live ni nouveau graphe Cargo n'est requis : `rel.001` ne modifie ni runtime, ni code métier, ni dépendances.
|
||||
|
||||
## 11. Décisions de publication
|
||||
|
||||
Aucune nouvelle décision fonctionnelle ou architecturale n'est introduite par `rel.001`.
|
||||
|
||||
La publication confirme uniquement que :
|
||||
|
||||
1. `0.2.13-pre.008` est la candidate directe de la release stable ;
|
||||
2. les lanes technique, documentaire et préparation de publication sont closes ;
|
||||
3. `CHANGELOG.md`, `ROADMAP.md` et `prompts/019-V0_2_14_START_PROMPT.md` restent inchangés dans `rel.001` ;
|
||||
4. `ksp-interface-lib` reste une façade wire passive et Core-only ;
|
||||
5. `ksp-program-api` reste réservé à `0.2.14` et ne doit pas être rétro-injecté dans Interface ;
|
||||
6. l'archive historique `khadhroony-bot3_v0.5.3-pre.005-fix010.zip` reste obligatoire pour l'audit `0.2.14-pre.001`, mais n'est pas une autorité architecturale ;
|
||||
7. la prochaine release s'ouvre exclusivement depuis le tag stable `v0.2.13`.
|
||||
|
||||
## 12. Questions ouvertes
|
||||
|
||||
Aucune question ouverte ne bloque la publication de `0.2.13`.
|
||||
|
||||
Les choix exacts concernant les contrats extensibles de `ksp-program-api`, les outcomes/proofs et l'héritage éventuel de concepts kbot3 appartiennent à l'audit/sizing de `0.2.14-pre.001` et ne constituent pas une dette bloquante de `0.2.13`.
|
||||
|
||||
## 13. Commit et tag stable
|
||||
|
||||
Après succès du gate stable :
|
||||
|
||||
```text
|
||||
commit : v0.2.13-rel.001
|
||||
tag : v0.2.13
|
||||
```
|
||||
|
||||
Aucun tag intermédiaire `rel.001` n'est requis.
|
||||
|
||||
Commandes Git typiques :
|
||||
|
||||
```bash
|
||||
git add Cargo.toml deltas/0.2.13/rel.001.md
|
||||
git commit -m "v0.2.13-rel.001"
|
||||
git tag v0.2.13
|
||||
git push
|
||||
git push origin v0.2.13
|
||||
```
|
||||
|
||||
Après le tag, produire l'archive opérateur stable KSP `v0.2.13` qui servira de première autorité à la session suivante.
|
||||
|
||||
## 14. Suite
|
||||
|
||||
Après publication du tag stable `v0.2.13`, ouvrir :
|
||||
|
||||
```text
|
||||
0.2.14-pre.001 — Program API foundation
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
```
|
||||
|
||||
Le démarrage de `0.2.14-pre.001` exige les deux archives prévues par le prompt :
|
||||
|
||||
```text
|
||||
archive opérateur KSP correspondant exactement à v0.2.13
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
L'audit kbot3 doit être réellement rejoué avant toute implémentation lourde de `ksp-program-api`.
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 63 -->
|
||||
<!-- version: 65 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -27,7 +27,8 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
- [`016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md`](016-V0_2_9_YELLOWSTONE_GRPC_PLAN.md) — plan historique clôturé de la release stable `0.2.9 — Yellowstone gRPC standard/provider-neutral`, publiée par `rel.001`; il fixe le moteur N1, le standard N2, Config V3, le replay prudent et la validation PublicNode Mainnet/Testnet.
|
||||
- [`017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md`](017-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC_PLAN.md) — plan historique clôturé de la release stable `0.2.10 — OrbitFlare Yellowstone gRPC`; il conserve le Devnet gRPC gratuit, N1/N2 immuables, la License Key `x-token` et le smoke final `Slot + Ping`.
|
||||
- [`018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md`](018-V0_2_11_OFFCHAIN_PRICE_TRANSPORT_PLAN.md) — plan historique clôturé de `0.2.11 — Off-chain price transport`; SOL/USD V1, huit providers REST sans SDK, registry/availability/rate limits Off-chain et Config `std.offchain_transport`.
|
||||
- [`019-V0_2_12_SOL_PRICES_DESK_PLAN.md`](019-V0_2_12_SOL_PRICES_DESK_PLAN.md) — plan actif de `0.2.12 — SOL Prices Desk + intégration prix Wallet Desk`; il fixe le gabarit 1434/1435, le composite Config, les DTO/commands provider-neutral, le threat model et la trajectoire d’intégration Wallet.
|
||||
- [`019-V0_2_12_SOL_PRICES_DESK_PLAN.md`](019-V0_2_12_SOL_PRICES_DESK_PLAN.md) — plan historique clôturé de `0.2.12 — SOL Prices Desk + intégration prix Wallet Desk`; il conserve le gabarit 1434/1435, le composite Config, les DTO/commands provider-neutral, l’intégration Wallet minimale et les gates live/build finaux.
|
||||
- [`020-V0_2_13_INTERFACE_PLAN.md`](020-V0_2_13_INTERFACE_PLAN.md) — plan candidat réconcilié de `0.2.13 — Interface / wire foundation`; il fixe la surface finale `ProgramAccountMeta` + `ProgramInstruction`, les bornes `255` / `10_240`, le firewall Interface -> Core, les canaris de complétude/consumer externe et la frontière avec Program API/RAW/CORE.
|
||||
|
||||
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: 93 -->
|
||||
<!-- version: 94 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -520,9 +520,11 @@ Metadata HTTP/IPFS/Arweave viendra au premier besoin Metadata réel. SOL/EUR et
|
||||
|
||||
### `0.2.13` — Interface foundation
|
||||
|
||||
`ksp-interface-lib` devient la façade wire officielle et expose une API publique wire utilisable par les implementations officielles et externes.
|
||||
`ksp-interface-lib` matérialise la première façade wire officielle KSP, volontairement passive et Program-facing. La surface candidate stable réexporte le `Pubkey` canonique de Core et expose `ProgramAccountMeta` ainsi que `ProgramInstruction` avec champs privés, accessors explicites et admission bornée à `255` account metas et `10_240` bytes de data. L'ordre et les doublons sont conservés, les Program Pubkeys opaques restent acceptés et les diagnostics ne recopient ni payload ni account material arbitraire.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue pour l'instant.
|
||||
La dependency direction reste strictement `Interface -> Core`; aucun serde/codec générique, `solana-instruction`, runtime réseau ou logging n'est introduit. La façade crate-root est verrouillée par canaris public API, consumer externe, release completeness et dependency firewall. [`../../crates/ksp-interface-lib/README.md`](../../crates/ksp-interface-lib/README.md) et [`../../crates/ksp-interface-lib/USAGE.md`](../../crates/ksp-interface-lib/USAGE.md) deviennent les références durables de cette foundation. Le gate technique final `pre.006` est vert avant réconciliation documentaire.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue pour l'instant. Les codecs/layouts spécifiques restent conditionnés à un vertical réel, tandis que les wires génériques d'acquisition/CORE restent reportés à `0.3.2+`.
|
||||
|
||||
### `0.2.14` — Program API foundation
|
||||
|
||||
|
||||
672
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
Normal file
672
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
Normal file
@@ -0,0 +1,672 @@
|
||||
<!-- file: docs/plans/020-V0_2_13_INTERFACE_PLAN.md -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Plan `0.2.13` — Interface / wire foundation
|
||||
|
||||
## 1. Base, autorité et nature de `pre.001`
|
||||
|
||||
La release est ouverte exclusivement depuis l'archive opérateur `khadhroony-solana-project-v0.2.12.zip`, annoncée comme issue du tag stable `v0.2.12`. L'archive fournie ne contient pas de metadata `.git`; `git describe` n'est donc pas vérifiable dans le sandbox. Les marqueurs internes sont cohérents :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.12
|
||||
prompts/018-V0_2_13_START_PROMPT.md présent
|
||||
deltas/0.2.12/rel.001.md présent
|
||||
crates/ksp-interface-lib absent
|
||||
crates/ksp-program-api absent
|
||||
```
|
||||
|
||||
Le log opérateur joint à la reprise établit sur la base stable :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Dans le sandbox de préparation, `cargo` n'est pas installé. Les audits Python de la base ont été rejoués et sont propres ; aucune commande Cargo non exécutée localement n'est déclarée PASS.
|
||||
|
||||
`0.2.13-pre.001` reste un gate de lecture/audit/sizing. Il ne crée pas encore `ksp-interface-lib` et ne porte aucun code de l'ancien dépôt.
|
||||
|
||||
## 2. Décision de scope
|
||||
|
||||
Le minimum retenu pour `0.2.13` est une foundation **Program-facing passive** :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
bornes locales explicites sur account metas et data
|
||||
façade crate-root explicite
|
||||
Error/Result communs via ksp-core-lib
|
||||
aucun serde/codec générique ajouté sans protocole réel
|
||||
aucun comportement Program
|
||||
```
|
||||
|
||||
Cette surface correspond à la forme fondamentale d'une invocation Solana : identité du programme, comptes ordonnés avec flags signer/writable, puis octets opaques. Elle prépare directement la future construction d'instructions de `ksp-program-api` sans absorber le modèle d'acquisition/replay qui appartient à `0.3.2+`.
|
||||
|
||||
Le scope est volontairement réduit par rapport au forecast initial : `0.2.13` ne crée ni modèle canonique de transaction, ni replay input, ni logs/return-data génériques, ni CPI path, ni discriminant spécifique d'un programme tant qu'aucun vertical slice officiel ne le justifie.
|
||||
|
||||
## 3. Règles et architecture confrontées à la base réelle
|
||||
|
||||
Sources internes relues avant décision :
|
||||
|
||||
```text
|
||||
RULES.md
|
||||
docs/000-README.md
|
||||
docs/rules/RULES_GENERAL.md
|
||||
docs/rules/RULES_KSP.md
|
||||
docs/rules/RULES_RUST.md
|
||||
docs/rules/RULES_DEPENDENCIES.md
|
||||
docs/rules/RULES_DOCUMENTATION.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/PROMPT_STRUCTURE.md
|
||||
docs/architecture/000-README.md
|
||||
docs/architecture/001-PROJECT_OBJECTIVES.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/architecture/006-WIRE_AND_PROGRAM.md
|
||||
docs/architecture/007-EXECUTION_AND_POLICY.md
|
||||
docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md
|
||||
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
|
||||
docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
ROADMAP.md
|
||||
```
|
||||
|
||||
Les contraintes structurantes sont confirmées :
|
||||
|
||||
```text
|
||||
Core possède Pubkey, Error/Result et les Program IDs fondamentaux
|
||||
Interface possède/reexporte de manière contrôlée les contrats wire officiels
|
||||
Program API pourra dépendre de Core + Interface, jamais l'inverse
|
||||
Transport reste propriétaire des DTOs RPC/WS/gRPC et ne dépend pas d'Interface
|
||||
RAW/CORE n'exige aucun decoder Program
|
||||
0.3.2 étendra Interface pour les wires génériques d'acquisition/CORE
|
||||
pas de pub mod ; exports explicites depuis crate root
|
||||
pas de dépendance externe sans usage réel
|
||||
```
|
||||
|
||||
## 4. Inventaire interne stable pertinent
|
||||
|
||||
### 4.1 Core
|
||||
|
||||
| Surface stable | Owner actuel | Visibilité/consumer | Décision `0.2.13` |
|
||||
|----------------------------------|----------------|-----------------------------------------------|---------------------------------------------------------------------|
|
||||
| `Pubkey` | `ksp-core-lib` | public crate-root; consommé dans le workspace | réutiliser directement; aucun wrapper Interface |
|
||||
| `Error` / `ErrorCode` / `Result` | `ksp-core-lib` | public crate-root; contrat commun | réutiliser pour les erreurs de bornes Interface |
|
||||
| 18 Program IDs + registry/filter | `ksp-core-lib` | public crate-root | laisser Core; Interface ne duplique pas les identités fondamentales |
|
||||
|
||||
Les anciens wrappers textuels `MdProgramId` / `MdPubkey` de kbot3 n'apportent donc aucune valeur à la frontière KSP actuelle : un `Pubkey` typé existe déjà et doit rester l'identité fondamentale.
|
||||
|
||||
### 4.2 Transport
|
||||
|
||||
| Type/famille observée | Owner actuel | Sémantique réelle | Décision |
|
||||
|----------------------------------------------------------|-------------------------|--------------------------------------------------------|-------------------|
|
||||
| `SolanaEncodedTransaction` | On-chain Transport HTTP | projection JSON-RPC encodée | laisser Transport |
|
||||
| `SolanaConfirmedTransaction` / `SolanaBlockTransaction` | On-chain Transport HTTP | réponse RPC avec états wire/metadata provider | laisser Transport |
|
||||
| `SolanaWireField<T>` | On-chain Transport HTTP | distinction omitted/null/value propre aux réponses RPC | laisser Transport |
|
||||
| `YellowstoneCompiledInstruction` | On-chain Transport gRPC | projection protobuf Yellowstone | laisser Transport |
|
||||
| `YellowstoneInnerInstructions` / `YellowstoneReturnData` | On-chain Transport gRPC | metadata d'update Geyser | laisser Transport |
|
||||
| `YellowstoneTransactionError` / `...Meta` | On-chain Transport gRPC | sémantique provider/protobuf | laisser Transport |
|
||||
|
||||
Ces DTOs peuvent ressembler à de futurs objets génériques, mais ils représentent aujourd'hui des formes de transport concrètes. `0.2.13` ne les déplace pas et ne force aucune dépendance `Transport -> Interface`.
|
||||
|
||||
### 4.3 Dépendances workspace
|
||||
|
||||
La base possède déjà notamment :
|
||||
|
||||
```text
|
||||
solana-pubkey = ^4.3, default-features = false
|
||||
serde = ^1.0
|
||||
serde_json = ^1.0
|
||||
```
|
||||
|
||||
Aucun `solana-instruction`, `borsh`, `wincode` ou crate d'interface Program n'est actuellement nécessaire au nouveau lot. Le graphe cible initial reste donc `Interface -> Core` uniquement.
|
||||
|
||||
## 5. Audit d'héritage `khadhroony-bot3`
|
||||
|
||||
Archive auditée : `khadhroony-bot3_v0.5.3-pre.005-fix010.zip`.
|
||||
|
||||
Familles inspectées :
|
||||
|
||||
```text
|
||||
ks-lib/src/model/solana.rs
|
||||
ks-lib/src/model/canonical_transaction.rs
|
||||
ks-lib/src/model/replay.rs
|
||||
ks-lib/src/decoder/api/contracts.rs
|
||||
ks-lib/src/executor/api/execution.rs
|
||||
familles decoder/* wire pertinentes comme points de comparaison uniquement
|
||||
```
|
||||
|
||||
La matrice suivante porte sur les **concepts**, pas sur un portage de code :
|
||||
|
||||
| Concept kbot3 | Verdict | Cible KSP | Raison |
|
||||
|--------------------------------------------------------------|------------|----------------------------------|--------------------------------------------------------------------------------|
|
||||
| account `{ pubkey, is_signer, is_writable }` ordonné | REPRENDRE | Interface `0.2.13` | forme passive fondamentale d'une instruction; retirer le naming execution |
|
||||
| instruction `{ program_id, accounts, data }` | REPRENDRE | Interface `0.2.13` | forme officielle minimale; retirer `operation_code` et toute policy |
|
||||
| `MdPubkey` / `MdProgramId` en `String` | REDESSINER | Core | remplacer par `ksp_core_lib::Pubkey` déjà possédé par Core |
|
||||
| payload `Vec<u8>` non borné | REDESSINER | Interface `0.2.13` | ajouter admission bornée et Debug résumé |
|
||||
| `DcApiInstructionDecoder` + recognition/outcomes/proofs | REPORTER | Program API `0.2.14` | comportement de reconnaissance/decode, interdit dans Interface |
|
||||
| `MdInstructionPath` / parent / stack height | REPORTER | Interface/CORE `0.3.2+` | contexte d'acquisition/replay, pas nécessaire au builder Program minimal |
|
||||
| logs / return data / tx failure / balance changes génériques | REPORTER | Interface/CORE `0.3.2+` | faits d'exécution/acquisition; ne pas préfigurer CORE |
|
||||
| `MdCanonicalTransaction` + canonical JSON/hash | REPORTER | CORE series après `0.3.2` | modèle source-neutral large à redéfinir avec Store/CORE réels |
|
||||
| `MdCoreInstructionReplayInput` | REPORTER | CORE/replay après RAW | contrat transversal trop large, dépend de données encore non possédées |
|
||||
| Prepared plan, signers, fee payer, policies | REPORTER | Program API/Execution ultérieurs | responsabilité d'orchestration/exécution, pas wire passif |
|
||||
| monolithe `ks-lib` + générations d'API coexistantes | REJETER | aucune | ownership flou et couplage vertical/horizontal à ne pas reproduire |
|
||||
| version/hash/JSON génériques par réflexe | REJETER | aucune dans `0.2.13` | aucun contrat sérialisé ne justifie une enveloppe/version générique maintenant |
|
||||
|
||||
Anti-patterns à ne pas reproduire :
|
||||
|
||||
```text
|
||||
wrappers Pubkey/ProgramId textuels alors qu'une primitive typée existe
|
||||
serde dérivé sur tous les contrats sans frontière de sérialisation réelle
|
||||
JSON Value comme échappatoire pour des formes structurelles futures
|
||||
contrat replay géant utilisé comme point de rencontre de toutes les couches
|
||||
operation_code/policy/signers mêlés à l'instruction passive
|
||||
traits decoder dans la même crate que les wires
|
||||
```
|
||||
|
||||
## 6. Audit externe actuel — 27 août 2026
|
||||
|
||||
L'audit externe est limité aux candidates réellement proches du lot retenu.
|
||||
|
||||
| Candidate | Version actuelle observée | Contrat / graphe | Décision |
|
||||
|------------------------------|---------------------------|----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------|
|
||||
| `solana-instruction` | 3.5.0 | `Instruction { program_id: Pubkey, accounts: Vec<AccountMeta>, data: Vec<u8> }`; `solana-pubkey ^4.3.0`; codecs optionnels | référence normative; pas de dépendance runtime `0.2.13` |
|
||||
| `solana-program` syscalls | 4.1.0 | `MAX_CPI_INSTRUCTION_ACCOUNTS = 255`; data `10 KiB`; account infos uniques `128` | source normative des plafonds d'admission initiaux; pas de dépendance |
|
||||
| `solana-loader-v3-interface` | 8.1.1 | interface officielle; dépend `solana-instruction ^3.5.0` + `solana-pubkey ^4.3.0`; wincode optionnel | compatible en apparence mais hors premier lot; réauditer au vertical loader-v3 |
|
||||
|
||||
Sources primaires/current utilisées :
|
||||
|
||||
```text
|
||||
https://docs.rs/solana-instruction/3.5.0/solana_instruction/struct.Instruction.html
|
||||
https://docs.rs/solana-program/4.1.0/solana_program/syscalls/index.html
|
||||
https://docs.rs/solana-loader-v3-interface/8.1.1/solana_loader_v3_interface/
|
||||
https://github.com/anza-xyz/solana-sdk
|
||||
```
|
||||
|
||||
`solana-instruction` 3.5.0 est Apache-2.0 via le workspace Anza. Ses features `serde`, `borsh`, `bincode` et `wincode` sont optionnelles. La génération `solana-pubkey ^4.3.0` est cohérente avec la base KSP.
|
||||
|
||||
La dépendance directe n'est néanmoins pas retenue maintenant : ses champs `Vec` publics ne permettent pas à KSP de garantir les bornes d'admission sur sa propre API, et aucun interop runtime ne requiert encore de convertir vers ce type. `DEP-KSP-005` impose de ne pas ajouter une dépendance seulement pour refléter une forme triviale que KSP doit de toute façon borner.
|
||||
|
||||
## 7. Matrice de frontières
|
||||
|
||||
| Concept/type | Owner cible | 0.2.13 ? | 0.2.14 ? | 0.3.2+ ? | Autorité / raison |
|
||||
|-------------------------------------------------------------|----------------|----------|------------------|------------------------|-----------------------------------------------|
|
||||
| `Pubkey` | Core | reuse | reuse | reuse | primitive fondamentale KSP déjà stable |
|
||||
| Program IDs fondamentaux | Core | reuse | reuse | reuse | registry Core déjà stable |
|
||||
| account meta d'instruction | Interface | OUI | consume | reuse | forme Solana officielle passive |
|
||||
| instruction Program passive | Interface | OUI | consume | reuse | minimum nécessaire au futur preparer |
|
||||
| codec/discriminant Program spécifique | Interface | NON | si vertical réel | selon besoin | aucun protocole concret dans foundation |
|
||||
| instruction path / CPI ancestry | Interface/CORE | NON | NON requis | OUI | fait structurel d'acquisition/normalisation |
|
||||
| logs / return data / tx failure / balance deltas génériques | Interface/CORE | NON | NON requis | OUI | surface RAW/CORE future |
|
||||
| DTOs RPC/WS/Yellowstone existants | Transport | laisser | laisser | adapter plus tard | projection transport concrète |
|
||||
| decoder identity/recognition/decode | Program API | NON | OUI audit | consume CORE plus tard | comportement extensible Program |
|
||||
| implémentations officielles de programmes | Program Lib | NON | NON | plus tard | vertical slices distincts |
|
||||
| RAW persistence | Store | NON | NON | `0.3.1` | architecture RAW |
|
||||
| transaction/replay canonique générique | CORE | NON | NON | après `0.3.2` | doit être défini avec acquisition/Store réels |
|
||||
|
||||
## 8. Surface API proposée
|
||||
|
||||
Les noms restent ajustables jusqu'à implémentation, mais le contrat conceptuel est fermé :
|
||||
|
||||
```rust
|
||||
pub use ksp_core_lib::Pubkey;
|
||||
|
||||
pub const MAX_PROGRAM_INSTRUCTION_ACCOUNTS: usize = 255;
|
||||
pub const MAX_PROGRAM_INSTRUCTION_DATA_LEN: usize = 10 * 1024;
|
||||
|
||||
pub struct ProgramAccountMeta { /* private */ }
|
||||
pub struct ProgramInstruction { /* private */ }
|
||||
```
|
||||
|
||||
Façade visée :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta::writable(pubkey, is_signer)
|
||||
ProgramAccountMeta::readonly(pubkey, is_signer)
|
||||
ProgramAccountMeta::{pubkey,is_signer,is_writable}
|
||||
|
||||
ProgramInstruction::try_new(program_id, accounts, data) -> ksp_core_lib::Result<Self>
|
||||
ProgramInstruction::{program_id,accounts,data}
|
||||
```
|
||||
|
||||
Décisions de contrat :
|
||||
|
||||
- `Pubkey` est consommé via Core ; aucun `ProgramId` wrapper supplémentaire ;
|
||||
- les comptes gardent exactement leur ordre et les doublons restent permis ;
|
||||
- comptes vides et data vide restent valides ;
|
||||
- aucune validation sémantique de Program ID, signer ou writable au-delà de la forme passive ;
|
||||
- les champs restent privés afin d'empêcher la construction d'un état hors bornes ;
|
||||
- la construction valide les longueurs sans cloner les vecteurs fournis ;
|
||||
- `Debug` de `ProgramInstruction` doit résumer `program_id`, `account_count` et `data_len`, sans imprimer tout le payload ;
|
||||
- pas de `serde::{Serialize, Deserialize}` dans la foundation : aucune persistence/IPC/wire sérialisée générique ne l'exige, et une dérive `Deserialize` naïve affaiblirait le gate de taille avant allocation ;
|
||||
- aucun `borsh`, `bincode` ou `wincode` générique : les codecs arrivent avec un vrai protocole Program dans Interface ;
|
||||
- pas de `format_version` artificiel tant qu'aucun format sérialisé KSP n'est défini.
|
||||
|
||||
### 8.1 Bornes
|
||||
|
||||
Les bornes initiales suivent les plafonds runtime Solana actuels :
|
||||
|
||||
```text
|
||||
account metas d'une instruction <= 255
|
||||
data d'une instruction <= 10_240 octets
|
||||
```
|
||||
|
||||
Elles sont des **bornes d'admission Interface**, pas la promesse qu'une instruction seule rentrera dans toute transaction top-level. Les contraintes de message/transaction, comptes uniques, fee payer, blockhash et assembly appartiennent aux couches d'exécution ultérieures.
|
||||
|
||||
### 8.2 Erreurs
|
||||
|
||||
Le crate n'introduit pas un second type d'erreur. Les violations de borne utilisent `ksp_core_lib::Error/Result` avec codes Interface stables et contexte sûr limité aux longueurs/plafonds. Aucun octet du payload, compte arbitraire ou valeur externe n'est copié dans les diagnostics.
|
||||
|
||||
Les codes exacts seront matérialisés avec la première primitive ; deux catégories suffisent conceptuellement :
|
||||
|
||||
```text
|
||||
invalid_program_instruction
|
||||
program_instruction_limit_exceeded
|
||||
```
|
||||
|
||||
Si la première implémentation démontre qu'une seule catégorie bornée suffit, ne pas créer la seconde par symétrie.
|
||||
|
||||
## 9. Threat / robustness model
|
||||
|
||||
| Risque | Décision | Canari prévu |
|
||||
|-------------------------------------|------------------------------------------------------|------------------------------------------------------|
|
||||
| data surdimensionnée | refus avant stockage/copie supplémentaire | `10_240` accepté; `10_241` refusé |
|
||||
| collection accounts surdimensionnée | refus déterministe | `255` accepté; `256` refusé |
|
||||
| conversion/index overflow | aucun cast étroit en foundation; comparer en `usize` | borne 255 + absence de casts unchecked |
|
||||
| ordre/doublons accounts | préserver exactement; ne pas dédupliquer | ordre et doublon round-trip structurel via accessors |
|
||||
| wire malformé | N/A : aucun decoder/codec dans le lot | aucun faux test; réouvrir au premier codec réel |
|
||||
| enum/discriminant inconnu | N/A : aucun discriminant dans le lot | réouvrir au vertical Program |
|
||||
| structures imbriquées pathologiques | N/A au-delà des deux Vec plates | bornes accounts/data suffisent pour ce lot |
|
||||
| Debug volumineux | Debug résumé | payload sentinelle absent du rendu Debug |
|
||||
| allocation/copie excessive | `try_new` consomme les Vec; pas de clone interne | canari structure/API + revue source |
|
||||
| serde hostile | serde absent | dependency/public API canary |
|
||||
| panic/unwrap/expect/? | interdits par règles/lints | audit Rust + Clippy workspace |
|
||||
| Program ID inconnu | accepté : Pubkey opaque typé | canari avec Pubkey non registry |
|
||||
|
||||
## 10. Dependency graph cible et firewall
|
||||
|
||||
Cible de `0.2.13` :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
-> ksp-core-lib
|
||||
-> solana-pubkey ^4.3
|
||||
```
|
||||
|
||||
Interdictions :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -X-> ksp-program-api
|
||||
ksp-interface-lib -X-> ksp-program-lib
|
||||
ksp-interface-lib -X-> ksp-onchain-transport-lib
|
||||
ksp-interface-lib -X-> ksp-offchain-transport-lib
|
||||
ksp-interface-lib -X-> ksp-config-lib
|
||||
ksp-interface-lib -X-> ksp-store-*
|
||||
ksp-interface-lib -X-> ksp-wallet-lib
|
||||
ksp-interface-lib -X-> Tauri
|
||||
ksp-interface-lib -X-> reqwest/tonic/tokio/network
|
||||
```
|
||||
|
||||
Aucun logging runtime n'est attendu dans une crate de contrats passifs. `ksp-logging-lib` reste absent sauf comportement futur démontré.
|
||||
|
||||
Validation Cargo prévue dès le scaffold :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Comme aucune nouvelle dépendance externe n'est retenue au gate, aucun doublon codec/Solana ne doit être créé par `pre.002`.
|
||||
|
||||
## 11. Stratégie de tests
|
||||
|
||||
### Tests unitaires privés
|
||||
|
||||
Sous `unit_tests/` rattachés aux modules privés :
|
||||
|
||||
```text
|
||||
constructeurs account meta writable/readonly
|
||||
bornes comptes 255/256
|
||||
bornes data 10_240/10_241
|
||||
empty accounts/data acceptés
|
||||
ordre et doublons préservés
|
||||
Pubkey inconnu accepté
|
||||
Debug borné et payload absent
|
||||
erreurs sans bytes ni valeur hostile
|
||||
```
|
||||
|
||||
### Tests d'intégration `tests/`
|
||||
|
||||
```text
|
||||
public_api.rs consommation uniquement via crate-root
|
||||
external_consumer.rs petit consumer/crate canary si le pattern workspace le permet
|
||||
dependency_boundary.rs manifest/source firewall et absence de serde/codecs/network
|
||||
release_completeness.rs inventaire exact de la surface 0.2.13 retenue
|
||||
```
|
||||
|
||||
Aucun smoke réseau n'est requis. Aucun round-trip binaire/JSON n'est inventé sans codec réel.
|
||||
|
||||
## 12. Hors scope explicite
|
||||
|
||||
```text
|
||||
ksp-program-api et tout trait decoder/preparer
|
||||
ksp-program-lib
|
||||
codec Program spécifique sans vertical réel
|
||||
system/token/loader/metaplex instruction families
|
||||
PDA seeds sans protocole concret
|
||||
transaction/message/compiled instruction génériques d'acquisition
|
||||
replay input / instruction path / CPI tree
|
||||
logs / return data / transaction errors / balances génériques
|
||||
Store/persistence
|
||||
Transport refactor ou dépendance vers Interface
|
||||
Wallet/Tauri/Config
|
||||
serde/JSON canonical/hash
|
||||
execution policy, signer selection, blockhash, simulation, send
|
||||
```
|
||||
|
||||
## 13. Prévision souple recalibrée
|
||||
|
||||
Le scope réduit permet de supprimer le second lot wire optionnel du forecast initial et de garder des tranches compatibles avec le budget KSP de 15–20 minutes de travail effectif.
|
||||
|
||||
### pre.001 — audit + héritage + frontières + sizing
|
||||
|
||||
**Statut : réalisé ; gate opérateur `pre.001` intégralement PASS.**
|
||||
|
||||
Relire les règles/architectures, auditer Core/Transport, classer kbot3, auditer les candidates externes, retenir la surface instruction passive, fixer bornes/firewall/threat model/tests et créer plan/validation.
|
||||
|
||||
### pre.002 — scaffold `ksp-interface-lib` + façade + firewall
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
Créer la crate, l'ajouter au workspace, poser `lib.rs` avec exports explicites, lints, README/USAGE initiaux et canaris manifest/firewall. Dépendance normale unique : `ksp-core-lib`.
|
||||
|
||||
### pre.003 — `ProgramAccountMeta` + bornes communes
|
||||
|
||||
**Statut : réalisé ; fmt/audits/check/Clippy/tests Interface PASS, `cargo test --workspace` non fourni dans la preuve opérateur.**
|
||||
|
||||
Matérialiser la primitive de compte ordonné, la borne accounts, le modèle d'erreur Interface minimal et les unit/public canaries associés. `ProgramInstruction` et la borne data restent réservés à `pre.004`.
|
||||
|
||||
### pre.004 — `ProgramInstruction` passif borné
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
Ajouter l'instruction `{ program_id, accounts, data }`, constructeur validé, accessors, Debug résumé et canaris d'ordre/doublons/limites. Aucun serde/codec ou comportement Program.
|
||||
|
||||
### pre.005 — adversarial + consumer externe + API/dependency hardening
|
||||
|
||||
**Statut : réalisé ; `pre.005-fix.001` validé, gate opérateur intégralement PASS.**
|
||||
|
||||
Fermer les cas limites, surface crate-root, consumer externe, firewall source/manifest et graphes Cargo. Ne pas ajouter un second domaine wire opportuniste.
|
||||
|
||||
### pre.006 — gate technique final
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
Workspace complet, canaris de complétude/public API/dependencies, ownership Logging, `cargo tree` et audit final du scope exact sont validés. Aucun README/USAGE final ni préparation de publication n'a été mélangé à cette tranche.
|
||||
|
||||
### pre.007 — réconciliation documentaire finale
|
||||
|
||||
**Statut : réalisé ; gate opérateur documentaire à confirmer.**
|
||||
|
||||
README/USAGE Interface, plan, validation, séquence fonctionnelle et index documentaires réellement affectés sont réconciliés. `CHANGELOG.md`, `ROADMAP.md` et le prompt suivant restent réservés à `pre.008`.
|
||||
|
||||
### pre.008 — préparation de publication minimale
|
||||
|
||||
**Statut : prévu**
|
||||
|
||||
Préparer uniquement `prompts/019-V0_2_14_START_PROMPT.md`, `CHANGELOG.md`, `ROADMAP.md`, le bump prerelease mécanique et le delta. Aucun code/test/README/USAGE/plan/validation/architecture ne doit être rouvert.
|
||||
|
||||
### rel.001 — publication stable
|
||||
|
||||
**Statut : prévu**
|
||||
|
||||
Passer `workspace.package.version` à `0.2.13`, rejouer le gate stable requis, publier le commit `v0.2.13-rel.001` puis le tag stable `v0.2.13`.
|
||||
|
||||
## 14. Sizing et critère session
|
||||
|
||||
| Tranche | Charge relative | Motif du découpage |
|
||||
|---------|------------------|----------------------------------|
|
||||
| pre.002 | petite | scaffold + firewall uniquement |
|
||||
| pre.003 | petite | une primitive + bornes/erreurs |
|
||||
| pre.004 | petite à moyenne | instruction + hardening local |
|
||||
| pre.005 | moyenne | consumer + adversarial + graphes |
|
||||
| pre.006 | gate | aucun développement fonctionnel |
|
||||
| pre.007 | documentation | réconciliation séparée |
|
||||
| pre.008 | publication prep | payload minimal séparé |
|
||||
|
||||
Le scope paraît clôturable dans une release/session sans sacrifier les lanes de sortie. Si `pre.003` ou `pre.004` révèle qu'une dépendance/codec spécifique est indispensable, le gate doit être rouvert avant d'étendre le scope ; il ne faut pas réactiver automatiquement `pre.005` comme second lot wire.
|
||||
|
||||
## 15. Gate `0.2.13-pre.001`
|
||||
|
||||
À la sortie préparée :
|
||||
|
||||
```text
|
||||
base stable / prompt / rel confirmé
|
||||
règles et architecture obligatoires relues
|
||||
Core / Transport inventoriés
|
||||
archive kbot3 auditée
|
||||
matrice REPRENDRE/REDESSINER/REPORTER/REJETER produite
|
||||
0.2.13 / 0.2.14 / 0.3.2 séparés
|
||||
premier lot ProgramAccountMeta + ProgramInstruction
|
||||
nouvelle dépendance externe aucune
|
||||
threat model / tests / dependency graph définis
|
||||
plan + validation créés
|
||||
implementation Program absente
|
||||
```
|
||||
|
||||
## 16. Gate attendu pour `pre.003`
|
||||
|
||||
`pre.002` matérialise le scaffold strict décidé par le gate précédent :
|
||||
|
||||
```text
|
||||
nouvelle crate membre ksp-interface-lib
|
||||
Cargo dépend uniquement de ksp-core-lib
|
||||
lints workspace hérités
|
||||
crate root explicite sans pub mod
|
||||
Pubkey réexporté depuis Core
|
||||
README/USAGE initiaux
|
||||
canari public API minimal
|
||||
canari dependency firewall
|
||||
aucun ProgramAccountMeta/ProgramInstruction fonctionnel
|
||||
aucun ksp-logging-lib / constants.rs / TRACING_TARGET
|
||||
```
|
||||
|
||||
`pre.003` peut commencer après application du delta et gate opérateur vert. Sa responsabilité reste limitée à `ProgramAccountMeta`, aux bornes communes et au modèle d'erreur Interface minimal ; `ProgramInstruction` reste réservé à `pre.004`.
|
||||
|
||||
## 17. État préparé `pre.003`
|
||||
|
||||
`pre.003` matérialise uniquement la primitive de compte et les contrats nécessaires à la future admission de `ProgramInstruction` :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta présent
|
||||
fields privés
|
||||
constructeurs readonly / writable
|
||||
accessors pubkey / is_signer / is_writable
|
||||
Pubkey Core réutilisé
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS 255
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED interface.program_instruction_limit_exceeded
|
||||
ProgramInstruction absent par contrat
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN absent jusqu'à pre.004
|
||||
serde / borsh / bincode / wincode absents
|
||||
ksp-logging-lib / constants.rs / TRACING_TARGET absents
|
||||
```
|
||||
|
||||
La constante `255` ferme le contrat public de borne accounts mais son enforcement `255/256` appartient au constructeur de `ProgramInstruction` de `pre.004`; `ProgramAccountMeta` représente un seul compte et n'invente donc pas une collection artificielle uniquement pour tester cette limite.
|
||||
|
||||
Une seule catégorie d'erreur Interface est introduite. `invalid_program_instruction` reste absent : aucun invariant de forme distinct des limites n'est encore matérialisé et le créer par symétrie serait prématuré. Les futures erreurs de borne doivent utiliser `ksp_core_lib::Error/Result` et ne projeter que des longueurs/plafonds sûrs.
|
||||
|
||||
La preuve opérateur fournie pour `pre.003` confirme fmt, audits, `cargo check`, Clippy, tests ciblés Interface et graphes Cargo. `cargo test --workspace` n'apparaît pas dans cette preuve ; il doit donc être rejoué au gate de `pre.004` avant de déclarer la continuité workspace complète.
|
||||
|
||||
## 18. État préparé `pre.004`
|
||||
|
||||
`pre.004` matérialise le second et dernier type du premier lot wire générique retenu :
|
||||
|
||||
```text
|
||||
ProgramInstruction présent
|
||||
fields privés
|
||||
program_id Pubkey Core
|
||||
accounts Vec<ProgramAccountMeta> consommé
|
||||
data Vec<u8> opaque consommé
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS 255
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN 10_240
|
||||
try_new bornes accounts puis data
|
||||
accounts 255 / 256 accepté / refusé
|
||||
data 10_240 / 10_241 accepté / refusé
|
||||
accounts/data vides acceptés
|
||||
ordre/doublons préservés
|
||||
Program Pubkey non registry accepté
|
||||
Debug program_id/account_count/data_len uniquement
|
||||
serde / borsh / bincode / wincode absents
|
||||
solana-instruction absent
|
||||
ksp-logging-lib / constants.rs / TRACING_TARGET absents
|
||||
```
|
||||
|
||||
`ProgramInstruction::try_new` consomme les deux `Vec` fournis et compare leurs longueurs en `usize` avant stockage dans l'objet. La foundation n'ajoute aucun clone, cast étroit ou allocation de conversion. Une allocation éventuellement déjà réalisée par l'appelant pour construire le `Vec` reste naturellement hors du contrôle de l'API.
|
||||
|
||||
Les deux limites utilisent le code commun `interface.program_instruction_limit_exceeded`. Le contexte d'erreur est volontairement réduit à `field`, `actual_len` et `maximum_len`; aucune donnée du payload ni aucun account arbitraire n'est recopié dans le diagnostic.
|
||||
|
||||
Le `Debug` manuel n'imprime ni la collection accounts ni les octets `data`. Il expose uniquement l'identité publique du programme et les deux longueurs structurelles utiles au diagnostic.
|
||||
|
||||
Le gate opérateur `pre.004` confirme désormais fmt, audits Rust/Markdown, `cargo check --workspace`, Clippy, tests ciblés Interface, `cargo test --workspace` et les deux graphes Cargo. Le passage à `pre.005` se concentre donc exclusivement sur les canaris adversariaux/consumer externe/API/dependency hardening, sans ajouter un second domaine wire.
|
||||
|
||||
## 19. État préparé `pre.005`
|
||||
|
||||
`pre.005` n'ajoute aucun code de production et ferme uniquement les preuves de consommation, complétude et résistance adversariale autour de la surface déjà matérialisée :
|
||||
|
||||
```text
|
||||
production src modifié non
|
||||
nouveau domaine wire non
|
||||
external consumer integration crate présent
|
||||
release completeness inventory présent
|
||||
façade crate-root exacte 6 exports contrôlés
|
||||
modules de production 4 fichiers exacts
|
||||
Vec accounts/data transfert sans réallocation interne testé
|
||||
payload hostile dans erreur absent attendu
|
||||
account material hostile dans erreur absent attendu
|
||||
narrowing casts absents par source canary
|
||||
codec encode/decode générique absent par source canary
|
||||
manifest dependency ksp-core-lib uniquement
|
||||
source dependency firewall renforcé sur tous les modules production
|
||||
```
|
||||
|
||||
Le canari `tests/external_consumer.rs` est volontairement un test d'intégration Rust séparé : Cargo le compile comme un crate consommateur externe de la bibliothèque. Il n'utilise que la façade `ksp_interface_lib::*` accessible depuis le crate-root et n'exige donc ni fixture workspace artificielle ni invocation Cargo imbriquée.
|
||||
|
||||
`tests/release_completeness.rs` verrouille l'inventaire exact de la foundation `0.2.13` :
|
||||
|
||||
```text
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
ProgramAccountMeta
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ProgramInstruction
|
||||
Pubkey
|
||||
```
|
||||
|
||||
Il verrouille également l'absence de `pub mod` et l'inventaire exact des quatre fichiers Rust de production. Ajouter une seconde famille wire dans `0.2.13` ferait ainsi échouer explicitement le canari de complétude au lieu d'élargir silencieusement la release.
|
||||
|
||||
Le hardening unitaire vérifie enfin que les allocations des `Vec` admis sont transférées telles quelles dans `ProgramInstruction` et que les erreurs de dépassement ne recopient ni marqueur hostile de payload ni représentation arbitraire d'account meta. Ces tests renforcent le contrat de construction sans changer l'API publique.
|
||||
|
||||
Après validation opérateur de `pre.005`, `pre.006` doit rester un gate technique pur sans nouveau développement fonctionnel.
|
||||
|
||||
## 20. Correctif préparé `pre.005-fix.001`
|
||||
|
||||
Le gate opérateur `pre.005` confirme les preuves suivantes :
|
||||
|
||||
```text
|
||||
fmt / audits Rust / Markdown PASS
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
external consumer PASS
|
||||
release completeness PASS
|
||||
hardening adversarial PASS
|
||||
cargo test --workspace FAIL cross-crate canary Logging
|
||||
cargo tree Interface Core-only confirmé
|
||||
```
|
||||
|
||||
L'échec workspace ne révèle aucun bypass runtime d'Interface. Le scanner `ksp-logging-lib/tests/ownership.rs` recherche littéralement le chemin source `tracing::` dans tous les fichiers Rust des crates KSP, tests compris. Le firewall `ksp-interface-lib/tests/dependency_boundary.rs` contenait cette chaîne comme **valeur de test interdite**, ce qui déclenchait le scanner Logging sur le canari lui-même.
|
||||
|
||||
Le fix conserve exactement la même interdiction mais construit le token de recherche sans faire apparaître le chemin littéral dans le source du test :
|
||||
|
||||
```rust
|
||||
concat!("tracing", "::")
|
||||
```
|
||||
|
||||
Le test Interface continue donc de refuser un chemin direct vers Tracing dans les sources de production, tandis que le scanner Logging ne confond plus la donnée du canari avec un usage runtime réel.
|
||||
|
||||
Aucun fichier `src/` de production, aucune dépendance, aucune API publique, aucune borne et aucune décision de logging ne sont modifiés. La version technique devient `0.2.13-pre.5.fix.1` parce que le fix touche un test Rust.
|
||||
|
||||
Le gate opérateur du fix est désormais intégralement vert : fmt, audits Rust/Markdown, `cargo check --workspace`, Clippy, tests Interface, canari Logging ciblé, `cargo test --workspace` et graphes Cargo sont tous validés/inspectés. Le faux positif est donc fermé sans élargissement du scope.
|
||||
|
||||
## 21. Gate technique final validé `pre.006`
|
||||
|
||||
`pre.006` n'a ajouté aucun code, aucun test et aucune dépendance. Le gate opérateur du **28 août 2026** ferme la lane technique avec les preuves suivantes :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audits Rust / export completeness / workspace PASS
|
||||
audit Markdown PASS — 162 tables / 119 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal Core-only confirmé
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
La surface technique finale avant documentation reste donc :
|
||||
|
||||
```text
|
||||
workspace.package.version 0.2.13-pre.6
|
||||
production Interface inchangée
|
||||
tests Interface inchangés
|
||||
surface crate-root 6 exports exacts
|
||||
modules production 4 fichiers exacts
|
||||
dépendance normale Interface ksp-core-lib uniquement
|
||||
codec / serde / solana-instruction absents
|
||||
ksp-logging-lib / tracing runtime Interface absents
|
||||
network/live smoke N/A pour foundation wire pure
|
||||
```
|
||||
|
||||
Le gate `pre.006` autorise la réconciliation documentaire finale sans réouverture technique.
|
||||
|
||||
## 22. Réconciliation documentaire finale `pre.007`
|
||||
|
||||
`pre.007` ne modifie aucun fichier Rust, test, manifest de crate, dépendance ou comportement. La version workspace avance mécaniquement à `0.2.13-pre.7` conformément au workflow de prerelease non-fix.
|
||||
|
||||
Les références durables sont réconciliées autour du contrat réellement livré :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
```
|
||||
|
||||
Le README Interface fixe l'ownership, la surface crate-root exacte, les deux bornes d'admission, le modèle d'erreur sûr, le Debug borné, le graphe `Interface -> Core`, l'absence de codecs/logging/runtime et les frontières avec Program API/Transport/Store. `USAGE.md` documente les constructeurs `readonly`/`writable`, `ProgramInstruction::try_new`, les accessors, les bornes et l'observation des erreurs sans dépendre des modules privés.
|
||||
|
||||
La séquence fonctionnelle précise désormais le contenu réellement livré par `0.2.13` et maintient les reports : Program API en `0.2.14`, wires génériques acquisition/CORE en `0.3.2+`. Les index plan/validation passent du statut actif au statut candidat réconcilié sans annoncer prématurément la release stable.
|
||||
|
||||
La tranche ne touche explicitement pas :
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
architecture
|
||||
code/tests/manifests de crate
|
||||
```
|
||||
|
||||
Ces surfaces appartiennent à `pre.008` pour la préparation minimale de publication, sauf découverte d'un défaut réel imposant une nouvelle tranche corrective.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/000-README.md -->
|
||||
<!-- version: 27 -->
|
||||
<!-- version: 29 -->
|
||||
|
||||
# Validations KSP
|
||||
|
||||
@@ -23,4 +23,5 @@ Documents :
|
||||
- [`012-V0_2_9_YELLOWSTONE_GRPC.md`](012-V0_2_9_YELLOWSTONE_GRPC.md) — matrice finale de la release stable `0.2.9` : service Geyser courant, `Subscribe` standard, 7 unary, filtres/updates, dépendances/licence, replay/backpressure, Config V3 et smoke PublicNode Mainnet/Testnet.
|
||||
- [`013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md`](013-V0_2_10_ORBITFLARE_YELLOWSTONE_GRPC.md) — matrice finale de la release stable `0.2.10` : Free Devnet, auth `x-token`, endpoint security, heartbeat standard, Config V3, smoke live `Slot + Ping` et invariant N1/N2 immuable.
|
||||
- [`014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md`](014-V0_2_11_OFFCHAIN_PRICE_TRANSPORT.md) — matrice historique clôturée de `0.2.11` : SOL/USD multi-provider, numeric safety, rate limiting/availability, Config capability-aware et smoke keyless final `7/7`.
|
||||
- [`015-V0_2_12_SOL_PRICES_DESK.md`](015-V0_2_12_SOL_PRICES_DESK.md) — matrice active ouverte par `0.2.12-pre.001` : screen/features, DTO/commands, Config/composite, frontières provider-neutral, sécurité, Wallet integration, packaging Tauri et gates live/build.
|
||||
- [`015-V0_2_12_SOL_PRICES_DESK.md`](015-V0_2_12_SOL_PRICES_DESK.md) — matrice historique clôturée de `0.2.12` : screen/features, DTO/commands, Config/composite, frontières provider-neutral, sécurité, Wallet integration, packaging Tauri et gates live/build.
|
||||
- [`016-V0_2_13_INTERFACE.md`](016-V0_2_13_INTERFACE.md) — matrice candidate finale de `0.2.13` : ownership Interface/Core/Transport/Program, surface passive, bornes/adversarial, façade publique exacte, consumer externe, release completeness, dependency firewall et gate technique `pre.006` intégralement vert.
|
||||
|
||||
371
docs/validation/016-V0_2_13_INTERFACE.md
Normal file
371
docs/validation/016-V0_2_13_INTERFACE.md
Normal file
@@ -0,0 +1,371 @@
|
||||
<!-- file: docs/validation/016-V0_2_13_INTERFACE.md -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Validation `0.2.13` — Interface / wire foundation
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Cette matrice est ouverte par `0.2.13-pre.001`. Elle suit la première surface de `ksp-interface-lib` et enregistre les critères de fermeture sans transformer Interface en Program API ou en modèle RAW/CORE générique.
|
||||
|
||||
Scope retenu :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
Pubkey via ksp-core-lib
|
||||
bornes comptes/data
|
||||
aucun codec générique
|
||||
aucun comportement Program
|
||||
```
|
||||
|
||||
## 2. Baseline stable
|
||||
|
||||
| Contrat | Attendu | Statut `pre.001` |
|
||||
|----------------------------|------------------------------------------------|------------------------------------------|
|
||||
| archive | `khadhroony-solana-project-v0.2.12.zip` stable | PASS marqueurs internes |
|
||||
| workspace version entrée | `0.2.12` | PASS |
|
||||
| `deltas/0.2.12/rel.001.md` | présent | PASS |
|
||||
| prompt 018 | présent | PASS |
|
||||
| `.git` | optionnel archive | ABSENT — tag non revérifiable localement |
|
||||
| `ksp-interface-lib` entrée | absent | PASS |
|
||||
| `ksp-program-api` entrée | absent | PASS |
|
||||
| gate Cargo stable | fmt/check/clippy/test | PASS preuve opérateur |
|
||||
| audits Python base | Rust + Markdown | PASS sandbox |
|
||||
|
||||
## 3. Lecture et ownership internes
|
||||
|
||||
| Famille | Constat | Décision |
|
||||
|-----------------------------------|-----------------------------------------------------|-------------------------------------|
|
||||
| Core `Pubkey` | public crate-root, `solana-pubkey ^4.3` | réutiliser; aucun wrapper Interface |
|
||||
| Core Program IDs | 18 identités fondamentales + registry | laisser Core |
|
||||
| Core Error/Result | contrat commun workspace | réutiliser pour Interface |
|
||||
| HTTP transaction/block DTOs | projections JSON-RPC Transport | laisser Transport |
|
||||
| Yellowstone instruction/meta DTOs | projections protobuf/Geyser | laisser Transport |
|
||||
| Architecture 006 | Interface wire passive; Program comportement séparé | scope conforme |
|
||||
| Roadmap 0.3.2 | wires génériques acquisition/CORE reportés | ne pas anticiper |
|
||||
|
||||
## 4. Héritage kbot3
|
||||
|
||||
| Concept | Verdict | Preuve attendue dans KSP |
|
||||
|-----------------------------------------|--------------------|--------------------------------------------|
|
||||
| ordered account meta | REPRENDRE | `ProgramAccountMeta` sans naming execution |
|
||||
| passive `{program_id, accounts, data}` | REPRENDRE | `ProgramInstruction` borné |
|
||||
| string Pubkey/ProgramId wrappers | REDESSINER | Core `Pubkey` directement |
|
||||
| unbounded payload | REDESSINER | borne + Debug résumé |
|
||||
| decoder traits/recognition/proofs | REPORTER 0.2.14 | absents d'Interface |
|
||||
| instruction path/CPI/replay context | REPORTER 0.3.2+ | absents de 0.2.13 |
|
||||
| canonical transaction/replay JSON model | REPORTER/redéfinir | aucun portage |
|
||||
| prepared execution policy/signers | REPORTER | absents d'Interface |
|
||||
| monolithic `ks-lib` organization | REJETER | crate ownership séparé |
|
||||
|
||||
## 5. Audit externe courant
|
||||
|
||||
| Référence | État observé 2026-08-27 | Décision de validation |
|
||||
|------------------------------|------------------------------------------------------------------|--------------------------------------------------------------|
|
||||
| `solana-instruction` | 3.5.0; `Pubkey ^4.3.0`; codecs optionnels | parité conceptuelle requise, dépendance non requise |
|
||||
| Solana `Instruction` | program_id + ordered AccountMeta + opaque bytes | forme cible exacte |
|
||||
| Solana syscall bounds | 255 account metas CPI; data 10 KiB; 128 unique account infos CPI | 255/10 KiB = admission Interface; 128 non appliqué aux metas |
|
||||
| `solana-loader-v3-interface` | 8.1.1; compatible générations observées | hors scope, réaudit au vertical réel |
|
||||
| licence Anza SDK | Apache-2.0 | compatible si future dépendance réellement retenue |
|
||||
|
||||
## 6. Matrice de frontière de release
|
||||
|
||||
| Surface | Owner | 0.2.13 | 0.2.14 | 0.3.2+ | Statut |
|
||||
|-----------------------------------|----------------|-----------|-----------------|----------------|---------|
|
||||
| Pubkey / Program IDs fondamentaux | Core | reuse | reuse | reuse | FIXÉ |
|
||||
| Program account meta | Interface | IMPLEMENT | consume | reuse | FIXÉ |
|
||||
| Program instruction passive | Interface | IMPLEMENT | consume | reuse | FIXÉ |
|
||||
| Program-specific codec/layout | Interface | OUT | si besoin réel | selon vertical | REPORTÉ |
|
||||
| decoder/preparer traits | Program API | OUT | AUDIT/IMPLEMENT | consume | REPORTÉ |
|
||||
| Transport provider DTOs | Transport | UNCHANGED | UNCHANGED | adapter future | FIXÉ |
|
||||
| generic acquisition/replay wire | Interface/CORE | OUT | OUT | IMPLEMENT | REPORTÉ |
|
||||
| RAW persistence | Store | OUT | OUT | `0.3.1`+ | REPORTÉ |
|
||||
|
||||
## 7. API publique cible
|
||||
|
||||
| Contrat | Attendu final `0.2.13` | Statut |
|
||||
|----------------------|--------------------------------------------------------|--------------|
|
||||
| crate | `ksp-interface-lib` membre workspace | PASS pre.002 |
|
||||
| façade | exports explicites crate-root; aucun `pub mod` | PASS pre.002 |
|
||||
| Pubkey | réexport/usage contrôlé de Core; pas de type parallèle | PASS pre.002 |
|
||||
| `ProgramAccountMeta` | private fields + writable/readonly + accessors | PASS pre.003 |
|
||||
| `ProgramInstruction` | private fields + `try_new` + accessors | PASS pre.006 |
|
||||
| account bound | constante publique `<= 255`; enforcement constructeur | PASS pre.006 |
|
||||
| data bound | `<= 10_240` | PASS pre.006 |
|
||||
| serde | absent | FIXÉ pre.001 |
|
||||
| generic codec | absent | FIXÉ pre.001 |
|
||||
| Debug instruction | résumé borné, pas payload complet | PASS pre.006 |
|
||||
| Error/Result | Core commun + code Interface sûr minimal | PASS pre.003 |
|
||||
|
||||
## 8. Robustness/adversarial
|
||||
|
||||
| Cas | Attendu | Gate |
|
||||
|------------------------------|--------------------------|-------------------------|
|
||||
| 0 account | accepté | unit |
|
||||
| 255 accounts | accepté | unit |
|
||||
| 256 accounts | refus avant état valide | unit |
|
||||
| 0 data | accepté | unit |
|
||||
| 10_240 bytes | accepté | unit |
|
||||
| 10_241 bytes | refus | unit |
|
||||
| duplicate accounts | ordre/doublons conservés | unit + public API |
|
||||
| unknown Program Pubkey | accepté | unit |
|
||||
| hostile data marker in Debug | absent du rendu | unit |
|
||||
| hostile data marker in Error | absent du rendu/context | unit |
|
||||
| unchecked narrowing cast | absent | source audit/Clippy |
|
||||
| malformed binary wire | N/A sans codec | ne pas inventer un test |
|
||||
| unknown discriminant | N/A sans enum wire | réouvrir au vertical |
|
||||
| serde hostile allocation | N/A serde absent | dependency canary |
|
||||
|
||||
## 9. Dependency firewall
|
||||
|
||||
| Dépendance depuis Interface | Attendu final | Preuve |
|
||||
|-------------------------------------|----------------------------------------|------------------------|
|
||||
| `ksp-core-lib` | AUTORISÉ / requis | manifest + cargo tree |
|
||||
| `ksp-program-api` / Program Lib | INTERDIT | manifest/source canary |
|
||||
| On-chain / Off-chain Transport | INTERDIT | manifest/source canary |
|
||||
| Config / Wallet / Store / Tauri | INTERDIT | manifest/source canary |
|
||||
| reqwest / tonic / tokio / websocket | INTERDIT | cargo tree + manifest |
|
||||
| serde / serde_json | ABSENT en foundation | manifest + cargo tree |
|
||||
| borsh / bincode / wincode | ABSENT en foundation | manifest + cargo tree |
|
||||
| `solana-instruction` | ABSENT tant qu'interop réel non requis | manifest + cargo tree |
|
||||
|
||||
Graphes attendus :
|
||||
|
||||
```bash
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Si une nouvelle dépendance externe apparaît après `pre.001`, la présente matrice doit être rouverte avant acceptation.
|
||||
|
||||
## 10. Tests de release
|
||||
|
||||
| Famille | Attendu | Statut |
|
||||
|--------------------------|-------------------------------------------------|--------------|
|
||||
| unit tests privés | account meta/borne puis instruction/adversarial | PASS pre.006 |
|
||||
| `tests/public_api.rs` | consommation crate-root uniquement | PASS pre.006 |
|
||||
| external consumer canary | surface utilisable hors modules privés | PASS pre.006 |
|
||||
| dependency boundary | firewall exact | PASS pre.006 |
|
||||
| release completeness | inventaire exact, aucun domaine supplémentaire | PASS pre.006 |
|
||||
| round-trip codec | aucun tant qu'aucun codec | N/A |
|
||||
| network smoke | aucun pour crate wire pure | N/A |
|
||||
|
||||
## 11. Gate technique final validé
|
||||
|
||||
Le gate opérateur `0.2.13-pre.006` du **28 août 2026** ferme la lane technique :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS — 162 tables / 119 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-interface-lib --edges normal Core-only confirmé
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Aucun smoke réseau/live n'est exigé : la crate reste une foundation wire pure sans I/O.
|
||||
|
||||
## 12. État `pre.001`
|
||||
|
||||
| Critère de sortie prompt | Statut |
|
||||
|-------------------------------------------|-----------------------------------|
|
||||
| sources internes obligatoires relues | PASS |
|
||||
| base stable confirmée | PASS marqueurs + preuve opérateur |
|
||||
| Core/Transport inventoriés | PASS |
|
||||
| architecture 006 confrontée à la base | PASS |
|
||||
| archive kbot3 auditée | PASS |
|
||||
| matrice héritage | PASS |
|
||||
| frontière 0.2.13 / 0.2.14 / 0.3.2 | PASS |
|
||||
| premier lot exact décidé | PASS |
|
||||
| ownership types | PASS |
|
||||
| dépendances candidates auditables/bornées | PASS |
|
||||
| threat model | PASS |
|
||||
| test strategy | PASS |
|
||||
| dependency graph cible | PASS |
|
||||
| plan + validation | PASS |
|
||||
| forecast/sizing | PASS |
|
||||
| implémentation Program lourde | ABSENTE |
|
||||
|
||||
Le passage à `pre.002` est autorisé après application du delta et validation opérateur. Le statut des items d'implémentation reste volontairement `TODO` jusqu'aux tranches correspondantes.
|
||||
|
||||
## 13. État préparé `pre.002`
|
||||
|
||||
Le scaffold matérialisé conserve volontairement une surface minimale :
|
||||
|
||||
```text
|
||||
workspace member PASS structurel
|
||||
normal dependency ksp-core-lib uniquement
|
||||
Pubkey réexport Core au crate-root
|
||||
public modules aucun
|
||||
ProgramAccountMeta absent par contrat pre.002
|
||||
ProgramInstruction absent par contrat pre.002
|
||||
serde / borsh / bincode / wincode absents
|
||||
network/runtime dependencies absentes
|
||||
ksp-logging-lib absent
|
||||
constants.rs / TRACING_TARGET absents
|
||||
README / USAGE initiaux
|
||||
public API canary présent
|
||||
dependency firewall canary présent
|
||||
```
|
||||
|
||||
Le logging reste volontairement absent : la foundation `0.2.13` est passive et n'émet aucun événement/span runtime. Si une future surface comportementale démontre un besoin réel de logging, `ksp-logging-lib`, `src/constants.rs` et `TRACING_TARGET` devront être introduits ensemble conformément à `DEP-LOG-004` et `DEP-LOG-010`.
|
||||
|
||||
Le passage à `pre.003` reste conditionné au gate opérateur complet sur l'overlay `pre.002`.
|
||||
|
||||
## 14. État préparé `pre.003`
|
||||
|
||||
| Critère | Statut |
|
||||
|-----------------------------------------------------|---------------------------------------------|
|
||||
| `ProgramAccountMeta` crate-root | PASS structurel |
|
||||
| champs privés | PASS |
|
||||
| constructeurs `readonly` / `writable` | PASS |
|
||||
| accessors identité/signer/writable | PASS |
|
||||
| Pubkey opaque non registry | PASS unit |
|
||||
| `MAX_PROGRAM_INSTRUCTION_ACCOUNTS == 255` | PASS unit + public API |
|
||||
| enforcement collection `255/256` | PENDING `pre.004` avec `ProgramInstruction` |
|
||||
| code `interface.program_instruction_limit_exceeded` | PASS public API |
|
||||
| type d'erreur propre Interface | ABSENT, Core commun conservé |
|
||||
| `ProgramInstruction` | ABSENT par contrat |
|
||||
| data bound | PENDING `pre.004` |
|
||||
| serde/codecs | ABSENTS |
|
||||
| logging/runtime | ABSENTS |
|
||||
| dépendance normale | `ksp-core-lib` uniquement |
|
||||
|
||||
Le statut `PASS/PENDING` de la borne accounts signifie que la valeur publique est désormais figée à `255`, tandis que le rejet concret de `256` comptes sera testé lorsque la collection existera dans `ProgramInstruction`. Aucun faux wrapper de collection n'est créé dans `pre.003`.
|
||||
|
||||
## 15. État préparé `pre.004`
|
||||
|
||||
| Critère | Statut |
|
||||
|------------------------------------------------------|----------------------------------------------|
|
||||
| `ProgramInstruction` crate-root | PASS structurel |
|
||||
| champs privés | PASS |
|
||||
| constructeur `try_new` | PASS |
|
||||
| accessors `program_id/accounts/data` | PASS |
|
||||
| `MAX_PROGRAM_INSTRUCTION_DATA_LEN == 10_240` | PASS unit + public API |
|
||||
| accounts `255` accepté / `256` refusé | PASS unit |
|
||||
| data `10_240` accepté / `10_241` refusé | PASS unit |
|
||||
| accounts/data vides | PASS unit |
|
||||
| ordre + doublons accounts | PASS unit |
|
||||
| Program Pubkey opaque/non registry | PASS unit |
|
||||
| erreur borne Core commune | PASS |
|
||||
| contexte erreur limité aux longueurs/plafonds sûrs | PASS unit |
|
||||
| Debug résumé sans accounts/payload | PASS unit |
|
||||
| serde/codecs | ABSENTS |
|
||||
| `solana-instruction` | ABSENT |
|
||||
| logging/runtime | ABSENTS |
|
||||
| dépendance normale | `ksp-core-lib` uniquement |
|
||||
| `cargo test --workspace` sur preuve entrée `pre.003` | NON FOURNI — à rejouer au gate opérateur 004 |
|
||||
|
||||
La tranche ferme ainsi le premier lot générique `{ program_id, accounts, data }` sans ajouter de codec ni de comportement Program. Le hardening `pre.005` doit porter sur l'usage externe, les cas adversariaux et le firewall, pas sur une nouvelle famille wire.
|
||||
|
||||
## 16. État préparé `pre.005`
|
||||
|
||||
Le gate opérateur `pre.004` est complet : fmt, audits Rust/Markdown, `cargo check --workspace`, Clippy, `cargo test -p ksp-interface-lib`, `cargo test --workspace` et graphes Cargo sont verts/inspectés.
|
||||
|
||||
La tranche `pre.005` ajoute uniquement des canaris de hardening :
|
||||
|
||||
```text
|
||||
external consumer crate présent via tests/external_consumer.rs
|
||||
release completeness présent via tests/release_completeness.rs
|
||||
crate-root exports exacts vérifiés par source canary
|
||||
production module inventory exact vérifié par filesystem canary
|
||||
source dependency firewall étendu à tous les src production
|
||||
narrowing cast / encode/decode caché interdits par source canary
|
||||
Vec accounts/data sans réallocation vérifié par identité de pointeur
|
||||
payload hostile dans Error/Debug absent attendu
|
||||
account material arbitraire dans Error absent attendu
|
||||
nouveau type wire aucun
|
||||
nouvelle dépendance aucune
|
||||
codec/logging/runtime toujours absents
|
||||
```
|
||||
|
||||
Les nouveaux tests sont **présents mais non déclarés PASS dans le sandbox**, qui ne dispose pas de Cargo. Leur statut final dépend du gate opérateur `pre.005`.
|
||||
|
||||
Le consumer externe est un test d'intégration Rust, donc compilé par Cargo dans un crate distinct de `ksp-interface-lib`. Sa source ne consomme que les exports du crate-root ; les modules privés ne sont pas utilisés.
|
||||
|
||||
Le canari de complétude impose exactement les exports publics retenus et exactement quatre modules/fichiers de production : `error.rs`, `lib.rs`, `program_account_meta.rs`, `program_instruction.rs`. Cette contrainte ferme explicitement le risque d'ajout opportuniste d'une seconde famille wire avant la release stable.
|
||||
|
||||
## 17. Gate `pre.005` et correctif `pre.005-fix.001`
|
||||
|
||||
Le gate ciblé Interface est intégralement vert :
|
||||
|
||||
```text
|
||||
unit tests Interface 10/10 PASS
|
||||
manifest/source firewall 4/4 PASS
|
||||
external consumer 1/1 PASS
|
||||
public API 5/5 PASS
|
||||
release completeness 3/3 PASS
|
||||
doctests 0 échec
|
||||
```
|
||||
|
||||
Le workspace échoue ensuite dans le canari transversal Logging :
|
||||
|
||||
```text
|
||||
ksp-logging-lib/tests/ownership.rs
|
||||
workspace_crates_do_not_bypass_ksp_logging_facade
|
||||
```
|
||||
|
||||
Diagnostic confirmé : `tests/dependency_boundary.rs` contient le littéral `tracing::` uniquement comme pattern interdit. Le scanner Logging travaille sur le texte brut des `.rs` et interprète donc ce pattern de test comme un bypass réel. Le graphe Cargo Interface reste pourtant :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
└── solana-pubkey 4.3.0
|
||||
```
|
||||
|
||||
`pre.005-fix.001` remplace uniquement ce littéral source par une construction compile-time équivalente `concat!("tracing", "::")`. La propriété testée reste identique ; seule l'interaction entre deux scanners est corrigée.
|
||||
|
||||
Statut final du fix après gate opérateur :
|
||||
|
||||
```text
|
||||
production src inchangé
|
||||
API publique inchangée
|
||||
dépendances inchangées
|
||||
logging runtime Interface toujours absent
|
||||
codec toujours absent
|
||||
version technique 0.2.13-pre.5.fix.1
|
||||
cargo test -p ksp-interface-lib PASS
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree Interface Core-only confirmé
|
||||
```
|
||||
|
||||
## 18. Gate technique final `pre.006`
|
||||
|
||||
Le gate final a confirmé la surface complète sans nouvelle modification technique :
|
||||
|
||||
```text
|
||||
unit Interface 10/10 PASS
|
||||
dependency boundary 4/4 PASS
|
||||
external consumer 1/1 PASS
|
||||
public API 5/5 PASS
|
||||
release completeness 3/3 PASS
|
||||
ownership Logging 2/2 PASS
|
||||
workspace PASS
|
||||
Cargo graph Interface ksp-core-lib uniquement
|
||||
```
|
||||
|
||||
Les duplicates observés dans le workspace sont extérieurs au graphe normal d'Interface et ne proviennent d'aucune dépendance ajoutée par `0.2.13`.
|
||||
|
||||
La validation technique de la release candidate est fermée.
|
||||
|
||||
## 19. Réconciliation documentaire `pre.007`
|
||||
|
||||
La documentation finale candidate est alignée sur les preuves techniques :
|
||||
|
||||
| Référence durable | Statut `pre.007` | Contrat réconcilié |
|
||||
|-------------------------------------------------|------------------|----------------------------------------------------------------------|
|
||||
| `crates/ksp-interface-lib/README.md` | PASS structurel | ownership, surface finale, bornes, firewall, frontières |
|
||||
| `crates/ksp-interface-lib/USAGE.md` | PASS structurel | usage crate-root, construction metas/instruction, erreurs et limites |
|
||||
| `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` | PASS structurel | contenu réel `0.2.13` + reports `0.2.14` / `0.3.2+` |
|
||||
| `docs/plans/020-V0_2_13_INTERFACE_PLAN.md` | PASS structurel | gate `pre.006` fermé + lane documentaire finale |
|
||||
| `docs/validation/016-V0_2_13_INTERFACE.md` | PASS structurel | statuts finaux et preuves opérateur |
|
||||
| index `docs/000`, plans et validation | PASS structurel | candidate réconciliée sans publication stable prématurée |
|
||||
|
||||
La tranche n'ajoute aucun code/test/codec/dépendance et ne modifie ni `CHANGELOG.md`, ni `ROADMAP.md`, ni le prompt `0.2.14`. Ces trois surfaces restent réservées à `pre.008`.
|
||||
|
||||
Le gate opérateur de `pre.007` doit rester déterministe : audits, check, Clippy et workspace tests suffisent ; aucun smoke live ni nouveau `cargo tree` n'est requis si l'overlay documentaire est appliqué exactement.
|
||||
1430
prompts/019-V0_2_14_START_PROMPT.md
Normal file
1430
prompts/019-V0_2_14_START_PROMPT.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user