Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d307be645 | |||
| 7dfe892467 | |||
| 2cf00e9426 | |||
| 4eba9be48c | |||
| bebfc63b75 | |||
| 0319794e59 | |||
| bcf2f16c05 | |||
| 27d4cb1f36 | |||
| c1f61a380f | |||
| 5e5ed6d1ab |
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,8 +1,16 @@
|
||||
<!-- file: CHANGELOG.md -->
|
||||
<!-- version: 17 -->
|
||||
<!-- version: 18 -->
|
||||
|
||||
# Changelog KSP
|
||||
|
||||
## 0.2.14 — Program API foundation — 2026-08-28
|
||||
|
||||
`0.2.14` introduit `ksp-program-api` comme première API publique extensible du domaine Program, volontairement limitée au décodage d’instructions et indépendante des runtimes supérieurs. La façade réexporte les contrats Core/Interface nécessaires puis possède `ProgramInstructionRecognition` (`NoMatch`, `ProgramMatch`, `ExactMatch`), `ProgramInstructionDecodeOutcome<Decoded>` (`Decoded`, `Unsupported`) et le trait `ProgramInstructionDecoder: Send + Sync`. L’output `Decoded` reste possédé par l’implémentation et ne reçoit aucun bound implicite `Debug`, `Clone`, `Send` ou `Sync`; les erreurs réelles restent dans le `Result` Core. Les Program IDs sont des `Pubkey` opaques : une implémentation externe peut prendre en charge un programme absent du registry Core sans enum centrale fermée, `Any`, JSON, descriptor global ni registry runtime.
|
||||
|
||||
Le graphe normal final reste strictement `ksp-program-api -> ksp-core-lib + ksp-interface-lib`, Interface dépendant elle-même de Core. Aucun `ksp-program-lib`, codec, serde, logging, réseau, filesystem, environnement, Store, Materializer, Wallet, Config ou Tauri n’entre dans cette foundation. Les canaris public API, implémentation externe, dependency firewall, release completeness et hardening couvrent notamment l’inventaire exact de dix exports crate-root, les trois modules de production, un Program Pubkey non enregistré, l’input Interface maximal de 255 accounts / 10 240 bytes, l’absence d’echo automatique d’un payload hostile et l’absence de claim `dyn` hétérogène. `pre.005-fix.001` corrige uniquement un faux positif cross-crate du scanner Logging provoqué par le motif de test recherché, sans changement fonctionnel. Les gates `pre.006` et `pre.007` passent ensuite audits Rust/Markdown, `cargo check`, Clippy, les 18 tests Program API, ownership Logging et le workspace complet avant la réconciliation documentaire finale.
|
||||
|
||||
`prompts/020-V0_3_1_START_PROMPT.md` ouvre `0.3.1 — Store RAW foundation` exclusivement depuis le tag stable `v0.2.14`. Le gate `pre.001` exige également l’archive historique `khadhroony-bot3_v0.5.3-pre.005-fix010.zip` afin d’auditer l’ancien `ks-store`, ses migrations PostgreSQL et ses contrats N1/N2/N3 sous une matrice `REPRENDRE / REDESSINER / REPORTER / REJETER`. L’archive reste une source historique uniquement : `0.3.1` doit créer `ksp-store-api` et `ksp-store-lib` avec PostgreSQL de référence et persistence **RAW seulement**, sans aspirer les contrats CORE/DECODE/SPECIALIZED, les jobs/workers, l’Interface `0.3.2` ni la configuration produit.
|
||||
|
||||
## 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`.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 312
|
||||
# version: 322
|
||||
|
||||
[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-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-wallet-lib"]
|
||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-wallet-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.13"
|
||||
version = "0.2.14"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 91 -->
|
||||
<!-- version: 92 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -58,7 +58,7 @@ Le roadmap décrit les objectifs à atteindre et les grandes étapes prévues. U
|
||||
- [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.
|
||||
- [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.
|
||||
- [X] `0.2.14` — Program API foundation stable : `ksp-program-api` expose une surface instruction-only ouverte avec `ProgramInstructionRecognition`, `ProgramInstructionDecodeOutcome<Decoded>` et `ProgramInstructionDecoder`; implémentation externe avec Program Pubkey opaque validée, 10 exports crate-root / 3 modules de production verrouillés, graphe strict Core + Interface, sans registry/runtime/serde/codec/Store/Materializer/Execution. Le prompt `0.3.1` prépare Store RAW-only.
|
||||
|
||||
### TODO/IDEAS — providers Yellowstone non planifiés
|
||||
|
||||
|
||||
15
crates/ksp-program-api/Cargo.toml
Normal file
15
crates/ksp-program-api/Cargo.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
# file: crates/ksp-program-api/Cargo.toml
|
||||
# version: 1
|
||||
|
||||
[package]
|
||||
name = "ksp-program-api"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[dependencies]
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
ksp-interface-lib = { path = "../ksp-interface-lib" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
156
crates/ksp-program-api/README.md
Normal file
156
crates/ksp-program-api/README.md
Normal file
@@ -0,0 +1,156 @@
|
||||
<!-- file: crates/ksp-program-api/README.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# ksp-program-api
|
||||
|
||||
`ksp-program-api` est la façade publique ouverte du domaine Program KSP. Elle porte uniquement les contrats communs nécessaires aux implémentations Program officielles futures comme aux crates externes ; elle ne possède aucun decoder concret, registry runtime, payload canonique DECODE ni logique d'exécution.
|
||||
|
||||
La surface candidate de `0.2.14` est volontairement **instruction-only** et reste indépendante des couches runtime supérieures.
|
||||
|
||||
## Ownership
|
||||
|
||||
Le graphe normal est limité à :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Core reste propriétaire de :
|
||||
|
||||
```text
|
||||
Error
|
||||
ErrorCode
|
||||
ErrorContext
|
||||
Result
|
||||
Pubkey
|
||||
```
|
||||
|
||||
Interface reste propriétaire de :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
```
|
||||
|
||||
Program API possède :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
ProgramInstructionDecoder
|
||||
```
|
||||
|
||||
`ksp-program-api` réexporte toute sa surface consommable depuis son crate-root. Aucun module interne n'est public.
|
||||
|
||||
## Surface publique candidate
|
||||
|
||||
L'inventaire crate-root de `0.2.14` contient exactement :
|
||||
|
||||
```text
|
||||
Error
|
||||
ErrorCode
|
||||
ErrorContext
|
||||
Result
|
||||
Pubkey
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
ProgramInstructionDecoder
|
||||
```
|
||||
|
||||
Les canaris de release completeness verrouillent cet inventaire ainsi que les trois fichiers/modules Rust de production de la crate.
|
||||
|
||||
## Recognition
|
||||
|
||||
`ProgramInstructionRecognition` est `#[non_exhaustive]` :
|
||||
|
||||
```text
|
||||
NoMatch l'implémentation ne revendique pas l'instruction
|
||||
ProgramMatch le Program correspond, sans reconnaissance instruction-local exacte
|
||||
ExactMatch l'implémentation affirme un match instruction-local exact
|
||||
```
|
||||
|
||||
La reconnaissance ne porte aucun score, priorité, proof, confidence, discriminator textuel ni inventaire central de Programs. `ExactMatch` reste une affirmation de l'implémentation, pas une preuve indépendante produite par KSP.
|
||||
|
||||
## Decode outcome
|
||||
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` est `#[non_exhaustive]` :
|
||||
|
||||
```text
|
||||
Decoded(Decoded) valeur typée possédée par l'implémentation
|
||||
Unsupported instruction reconnue mais non supportée par cette capability
|
||||
```
|
||||
|
||||
Les échecs réels utilisent le `Result` Core. Il n'existe aucune variante parallèle `Failed` ou `Ignored`.
|
||||
|
||||
Le `Debug` de l'outcome n'impose pas `Decoded: Debug` et n'affiche jamais la valeur `Decoded`.
|
||||
|
||||
## Decoder instruction-only
|
||||
|
||||
`ProgramInstructionDecoder` est un trait ouvert `Send + Sync` :
|
||||
|
||||
```text
|
||||
type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction) -> ProgramInstructionRecognition
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
```
|
||||
|
||||
`Decoded` ne reçoit aucun bound implicite supplémentaire : une implémentation reste propriétaire de son type de sortie concret. Le trait ne fournit aucun default method et ne promet pas de composition `dyn` hétérogène.
|
||||
|
||||
`program_ids()` expose des `Pubkey` opaques ; une implémentation externe peut prendre en charge un Program ID absent du registry Core. Aucun enum central, `Any`, JSON ou descriptor global n'est nécessaire.
|
||||
|
||||
`program_ids` et `recognize` servent à la sélection explicite. `decode` consomme par référence une `ProgramInstruction` déjà admise/bornée par Interface et déjà sélectionnée pour le decoder.
|
||||
|
||||
## Hardening validé
|
||||
|
||||
La candidate verrouille notamment :
|
||||
|
||||
```text
|
||||
Program Pubkey non enregistré accepté
|
||||
input Interface maximal 255 accounts + 10_240 bytes accepté à la frontière decoder
|
||||
payload hostile aucun echo automatique ajouté par Program API
|
||||
Debug outcome valeur Decoded jamais rendue
|
||||
associated Decoded aucun Debug/Clone/Send/Sync imposé
|
||||
closed-world Program enum absent
|
||||
registry / descriptors / priority absents
|
||||
ProgramExecutionPreparer absent
|
||||
serde / JSON / Any / codecs absents
|
||||
logging / runtime / filesystem / environment / I/O absents
|
||||
```
|
||||
|
||||
Une implémentation tierce reste responsable du contenu des erreurs qu'elle construit explicitement. `ksp-program-api` garantit seulement qu'il n'ajoute aucun canal parallèle ni copie automatique du payload d'entrée.
|
||||
|
||||
## Frontières
|
||||
|
||||
La foundation `0.2.14` ne contient pas :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
registry runtime
|
||||
identity/version/coverage de decoder
|
||||
payload canonique D3
|
||||
ProgramAccountDecoder
|
||||
ProgramEventDecoder
|
||||
ProgramReturnDataDecoder
|
||||
ProgramExecutionPreparer
|
||||
serde / serde_json
|
||||
borsh / wincode / bincode
|
||||
solana-instruction
|
||||
network / async runtime
|
||||
logging / tracing
|
||||
Wallet / Transport / Store / Materializer / Config / Tauri
|
||||
```
|
||||
|
||||
Ces surfaces restent reportées jusqu'aux vertical slices qui démontreront leurs contrats réels. En particulier, les codecs wire officiels restent possédés par `ksp-interface-lib` et ne sont introduits qu'en présence d'un protocole réel.
|
||||
|
||||
## Références
|
||||
|
||||
- [Usage public](USAGE.md)
|
||||
- [Plan `0.2.14`](../../docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md)
|
||||
- [Validation `0.2.14`](../../docs/validation/017-V0_2_14_PROGRAM_API.md)
|
||||
- [Architecture Wire + Program](../../docs/architecture/006-WIRE_AND_PROGRAM.md)
|
||||
166
crates/ksp-program-api/USAGE.md
Normal file
166
crates/ksp-program-api/USAGE.md
Normal file
@@ -0,0 +1,166 @@
|
||||
<!-- file: crates/ksp-program-api/USAGE.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Usage de ksp-program-api
|
||||
|
||||
Cette page décrit la surface publique candidate de `0.2.14`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable.
|
||||
|
||||
## Construire un input Program avec la façade
|
||||
|
||||
```rust
|
||||
let program_id = ksp_program_api::Pubkey::new_from_array([1_u8; 32]);
|
||||
let account_id = ksp_program_api::Pubkey::new_from_array([2_u8; 32]);
|
||||
let account = ksp_program_api::ProgramAccountMeta::readonly(account_id, true);
|
||||
|
||||
let instruction = ksp_program_api::ProgramInstruction::try_new(
|
||||
program_id,
|
||||
std::vec![account],
|
||||
std::vec![0x01_u8, 0x02, 0x03],
|
||||
);
|
||||
|
||||
assert!(instruction.is_ok());
|
||||
```
|
||||
|
||||
`Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. Les bornes `255` account metas et `10_240` bytes de data sont appliquées par Interface avant l'entrée dans le decoder.
|
||||
|
||||
## Implémenter un decoder externe
|
||||
|
||||
Le type décodé reste entièrement possédé par la crate d'implémentation :
|
||||
|
||||
```rust
|
||||
struct ExternalDecodedInstruction {
|
||||
opcode: u8,
|
||||
}
|
||||
|
||||
struct ExternalDecoder {
|
||||
program_ids: [ksp_program_api::Pubkey; 1],
|
||||
}
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for ExternalDecoder {
|
||||
type Decoded = ExternalDecodedInstruction;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &self.program_ids;
|
||||
}
|
||||
|
||||
fn recognize(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
if instruction.program_id() != &self.program_ids[0] {
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
|
||||
if instruction.data().first() == std::option::Option::Some(&0x2A_u8) {
|
||||
return ksp_program_api::ProgramInstructionRecognition::ExactMatch;
|
||||
}
|
||||
|
||||
return ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
let opcode = match instruction.data().first() {
|
||||
std::option::Option::Some(value) if *value == 0x2A_u8 => *value,
|
||||
_ => {
|
||||
return std::result::Result::Ok(
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return std::result::Result::Ok(
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(
|
||||
ExternalDecodedInstruction { opcode },
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Aucun `ksp-program-lib`, enum centrale, `Any`, JSON ou codec n'est nécessaire. Le Program ID peut être un `Pubkey` opaque non enregistré par Core.
|
||||
|
||||
## Sélection explicite
|
||||
|
||||
La sélection reste distincte du décodage :
|
||||
|
||||
```rust
|
||||
let recognition = ksp_program_api::ProgramInstructionDecoder::recognize(
|
||||
&decoder,
|
||||
&instruction,
|
||||
);
|
||||
|
||||
match recognition {
|
||||
ksp_program_api::ProgramInstructionRecognition::NoMatch => {}
|
||||
ksp_program_api::ProgramInstructionRecognition::ProgramMatch => {}
|
||||
ksp_program_api::ProgramInstructionRecognition::ExactMatch => {}
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
L'enum est `#[non_exhaustive]`. `ExactMatch` exprime l'affirmation du decoder. `decode` n'est pas un substitut à `recognize` : il traite une instruction déjà sélectionnée pour cette implémentation.
|
||||
|
||||
## Outcome et erreur
|
||||
|
||||
```rust
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(
|
||||
&decoder,
|
||||
&instruction,
|
||||
)?;
|
||||
|
||||
match outcome {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => {
|
||||
let _opcode = value.opcode;
|
||||
}
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported => {}
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
Une erreur réelle est un `Err(ksp_program_api::Error)`. `Unsupported` n'est pas une deuxième forme d'erreur : il indique qu'une instruction reconnue n'est volontairement pas décodée par cette capability.
|
||||
|
||||
Program API ne recopie automatiquement ni le payload de l'instruction ni les account metas dans l'erreur. Une implémentation externe reste responsable des messages/contextes qu'elle construit explicitement.
|
||||
|
||||
## Output sans bounds implicites
|
||||
|
||||
L'associated type `Decoded` n'impose pas `Debug`, `Clone`, `Send` ou `Sync`. Les supertraits `Send + Sync` s'appliquent au decoder lui-même, pas à la valeur décodée :
|
||||
|
||||
```rust
|
||||
struct LocalDecoded(std::rc::Rc<std::cell::Cell<u8>>);
|
||||
```
|
||||
|
||||
Un decoder peut utiliser ce type comme `Decoded` tant que son propre état satisfait `Send + Sync`.
|
||||
|
||||
## Debug sûr
|
||||
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` possède un `Debug` volontairement opaque :
|
||||
|
||||
```rust
|
||||
struct SecretDecoded;
|
||||
|
||||
let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(SecretDecoded);
|
||||
assert_eq!(std::format!("{outcome:?}"), "Decoded");
|
||||
```
|
||||
|
||||
`SecretDecoded` n'a pas besoin d'implémenter `Debug` et sa valeur n'est jamais rendue par l'outcome.
|
||||
|
||||
## Ce qui n'est pas simulé côté consumer
|
||||
|
||||
Il n'existe dans `0.2.14` aucun :
|
||||
|
||||
```text
|
||||
registry de decoders
|
||||
composition dyn hétérogène
|
||||
identity/version/coverage descriptor
|
||||
priority/conflict policy
|
||||
payload canonique D3
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
ProgramExecutionPreparer
|
||||
execution policy
|
||||
serde / JSON / codec
|
||||
logging / runtime réseau
|
||||
```
|
||||
|
||||
Ces surfaces ne doivent pas être recréées localement comme si elles faisaient déjà partie du contrat commun. Elles attendent les vertical slices qui justifieront leurs invariants réels.
|
||||
37
crates/ksp-program-api/src/lib.rs
Normal file
37
crates/ksp-program-api/src/lib.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
// file: crates/ksp-program-api/src/lib.rs
|
||||
// version: 3
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Open Program contracts shared by KSP and external Program implementations.
|
||||
//!
|
||||
//! The foundation exposes Core/Interface types plus the minimal instruction
|
||||
//! recognition/decode vocabulary and the instruction decoder trait. Registries,
|
||||
//! codecs, runtime logging and execution preparation remain outside this
|
||||
//! foundation until their ownership is justified.
|
||||
|
||||
mod program_instruction_decode;
|
||||
mod program_instruction_decoder;
|
||||
|
||||
/// Result of a successful Program instruction decode attempt.
|
||||
pub use self::program_instruction_decode::ProgramInstructionDecodeOutcome;
|
||||
/// Recognition strength reported by one Program instruction implementation.
|
||||
pub use self::program_instruction_decode::ProgramInstructionRecognition;
|
||||
/// Open contract implemented by one Program instruction decoder.
|
||||
pub use self::program_instruction_decoder::ProgramInstructionDecoder;
|
||||
/// Common KSP error type used by Program-facing contracts.
|
||||
pub use ksp_core_lib::Error;
|
||||
/// Stable structured code identifying a KSP error category and condition.
|
||||
pub use ksp_core_lib::ErrorCode;
|
||||
/// Structured contextual field attached to a KSP error.
|
||||
pub use ksp_core_lib::ErrorContext;
|
||||
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
|
||||
pub use ksp_core_lib::Pubkey;
|
||||
/// Common KSP result alias using [`Error`].
|
||||
pub use ksp_core_lib::Result;
|
||||
/// Passive account metadata attached to one Program instruction.
|
||||
pub use ksp_interface_lib::ProgramAccountMeta;
|
||||
/// Passive, bounded Program instruction wire contract.
|
||||
pub use ksp_interface_lib::ProgramInstruction;
|
||||
50
crates/ksp-program-api/src/program_instruction_decode.rs
Normal file
50
crates/ksp-program-api/src/program_instruction_decode.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
// file: crates/ksp-program-api/src/program_instruction_decode.rs
|
||||
// version: 1
|
||||
|
||||
/// Recognition strength reported by one Program instruction implementation.
|
||||
///
|
||||
/// Recognition is intentionally instruction-local. It does not encode registry
|
||||
/// priority, a persisted proof, a textual discriminator or a global Program
|
||||
/// kind. [`Self::ExactMatch`] is an assertion made by the implementation for
|
||||
/// the current instruction, while [`Self::ProgramMatch`] only establishes the
|
||||
/// Program-level match.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum ProgramInstructionRecognition {
|
||||
/// The implementation does not claim the instruction.
|
||||
NoMatch,
|
||||
/// The Program or Program family matches, but the instruction is not proven exact.
|
||||
ProgramMatch,
|
||||
/// The implementation claims an exact instruction-local match.
|
||||
ExactMatch,
|
||||
}
|
||||
|
||||
/// Result of a successful Program instruction decode attempt.
|
||||
///
|
||||
/// Decode failures are represented by the surrounding KSP [`crate::Result`],
|
||||
/// not by a parallel failure variant. `Unsupported` is reserved for a known
|
||||
/// Program instruction that the implementation deliberately does not decode.
|
||||
///
|
||||
/// The custom [`std::fmt::Debug`] implementation never formats the `Decoded`
|
||||
/// value, so external decoded payloads are not exposed accidentally through
|
||||
/// generic diagnostics.
|
||||
#[non_exhaustive]
|
||||
pub enum ProgramInstructionDecodeOutcome<Decoded> {
|
||||
/// The instruction was decoded into the implementation-owned output type.
|
||||
Decoded(Decoded),
|
||||
/// The instruction is known but unsupported by this decode capability.
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
impl<Decoded> std::fmt::Debug for ProgramInstructionDecodeOutcome<Decoded> {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Decoded(_) => return formatter.write_str("Decoded"),
|
||||
Self::Unsupported => return formatter.write_str("Unsupported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/program_instruction_decode.rs"]
|
||||
mod tests;
|
||||
28
crates/ksp-program-api/src/program_instruction_decoder.rs
Normal file
28
crates/ksp-program-api/src/program_instruction_decoder.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
// file: crates/ksp-program-api/src/program_instruction_decoder.rs
|
||||
// version: 1
|
||||
|
||||
/// Open contract implemented by one Program instruction decoder.
|
||||
///
|
||||
/// The decoder owns its concrete [`Self::Decoded`] type. No central Program
|
||||
/// enum, erased `Any` payload or serialization contract is required. Program
|
||||
/// identifiers remain opaque [`crate::Pubkey`] values and do not need to be
|
||||
/// registered by Core.
|
||||
///
|
||||
/// Candidate selection is explicit: callers use [`Self::program_ids`] and
|
||||
/// [`Self::recognize`] before invoking [`Self::decode`]. `decode` therefore
|
||||
/// reports only a successful typed value, an intentional unsupported state, or
|
||||
/// a KSP [`crate::Result`] error. The trait defines no default methods and does
|
||||
/// not promise heterogeneous runtime object composition.
|
||||
pub trait ProgramInstructionDecoder: Send + Sync {
|
||||
/// Concrete decoded instruction type owned by the implementation.
|
||||
type Decoded;
|
||||
|
||||
/// Returns the opaque Program identifiers claimed by this decoder.
|
||||
fn program_ids(&self) -> &[crate::Pubkey];
|
||||
|
||||
/// Reports how strongly this decoder recognizes one bounded instruction.
|
||||
fn recognize(&self, instruction: &crate::ProgramInstruction) -> crate::ProgramInstructionRecognition;
|
||||
|
||||
/// Decodes one instruction already selected for this decoder.
|
||||
fn decode(&self, instruction: &crate::ProgramInstruction) -> crate::Result<crate::ProgramInstructionDecodeOutcome<Self::Decoded>>;
|
||||
}
|
||||
105
crates/ksp-program-api/tests/dependency_boundary.rs
Normal file
105
crates/ksp-program-api/tests/dependency_boundary.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
// file: crates/ksp-program-api/tests/dependency_boundary.rs
|
||||
// version: 3
|
||||
|
||||
//! Dependency and declarative-surface canaries for the Program API foundation.
|
||||
|
||||
#[test]
|
||||
fn pre_002_manifest_has_exact_core_and_interface_runtime_dependencies() {
|
||||
let manifest = include_str!("../Cargo.toml");
|
||||
let dependencies_tail = manifest.split("[dependencies]").nth(1);
|
||||
assert!(dependencies_tail.is_some(), "Program API dependencies section must exist");
|
||||
let dependencies_tail = match dependencies_tail {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let dependencies = match dependencies_tail.split("[lints]").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert_eq!(manifest_dependency_names(dependencies), std::vec!["ksp-core-lib", "ksp-interface-lib"]);
|
||||
for forbidden in [
|
||||
"ksp-config-lib",
|
||||
"ksp-logging-lib",
|
||||
"ksp-materializer-api",
|
||||
"ksp-materializer-lib",
|
||||
"ksp-offchain-transport-lib",
|
||||
"ksp-onchain-transport-lib",
|
||||
"ksp-program-lib",
|
||||
"ksp-store-api",
|
||||
"ksp-store-lib",
|
||||
"ksp-wallet-lib",
|
||||
"borsh",
|
||||
"bincode",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"solana-instruction",
|
||||
"tauri",
|
||||
"tokio",
|
||||
"tonic",
|
||||
"tracing",
|
||||
"wincode",
|
||||
] {
|
||||
assert!(!dependencies.contains(forbidden), "forbidden Program API dependency detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_004_crate_root_adds_decoder_without_runtime_surface() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
for required in [
|
||||
"ProgramInstructionDecodeOutcome",
|
||||
"ProgramInstructionDecoder",
|
||||
"ProgramInstructionRecognition",
|
||||
"Error",
|
||||
"ErrorCode",
|
||||
"ErrorContext",
|
||||
"Pubkey",
|
||||
"Result",
|
||||
"ProgramAccountMeta",
|
||||
"ProgramInstruction",
|
||||
] {
|
||||
assert!(crate_root.contains(required), "required Program API facade export missing: {required}");
|
||||
}
|
||||
for forbidden in ["pub mod ", "ProgramExecutionPreparer", "TRACING_TARGET", "ksp_logging_lib", "serde", "Any"] {
|
||||
assert!(!crate_root.contains(forbidden), "forbidden pre.004 Program API surface detected: {forbidden}");
|
||||
}
|
||||
let decoder_source = include_str!("../src/program_instruction_decoder.rs");
|
||||
assert!(decoder_source.contains("pub trait ProgramInstructionDecoder: Send + Sync"));
|
||||
assert!(decoder_source.contains("type Decoded;"));
|
||||
assert!(decoder_source.contains("fn program_ids(&self) -> &[crate::Pubkey];"));
|
||||
assert!(decoder_source.contains("fn recognize(&self, instruction: &crate::ProgramInstruction)"));
|
||||
assert!(decoder_source.contains("crate::Result<crate::ProgramInstructionDecodeOutcome<Self::Decoded>>"));
|
||||
assert!(!decoder_source.contains("ProgramExecutionPreparer"));
|
||||
assert!(!decoder_source.contains("serde"));
|
||||
assert!(!decoder_source.contains("std::any::Any"));
|
||||
let outcome_source = include_str!("../src/program_instruction_decode.rs");
|
||||
for forbidden in ["Ignored", "Failed", "serde", "Any"] {
|
||||
assert!(!outcome_source.contains(forbidden), "forbidden recognition/outcome concept detected: {forbidden}");
|
||||
}
|
||||
assert!(!std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/constants.rs").exists());
|
||||
return;
|
||||
}
|
||||
|
||||
fn manifest_dependency_names(section: &str) -> std::vec::Vec<&str> {
|
||||
let mut names = std::vec::Vec::new();
|
||||
for line in section.lines() {
|
||||
let content = match line.split('#').next() {
|
||||
std::option::Option::Some(value) => value.trim(),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if content.is_empty() {
|
||||
continue;
|
||||
}
|
||||
let name = match content.split('=').next() {
|
||||
std::option::Option::Some(value) => value.trim().trim_end_matches(".workspace"),
|
||||
std::option::Option::None => continue,
|
||||
};
|
||||
if !name.is_empty() {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
return names;
|
||||
}
|
||||
115
crates/ksp-program-api/tests/external_implementation.rs
Normal file
115
crates/ksp-program-api/tests/external_implementation.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
// file: crates/ksp-program-api/tests/external_implementation.rs
|
||||
// version: 1
|
||||
|
||||
//! Downstream-style implementation canary for the open Program decoder contract.
|
||||
|
||||
const EXTERNAL_PROGRAM_ID_BYTES: [u8; 32] = [0xE7_u8; 32];
|
||||
const FOREIGN_PROGRAM_ID_BYTES: [u8; 32] = [0xE8_u8; 32];
|
||||
const SUPPORTED_OPCODE: u8 = 0x2A_u8;
|
||||
|
||||
struct ExternalDecodedInstruction {
|
||||
opcode: u8,
|
||||
}
|
||||
|
||||
struct ExternalProgramDecoder {
|
||||
program_ids: [ksp_program_api::Pubkey; 1],
|
||||
}
|
||||
|
||||
impl ExternalProgramDecoder {
|
||||
fn new() -> Self {
|
||||
return Self { program_ids: [ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES)] };
|
||||
}
|
||||
}
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for ExternalProgramDecoder {
|
||||
type Decoded = ExternalDecodedInstruction;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &self.program_ids;
|
||||
}
|
||||
|
||||
fn recognize(&self, instruction: &ksp_program_api::ProgramInstruction) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
if instruction.program_id() != &self.program_ids[0] {
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
if instruction.data().first() == std::option::Option::Some(&SUPPORTED_OPCODE) {
|
||||
return ksp_program_api::ProgramInstructionRecognition::ExactMatch;
|
||||
}
|
||||
return ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
if instruction.program_id() != &self.program_ids[0] {
|
||||
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported);
|
||||
}
|
||||
let opcode = match instruction.data().first() {
|
||||
std::option::Option::Some(value) if *value == SUPPORTED_OPCODE => *value,
|
||||
_ => return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported),
|
||||
};
|
||||
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(ExternalDecodedInstruction { opcode }));
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_send_sync<T: Send + Sync>(_value: &T) {
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_004_external_decoder_uses_unregistered_pubkey_and_implementation_owned_output() {
|
||||
let decoder = ExternalProgramDecoder::new();
|
||||
assert_send_sync(&decoder);
|
||||
let external_program_id = ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES);
|
||||
assert!(ksp_core_lib::find_program_pubkey(&external_program_id).is_none());
|
||||
assert_eq!(ksp_program_api::ProgramInstructionDecoder::program_ids(&decoder), &[external_program_id]);
|
||||
let exact = ksp_program_api::ProgramInstruction::try_new(external_program_id, std::vec![], std::vec![SUPPORTED_OPCODE]);
|
||||
assert!(exact.is_ok());
|
||||
let exact = match exact {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &exact), ksp_program_api::ProgramInstructionRecognition::ExactMatch);
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &exact);
|
||||
assert!(outcome.is_ok());
|
||||
let outcome = match outcome {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let decoded = match outcome {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
||||
_ => return,
|
||||
};
|
||||
assert_eq!(decoded.opcode, SUPPORTED_OPCODE);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_004_external_decoder_distinguishes_program_match_unsupported_and_no_match() {
|
||||
let decoder = ExternalProgramDecoder::new();
|
||||
let external_program_id = ksp_program_api::Pubkey::new_from_array(EXTERNAL_PROGRAM_ID_BYTES);
|
||||
let program_only = ksp_program_api::ProgramInstruction::try_new(external_program_id, std::vec![], std::vec![0x11_u8]);
|
||||
assert!(program_only.is_ok());
|
||||
let program_only = match program_only {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &program_only), ksp_program_api::ProgramInstructionRecognition::ProgramMatch);
|
||||
let unsupported = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &program_only);
|
||||
assert!(unsupported.is_ok());
|
||||
let unsupported = match unsupported {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert!(matches!(unsupported, ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported));
|
||||
let foreign_program_id = ksp_program_api::Pubkey::new_from_array(FOREIGN_PROGRAM_ID_BYTES);
|
||||
let foreign = ksp_program_api::ProgramInstruction::try_new(foreign_program_id, std::vec![], std::vec![SUPPORTED_OPCODE]);
|
||||
assert!(foreign.is_ok());
|
||||
let foreign = match foreign {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(ksp_program_api::ProgramInstructionDecoder::recognize(&decoder, &foreign), ksp_program_api::ProgramInstructionRecognition::NoMatch);
|
||||
return;
|
||||
}
|
||||
77
crates/ksp-program-api/tests/public_api.rs
Normal file
77
crates/ksp-program-api/tests/public_api.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
// file: crates/ksp-program-api/tests/public_api.rs
|
||||
// version: 3
|
||||
|
||||
//! Integration canaries for the public `ksp-program-api` foundation.
|
||||
|
||||
fn consume_result(value: ksp_program_api::Result<ksp_program_api::Pubkey>) -> ksp_program_api::Result<ksp_program_api::Pubkey> {
|
||||
return value;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_002_core_and_interface_facade_is_available_from_crate_root() {
|
||||
let program_id = ksp_program_api::Pubkey::new_from_array([0xA1_u8; 32]);
|
||||
let account_id = ksp_program_api::Pubkey::new_from_array([0xA2_u8; 32]);
|
||||
let account = ksp_program_api::ProgramAccountMeta::readonly(account_id, true);
|
||||
let instruction = ksp_program_api::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xA3_u8]);
|
||||
assert!(instruction.is_ok());
|
||||
let forwarded = consume_result(std::result::Result::Ok(program_id));
|
||||
assert!(forwarded.is_ok());
|
||||
let error_code_type: std::option::Option<ksp_program_api::ErrorCode> = std::option::Option::None;
|
||||
let error_context_type: std::option::Option<ksp_program_api::ErrorContext> = std::option::Option::None;
|
||||
let error_type: std::option::Option<ksp_program_api::Error> = std::option::Option::None;
|
||||
assert!(error_code_type.is_none());
|
||||
assert!(error_context_type.is_none());
|
||||
assert!(error_type.is_none());
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_002_scaffold_does_not_require_private_modules() {
|
||||
let source = include_str!("../src/lib.rs");
|
||||
assert!(!source.contains("pub mod "));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_003_recognition_and_decode_outcome_are_available_from_crate_root() {
|
||||
let recognition = ksp_program_api::ProgramInstructionRecognition::ProgramMatch;
|
||||
assert_eq!(std::format!("{recognition:?}"), "ProgramMatch");
|
||||
let decoded = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(31_u16);
|
||||
assert_eq!(std::format!("{decoded:?}"), "Decoded");
|
||||
let decoded_value = match decoded {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
||||
_ => 0_u16,
|
||||
};
|
||||
assert_eq!(decoded_value, 31_u16);
|
||||
let unsupported = ksp_program_api::ProgramInstructionDecodeOutcome::<u16>::Unsupported;
|
||||
assert_eq!(std::format!("{unsupported:?}"), "Unsupported");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_pre_004_instruction_decoder_trait_is_available_from_crate_root() {
|
||||
let decoder = NeverInstantiatedDecoder;
|
||||
assert!(ksp_program_api::ProgramInstructionDecoder::program_ids(&decoder).is_empty());
|
||||
return;
|
||||
}
|
||||
|
||||
struct NeverInstantiatedDecoder;
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for NeverInstantiatedDecoder {
|
||||
type Decoded = u8;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &[];
|
||||
}
|
||||
|
||||
fn recognize(&self, _instruction: &ksp_program_api::ProgramInstruction) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
_instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported);
|
||||
}
|
||||
}
|
||||
128
crates/ksp-program-api/tests/release_completeness.rs
Normal file
128
crates/ksp-program-api/tests/release_completeness.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
// file: crates/ksp-program-api/tests/release_completeness.rs
|
||||
// version: 2
|
||||
|
||||
//! Release-level completeness canaries for the `0.2.14` Program API 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::program_instruction_decode::ProgramInstructionDecodeOutcome;",
|
||||
"pub use self::program_instruction_decode::ProgramInstructionRecognition;",
|
||||
"pub use self::program_instruction_decoder::ProgramInstructionDecoder;",
|
||||
"pub use ksp_core_lib::Error;",
|
||||
"pub use ksp_core_lib::ErrorCode;",
|
||||
"pub use ksp_core_lib::ErrorContext;",
|
||||
"pub use ksp_core_lib::Pubkey;",
|
||||
"pub use ksp_core_lib::Result;",
|
||||
"pub use ksp_interface_lib::ProgramAccountMeta;",
|
||||
"pub use ksp_interface_lib::ProgramInstruction;",
|
||||
];
|
||||
expected.sort_unstable();
|
||||
assert_eq!(actual, expected);
|
||||
assert!(!crate_root.contains("pub mod "));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_production_module_inventory_is_instruction_only() -> 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!["lib.rs", "program_instruction_decode.rs", "program_instruction_decoder.rs"]);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_public_enum_and_trait_inventory_remains_open_world() {
|
||||
let sources = [include_str!("../src/lib.rs"), include_str!("../src/program_instruction_decode.rs"), include_str!("../src/program_instruction_decoder.rs")];
|
||||
let mut public_enums = std::vec::Vec::new();
|
||||
let mut public_traits = std::vec::Vec::new();
|
||||
for source in sources {
|
||||
for line in source.lines() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with("pub enum ") {
|
||||
public_enums.push(trimmed);
|
||||
}
|
||||
if trimmed.starts_with("pub trait ") {
|
||||
public_traits.push(trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
public_enums.sort_unstable();
|
||||
public_traits.sort_unstable();
|
||||
assert_eq!(public_enums, std::vec!["pub enum ProgramInstructionDecodeOutcome<Decoded> {", "pub enum ProgramInstructionRecognition {"]);
|
||||
assert_eq!(public_traits, std::vec!["pub trait ProgramInstructionDecoder: Send + Sync {"]);
|
||||
let decode_source = include_str!("../src/program_instruction_decode.rs");
|
||||
assert!(decode_source.contains("#[non_exhaustive]\npub enum ProgramInstructionRecognition"));
|
||||
assert!(decode_source.contains("#[non_exhaustive]\npub enum ProgramInstructionDecodeOutcome<Decoded>"));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_production_sources_have_no_registry_preparer_codec_or_runtime_creep() {
|
||||
let direct_tracing_path = ["tracing", "::"].concat();
|
||||
let sources = [include_str!("../src/lib.rs"), include_str!("../src/program_instruction_decode.rs"), include_str!("../src/program_instruction_decoder.rs")];
|
||||
for source in sources {
|
||||
for forbidden in [
|
||||
"pub enum ProgramKind",
|
||||
"pub struct ProgramRegistry",
|
||||
"pub trait ProgramAccountDecoder",
|
||||
"pub trait ProgramEventDecoder",
|
||||
"pub trait ProgramReturnDataDecoder",
|
||||
"pub trait ProgramExecutionPreparer",
|
||||
"std::any::Any",
|
||||
"serde::",
|
||||
"serde_json::",
|
||||
"borsh::",
|
||||
"bincode::",
|
||||
"wincode::",
|
||||
"ksp_logging_lib::",
|
||||
"reqwest::",
|
||||
"tokio::",
|
||||
"tonic::",
|
||||
"tauri::",
|
||||
"std::env::",
|
||||
"std::fs::",
|
||||
"std::net::",
|
||||
"dyn ProgramInstructionDecoder",
|
||||
"dyn crate::ProgramInstructionDecoder",
|
||||
] {
|
||||
assert!(!source.contains(forbidden), "forbidden Program API production surface detected: {forbidden}");
|
||||
}
|
||||
assert!(!source.contains(direct_tracing_path.as_str()), "forbidden Program API production direct tracing path detected");
|
||||
}
|
||||
return;
|
||||
}
|
||||
156
crates/ksp-program-api/tests/security_hardening.rs
Normal file
156
crates/ksp-program-api/tests/security_hardening.rs
Normal file
@@ -0,0 +1,156 @@
|
||||
// file: crates/ksp-program-api/tests/security_hardening.rs
|
||||
// version: 1
|
||||
|
||||
//! Adversarial and bound-safety canaries for the Program API foundation.
|
||||
|
||||
const HOSTILE_MARKER: &str = "PROGRAM-SECRET-CANARY";
|
||||
const MALFORMED_OPCODE: u8 = 0xFF_u8;
|
||||
const PROGRAM_ID_BYTES: [u8; 32] = [0xD1_u8; 32];
|
||||
|
||||
struct BoundsObserved {
|
||||
account_count: usize,
|
||||
data_len: usize,
|
||||
}
|
||||
|
||||
struct BoundedDecoder {
|
||||
program_ids: [ksp_program_api::Pubkey; 1],
|
||||
}
|
||||
|
||||
impl BoundedDecoder {
|
||||
fn new() -> Self {
|
||||
return Self { program_ids: [ksp_program_api::Pubkey::new_from_array(PROGRAM_ID_BYTES)] };
|
||||
}
|
||||
}
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for BoundedDecoder {
|
||||
type Decoded = BoundsObserved;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &self.program_ids;
|
||||
}
|
||||
|
||||
fn recognize(&self, instruction: &ksp_program_api::ProgramInstruction) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
if instruction.program_id() == &self.program_ids[0] {
|
||||
return ksp_program_api::ProgramInstructionRecognition::ExactMatch;
|
||||
}
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
if instruction.data().first() == std::option::Option::Some(&MALFORMED_OPCODE) {
|
||||
return std::result::Result::Err(ksp_program_api::Error::new(
|
||||
ksp_program_api::ErrorCode::new("program_test", "malformed_instruction"),
|
||||
"malformed external Program instruction",
|
||||
));
|
||||
}
|
||||
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(BoundsObserved {
|
||||
account_count: instruction.accounts().len(),
|
||||
data_len: instruction.data().len(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
struct BoundlessDecoded {
|
||||
marker: std::rc::Rc<std::cell::Cell<u8>>,
|
||||
}
|
||||
|
||||
struct BoundlessOutputDecoder;
|
||||
|
||||
impl ksp_program_api::ProgramInstructionDecoder for BoundlessOutputDecoder {
|
||||
type Decoded = BoundlessDecoded;
|
||||
|
||||
fn program_ids(&self) -> &[ksp_program_api::Pubkey] {
|
||||
return &[];
|
||||
}
|
||||
|
||||
fn recognize(&self, _instruction: &ksp_program_api::ProgramInstruction) -> ksp_program_api::ProgramInstructionRecognition {
|
||||
return ksp_program_api::ProgramInstructionRecognition::NoMatch;
|
||||
}
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
_instruction: &ksp_program_api::ProgramInstruction,
|
||||
) -> ksp_program_api::Result<ksp_program_api::ProgramInstructionDecodeOutcome<Self::Decoded>> {
|
||||
return std::result::Result::Ok(ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(BoundlessDecoded {
|
||||
marker: std::rc::Rc::new(std::cell::Cell::new(0x5A_u8)),
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_max_interface_instruction_crosses_decoder_boundary_without_new_contract() {
|
||||
let decoder = BoundedDecoder::new();
|
||||
let account = ksp_program_api::ProgramAccountMeta::readonly(ksp_program_api::Pubkey::new_from_array([0xD2_u8; 32]), false);
|
||||
let accounts = std::vec![account; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS];
|
||||
let data = std::vec![0x5A_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN];
|
||||
let instruction = ksp_program_api::ProgramInstruction::try_new(decoder.program_ids[0], accounts, data);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &instruction);
|
||||
assert!(outcome.is_ok());
|
||||
let outcome = match outcome {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let observed = match outcome {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
||||
_ => return,
|
||||
};
|
||||
assert_eq!(observed.account_count, ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS);
|
||||
assert_eq!(observed.data_len, ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_malformed_payload_error_path_does_not_gain_automatic_payload_echo() {
|
||||
let decoder = BoundedDecoder::new();
|
||||
let mut payload = std::vec![MALFORMED_OPCODE];
|
||||
payload.extend_from_slice(HOSTILE_MARKER.as_bytes());
|
||||
let instruction = ksp_program_api::ProgramInstruction::try_new(decoder.program_ids[0], std::vec![], payload);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &instruction);
|
||||
assert!(outcome.is_err());
|
||||
let error = match outcome {
|
||||
std::result::Result::Err(value) => value,
|
||||
std::result::Result::Ok(_) => return,
|
||||
};
|
||||
assert_eq!(error.code().domain(), "program_test");
|
||||
assert_eq!(error.code().code(), "malformed_instruction");
|
||||
assert!(!std::format!("{error}").contains(HOSTILE_MARKER));
|
||||
assert!(!std::format!("{error:?}").contains(HOSTILE_MARKER));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_associated_decoded_type_keeps_no_implicit_debug_clone_send_or_sync_bound() {
|
||||
let decoder = BoundlessOutputDecoder;
|
||||
let instruction = ksp_program_api::ProgramInstruction::try_new(ksp_program_api::Pubkey::new_from_array([0xD3_u8; 32]), std::vec![], std::vec![]);
|
||||
assert!(instruction.is_ok());
|
||||
let instruction = match instruction {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
let outcome = ksp_program_api::ProgramInstructionDecoder::decode(&decoder, &instruction);
|
||||
assert!(outcome.is_ok());
|
||||
let outcome = match outcome {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(std::format!("{outcome:?}"), "Decoded");
|
||||
let decoded = match outcome {
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
||||
_ => return,
|
||||
};
|
||||
assert_eq!(decoded.marker.get(), 0x5A_u8);
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
// file: crates/ksp-program-api/unit_tests/program_instruction_decode.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn recognition_variants_are_distinct_and_payload_free() {
|
||||
assert_ne!(crate::ProgramInstructionRecognition::NoMatch, crate::ProgramInstructionRecognition::ProgramMatch);
|
||||
assert_ne!(crate::ProgramInstructionRecognition::ProgramMatch, crate::ProgramInstructionRecognition::ExactMatch);
|
||||
assert_eq!(std::format!("{:?}", crate::ProgramInstructionRecognition::NoMatch), "NoMatch");
|
||||
assert_eq!(std::format!("{:?}", crate::ProgramInstructionRecognition::ProgramMatch), "ProgramMatch");
|
||||
assert_eq!(std::format!("{:?}", crate::ProgramInstructionRecognition::ExactMatch), "ExactMatch");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_outcome_preserves_decoded_value_and_unsupported_state() {
|
||||
let decoded = crate::ProgramInstructionDecodeOutcome::Decoded(17_u64);
|
||||
let decoded_value = match decoded {
|
||||
crate::ProgramInstructionDecodeOutcome::Decoded(value) => value,
|
||||
crate::ProgramInstructionDecodeOutcome::Unsupported => 0_u64,
|
||||
};
|
||||
assert_eq!(decoded_value, 17_u64);
|
||||
let unsupported = crate::ProgramInstructionDecodeOutcome::<u64>::Unsupported;
|
||||
assert!(matches!(unsupported, crate::ProgramInstructionDecodeOutcome::Unsupported));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_outcome_debug_never_requires_or_renders_decoded_debug() {
|
||||
struct ExternalDecoded {
|
||||
secret_marker: u8,
|
||||
}
|
||||
let decoded = crate::ProgramInstructionDecodeOutcome::Decoded(ExternalDecoded { secret_marker: 0xA7_u8 });
|
||||
assert_eq!(std::format!("{decoded:?}"), "Decoded");
|
||||
let secret_marker = match decoded {
|
||||
crate::ProgramInstructionDecodeOutcome::Decoded(value) => value.secret_marker,
|
||||
crate::ProgramInstructionDecodeOutcome::Unsupported => 0_u8,
|
||||
};
|
||||
assert_eq!(secret_marker, 0xA7_u8);
|
||||
assert_eq!(std::format!("{:?}", crate::ProgramInstructionDecodeOutcome::<ExternalDecoded>::Unsupported), "Unsupported");
|
||||
return;
|
||||
}
|
||||
201
deltas/0.2.14/pre.001.md
Normal file
201
deltas/0.2.14/pre.001.md
Normal file
@@ -0,0 +1,201 @@
|
||||
<!-- file: deltas/0.2.14/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.001` — audit Program API, héritage kbot3 et sizing
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Base directe attendue :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
workspace.package.version = 0.2.13
|
||||
```
|
||||
|
||||
Sources obligatoires réellement disponibles à l'ouverture :
|
||||
|
||||
```text
|
||||
archive opérateur khadhroony-solana-project-v0.2.13.zip
|
||||
archive historique khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
La metadata Git n'est pas incluse dans l'archive opérateur; le tag `v0.2.13` ne peut donc pas être interrogé localement. La version Cargo, `deltas/0.2.13/rel.001.md`, le prompt 019 et la surface Interface publiée concordent avec la base stable attendue.
|
||||
|
||||
Commit attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.001
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Ouvrir `0.2.14 — Program API foundation` uniquement par le gate prévu :
|
||||
|
||||
```text
|
||||
lecture règles + architecture
|
||||
audit Core + Interface stables
|
||||
audit historique kbot3 réel
|
||||
matrice d'héritage
|
||||
ownership
|
||||
API candidate
|
||||
threat/API model
|
||||
dependency graph
|
||||
stratégie de tests
|
||||
sizing et prévision souple recalibrée
|
||||
```
|
||||
|
||||
Aucun scaffold `ksp-program-api`, decoder concret, registry runtime ou execution preparer n'est ajouté dans cette livraison.
|
||||
|
||||
## 3. Décisions principales
|
||||
|
||||
Le scope est réduit à une foundation instruction-only :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
ProgramInstructionDecoder avec associated output
|
||||
```
|
||||
|
||||
Le candidat trait utilise :
|
||||
|
||||
```text
|
||||
&ProgramInstruction
|
||||
&[Pubkey]
|
||||
ksp_core_lib::Result
|
||||
Send + Sync
|
||||
```
|
||||
|
||||
L'output concret appartient à l'implémentation externe ou au futur `ksp-program-lib`.
|
||||
|
||||
Sont explicitement reportés :
|
||||
|
||||
```text
|
||||
payload canonique D3
|
||||
registry runtime hétérogène
|
||||
identity/version/coverage génériques
|
||||
diagnostics/proofs Program dédiés
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
ProgramExecutionPreparer
|
||||
```
|
||||
|
||||
Le design n'ajoute aucune dépendance externe et ne requiert donc aucun audit web/Solana supplémentaire en `pre.001`.
|
||||
|
||||
## 4. Héritage kbot3
|
||||
|
||||
L'archive historique a été réellement extraite et les contrats prioritaires ont été relus.
|
||||
|
||||
Conclusions :
|
||||
|
||||
```text
|
||||
REPRENDRE séparation recognition/decode, trait instruction, Send+Sync, préparation pure conceptuelle
|
||||
REDESSINER recognition, outcomes, execution capability/prepared plan
|
||||
REPORTER identity/version, coverage, diagnostics, proofs, replay context, decoded event, registry, preparer
|
||||
REJETER Program IDs/Pubkeys String, generic JSON payload, generic protocol monolith, executor, policy dans Program, ks-lib monolithique
|
||||
```
|
||||
|
||||
Les decoders Solana Core, SPL Token et SPL Token-2022 confirment que l'ancien trait contextualisé dépendait réellement de signature/slot/path/transaction status/hash et JSON. Ces champs appartiennent aux futures couches CORE/DECODE et ne sont pas reconstruits dans Program API.
|
||||
|
||||
## 5. Sizing recalibré
|
||||
|
||||
Prévision active :
|
||||
|
||||
```text
|
||||
pre.001 audit/design/sizing
|
||||
pre.002 scaffold + facade + dependency firewall
|
||||
pre.003 recognition + outcome
|
||||
pre.004 decoder trait + external implementation
|
||||
pre.005 adversarial/API hardening + completeness
|
||||
pre.006 gate technique final
|
||||
pre.007 réconciliation documentaire
|
||||
pre.008 préparation de publication minimale
|
||||
rel.001 publication stable
|
||||
```
|
||||
|
||||
Registry, canonical payload et execution preparation ne sont plus des tranches de `0.2.14`.
|
||||
|
||||
## 6. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
deltas/0.2.14/pre.001.md
|
||||
```
|
||||
|
||||
## 7. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/000-README.md
|
||||
docs/validation/000-README.md
|
||||
```
|
||||
|
||||
## 8. Fichiers supprimés
|
||||
|
||||
```text
|
||||
aucun
|
||||
```
|
||||
|
||||
## 9. Version Cargo
|
||||
|
||||
La prerelease non-fix synchronise :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.14-pre.1
|
||||
```
|
||||
|
||||
Aucune crate Program n'existe encore; le changement Cargo sert uniquement à identifier la tranche `pre.001` conformément au workflow.
|
||||
|
||||
## 10. Validations exécutées pendant la préparation
|
||||
|
||||
Le journal opérateur fourni à l'ouverture sur la base stable `v0.2.13` montre un baseline complet vert avant application de ce delta, notamment audits Rust/Markdown, `cargo check --workspace`, Clippy, tests ciblés des crates et `cargo test --workspace`. Cette preuve de base ne remplace pas le gate après application.
|
||||
|
||||
Dans l'environnement de génération du présent overlay, les contrôles statiques suivants ont été réellement exécutés après modification :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
Markdown table audit: clean (170 tables, 116 files)
|
||||
```
|
||||
|
||||
`cargo` n'est pas installé dans l'environnement de génération utilisé pour préparer l'archive. Les commandes Cargo de validation après application n'ont donc pas été rejouées ici et ne sont pas déclarées PASS.
|
||||
|
||||
## 11. Validations non requises dans cette tranche
|
||||
|
||||
```text
|
||||
cargo test -p ksp-program-api crate encore absente
|
||||
cargo tree -p ksp-program-api crate encore absente
|
||||
smokes réseau/live hors scope d'une API déclarative
|
||||
```
|
||||
|
||||
## 12. Questions ouvertes
|
||||
|
||||
Aucune question ne bloque le passage à `pre.002`.
|
||||
|
||||
Les sujets suivants restent ouverts volontairement pour des releases ultérieures, pas pour compléter `0.2.14` :
|
||||
|
||||
```text
|
||||
canonical DECODE/D3 payload
|
||||
runtime registry / conflict policy / erased composition
|
||||
processor identity/version durable
|
||||
coverage descriptors
|
||||
contextual proofs/diagnostics
|
||||
ProgramExecutionPreparer exact
|
||||
```
|
||||
|
||||
## 13. Application et validation opérateur
|
||||
|
||||
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.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
```
|
||||
|
||||
Aucun développement fonctionnel Program ne doit être ajouté à ce delta.
|
||||
235
deltas/0.2.14/pre.002.md
Normal file
235
deltas/0.2.14/pre.002.md
Normal file
@@ -0,0 +1,235 @@
|
||||
<!-- file: deltas/0.2.14/pre.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.002` — scaffold `ksp-program-api` + façade + firewall
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
+ 0.2.14-pre.001
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour `pre.001` est vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS — 170 tables / 116 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS sans warning
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.14-pre.1
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.14-pre.2
|
||||
```
|
||||
|
||||
Commit attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.002
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Matérialiser uniquement le scaffold de `ksp-program-api` et verrouiller sa façade/dependency firewall avant toute capability de décodage.
|
||||
|
||||
La tranche ajoute :
|
||||
|
||||
```text
|
||||
nouveau membre workspace ksp-program-api
|
||||
manifest Core + Interface uniquement
|
||||
façade crate-root explicite
|
||||
réexports Core retenus
|
||||
réexports Interface retenus
|
||||
README/USAGE initiaux
|
||||
canari public API
|
||||
canari dependency firewall
|
||||
```
|
||||
|
||||
Elle n'ajoute pas :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome
|
||||
ProgramInstructionDecoder
|
||||
ProgramExecutionPreparer
|
||||
registry runtime
|
||||
identity/version/coverage
|
||||
payload canonique D3
|
||||
serde / JSON / Any
|
||||
codec
|
||||
runtime logging
|
||||
network / async runtime
|
||||
```
|
||||
|
||||
## 3. Façade publique de scaffold
|
||||
|
||||
Le crate-root réexporte explicitement :
|
||||
|
||||
```text
|
||||
ksp-core-lib
|
||||
Error
|
||||
ErrorCode
|
||||
ErrorContext
|
||||
Result
|
||||
Pubkey
|
||||
|
||||
ksp-interface-lib
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
```
|
||||
|
||||
Ces réexports ne changent pas l'ownership des types. Ils fournissent la façade retenue par le plan afin qu'une future implémentation externe puisse dépendre du contrat Program sans reconstruire les types Core/Interface ni accéder à leurs modules privés.
|
||||
|
||||
Aucun `pub mod` n'est exposé.
|
||||
|
||||
## 4. Dependency firewall
|
||||
|
||||
Le manifest membre possède exactement :
|
||||
|
||||
```text
|
||||
[dependencies]
|
||||
ksp-core-lib
|
||||
ksp-interface-lib
|
||||
```
|
||||
|
||||
Le canari `tests/dependency_boundary.rs` verrouille notamment l'absence de :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
ksp-logging-lib
|
||||
Transport / Config / Wallet / Store / Materializer
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
reqwest / tokio / tonic / tauri / tracing
|
||||
```
|
||||
|
||||
Il verrouille aussi l'absence de `src/constants.rs`, `TRACING_TARGET`, recognition/outcome/decoder/preparer et de module public pendant `pre.002`.
|
||||
|
||||
## 5. Logging
|
||||
|
||||
La crate reste une API déclarative sans comportement runtime. Aucun span/event n'est émis et aucun logging n'est nécessaire.
|
||||
|
||||
Restent donc volontairement absents :
|
||||
|
||||
```text
|
||||
ksp-logging-lib
|
||||
src/constants.rs
|
||||
TRACING_TARGET
|
||||
tracing direct
|
||||
```
|
||||
|
||||
Si une future surface Program comportementale nécessite réellement une instrumentation, elle devra respecter les règles Logging KSP dans la crate qui possède ce comportement. Le scaffold API ne doit pas tirer un runtime logging par anticipation.
|
||||
|
||||
## 6. Tests ajoutés
|
||||
|
||||
`tests/public_api.rs` vérifie que la façade crate-root permet de construire `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction`, et que les types d'erreur Core sont adressables sans module privé.
|
||||
|
||||
`tests/dependency_boundary.rs` vérifie :
|
||||
|
||||
```text
|
||||
dépendances normales exactes = Core + Interface
|
||||
absence des dépendances interdites
|
||||
absence de pub mod
|
||||
absence des contrats réservés à pre.003/pre.004
|
||||
absence de logging/runtime/codec
|
||||
```
|
||||
|
||||
Aucun unit test métier n'est ajouté : la crate ne possède encore aucun comportement propre.
|
||||
|
||||
## 7. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
crates/ksp-program-api/src/lib.rs
|
||||
crates/ksp-program-api/tests/dependency_boundary.rs
|
||||
crates/ksp-program-api/tests/public_api.rs
|
||||
deltas/0.2.14/pre.002.md
|
||||
```
|
||||
|
||||
## 8. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
## 9. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
README.md
|
||||
RULES.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-interface-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-*-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
Aucune architecture durable n'est rouverte : la direction `Program API -> Core + Interface` est déjà normative.
|
||||
|
||||
## 10. Validations de génération
|
||||
|
||||
Les audits Python sont rejoués sur l'arbre matérialisé avant livraison. L'environnement de génération ne fournit pas `cargo`, `rustc` ou `rustfmt`; aucun PASS Cargo nouveau n'est revendiqué localement.
|
||||
|
||||
## 11. Gate opérateur attendu
|
||||
|
||||
Après application :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le graphe normal doit confirmer :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.14-pre.002-fix.NNN` et n'avance pas `pre.003`.
|
||||
|
||||
## 12. Suite
|
||||
|
||||
Après gate vert, `pre.003` pourra matérialiser uniquement :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
invariants / Debug sûr associés
|
||||
unit/public canaries correspondants
|
||||
```
|
||||
|
||||
`ProgramInstructionDecoder` et l'implémentation externe restent réservés à `pre.004`.
|
||||
285
deltas/0.2.14/pre.003.md
Normal file
285
deltas/0.2.14/pre.003.md
Normal file
@@ -0,0 +1,285 @@
|
||||
<!-- file: deltas/0.2.14/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.003` — recognition + outcome minimal
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
+ 0.2.14-pre.001
|
||||
+ 0.2.14-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 — 170 tables / 119 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.14-pre.2
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.14-pre.3
|
||||
```
|
||||
|
||||
Commit attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.003
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Matérialiser uniquement le vocabulaire minimal nécessaire au futur decoder d'instruction :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
```
|
||||
|
||||
La tranche ne crée toujours aucun comportement de décodage, registry ou contrat d'exécution.
|
||||
|
||||
## 3. Recognition
|
||||
|
||||
`ProgramInstructionRecognition` est public depuis le crate-root, `#[non_exhaustive]` et possède exactement :
|
||||
|
||||
```text
|
||||
NoMatch
|
||||
ProgramMatch
|
||||
ExactMatch
|
||||
```
|
||||
|
||||
Sémantique :
|
||||
|
||||
```text
|
||||
NoMatch l'implémentation ne revendique pas l'instruction
|
||||
ProgramMatch le Program ou la famille correspond sans preuve instruction-locale exacte
|
||||
ExactMatch l'implémentation affirme un match instruction-local exact
|
||||
```
|
||||
|
||||
Aucun score, priorité, confidence, proof, surface code ou discriminator textuel n'est introduit.
|
||||
|
||||
## 4. Decode outcome
|
||||
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` est public depuis le crate-root, `#[non_exhaustive]` et possède exactement :
|
||||
|
||||
```text
|
||||
Decoded(Decoded)
|
||||
Unsupported
|
||||
```
|
||||
|
||||
La valeur `Decoded` reste possédée par l'implémentation future. Il n'existe aucun `Any`, JSON, payload D3 ou enum centrale pour l'effacer.
|
||||
|
||||
`Failed` est volontairement absent : le futur `ProgramInstructionDecoder::decode` retournera le `Result` Core. Une erreur réelle sera donc `Err`, sans deuxième canal de failure.
|
||||
|
||||
`Ignored` reste absent : une capability de décodage doit produire une valeur, déclarer l'instruction connue mais unsupported, ou échouer.
|
||||
|
||||
## 5. Debug sûr
|
||||
|
||||
`ProgramInstructionRecognition` ne transporte aucun payload.
|
||||
|
||||
`ProgramInstructionDecodeOutcome<Decoded>` possède une implémentation `Debug` manuelle :
|
||||
|
||||
```text
|
||||
Decoded(_) -> "Decoded"
|
||||
Unsupported -> "Unsupported"
|
||||
```
|
||||
|
||||
Cette implémentation :
|
||||
|
||||
```text
|
||||
n'impose pas Decoded: Debug
|
||||
ne formate jamais la valeur Decoded
|
||||
ne copie aucun payload externe
|
||||
reste bornée à un nom de variante fixe
|
||||
```
|
||||
|
||||
Le test unitaire utilise volontairement un type externe sans implémentation `Debug` pour prouver cette propriété à la compilation.
|
||||
|
||||
## 6. Structure et façade
|
||||
|
||||
Un seul module privé est ajouté :
|
||||
|
||||
```text
|
||||
src/program_instruction_decode.rs
|
||||
```
|
||||
|
||||
Le crate-root réexporte :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome
|
||||
```
|
||||
|
||||
Aucun `pub mod` n'est introduit. Les réexports Core/Interface de `pre.002` restent inchangés.
|
||||
|
||||
## 7. Dependency firewall
|
||||
|
||||
Le manifest de `ksp-program-api` est inchangé :
|
||||
|
||||
```text
|
||||
ksp-core-lib
|
||||
ksp-interface-lib
|
||||
```
|
||||
|
||||
Restent interdits et absents :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
ksp-logging-lib
|
||||
Transport / Config / Wallet / Store / Materializer
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
reqwest / tokio / tonic / tauri / tracing
|
||||
```
|
||||
|
||||
Aucun `constants.rs` ou `TRACING_TARGET` n'est justifié pour ces types déclaratifs.
|
||||
|
||||
## 8. Tests
|
||||
|
||||
### Unit
|
||||
|
||||
`unit_tests/program_instruction_decode.rs` vérifie :
|
||||
|
||||
```text
|
||||
variants Recognition distincts
|
||||
Debug Recognition exact et payload-free
|
||||
Decoded conserve sa valeur
|
||||
Unsupported reste distinct
|
||||
Debug outcome sans Decoded: Debug
|
||||
Debug outcome ne rend pas la valeur externe
|
||||
```
|
||||
|
||||
### Public API
|
||||
|
||||
`tests/public_api.rs` ajoute un canari `pre.003` consommant uniquement :
|
||||
|
||||
```text
|
||||
ksp_program_api::ProgramInstructionRecognition
|
||||
ksp_program_api::ProgramInstructionDecodeOutcome
|
||||
```
|
||||
|
||||
### Boundary
|
||||
|
||||
`tests/dependency_boundary.rs` est avancé pour autoriser uniquement recognition/outcome tout en maintenant l'absence de trait decoder, preparer, logging, serde et module public.
|
||||
|
||||
## 9. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/src/program_instruction_decode.rs
|
||||
crates/ksp-program-api/unit_tests/program_instruction_decode.rs
|
||||
deltas/0.2.14/pre.003.md
|
||||
```
|
||||
|
||||
## 10. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
crates/ksp-program-api/src/lib.rs
|
||||
crates/ksp-program-api/tests/dependency_boundary.rs
|
||||
crates/ksp-program-api/tests/public_api.rs
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
## 11. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
README.md
|
||||
RULES.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-interface-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-*-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
## 12. Scope négatif maintenu
|
||||
|
||||
Cette tranche n'introduit pas :
|
||||
|
||||
```text
|
||||
ProgramInstructionDecoder
|
||||
program_ids(...)
|
||||
recognize(...) sur un trait
|
||||
decode(...) sur un trait
|
||||
associated output contract du trait
|
||||
external implementation fixture
|
||||
registry runtime
|
||||
identity/version/coverage
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
payload canonique D3
|
||||
ProgramExecutionPreparer
|
||||
```
|
||||
|
||||
Ces éléments ne doivent pas être anticipés dans un fix de `pre.003`.
|
||||
|
||||
## 13. Gate opérateur attendu
|
||||
|
||||
Après application :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le graphe normal doit rester :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.14-pre.003-fix.NNN` et n'avance pas `pre.004`.
|
||||
|
||||
## 14. Suite
|
||||
|
||||
Après gate vert, `pre.004` pourra introduire uniquement :
|
||||
|
||||
```text
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
associated type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction)
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
external implementation canary avec Pubkey non enregistré
|
||||
```
|
||||
|
||||
Registry runtime, payload canonique D3 et `ProgramExecutionPreparer` resteront hors scope.
|
||||
264
deltas/0.2.14/pre.004.md
Normal file
264
deltas/0.2.14/pre.004.md
Normal file
@@ -0,0 +1,264 @@
|
||||
<!-- file: deltas/0.2.14/pre.004.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.004` — decoder instruction-only + implémentation externe
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
+ 0.2.14-pre.001
|
||||
+ 0.2.14-pre.002
|
||||
+ 0.2.14-pre.003
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour `pre.003` est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS
|
||||
python3 scripts/audit_markdown_tables.py ... PASS — 171 tables / 120 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 8 tests Rust
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.14-pre.3
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.14-pre.4
|
||||
```
|
||||
|
||||
Commit attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.004
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Matérialiser le contrat instruction-only ouvert retenu par `pre.001` :
|
||||
|
||||
```text
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
associated type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction) -> ProgramInstructionRecognition
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
```
|
||||
|
||||
Puis prouver qu'une crate consommatrice séparée peut l'implémenter avec son propre type décodé et un Program `Pubkey` absent du registry Core.
|
||||
|
||||
## 3. Trait `ProgramInstructionDecoder`
|
||||
|
||||
Le trait est défini dans un module privé et réexporté depuis le crate-root.
|
||||
|
||||
Propriétés :
|
||||
|
||||
```text
|
||||
Send + Sync requis sur l'implémentation
|
||||
Decoded associated type sans bound imposé
|
||||
program_ids slice de Pubkey opaques
|
||||
recognize sélection instruction-local explicite
|
||||
decode Result Core + outcome générique
|
||||
méthodes par défaut aucune
|
||||
registry / object composition aucune promesse
|
||||
```
|
||||
|
||||
`decode` est destiné à une instruction déjà sélectionnée via `program_ids` / `recognize`; il ne remplace pas le signal de reconnaissance.
|
||||
|
||||
## 4. Open-world Program IDs
|
||||
|
||||
Aucun `ProgramKind`, enum centrale ou validation contre le registry Core n'est introduit.
|
||||
|
||||
Le canari externe utilise :
|
||||
|
||||
```text
|
||||
Pubkey::new_from_array([0xE7; 32])
|
||||
```
|
||||
|
||||
et vérifie explicitement :
|
||||
|
||||
```text
|
||||
ksp_core_lib::find_program_pubkey(&external_program_id) == None
|
||||
```
|
||||
|
||||
Cette consultation du registry est limitée au test négatif. `ksp-program-api` ne réexporte pas `find_program_pubkey` et le decoder externe n'a besoin que de la façade Program API pour son implémentation.
|
||||
|
||||
## 5. Associated output externe
|
||||
|
||||
Le test d'intégration définit hors du code de production :
|
||||
|
||||
```text
|
||||
ExternalDecodedInstruction
|
||||
ExternalProgramDecoder
|
||||
```
|
||||
|
||||
`ExternalProgramDecoder` implémente le trait et produit :
|
||||
|
||||
```text
|
||||
ExactMatch pour l'opcode supporté
|
||||
ProgramMatch pour le Program connu avec opcode non supporté
|
||||
NoMatch pour un autre Program
|
||||
Decoded(...) pour l'opcode supporté
|
||||
Unsupported pour le Program connu mais non supporté
|
||||
```
|
||||
|
||||
Aucun `Any`, JSON, serde, codec ou enum centrale n'intervient dans le transport du type décodé.
|
||||
|
||||
## 6. Dependency firewall
|
||||
|
||||
Le manifest de `ksp-program-api` reste inchangé :
|
||||
|
||||
```text
|
||||
ksp-core-lib
|
||||
ksp-interface-lib
|
||||
```
|
||||
|
||||
Toujours absents :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
ksp-logging-lib
|
||||
Transport / Config / Wallet / Store / Materializer
|
||||
serde / serde_json
|
||||
borsh / bincode / wincode
|
||||
solana-instruction
|
||||
reqwest / tokio / tonic / tauri / tracing
|
||||
```
|
||||
|
||||
## 7. Tests
|
||||
|
||||
### Public API
|
||||
|
||||
`tests/public_api.rs` prouve que le trait est implémentable depuis la façade crate-root sans module privé.
|
||||
|
||||
### External implementation
|
||||
|
||||
`tests/external_implementation.rs` est compilé par Cargo comme crate d'intégration séparée et vérifie :
|
||||
|
||||
```text
|
||||
Send + Sync de l'implémentation
|
||||
associated output tiers
|
||||
Program Pubkey non enregistré
|
||||
program_ids
|
||||
NoMatch / ProgramMatch / ExactMatch
|
||||
Decoded / Unsupported
|
||||
absence de ksp-program-lib
|
||||
```
|
||||
|
||||
### Boundary
|
||||
|
||||
`tests/dependency_boundary.rs` avance l'inventaire autorisé jusqu'au trait et maintient l'absence de preparer, logging, serde, `Any` et module public.
|
||||
|
||||
## 8. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/src/program_instruction_decoder.rs
|
||||
crates/ksp-program-api/tests/external_implementation.rs
|
||||
deltas/0.2.14/pre.004.md
|
||||
```
|
||||
|
||||
## 9. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
crates/ksp-program-api/src/lib.rs
|
||||
crates/ksp-program-api/tests/dependency_boundary.rs
|
||||
crates/ksp-program-api/tests/public_api.rs
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
## 10. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
README.md
|
||||
RULES.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-interface-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-*-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
## 11. Scope négatif maintenu
|
||||
|
||||
Cette tranche n'introduit pas :
|
||||
|
||||
```text
|
||||
runtime decoder registry
|
||||
Vec<Box<dyn ProgramInstructionDecoder>>
|
||||
object-safety promise
|
||||
identity/version/coverage descriptor
|
||||
priority/conflict policy
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
payload canonique D3
|
||||
serde / JSON / Any
|
||||
proof/confidence contextuels
|
||||
ProgramExecutionPreparer
|
||||
ExecutionPolicy / Execution
|
||||
```
|
||||
|
||||
## 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.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le graphe normal doit rester :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.14-pre.004-fix.NNN` et n'avance pas `pre.005`.
|
||||
|
||||
## 13. Suite
|
||||
|
||||
Après gate vert, `pre.005` doit rester une tranche de hardening/API completeness :
|
||||
|
||||
```text
|
||||
bounds et sécurité Debug/error
|
||||
inventaire exact des exports publics
|
||||
absence de closed-world Program enum
|
||||
absence de serde/codec/logging/runtime
|
||||
scope négatif registry/preparer/payload D3
|
||||
test de complétude release
|
||||
```
|
||||
|
||||
Aucun nouveau contrat fonctionnel n'est prévu dans `pre.005`.
|
||||
128
deltas/0.2.14/pre.005-fix.001.md
Normal file
128
deltas/0.2.14/pre.005-fix.001.md
Normal file
@@ -0,0 +1,128 @@
|
||||
<!-- file: deltas/0.2.14/pre.005-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.005-fix.001` — faux positif du canari logging
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Ce correctif s'applique exclusivement après :
|
||||
|
||||
```text
|
||||
0.2.14-pre.005
|
||||
```
|
||||
|
||||
Le gate opérateur du 28 août 2026 confirme :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 173 tables / 122 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test --workspace FAIL — ksp-logging-lib/tests/ownership.rs
|
||||
```
|
||||
|
||||
L'unique échec observé est :
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/tests/release_completeness.rs bypasses ksp-logging-lib via tracing
|
||||
```
|
||||
|
||||
## 2. Diagnostic
|
||||
|
||||
`release_completeness.rs` doit vérifier que les sources de production Program API ne contiennent aucun chemin direct vers tracing. Le canari écrivait cependant lui-même ce chemin sous forme de chaîne littérale dans sa liste de motifs interdits.
|
||||
|
||||
Le scanner workspace de `ksp-logging-lib/tests/ownership.rs` inspecte tous les fichiers Rust des autres crates, tests d'intégration compris, et recherche textuellement ce chemin. Il classait donc le motif de test lui-même comme un bypass alors qu'aucune dépendance, importation ou utilisation de tracing n'existe dans `ksp-program-api`.
|
||||
|
||||
Le graphe normal observé reste :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
## 3. Correction
|
||||
|
||||
Le canari conserve exactement la même interdiction sur les sources de production, mais construit désormais le motif recherché à partir de deux fragments. Son propre fichier ne contient donc plus le chemin direct littéral que le scanner logging doit légitimement refuser.
|
||||
|
||||
Aucune règle logging n'est contournée ou affaiblie. Le scanner de `ksp-logging-lib` reste inchangé.
|
||||
|
||||
Comme un fichier `.rs` est modifié, `VER-ID-007` et `VER-ID-010` imposent :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.14-pre.5.fix.1
|
||||
```
|
||||
|
||||
La livraison est :
|
||||
|
||||
```text
|
||||
0.2.14-pre.005-fix.001
|
||||
```
|
||||
|
||||
## 4. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-program-api/tests/release_completeness.rs
|
||||
```
|
||||
|
||||
## 5. Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.2.14/pre.005-fix.001.md
|
||||
```
|
||||
|
||||
## 6. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/src/**
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
crates/ksp-program-api/tests/security_hardening.rs
|
||||
crates/ksp-logging-lib/**
|
||||
docs/plans/**
|
||||
docs/validation/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
prompts/**
|
||||
```
|
||||
|
||||
## 7. Scope négatif
|
||||
|
||||
Ce fix n'ajoute aucun :
|
||||
|
||||
```text
|
||||
contrat Program
|
||||
trait ou type public
|
||||
dependency
|
||||
logging runtime
|
||||
registry
|
||||
descriptor
|
||||
codec
|
||||
payload D3
|
||||
preparer
|
||||
```
|
||||
|
||||
## 8. Validations de génération
|
||||
|
||||
Les audits statiques disponibles dans l'environnement de génération doivent rester propres. Cargo n'y est pas disponible ; aucun PASS Cargo n'est revendiqué par ce delta.
|
||||
|
||||
## 9. Gate opérateur attendu
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Si ce gate est vert, `pre.005` est considéré corrigé et `pre.006` peut ouvrir le gate technique final sans développement fonctionnel.
|
||||
217
deltas/0.2.14/pre.005.md
Normal file
217
deltas/0.2.14/pre.005.md
Normal file
@@ -0,0 +1,217 @@
|
||||
<!-- file: deltas/0.2.14/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.005` — adversarial/API hardening + completeness
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement sur :
|
||||
|
||||
```text
|
||||
v0.2.13
|
||||
+ 0.2.14-pre.001
|
||||
+ 0.2.14-pre.002
|
||||
+ 0.2.14-pre.003
|
||||
+ 0.2.14-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 — 172 tables / 121 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 11 tests Rust
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté
|
||||
```
|
||||
|
||||
La version workspace passe de :
|
||||
|
||||
```text
|
||||
0.2.14-pre.4
|
||||
```
|
||||
|
||||
à :
|
||||
|
||||
```text
|
||||
0.2.14-pre.5
|
||||
```
|
||||
|
||||
Commit attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.005
|
||||
```
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Fermer la surface Program API déjà matérialisée sans ajouter de contrat fonctionnel :
|
||||
|
||||
```text
|
||||
bounds et sécurité Debug/error
|
||||
inventaire exact des exports publics
|
||||
inventaire exact des modules de production
|
||||
absence de closed-world Program enum
|
||||
absence de registry/descriptors/preparer/payload D3
|
||||
absence de serde/codec/logging/runtime
|
||||
associated output sans bound implicite
|
||||
```
|
||||
|
||||
## 3. Release completeness
|
||||
|
||||
Le nouveau `tests/release_completeness.rs` verrouille :
|
||||
|
||||
```text
|
||||
10 réexports crate-root exacts
|
||||
aucun pub mod
|
||||
3 fichiers Rust de production exacts
|
||||
2 enums publics exacts, tous deux non_exhaustive
|
||||
1 trait public exact : ProgramInstructionDecoder
|
||||
aucun ProgramKind / registry / autre famille decoder / preparer
|
||||
aucun Any / serde / codec / logging / réseau / IO runtime
|
||||
aucun dyn ProgramInstructionDecoder ou registry hétérogène anticipé
|
||||
```
|
||||
|
||||
La surface publique reste donc ouverte par `Pubkey` et associated output, pas par un inventaire central fermé.
|
||||
|
||||
## 4. Hardening adversarial
|
||||
|
||||
Le nouveau `tests/security_hardening.rs` couvre trois propriétés.
|
||||
|
||||
### Input Interface maximal
|
||||
|
||||
Une instruction au maximum déjà admis par Interface :
|
||||
|
||||
```text
|
||||
255 account metas
|
||||
10 240 bytes de data
|
||||
```
|
||||
|
||||
traverse `ProgramInstructionDecoder::decode` par référence et le decoder observe les tailles exactes. Program API n'introduit aucun second bound ni nouveau type d'input.
|
||||
|
||||
### Payload hostile et erreur Core
|
||||
|
||||
Un decoder de test reçoit un payload contenant un marqueur hostile puis retourne un `ksp_program_api::Error` sûr. Le contrat Program API ne copie automatiquement ni l'instruction ni ses bytes dans l'erreur, son `Display` ou son `Debug`.
|
||||
|
||||
L'hygiène des messages/contextes qu'une implémentation tierce construit volontairement reste la responsabilité de cette implémentation ; Program API n'ajoute aucun canal `Failed` parallèle susceptible de dupliquer le payload.
|
||||
|
||||
### Associated output sans bound implicite
|
||||
|
||||
Un second decoder de test utilise un output contenant `Rc<Cell<u8>>`. Ce type n'implémente donc pas `Send`/`Sync` et aucun `Debug`/`Clone` n'est dérivé. La compilation prouve que `type Decoded` reste sans bound implicite ; le `Debug` de l'outcome demeure `Decoded` sans rendre la valeur.
|
||||
|
||||
## 5. Dependency/runtime firewall
|
||||
|
||||
Le manifest de production reste inchangé :
|
||||
|
||||
```text
|
||||
ksp-core-lib
|
||||
ksp-interface-lib
|
||||
```
|
||||
|
||||
Les canaris refusent toujours :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
ksp-logging-lib
|
||||
Config / Transport / Wallet / Store / Materializer
|
||||
serde / serde_json / Any
|
||||
borsh / bincode / wincode
|
||||
reqwest / tokio / tonic / tauri / tracing
|
||||
std::env / std::fs / std::net dans la production Program API
|
||||
```
|
||||
|
||||
## 6. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/tests/release_completeness.rs
|
||||
crates/ksp-program-api/tests/security_hardening.rs
|
||||
deltas/0.2.14/pre.005.md
|
||||
```
|
||||
|
||||
## 7. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
## 8. Fichiers volontairement inchangés
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
crates/ksp-program-api/src/**
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
crates/ksp-program-api/tests/dependency_boundary.rs
|
||||
crates/ksp-program-api/tests/external_implementation.rs
|
||||
crates/ksp-program-api/tests/public_api.rs
|
||||
README.md
|
||||
RULES.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
docs/architecture/**
|
||||
docs/rules/**
|
||||
crates/ksp-core-lib/**
|
||||
crates/ksp-interface-lib/**
|
||||
crates/ksp-logging-lib/**
|
||||
crates/ksp-*-transport-lib/**
|
||||
crates/ksp-config-lib/**
|
||||
crates/ksp-wallet-lib/**
|
||||
crates/ksp-app-*/**
|
||||
prompts/**
|
||||
```
|
||||
|
||||
## 9. Scope négatif maintenu
|
||||
|
||||
Cette tranche n'introduit pas :
|
||||
|
||||
```text
|
||||
nouveau type ou trait de production
|
||||
runtime decoder registry
|
||||
Vec<Box<dyn ProgramInstructionDecoder>>
|
||||
object-safety heterogeneous promise
|
||||
identity/version/coverage descriptor
|
||||
priority/conflict policy
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
payload canonique D3
|
||||
serde / JSON / Any
|
||||
proof/confidence contextuels
|
||||
ProgramExecutionPreparer
|
||||
ExecutionPolicy / Execution
|
||||
```
|
||||
|
||||
## 10. Gate opérateur attendu
|
||||
|
||||
Après application :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Le graphe normal doit rester :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Une correction découverte par ce gate reste un `0.2.14-pre.005-fix.NNN` et n'avance pas `pre.006`.
|
||||
|
||||
## 11. Suite
|
||||
|
||||
Après gate vert, `pre.006` est un **gate technique final sans développement fonctionnel**. Il ne doit ajouter ni contrat, ni decoder officiel, ni registry, ni preparer.
|
||||
147
deltas/0.2.14/pre.006.md
Normal file
147
deltas/0.2.14/pre.006.md
Normal file
@@ -0,0 +1,147 @@
|
||||
<!-- file: deltas/0.2.14/pre.006.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.006` — gate technique final Program API
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Cette tranche s'applique exclusivement après `0.2.14-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 — 173 tables / 123 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2/2
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal Core + Interface uniquement
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Le faux positif logging 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.14` sans rouvrir la surface fonctionnelle.
|
||||
|
||||
Aucun nouveau type, trait, test métier, registry, codec, runtime ou comportement n'est ajouté. Les canaris existants couvrent déjà :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
associated Decoded sans bounds implicites
|
||||
extension externe avec Pubkey non enregistré
|
||||
NoMatch / ProgramMatch / ExactMatch
|
||||
Decoded / Unsupported / Err Core
|
||||
input Interface maximal 255 comptes / 10 240 bytes
|
||||
Debug outcome opaque
|
||||
façade crate-root exacte
|
||||
inventaire de production exact
|
||||
absence de ProgramKind / registry / preparer / payload D3
|
||||
absence de serde / JSON / Any / codecs
|
||||
absence de logging runtime / IO
|
||||
firewall Core + Interface
|
||||
```
|
||||
|
||||
## 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.14-pre.5.fix.1
|
||||
→
|
||||
0.2.14-pre.6
|
||||
```
|
||||
|
||||
Commit attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.006
|
||||
```
|
||||
|
||||
Aucun tag prerelease.
|
||||
|
||||
## 5. Fichier ajouté
|
||||
|
||||
```text
|
||||
deltas/0.2.14/pre.006.md
|
||||
```
|
||||
|
||||
## 6. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
## 7. Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## 8. Surface explicitement inchangée
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/src/**
|
||||
crates/ksp-program-api/tests/**
|
||||
crates/ksp-program-api/unit_tests/**
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/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 — 174 tables / 124 fichiers
|
||||
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.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
## 11. Décisions prises
|
||||
|
||||
- le scope fonctionnel `0.2.14` est figé ;
|
||||
- aucun nouveau contrat Program n'est introduit ;
|
||||
- aucun registry, payload D3 ou `ProgramExecutionPreparer` n'est anticipé ;
|
||||
- Program API reste déclarative et sans logging runtime ;
|
||||
- Core + Interface restent les seules dépendances normales ;
|
||||
- aucun smoke réseau n'est pertinent pour cette crate instruction-only sans I/O ;
|
||||
- `pre.007` ne commence qu'après gate `pre.006` intégralement vert.
|
||||
|
||||
## 12. Questions ouvertes
|
||||
|
||||
Aucune question technique bloquante pour `0.2.14`. Après gate vert, la seule étape suivante est la réconciliation documentaire finale.
|
||||
194
deltas/0.2.14/pre.007.md
Normal file
194
deltas/0.2.14/pre.007.md
Normal file
@@ -0,0 +1,194 @@
|
||||
<!-- file: deltas/0.2.14/pre.007.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.007` — réconciliation documentaire finale Program API
|
||||
|
||||
## 1. Base
|
||||
|
||||
```text
|
||||
0.2.14-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 — 174 tables / 124 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2/2
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
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.14` défini par `VER-LIFECYCLE-006`.
|
||||
|
||||
Aucun fichier Rust, test, manifest de crate, dépendance, codec, runtime ou comportement n'est modifié. La tranche transforme les README/USAGE initiaux de Program API 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.14-pre.6
|
||||
->
|
||||
0.2.14-pre.7
|
||||
```
|
||||
|
||||
Le bump est mécanique pour une prerelease non-fix. Aucun autre manifest/version applicative n'est synchronisé artificiellement.
|
||||
|
||||
Commit/tag prerelease attendu :
|
||||
|
||||
```text
|
||||
v0.2.14-pre.007
|
||||
```
|
||||
|
||||
## 4. Surface finale candidate documentée
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
NoMatch / ProgramMatch / ExactMatch
|
||||
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
Decoded(Decoded) / Unsupported
|
||||
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction) -> ProgramInstructionRecognition
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
```
|
||||
|
||||
La façade crate-root conserve exactement 10 exports et trois modules/fichiers Rust de production. Le type `Decoded` reste possédé par l'implémentation et sans bound implicite `Debug/Clone/Send/Sync`.
|
||||
|
||||
## 5. Open-world et hardening final
|
||||
|
||||
Les références durables enregistrent les preuves acquises :
|
||||
|
||||
```text
|
||||
Program Pubkey non enregistré accepté
|
||||
external implementation canary PASS
|
||||
input Interface maximal 255 accounts + 10_240 bytes
|
||||
payload hostile aucun echo automatique ajouté par Program API
|
||||
Debug outcome valeur Decoded non rendue
|
||||
closed-world Program enum absent
|
||||
registry / descriptor / priority absents
|
||||
ProgramExecutionPreparer absent
|
||||
serde / JSON / Any / codecs absents
|
||||
logging / runtime / filesystem / environment / I/O absents
|
||||
```
|
||||
|
||||
Une implémentation tierce reste responsable du contenu des erreurs qu'elle produit explicitement ; Program API n'ajoute aucun canal parallèle ni copie automatique du payload hostile.
|
||||
|
||||
## 6. Dependency firewall final
|
||||
|
||||
Le graphe normal confirmé par l'opérateur reste :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
│ └── solana-pubkey
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Aucun `ksp-program-lib`, runtime, codec, serde, logging, Transport, Store, Wallet, Materializer, Config ou Tauri n'est introduit.
|
||||
|
||||
## 7. Références durables réconciliées
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
Le README fixe l'ownership, l'inventaire public exact, les semantics Recognition/Outcome, le trait externe, le hardening et les frontières. `USAGE.md` documente uniquement la façade crate-root, l'implémentation externe, la sélection explicite, le decode outcome, les erreurs et le Debug sûr.
|
||||
|
||||
La séquence fonctionnelle enregistre le contenu effectivement livré par `0.2.14` et maintient les reports de `ksp-program-lib`, du payload D3, du registry runtime, des autres familles de decoder et du preparer jusqu'aux vertical slices réels.
|
||||
|
||||
## 8. Fichiers ajoutés/modifiés
|
||||
|
||||
Ajouté :
|
||||
|
||||
```text
|
||||
deltas/0.2.14/pre.007.md
|
||||
```
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
Aucun fichier supprimé.
|
||||
|
||||
## 9. Surfaces volontairement inchangées
|
||||
|
||||
Cette tranche ne touche pas :
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/src/**
|
||||
crates/ksp-program-api/tests/**
|
||||
crates/ksp-program-api/Cargo.toml
|
||||
docs/architecture/**
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/**
|
||||
```
|
||||
|
||||
L'architecture durable `006-WIRE_AND_PROGRAM.md` reste compatible avec la foundation réellement livrée : ses registry/preparer/autres familles sont des surfaces futures explicitement non matérialisées par `0.2.14`.
|
||||
|
||||
## 10. 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.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
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`.
|
||||
|
||||
## 11. Suite
|
||||
|
||||
Si le gate est vert :
|
||||
|
||||
```text
|
||||
0.2.14-pre.008 — préparation minimale de publication
|
||||
```
|
||||
|
||||
`pre.008` reste limitée à :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompt de démarrage 0.3.1
|
||||
deltas/0.2.14/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.
|
||||
259
deltas/0.2.14/pre.008.md
Normal file
259
deltas/0.2.14/pre.008.md
Normal file
@@ -0,0 +1,259 @@
|
||||
<!-- file: deltas/0.2.14/pre.008.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-pre.008` — préparation de publication et prompt `0.3.1`
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
```text
|
||||
0.2.14-pre.007
|
||||
workspace.package.version = 0.2.14-pre.7
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.007` fourni le 28 août 2026 est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 175 tables / 125 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2 tests
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Les tests live/bench explicitement `ignored` restent volontairement hors de ce gate documentaire.
|
||||
|
||||
`pre.007` a fermé la réconciliation durable de `ksp-program-api`, des indexes, du plan et de la validation sans rouvrir `CHANGELOG.md`, `ROADMAP.md` ni le prompt suivant.
|
||||
|
||||
## 2. Objectif
|
||||
|
||||
Dernière prerelease avant `rel.001`, strictement limitée à la préparation de publication :
|
||||
|
||||
- ajouter l'entrée préparatoire stable `0.2.14` dans `CHANGELOG.md` ;
|
||||
- fermer `0.2.14` dans `ROADMAP.md` ;
|
||||
- produire `prompts/020-V0_3_1_START_PROMPT.md` ;
|
||||
- bump mécanique de la version workspace vers `0.2.14-pre.8` ;
|
||||
- ne rouvrir aucun code, test, README/USAGE, plan, validation, architecture ou règle normative.
|
||||
|
||||
## 3. Version Cargo
|
||||
|
||||
Publication non-fix de prerelease :
|
||||
|
||||
```text
|
||||
0.2.14-pre.7
|
||||
-> 0.2.14-pre.8
|
||||
```
|
||||
|
||||
Aucune crate membre ne redéfinit localement la version.
|
||||
|
||||
## 4. Changelog / Roadmap
|
||||
|
||||
`CHANGELOG.md` résume la surface stable candidate `0.2.14` :
|
||||
|
||||
```text
|
||||
ksp-program-api instruction-only
|
||||
ProgramInstructionRecognition
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
10 exports crate-root / 3 modules de production
|
||||
implémentation externe avec Program Pubkey opaque
|
||||
Core + Interface uniquement
|
||||
aucun registry/runtime/serde/codec/Store/Materializer/Execution
|
||||
18 tests Program API au gate final
|
||||
```
|
||||
|
||||
`ROADMAP.md` passe `0.2.14` à `[X]` et conserve `0.3.1` comme prochaine release ouverte :
|
||||
|
||||
```text
|
||||
ksp-store-api + ksp-store-lib
|
||||
PostgreSQL de référence
|
||||
RAW seulement
|
||||
```
|
||||
|
||||
## 5. Prompt `0.3.1`
|
||||
|
||||
Le nouveau prompt a été confronté à :
|
||||
|
||||
```text
|
||||
docs/rules/PROMPT_STRUCTURE.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
docs/rules/RULES_KSP.md
|
||||
docs/rules/RULES_DEPENDENCIES.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/008-DATA_MATERIALIZATION_AND_STORE.md
|
||||
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
|
||||
|
||||
prompts/018-V0_2_13_START_PROMPT.md
|
||||
prompts/019-V0_2_14_START_PROMPT.md
|
||||
```
|
||||
|
||||
L'archive historique suivante a également été reconnue pour déterminer si elle devait être requise dans la prochaine session :
|
||||
|
||||
```text
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
Elle contient notamment :
|
||||
|
||||
```text
|
||||
ks-store/**
|
||||
ks-store/migrations/postgres/**
|
||||
config/store.config.json
|
||||
config/schemas/store.config.schema.json
|
||||
ks-config/src/store.rs
|
||||
docs/architecture/STORAGE_ARCHITECTURE.md
|
||||
docs/guides/POSTGRES_STORAGE.md
|
||||
docs/plans/V0_5_3_KS_STORE_NORMALIZATION_PLAN.md
|
||||
```
|
||||
|
||||
Conclusion : **l'archive est obligatoire pour `0.3.1-pre.001`**, mais seulement comme source historique à classer sous :
|
||||
|
||||
```text
|
||||
REPRENDRE / REDESSINER / REPORTER / REJETER
|
||||
```
|
||||
|
||||
L'ancien `ks-store` couvre RAW + CORE + DECODE/materialization et ne doit donc pas être recopié dans `0.3.1`.
|
||||
|
||||
Le prompt protège explicitement les frontières :
|
||||
|
||||
```text
|
||||
0.3.1 Store API + PostgreSQL RAW-only
|
||||
0.3.2 wires génériques Interface acquisition/CORE
|
||||
0.3.3 Job API + backfill RAW
|
||||
0.3.4 application backfill/inspection RAW
|
||||
plus tard CORE -> DECODE -> SPECIALIZED
|
||||
```
|
||||
|
||||
Il impose en `pre.001` :
|
||||
|
||||
```text
|
||||
audit base stable
|
||||
audit kbot3 Store
|
||||
audit PostgreSQL + dépendance Rust candidate avec sources actuelles
|
||||
inventaire RAW minimal
|
||||
ownership API/impl/composition
|
||||
dependency graph
|
||||
API backend-agnostic candidate
|
||||
schema PostgreSQL RAW candidate
|
||||
migration strategy
|
||||
threat model
|
||||
PostgreSQL integration strategy
|
||||
sizing + prévision souple recalibrée
|
||||
```
|
||||
|
||||
## 6. Prévision souple intégrée au prompt
|
||||
|
||||
La prévision initiale réserve distinctement :
|
||||
|
||||
```text
|
||||
pre.001 audit/sizing
|
||||
pre.002 scaffold API + lib
|
||||
pre.003 contrats RAW
|
||||
pre.004 Store API + backend externe canari
|
||||
pre.005 PostgreSQL runtime foundation
|
||||
pre.006 schema/migrations RAW
|
||||
pre.007 writes/idempotence/atomicité
|
||||
pre.008 reads/pagination/notification si retenue
|
||||
pre.009 hardening/completeness
|
||||
pre.010 gate PostgreSQL réel
|
||||
pre.011 réconciliation documentaire
|
||||
pre.012 préparation de publication
|
||||
rel.001 publication stable
|
||||
```
|
||||
|
||||
Cette prévision reste souple et doit être recalibrée par `0.3.1-pre.001` selon le scope RAW réel.
|
||||
|
||||
## 7. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
prompts/020-V0_3_1_START_PROMPT.md
|
||||
deltas/0.2.14/pre.008.md
|
||||
```
|
||||
|
||||
## 8. Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
```
|
||||
|
||||
## 9. Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## 10. Surfaces explicitement non rouvertes
|
||||
|
||||
```text
|
||||
README.md
|
||||
RULES.md
|
||||
.env.example
|
||||
config/**
|
||||
crates/**
|
||||
docs/**
|
||||
prompts/001..019
|
||||
```
|
||||
|
||||
En particulier :
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/**
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
docs/architecture/**
|
||||
```
|
||||
|
||||
## 11. Validations de préparation
|
||||
|
||||
À exécuter sur l'arbre reconstruit :
|
||||
|
||||
```text
|
||||
audit Rust workspace
|
||||
audit Markdown
|
||||
contrôle exact du payload overlay
|
||||
contrôle des versions/file headers
|
||||
contrôle qu'aucun fichier hors lane n'est modifié
|
||||
```
|
||||
|
||||
Aucun résultat Cargo nouveau n'est revendiqué par la génération de ce delta.
|
||||
|
||||
## 12. 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.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Aucun smoke réseau/live ni nouveau graphe Cargo n'est requis : cette lane ne modifie ni code, ni dépendance, ni runtime.
|
||||
|
||||
## 13. Étape suivante
|
||||
|
||||
Si le gate reste vert :
|
||||
|
||||
```text
|
||||
0.2.14-rel.001
|
||||
```
|
||||
|
||||
La publication stable devra être strictement mécanique :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.14
|
||||
delta deltas/0.2.14/rel.001.md
|
||||
commit de publication
|
||||
tag stable v0.2.14 après validation opérateur
|
||||
```
|
||||
|
||||
`rel.001` ne doit modifier ni `CHANGELOG.md`, ni `ROADMAP.md`, ni le prompt `0.3.1`, sauf anomalie découverte qui renverrait d'abord vers une prerelease dédiée conformément au workflow.
|
||||
307
deltas/0.2.14/rel.001.md
Normal file
307
deltas/0.2.14/rel.001.md
Normal file
@@ -0,0 +1,307 @@
|
||||
<!-- file: deltas/0.2.14/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.2.14-rel.001` — publication stable Program API foundation
|
||||
|
||||
## 1. Base requise
|
||||
|
||||
Base directe attendue :
|
||||
|
||||
```text
|
||||
0.2.14-pre.008
|
||||
workspace.package.version = 0.2.14-pre.8
|
||||
```
|
||||
|
||||
Commit attendu pour cette livraison :
|
||||
|
||||
```text
|
||||
v0.2.14-rel.001
|
||||
```
|
||||
|
||||
Tag stable attendu après validation :
|
||||
|
||||
```text
|
||||
v0.2.14
|
||||
```
|
||||
|
||||
## 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.14-pre.8` à `0.2.14` ;
|
||||
- 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.14-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 — 174 tables / 124 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2 tests
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS / inspecté
|
||||
cargo tree --duplicates PASS / inspecté
|
||||
```
|
||||
|
||||
Le graphe normal ciblé est resté strictement :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
│ └── solana-pubkey
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Le gate opérateur de la réconciliation documentaire `0.2.14-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 — 175 tables / 125 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS
|
||||
cargo test --workspace PASS
|
||||
```
|
||||
|
||||
Enfin, le gate opérateur de la préparation minimale de publication `0.2.14-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 — 175 tables / 127 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership 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.
|
||||
|
||||
Le seul incident technique de la release, le faux positif cross-crate du scanner Logging observé en `pre.005`, a été corrigé dans `pre.005-fix.001` sans changement fonctionnel ; son gate ciblé puis le workspace complet sont passés avant l'ouverture de `pre.006`.
|
||||
|
||||
## 4. Version stable publiée
|
||||
|
||||
La version Cargo devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.14
|
||||
```
|
||||
|
||||
La release stable publiée est :
|
||||
|
||||
```text
|
||||
0.2.14 — Program API foundation
|
||||
```
|
||||
|
||||
La surface stable comprend :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
ProgramInstructionRecognition
|
||||
NoMatch
|
||||
ProgramMatch
|
||||
ExactMatch
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
Decoded(Decoded)
|
||||
Unsupported
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
associated type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction) -> ProgramInstructionRecognition
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
10 exports crate-root exacts
|
||||
3 modules/fichiers Rust de production exacts
|
||||
Program Pubkey opaque non enregistré supporté
|
||||
output Decoded possédé par l'implémentation externe
|
||||
aucun bound implicite Debug / Clone / Send / Sync sur Decoded
|
||||
```
|
||||
|
||||
La dependency direction stable reste :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
-> ksp-core-lib
|
||||
-> ksp-interface-lib
|
||||
-> ksp-core-lib
|
||||
```
|
||||
|
||||
Sont volontairement absents de cette foundation :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
registry runtime / dyn registry
|
||||
ProgramKind / descriptor global
|
||||
identity / version / coverage
|
||||
proofs / diagnostics de replay
|
||||
ProgramAccountDecoder
|
||||
ProgramEventDecoder
|
||||
ProgramReturnDataDecoder
|
||||
ProgramExecutionPreparer
|
||||
payload canonique D3
|
||||
serde / serde_json / Any
|
||||
borsh / wincode / bincode
|
||||
ksp-logging-lib / tracing runtime
|
||||
réseau / filesystem / environnement
|
||||
Store / Materializer / Wallet / Config / Tauri
|
||||
```
|
||||
|
||||
`ProgramInstructionRecognition::ExactMatch` reste une assertion de reconnaissance du decoder et non une preuve indépendante. Les erreurs réelles restent transportées par le `Result` Core ; `Unsupported` représente un état de décodage non supporté et non une erreur artificielle.
|
||||
|
||||
## 5. Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.2.14/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.14
|
||||
Cargo.toml header version 322
|
||||
payload rel.001 2 fichiers exactement
|
||||
CHANGELOG.md non rouvert
|
||||
ROADMAP.md non rouvert
|
||||
prompt 020 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-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --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.14
|
||||
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.14-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/020-V0_3_1_START_PROMPT.md` restent inchangés dans `rel.001` ;
|
||||
4. `ksp-program-api` reste instruction-only et sans runtime `ksp-program-lib` ;
|
||||
5. l'output typé reste possédé par l'implémentation et aucun registry hétérogène n'est promis par la foundation ;
|
||||
6. l'archive historique `khadhroony-bot3_v0.5.3-pre.005-fix010.zip` est obligatoire pour l'audit `0.3.1-pre.001`, mais reste une source historique non normative ;
|
||||
7. `0.3.1` ouvre `ksp-store-api` + `ksp-store-lib` avec PostgreSQL de référence et persistence RAW-only ;
|
||||
8. la prochaine release s'ouvre exclusivement depuis le tag stable `v0.2.14`.
|
||||
|
||||
## 12. Questions ouvertes
|
||||
|
||||
Aucune question ouverte ne bloque la publication de `0.2.14`.
|
||||
|
||||
Les choix de registry/runtime Program, payload canonique D3, decoders account/event/return-data et préparation d'exécution restent explicitement reportés. Ils ne constituent pas une dette bloquante de cette foundation et ne doivent pas être réintroduits pendant la publication stable.
|
||||
|
||||
Le détail du modèle RAW, de l'API backend-agnostic Store, du schéma PostgreSQL et des migrations appartient à l'audit/sizing de `0.3.1-pre.001`.
|
||||
|
||||
## 13. Commit et tag stable
|
||||
|
||||
Après succès du gate stable :
|
||||
|
||||
```text
|
||||
commit : v0.2.14-rel.001
|
||||
tag : v0.2.14
|
||||
```
|
||||
|
||||
Aucun tag intermédiaire `rel.001` n'est requis.
|
||||
|
||||
Commandes Git typiques :
|
||||
|
||||
```bash
|
||||
git add Cargo.toml deltas/0.2.14/rel.001.md
|
||||
git commit -m "v0.2.14-rel.001"
|
||||
git tag v0.2.14
|
||||
git push
|
||||
git push origin v0.2.14
|
||||
```
|
||||
|
||||
## 14. Suite
|
||||
|
||||
Après publication du tag stable `v0.2.14`, ouvrir :
|
||||
|
||||
```text
|
||||
0.3.1-pre.001 — Store RAW foundation
|
||||
```
|
||||
|
||||
avec :
|
||||
|
||||
```text
|
||||
prompts/020-V0_3_1_START_PROMPT.md
|
||||
```
|
||||
|
||||
La session suivante doit recevoir :
|
||||
|
||||
```text
|
||||
archive opérateur exacte de v0.2.14
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
`0.3.1-pre.001` reste une tranche d'audit/brainstorming/sizing avant toute implémentation lourde ; elle doit auditer l'ancien `ks-store` et PostgreSQL actuel, définir le minimum RAW réellement replayable, choisir le modèle API/backend extensible et préserver les reports `0.3.2`/`0.3.3`/`0.3.4` ainsi que CORE/DECODE/SPECIALIZED.
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/plans/000-README.md -->
|
||||
<!-- version: 65 -->
|
||||
<!-- version: 67 -->
|
||||
|
||||
# Plans KSP
|
||||
|
||||
@@ -29,6 +29,7 @@ Un plan décrit le périmètre, les décisions déjà acquises, les questions ou
|
||||
- [`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 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.
|
||||
- [`021-V0_2_14_PROGRAM_API_PLAN.md`](021-V0_2_14_PROGRAM_API_PLAN.md) — plan candidat réconcilié de `0.2.14 — Program API foundation`; il fixe la façade instruction-only ouverte, les enums Recognition/Outcome, `ProgramInstructionDecoder`, l'output associé possédé par l'implémentation, le canari externe avec Program Pubkey non enregistré, le firewall Core/Interface et le report du payload canonique D3, du registry runtime et de `ProgramExecutionPreparer`.
|
||||
|
||||
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: 94 -->
|
||||
<!-- version: 95 -->
|
||||
|
||||
# Séquence des releases fonctionnelles KSP
|
||||
|
||||
@@ -528,9 +528,29 @@ Aucune `ksp-interface-api` séparée n'est retenue pour l'instant. Les codecs/la
|
||||
|
||||
### `0.2.14` — Program API foundation
|
||||
|
||||
Introduire `ksp-program-api`, sans suffixe `-lib`, comme contrat d'extension Program.
|
||||
`ksp-program-api`, sans suffixe `-lib`, matérialise la première façade publique ouverte du domaine Program. La candidate reste volontairement instruction-only et dépend uniquement de Core + Interface.
|
||||
|
||||
`ksp-program-lib` et les vertical slices réels arrivent plus tard.
|
||||
La surface commune est :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition
|
||||
NoMatch / ProgramMatch / ExactMatch
|
||||
|
||||
ProgramInstructionDecodeOutcome<Decoded>
|
||||
Decoded(Decoded) / Unsupported
|
||||
|
||||
ProgramInstructionDecoder: Send + Sync
|
||||
type Decoded
|
||||
program_ids(&self) -> &[Pubkey]
|
||||
recognize(&self, &ProgramInstruction) -> ProgramInstructionRecognition
|
||||
decode(&self, &ProgramInstruction) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>
|
||||
```
|
||||
|
||||
L'output concret reste possédé par l'implémentation et ne reçoit aucun bound implicite `Debug/Clone/Send/Sync`. Une crate externe peut implémenter le trait pour un Program Pubkey absent du registry Core ; aucun enum central de Programs, `Any`, JSON, registry runtime ou descriptor global n'est requis.
|
||||
|
||||
Le hardening final verrouille l'inventaire crate-root exact, le passage d'une `ProgramInstruction` Interface maximale par référence, l'absence d'echo automatique de payload hostile, l'absence de default methods et le firewall `Program API -> Core + Interface`. `pre.006` ferme le gate technique avec audits/check/Clippy/tests workspace et graphe Cargo verts. [`../../crates/ksp-program-api/README.md`](../../crates/ksp-program-api/README.md) et [`../../crates/ksp-program-api/USAGE.md`](../../crates/ksp-program-api/USAGE.md) deviennent les références durables de la candidate.
|
||||
|
||||
Restent explicitement reportés : `ksp-program-lib`, payload canonique D3, registry runtime, identity/version/coverage génériques, autres familles de decoder et `ProgramExecutionPreparer`. Ils seront introduits uniquement par les vertical slices qui démontreront leurs contrats réels.
|
||||
|
||||
## Architecture durable : RAW -> CORE -> DECODE -> SPECIALIZED
|
||||
|
||||
|
||||
801
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
Normal file
801
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
Normal file
@@ -0,0 +1,801 @@
|
||||
<!-- file: docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Plan `0.2.14` — Program API foundation
|
||||
|
||||
## 1. Statut et base
|
||||
|
||||
Ce plan est établi par `0.2.14-pre.001` à partir de la release stable `v0.2.13` et de l'archive historique obligatoire `khadhroony-bot3_v0.5.3-pre.005-fix010.zip`.
|
||||
|
||||
La base KSP vérifiée à l'ouverture est :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.2.13
|
||||
deltas/0.2.13/rel.001.md présent
|
||||
prompts/019-V0_2_14_START_PROMPT.md présent
|
||||
ksp-interface-lib présent
|
||||
ksp-program-api absent
|
||||
ksp-program-lib absent
|
||||
```
|
||||
|
||||
L'archive opérateur ne contient pas de metadata Git exploitable ; le tag `v0.2.13` ne peut donc pas être revérifié localement. L'identité stable est établie par la version Cargo, le delta `rel.001`, le prompt suivant et la surface Interface publiée. Aucun écart bloquant n'a été trouvé entre la base réelle et le prompt.
|
||||
|
||||
Après application de `pre.001`, la version Cargo cible est :
|
||||
|
||||
```text
|
||||
0.2.14-pre.1
|
||||
```
|
||||
|
||||
## 2. Mission recalibrée
|
||||
|
||||
`0.2.14` introduit `ksp-program-api` comme première crate publique extensible du domaine Program.
|
||||
|
||||
Le scope est volontairement réduit à une **foundation de décodage d'instruction typée** :
|
||||
|
||||
```text
|
||||
Core
|
||||
-> Pubkey + Error/Result
|
||||
|
||||
Interface
|
||||
-> ProgramAccountMeta + ProgramInstruction
|
||||
|
||||
Program API
|
||||
-> reconnaissance instruction-local
|
||||
-> outcome de décodage minimal
|
||||
-> trait ProgramInstructionDecoder ouvert
|
||||
-> output associé possédé par l'implémentation
|
||||
```
|
||||
|
||||
La release ne crée pas :
|
||||
|
||||
```text
|
||||
payload canonique D3
|
||||
registry runtime hétérogène
|
||||
identity/version runtime de decoder
|
||||
coverage matrix générique
|
||||
ProgramAccountDecoder
|
||||
ProgramEventDecoder
|
||||
ProgramReturnDataDecoder
|
||||
ProgramExecutionPreparer
|
||||
ksp-program-lib
|
||||
```
|
||||
|
||||
Ce réduction évite de figer des contrats appartenant aux futures couches CORE, DECODE, Materializer, Store ou Execution.
|
||||
|
||||
## 3. Sources KSP relues
|
||||
|
||||
Le gate `pre.001` a relu les sources prescrites par le prompt :
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Les règles structurantes sont notamment `KSP-NAME-002..003`, `KSP-API-001..007`, `KSP-PROGRAM-001..006`, `DEP-LOG-005`, `DEP-PROGRAM-001..004`, `DEP-WIRE-001..007`, `DEP-PIPE-007..008`, `DEP-SOL-001..006`, `DEP-PROTO-001..005` et `DEP-CARGO-001..007`.
|
||||
|
||||
Le résultat normatif est sans ambiguïté : `ksp-program-api` porte des contrats ouverts, reste principalement déclaratif, doit être implémentable depuis une crate externe, utilise les types KSP existants et ne dépend pas des couches runtime supérieures.
|
||||
|
||||
## 4. Inventaire KSP actuel
|
||||
|
||||
### 4.1 Core
|
||||
|
||||
`ksp-core-lib` fournit déjà :
|
||||
|
||||
```text
|
||||
Error
|
||||
ErrorCode
|
||||
ErrorContext
|
||||
Result
|
||||
Pubkey
|
||||
registry KSP des Program IDs fondamentaux
|
||||
```
|
||||
|
||||
Le registry Core est un inventaire KSP de Program IDs fondamentaux. Il n'est pas un registry d'implémentations Program et ne doit pas devenir un closed-world gate : un decoder externe peut viser un `Pubkey` absent de ce registry.
|
||||
|
||||
### 4.2 Interface
|
||||
|
||||
La surface stable `0.2.13` fournit exactement :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS = 255
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN = 10_240
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
`ProgramInstruction` apporte déjà l'input minimal nécessaire au premier decoder :
|
||||
|
||||
```text
|
||||
program_id: Pubkey
|
||||
accounts: ordered bounded ProgramAccountMeta slice
|
||||
data: bounded opaque byte slice
|
||||
```
|
||||
|
||||
Les comptes conservent ordre et doublons. Les Program IDs sont opaques. Le `Debug` de l'instruction ne copie ni accounts ni bytes. Il n'existe donc aucune lacune Interface à combler pour le scope instruction-only.
|
||||
|
||||
### 4.3 Pipeline futur
|
||||
|
||||
La frontière durable reste :
|
||||
|
||||
```text
|
||||
RAW -> CORE -> DECODE -> SPECIALIZED
|
||||
```
|
||||
|
||||
`RAW -> CORE` ne dépend pas de Program. Le futur `CORE -> DECODE` pourra fournir une instruction Interface accompagnée d'un contexte CORE séparé lorsque ce contexte existera. `0.2.14` ne crée pas ce contexte par anticipation.
|
||||
|
||||
## 5. Audit historique kbot3
|
||||
|
||||
### 5.1 Fichiers audités
|
||||
|
||||
Les contrats et usages historiques ont été relus dans :
|
||||
|
||||
```text
|
||||
ks-lib/src/decoder/api/contracts.rs
|
||||
ks-lib/src/decoder/api/decoder.rs
|
||||
ks-lib/src/decoder/api.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
|
||||
ks-lib/src/executor/api.rs
|
||||
ks-lib/src/decoder/solana/core/decoder.rs
|
||||
ks-lib/src/decoder/spl/token/decoder.rs
|
||||
ks-lib/src/decoder/spl/token_2022/decoder.rs
|
||||
ks-lib/src/lib.rs
|
||||
ks-lib/Cargo.toml
|
||||
ks-lib/README.md
|
||||
ks-lib/USAGE.md
|
||||
docs/OPERATION_NAMING_CONVENTION.md
|
||||
docs/IDL_AUDIT.md
|
||||
docs/IDL_TO_KB_LIB_NOMENCLATURE.md
|
||||
docs/architecture/ARCHITECTURE.md
|
||||
docs/architecture/CRATE_MAP.md
|
||||
docs/architecture/PIPELINE_ARCHITECTURE.md
|
||||
```
|
||||
|
||||
Les trois decoders concrets montrent que l'ancien `DcApiInstructionDecoder` était réellement utilisé pour `identity`, `surfaces`, `coverage`, `recognize` puis `decode`, mais contre un input contextualisé contenant signature, slot, instruction path, transaction failure, hashes, logs, balance changes et JSON. Ces dépendances contextuelles ne sont pas présentes dans la foundation KSP actuelle.
|
||||
|
||||
`ks-lib` regroupait en outre modèles, decoders, executors et materializers avec un graphe comprenant codecs, serde/JSON, interfaces Solana et tracing. Cette ownership monolithique est incompatible avec les frontières KSP actuelles.
|
||||
|
||||
### 5.2 Matrice d'héritage
|
||||
|
||||
| Concept historique | Observation réelle kbot3 | Décision | Application KSP `0.2.14` |
|
||||
|-----------------------------------|----------------------------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------------------|
|
||||
| `DcApiDecoderIdentity` | nom et version alloués en `String` | REPORTER | aucune identity runtime tant qu'aucun registry ou replay persistant ne la consomme |
|
||||
| `DcApiDecoderSurface` | Program ID textuel, surface code et priorité | REDESSINER | Program IDs typés; surface code et priorité reportés avec le registry |
|
||||
| `DcApiDecoderCoverageDeclaration` | matrice sérialisable instruction/event/discriminator | REPORTER | couverture machine-readable reportée au premier besoin d'inventaire/runtime |
|
||||
| `DcApiDecoderRecognition` | compatible, exact, priority et codes textuels | REPRENDRE | reconnaissance conservée mais réduite à trois niveaux sans priorité ni strings |
|
||||
| `DcApiDecoderOutcomeStatus` | `Decoded`, `Ignored`, `Unsupported`, `Failed` | REDESSINER | `Decoded(T)` ou `Unsupported`; `Failed` devient `Err`, `Ignored` n'est pas justifié pour un decoder d'instruction |
|
||||
| `DcApiDecoderDiagnostic` | code, message et retriable sérialisables | REPORTER | `ksp_core_lib::Error/Result` suffit à la foundation; diagnostic Program dédié reporté |
|
||||
| `DcApiDecoderProof` | preuve et confidence, dont logs/balances/heuristique | REPORTER | aucun proof sans contexte CORE réel; l'exactitude de recognition reste une assertion du decoder |
|
||||
| `DcApiInstructionDecoder` | trait `Send + Sync` avec identity, coverage, recognize, decode | REPRENDRE | trait instruction-only conservé, input remplacé par `ProgramInstruction`, output devient associated type |
|
||||
| `DcApiProtocolDecoder` | trait générique parallèle avec support `No/Maybe/Yes` | REJETER | pas de second trait monolithique; les capabilities restent séparées par trait |
|
||||
| `MdCoreInstructionReplayInput` | input JSON riche de transaction/CPI/logs/balances | REPORTER | futur CORE; aucune reconstruction en `0.2.14` |
|
||||
| `MdDecodedProtocolEvent` | identité événement liée à signature, slot, path et strings protocole | REPORTER | futur contrat DECODE/Materializer; absent de la foundation |
|
||||
| `MdProgramId` / `MdPubkey` | wrappers `String` | REJETER | `ksp_core_lib::Pubkey` reste canonique |
|
||||
| `MdInstructionPath` | path CPI textuel | REPORTER | futur CORE; absent de `ProgramInstruction` |
|
||||
| `ExApiExecutionRequest` | operation code + `payload_json` générique | REJETER | ne pas créer de JSON générique pour masquer un contrat d'intent non conçu |
|
||||
| `ExApiExecutionCapability` | supported/unsupported avec strings | REDESSINER | concept utile pour un futur preparer, mais aucun contrat execution en `0.2.14` |
|
||||
| `ExApiPreparedExecutionPlan` | instructions, signers, policy, spend et metadata | REDESSINER | séparer plus tard préparation technique et policy; réutiliser `ProgramInstruction` pour le wire |
|
||||
| `ExApiInstructionExecutor` | support + plan générique JSON | REJETER | concept `ProgramExecutor` abandonné |
|
||||
| `ExApiTypedInstructionExecutor` | associated `Intent` et build pur d'un plan | REPRENDRE | idée de préparation pure conservée conceptuellement pour futur `ProgramExecutionPreparer` |
|
||||
| policy intégrée au plan | cluster, simulation, spend, blockhash, post-validation | REJETER | owner futur `ksp-execution-policy-api` / `ksp-execution-lib` |
|
||||
| `ks-lib` monolithique | decoder + executor + materializer + model + codecs | REJETER | frontières `Interface`, `Program API`, futurs `Program Lib`, `Materializer`, `Execution` séparées |
|
||||
|
||||
## 6. Matrice d'ownership
|
||||
|
||||
| Concept | Owner | Décision `0.2.14` |
|
||||
|------------------------------------|----------------------------------------------|--------------------------------------------|
|
||||
| `Pubkey` | `ksp-core-lib` | réutilisé; jamais dupliqué |
|
||||
| Program IDs fondamentaux KSP | `ksp-core-lib` | inchangés; non exhaustifs du monde externe |
|
||||
| `ProgramAccountMeta` | `ksp-interface-lib` | réutilisé |
|
||||
| `ProgramInstruction` | `ksp-interface-lib` | input du premier decoder |
|
||||
| bornes wire instruction | `ksp-interface-lib` | inchangées |
|
||||
| recognition instruction-local | `ksp-program-api` | introduite |
|
||||
| capability decoder instruction | `ksp-program-api` | introduite |
|
||||
| output décodé protocolaire concret | extension externe ou futur `ksp-program-lib` | associated type de l'implémentation |
|
||||
| payload canonique DECODE/D3 | future frontière DECODE/Materializer/Store | reporté |
|
||||
| decoder officiel | futur `ksp-program-lib` | hors scope |
|
||||
| contexte transaction/CPI/logs | future couche CORE | reporté |
|
||||
| registry runtime d'implémentations | future composition Program/DECODE | reporté |
|
||||
| wire codec officiel | `ksp-interface-lib` | hors Program API |
|
||||
| execution preparation | `ksp-program-api` futur | reporté de cette release |
|
||||
| execution policy | futur `ksp-execution-policy-api` | hors scope |
|
||||
| signature/simulation/send/confirm | futur `ksp-execution-lib` + Wallet/Transport | hors scope |
|
||||
| persistence/materialization | futurs Store/Materializer | hors scope |
|
||||
|
||||
## 7. API candidate retenue
|
||||
|
||||
Le design cible à matérialiser dans les tranches suivantes est volontairement petit.
|
||||
|
||||
### 7.1 Façade héritée
|
||||
|
||||
`ksp-program-api` dépendra de Core et Interface et pourra réexporter explicitement depuis son crate root les types nécessaires à une implémentation externe sans module privé :
|
||||
|
||||
```rust
|
||||
pub use ksp_core_lib::{Error, ErrorCode, ErrorContext, Pubkey, Result};
|
||||
pub use ksp_interface_lib::{ProgramAccountMeta, ProgramInstruction};
|
||||
```
|
||||
|
||||
Ces réexports ne changent pas l'ownership : Error/Pubkey restent Core-owned et les structures wire restent Interface-owned.
|
||||
|
||||
Les constantes d'admission Interface ne sont pas réexportées par défaut : l'input reçu a déjà franchi ces bornes et Program API ne les possède pas.
|
||||
|
||||
### 7.2 Recognition
|
||||
|
||||
Candidat retenu :
|
||||
|
||||
```rust
|
||||
#[non_exhaustive]
|
||||
pub enum ProgramInstructionRecognition {
|
||||
NoMatch,
|
||||
ProgramMatch,
|
||||
ExactMatch,
|
||||
}
|
||||
```
|
||||
|
||||
Sémantique :
|
||||
|
||||
```text
|
||||
NoMatch l'implémentation ne revendique pas cette instruction
|
||||
ProgramMatch le Program ID ou la famille est reconnue, mais l'entrée n'est pas prouvée exacte
|
||||
ExactMatch l'implémentation affirme une reconnaissance instruction-locale exacte
|
||||
```
|
||||
|
||||
Aucun score flottant, confidence, priority, surface code ou discriminator textuel n'entre dans la foundation.
|
||||
|
||||
Alternatives rejetées :
|
||||
|
||||
```text
|
||||
bool trop pauvre pour distinguer Program-only et exact
|
||||
No / Maybe / Yes sémantique moins explicite et héritée du generic protocol decoder
|
||||
priority inutile sans registry conflict policy
|
||||
entry code String crée un contrat textuel non consommé
|
||||
proof enum dépend en partie du futur contexte CORE
|
||||
```
|
||||
|
||||
### 7.3 Outcome
|
||||
|
||||
Candidat retenu :
|
||||
|
||||
```rust
|
||||
#[non_exhaustive]
|
||||
pub enum ProgramInstructionDecodeOutcome<Decoded> {
|
||||
Decoded(Decoded),
|
||||
Unsupported,
|
||||
}
|
||||
```
|
||||
|
||||
`decode` retourne un `ksp_core_lib::Result`. Un échec de validation/décodage est donc `Err`, pas un doublon `Failed` dans l'outcome.
|
||||
|
||||
`Ignored` n'est pas retenu : pour une capability qui décode une instruction en une valeur typée, une entrée connue doit soit produire la valeur, soit être unsupported, soit échouer. Une politique de filtrage ou de matérialisation n'appartient pas à ce contrat.
|
||||
|
||||
Le `Debug` de cet outcome, s'il est exposé, devra être borné et ne pas rendre automatiquement le contenu `Decoded`.
|
||||
|
||||
### 7.4 Decoder instruction
|
||||
|
||||
Candidat retenu :
|
||||
|
||||
```rust
|
||||
pub trait ProgramInstructionDecoder: Send + Sync {
|
||||
type Decoded;
|
||||
|
||||
fn program_ids(&self) -> &[Pubkey];
|
||||
|
||||
fn recognize(
|
||||
&self,
|
||||
instruction: &ProgramInstruction,
|
||||
) -> ProgramInstructionRecognition;
|
||||
|
||||
fn decode(
|
||||
&self,
|
||||
instruction: &ProgramInstruction,
|
||||
) -> Result<ProgramInstructionDecodeOutcome<Self::Decoded>>;
|
||||
}
|
||||
```
|
||||
|
||||
Propriétés recherchées :
|
||||
|
||||
```text
|
||||
input entièrement KSP-owned et déjà borné
|
||||
Program IDs typés
|
||||
aucun serde/JSON/codec
|
||||
aucun contexte transactionnel inventé
|
||||
aucun I/O
|
||||
aucun default method
|
||||
Send + Sync sur l'implémentation
|
||||
output concret possédé par la crate externe
|
||||
```
|
||||
|
||||
Le `program_ids()` peut contenir un `Pubkey` absent du registry Core. Il sert uniquement à déclarer la portée Program de l'implémentation; il n'introduit aucun enum central.
|
||||
|
||||
### 7.5 Associated output et composition
|
||||
|
||||
L'associated type est retenu précisément parce que `0.2.14` ne possède pas encore le payload canonique D3.
|
||||
|
||||
Une extension peut définir :
|
||||
|
||||
```text
|
||||
ExternalDecodedInstruction
|
||||
```
|
||||
|
||||
sans forcer KSP à utiliser `Any`, JSON ou une enum centrale.
|
||||
|
||||
Conséquence assumée : le trait n'est **pas** une promesse de registry hétérogène `dyn ProgramInstructionDecoder` sans fixer `Decoded`. `0.2.14` ne crée donc aucun registry runtime et n'annonce aucun object-safe erased decoder.
|
||||
|
||||
Quand la frontière DECODE/D3 réelle existera, KSP pourra introduire un contrat séparé de composition/erasure ou un envelope canonique réellement justifié, sans transformer cette foundation typée en faux format persistant.
|
||||
|
||||
## 8. Décisions sur les questions ouvertes du prompt
|
||||
|
||||
### Capability initiale
|
||||
|
||||
Retenu :
|
||||
|
||||
```text
|
||||
instruction decoder uniquement
|
||||
```
|
||||
|
||||
`ProgramAccountDecoder` est reporté : aucun input account Program-facing stable n'existe encore dans Interface/CORE.
|
||||
|
||||
### Input
|
||||
|
||||
Retenu :
|
||||
|
||||
```text
|
||||
&ProgramInstruction
|
||||
```
|
||||
|
||||
Aucun signature, slot, CPI path, logs, return data, balance delta ou transaction error n'est ajouté.
|
||||
|
||||
### Identity / descriptors / coverage
|
||||
|
||||
Reportés. Le trait lui-même représente la capability; `program_ids()` suffit au besoin immédiat. Nom/version d'implémentation et coverage matrix ne sont pas consommés par la foundation.
|
||||
|
||||
### Payload ouvert
|
||||
|
||||
Retenu : output associé à l'implémentation. Aucun payload canonique commun n'est créé.
|
||||
|
||||
### Proof / confidence
|
||||
|
||||
Reportés. `ExactMatch` est une assertion instruction-locale du decoder, pas une preuve persistée. Logs, balance deltas et audit contextuel appartiennent à CORE/DECODE ultérieur.
|
||||
|
||||
### Diagnostics
|
||||
|
||||
Aucun diagnostic Program dédié. `Error/Result` Core suffit à la foundation. Les erreurs d'une extension doivent rester bornées et ne pas recopier le payload hostile.
|
||||
|
||||
### Registry
|
||||
|
||||
Reporté. `0.2.14` prouve l'extension par une crate externe, pas par un `Vec<Box<dyn ...>>` runtime.
|
||||
|
||||
### Object safety
|
||||
|
||||
Aucun gate object-safety n'est requis pour la surface retenue puisque le registry hétérogène est explicitement hors scope. Le trait reste `Send + Sync`, mais son associated output est intentionnellement typé.
|
||||
|
||||
### `ProgramExecutionPreparer`
|
||||
|
||||
Reporté au premier vertical slice qui possède un intent technique réel. L'ancien bot démontre qu'un preparer pur est utile, mais son ancien plan mélangeait encore policy, wallet/signers, blockhash, simulation et post-replay.
|
||||
|
||||
### Logging
|
||||
|
||||
Aucun `ksp-logging-lib`, `tracing`, `constants.rs` ou `TRACING_TARGET` dans l'API déclarative.
|
||||
|
||||
### Sérialisation
|
||||
|
||||
Aucun `serde` ou `serde_json`.
|
||||
|
||||
## 9. Dependency graph cible
|
||||
|
||||
Le graphe normal final visé est :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
│ └── solana-pubkey
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Dépendances de production interdites pour cette release :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
ksp-onchain-transport-lib
|
||||
ksp-offchain-transport-lib
|
||||
ksp-config-lib
|
||||
ksp-wallet-lib
|
||||
ksp-store-api
|
||||
ksp-store-lib
|
||||
ksp-materializer-api
|
||||
ksp-materializer-lib
|
||||
ksp-logging-lib
|
||||
serde
|
||||
serde_json
|
||||
borsh
|
||||
wincode
|
||||
bincode
|
||||
solana-instruction
|
||||
reqwest
|
||||
tokio
|
||||
tonic
|
||||
tauri
|
||||
tracing
|
||||
```
|
||||
|
||||
Aucune nouvelle dépendance externe n'est nécessaire. L'audit externe ciblé de `pre.001` est donc `N/A` : le design ne dépend d'aucune nouvelle sémantique Solana, crate protocolaire ou registry dyn actuel.
|
||||
|
||||
## 10. Threat / API model
|
||||
|
||||
| Risque | Traitement de la foundation |
|
||||
|-----------------------------------|-----------------------------------------------------------------------------------------------------------------------|
|
||||
| payload hostile | input data déjà borné par Interface à `10_240` bytes; aucun Debug Program ne doit recopier ces bytes |
|
||||
| account vector hostile | input déjà borné à `255` metas; ordre et doublons restent visibles au decoder |
|
||||
| Program Pubkey inconnu | accepté; aucun lookup Core obligatoire |
|
||||
| closed-world enum | interdit; aucun `ProgramKind` central |
|
||||
| implémentation externe incorrecte | trait in-process non sandboxé; KSP ne prétend pas contenir un code tiers arbitraire |
|
||||
| panic externe | aucun default method Program; un panic d'une implémentation tierce reste un défaut de cette implémentation |
|
||||
| false `ExactMatch` | assertion du decoder; pas de proof contextuel inventé; futures compositions peuvent auditer les conflits |
|
||||
| strings non bornées | aucun nouveau String dans l'API candidate |
|
||||
| Debug leak | Recognition sans payload; outcome ne doit pas rendre automatiquement `Decoded`; input Interface a déjà un Debug borné |
|
||||
| status incohérent | `Failed` supprimé au profit de `Err`; outcome minimal réduit les combinaisons invalides |
|
||||
| priority ambiguity | aucun priority sans registry; les conflits sont reportés au contrat de composition futur |
|
||||
| registry conflicts | registry absent de la release |
|
||||
| object-safety impossible | aucune promesse de dyn hétérogène; associated output assumé |
|
||||
| accidental serialization | aucune dépendance/derive serde |
|
||||
| network/policy creep | aucune dépendance runtime et aucun client/wallet/context réseau dans les signatures |
|
||||
|
||||
## 11. Stratégie de tests
|
||||
|
||||
### Unit tests
|
||||
|
||||
Prévoir :
|
||||
|
||||
```text
|
||||
Recognition variants distincts
|
||||
outcome Decoded / Unsupported
|
||||
Debug outcome borné si implémenté
|
||||
unknown Program Pubkey
|
||||
empty/max-boundary ProgramInstruction déjà garanti par Interface et réutilisé sans recopie
|
||||
```
|
||||
|
||||
### Public API
|
||||
|
||||
Le canari `tests/public_api.rs` devra utiliser uniquement les exports crate-root de `ksp-program-api`.
|
||||
|
||||
### External implementation
|
||||
|
||||
Un test d'intégration doit construire une crate consommatrice séparée qui :
|
||||
|
||||
```text
|
||||
dépend uniquement de ksp-program-api pour le contrat Program
|
||||
implémente ProgramInstructionDecoder
|
||||
définit son propre type ExternalDecodedInstruction
|
||||
utilise un Pubkey opaque absent du registry Core
|
||||
reconnaît et décode une instruction
|
||||
n'accède à aucun module privé
|
||||
ne dépend pas de ksp-program-lib
|
||||
```
|
||||
|
||||
La technique exacte de crate fixture temporaire sera choisie lors de la tranche d'implémentation, sans ajouter de dépendance runtime.
|
||||
|
||||
### Dependency firewall
|
||||
|
||||
Canaris manifest/source pour interdire les dépendances listées en section 9.
|
||||
|
||||
### Release completeness
|
||||
|
||||
Verrouiller la surface décidée, l'absence de registry/preparer/payload canonique et l'absence de `pub mod`.
|
||||
|
||||
### Aucun smoke réseau
|
||||
|
||||
Aucun HTTP/WS/gRPC/live smoke n'est pertinent pour une API in-memory déclarative.
|
||||
|
||||
## 12. Sizing
|
||||
|
||||
Le scope initial du prompt contenait decoder, descriptors, registry, payload ouvert et possiblement execution preparation. L'audit montre que stabiliser ces surfaces ensemble obligerait à anticiper D3 et Execution.
|
||||
|
||||
Le gate réduit donc la release à :
|
||||
|
||||
```text
|
||||
crate + facade + firewall
|
||||
recognition + outcome minimal
|
||||
decoder instruction avec associated output
|
||||
external implementation canary
|
||||
hardening/completeness
|
||||
gate technique
|
||||
documentation
|
||||
publication
|
||||
```
|
||||
|
||||
Ce périmètre reste compatible avec une release clôturable dans une session et avec des tranches intermédiaires bornées.
|
||||
|
||||
## 13. Prévision souple recalibrée
|
||||
|
||||
### `pre.001` — Audit KSP + kbot3 + API model + sizing
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
Baseline, règles/architecture, héritage, ownership, API candidate, dependency graph, threat model, tests et scope réduit. Aucun code Program.
|
||||
|
||||
### `pre.002` — Scaffold `ksp-program-api` + façade + firewall
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
La crate est membre du workspace avec exactement `ksp-core-lib` et `ksp-interface-lib` comme dépendances normales. Le crate-root réexporte `Error`, `ErrorCode`, `ErrorContext`, `Result`, `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction`. README/USAGE initiaux et canaris `public_api` / `dependency_boundary` sont présents.
|
||||
|
||||
Aucun trait decoder, recognition, outcome, registry, codec, runtime logging ou execution preparer n'est avancé.
|
||||
|
||||
### `pre.003` — Recognition + outcome minimal
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
`ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome<Decoded>` sont ajoutés dans un module privé puis réexportés depuis le crate-root. Les deux enums sont `#[non_exhaustive]`. Le `Debug` de l'outcome est manuel, ne requiert pas `Decoded: Debug` et n'affiche jamais la valeur décodée. Aucun descriptor, registry ou trait decoder n'est avancé.
|
||||
|
||||
### `pre.004` — `ProgramInstructionDecoder` + external implementation
|
||||
|
||||
**Statut : réalisé ; gate opérateur intégralement PASS.**
|
||||
|
||||
Le trait `ProgramInstructionDecoder: Send + Sync` expose l'associated type `Decoded`, `program_ids`, `recognize` et `decode`. Un test d'intégration downstream-style l'implémente avec un type décodé tiers et un `Pubkey` explicitement absent du registry Core. L'implémentation ne requiert ni `ksp-program-lib`, ni enum centrale, ni `Any`, JSON ou codec.
|
||||
|
||||
### `pre.005` — Adversarial/API hardening + completeness
|
||||
|
||||
**Statut : réalisé ; `pre.005-fix.001` validé, gate opérateur intégralement PASS.**
|
||||
|
||||
Deux canaris de fermeture sont ajoutés : `release_completeness.rs` verrouille l'inventaire exact des exports/modules et l'absence de surface closed-world/runtime ; `security_hardening.rs` couvre input Interface maximal, erreur sûre sur payload hostile et associated output sans bound implicite. Aucun contrat fonctionnel n'est ajouté.
|
||||
|
||||
### `pre.006` — Gate technique final
|
||||
|
||||
**Statut : matérialisé ; gate opérateur à confirmer.**
|
||||
|
||||
Aucun développement fonctionnel. Audits Rust/Markdown, check, Clippy, `cargo test -p ksp-program-api`, ownership Logging ciblé, workspace complet et graphes Cargo. Aucun README/USAGE final ni préparation de publication n’est mélangé à cette tranche.
|
||||
|
||||
### `pre.007` — Réconciliation documentaire finale
|
||||
|
||||
README/USAGE, plan, validation, index et références durables réellement concernées. Aucun `CHANGELOG.md`, `ROADMAP.md` ou prompt suivant.
|
||||
|
||||
### `pre.008` — Préparation de publication minimale
|
||||
|
||||
Uniquement `Cargo.toml`, `CHANGELOG.md`, `ROADMAP.md`, prompt `0.3.1` et delta `pre.008`.
|
||||
|
||||
### `rel.001` — Publication stable
|
||||
|
||||
Mécanique de publication uniquement.
|
||||
|
||||
La numérotation reste souple : une anomalie peut insérer une tranche dédiée, mais les couloirs `gate technique -> réconciliation documentaire -> publication minimale` restent séparés.
|
||||
|
||||
## 13.1 État préparé après `pre.002`
|
||||
|
||||
Le scaffold strict attendu pour ouvrir `pre.003` est :
|
||||
|
||||
```text
|
||||
ksp-program-api membre workspace
|
||||
normal dependencies ksp-core-lib + ksp-interface-lib uniquement
|
||||
crate-root facade Core/Interface réexportés explicitement
|
||||
public modules aucun
|
||||
ProgramInstructionRecognition absent par contrat pre.002
|
||||
ProgramInstructionDecodeOutcome absent par contrat pre.002
|
||||
ProgramInstructionDecoder absent par contrat pre.002
|
||||
ProgramExecutionPreparer absent
|
||||
serde / JSON / codecs absents
|
||||
ksp-logging-lib / tracing absents
|
||||
README / USAGE initiaux
|
||||
public API canary présent
|
||||
dependency firewall canary présent
|
||||
```
|
||||
|
||||
`pre.003` reste limité à `ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome<Decoded>` avec leur sémantique et leur Debug sûr. Le trait decoder reste réservé à `pre.004`.
|
||||
|
||||
## 13.2 État préparé après `pre.003`
|
||||
|
||||
Le gate opérateur `pre.002` fourni le 28 août 2026 est intégralement vert : audits Rust/Markdown, check, Clippy, tests de `ksp-program-api`, workspace complet et graphes Cargo ont été exécutés. Le graphe normal ciblé reste exactement `Core + Interface`.
|
||||
|
||||
La tranche `pre.003` matérialise :
|
||||
|
||||
```text
|
||||
ProgramInstructionRecognition NoMatch / ProgramMatch / ExactMatch
|
||||
ProgramInstructionDecodeOutcome<T> Decoded(T) / Unsupported
|
||||
non_exhaustive oui sur les deux enums
|
||||
Debug recognition payload-free par construction
|
||||
Debug outcome opaque, sans bound T: Debug
|
||||
Failed / Ignored absents
|
||||
priority / confidence / proof absents de la surface
|
||||
ProgramInstructionDecoder absent par contrat pre.003
|
||||
registry / canonical payload / preparer absents
|
||||
normal dependencies inchangées : Core + Interface
|
||||
```
|
||||
|
||||
Les tests unitaires vérifient notamment qu'un type décodé externe dépourvu de `Debug` peut être contenu et formaté via l'outcome sans exposer sa valeur. Le gate opérateur `pre.003` fourni le 28 août 2026 est intégralement vert et autorise `pre.004`.
|
||||
|
||||
## 13.3 État préparé après `pre.004`
|
||||
|
||||
La tranche matérialise exactement :
|
||||
|
||||
```text
|
||||
ProgramInstructionDecoder public depuis le crate-root
|
||||
supertraits Send + Sync
|
||||
associated output type Decoded possédé par l'implémentation
|
||||
program_ids &[Pubkey] opaque/open-world
|
||||
recognize &ProgramInstruction -> Recognition
|
||||
decode &ProgramInstruction -> Result<Outcome<Self::Decoded>>
|
||||
default methods aucun
|
||||
external implementation canary présent comme crate d'intégration séparée
|
||||
external decoded type défini hors code de production KSP
|
||||
external Program Pubkey explicitement absent du registry Core
|
||||
central Program enum / Any / JSON absents
|
||||
registry dyn / descriptor / D3 payload absents
|
||||
ProgramExecutionPreparer absent
|
||||
normal dependencies inchangées : Core + Interface
|
||||
```
|
||||
|
||||
Le canari externe utilise uniquement la façade `ksp_program_api::*` pour l'implémentation du trait ; l'accès direct à `ksp_core_lib::find_program_pubkey` est limité à l'assertion de test prouvant que le Program choisi n'est pas enregistré. Aucune API de registry n'est réexportée par Program API.
|
||||
|
||||
`pre.005` reste une tranche de hardening/completeness : elle ne doit pas élargir le contrat fonctionnel.
|
||||
|
||||
## 13.4 État préparé après `pre.005`
|
||||
|
||||
Le gate opérateur `pre.004` fourni le 28 août 2026 est intégralement vert : audits Rust/Markdown, check, Clippy, tests ciblés, workspace complet, canari externe et graphes Cargo passent.
|
||||
|
||||
La tranche `pre.005` ajoute uniquement des preuves de fermeture :
|
||||
|
||||
```text
|
||||
exact crate-root exports 10 exports explicitement verrouillés
|
||||
production modules lib + decode vocabulary + decoder trait uniquement
|
||||
public enums Recognition + DecodeOutcome uniquement
|
||||
public traits ProgramInstructionDecoder uniquement
|
||||
closed-world Program enum absent
|
||||
registry / descriptors / preparer absents
|
||||
serde / JSON / Any / codecs absents
|
||||
logging / runtime / IO absents
|
||||
max Interface instruction consommable par référence
|
||||
malformed hostile payload Err Core sûr sans copie automatique du payload
|
||||
associated Decoded bounds aucun bound implicite ajouté
|
||||
dyn heterogeneous registry aucune promesse
|
||||
normal dependencies inchangées : Core + Interface
|
||||
```
|
||||
|
||||
`pre.006` reste un gate technique final sans développement fonctionnel.
|
||||
|
||||
## 13.5 Gate opérateur `pre.005-fix.001` et ouverture de `pre.006`
|
||||
|
||||
Le gate opérateur du 28 août 2026 ferme le correctif de `pre.005` :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 173 tables / 123 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2 tests
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté, inventaire workspace observé
|
||||
```
|
||||
|
||||
Le faux positif du canari logging est donc fermé sans changement de production ni de dépendances. Le scope fonctionnel `0.2.14` est figé avant `pre.006`.
|
||||
|
||||
La tranche `pre.006` ne matérialise aucun nouveau code ou test : elle synchronise seulement la version workspace, le plan, la validation et son delta afin de rejouer le gate technique final sur la surface candidate déjà durcie.
|
||||
|
||||
## 13.6 Gate technique final `pre.006` et réconciliation `pre.007`
|
||||
|
||||
Le gate opérateur de `pre.006`, fourni le 28 août 2026, ferme intégralement la lane technique sans modification de production ni de tests :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audits Rust / export completeness / workspace PASS
|
||||
audit Markdown PASS — 174 tables / 124 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2/2
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
La surface technique candidate est donc figée :
|
||||
|
||||
```text
|
||||
crate-root exports 10 exacts
|
||||
production modules 3 exacts
|
||||
public enums Recognition + DecodeOutcome uniquement
|
||||
public trait ProgramInstructionDecoder uniquement
|
||||
normal dependencies Core + Interface uniquement
|
||||
Program Pubkey hors registry accepté par canari externe
|
||||
max Interface instruction admise à la frontière decoder par référence
|
||||
registry / descriptors / preparer absents
|
||||
serde / JSON / Any / codecs absents
|
||||
logging / runtime / IO absents
|
||||
```
|
||||
|
||||
`pre.007` ne rouvre aucun fichier Rust, test, manifest de crate, dépendance ou comportement. La version workspace avance mécaniquement à `0.2.14-pre.7` et les références durables suivantes sont réconciliées :
|
||||
|
||||
```text
|
||||
crates/ksp-program-api/README.md
|
||||
crates/ksp-program-api/USAGE.md
|
||||
docs/000-README.md
|
||||
docs/plans/000-README.md
|
||||
docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md
|
||||
docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
|
||||
docs/validation/000-README.md
|
||||
docs/validation/017-V0_2_14_PROGRAM_API.md
|
||||
```
|
||||
|
||||
La documentation finale fixe l'ownership, l'inventaire crate-root, les semantics Recognition/Outcome, le trait externe, les preuves open-world/adversariales et le dependency firewall. Les index passent au statut candidat réconcilié sans annoncer prématurément la release stable.
|
||||
|
||||
Cette tranche ne touche explicitement pas `CHANGELOG.md`, `ROADMAP.md`, le prompt suivant, l'architecture ni les surfaces techniques. Ces responsabilités appartiennent à `pre.008`, sauf découverte d'un défaut documentaire réel imposant une nouvelle tranche de réconciliation.
|
||||
|
||||
## 14. Hors périmètre confirmé
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
decoder officiel Solana/SPL
|
||||
ProgramAccountDecoder / Event / ReturnData
|
||||
registry runtime
|
||||
priority/conflict policy
|
||||
descriptor identity/version/coverage
|
||||
payload canonique D3
|
||||
serde/JSON/Any
|
||||
proof/confidence contextuels
|
||||
CORE replay input
|
||||
Materializer / Store
|
||||
ProgramExecutionPreparer
|
||||
ExecutionPolicy / Execution
|
||||
Wallet / Transport / Config / Tauri
|
||||
IDL runtime / Anchor generic decoder
|
||||
```
|
||||
|
||||
## 15. Critères de clôture
|
||||
|
||||
La candidate satisfait les critères techniques et documentaires suivants avant préparation de publication :
|
||||
|
||||
```text
|
||||
ksp-program-api existe
|
||||
le trait instruction-only est public et documenté
|
||||
une extension externe l'implémente avec un Pubkey non enregistré
|
||||
aucun enum central Program n'est requis
|
||||
aucun payload canonique prématuré n'est figé
|
||||
aucun registry/preparer n'est anticipé
|
||||
Core/Interface sont les seules dépendances KSP normales
|
||||
aucun runtime/codec/logging/serde n'est tiré
|
||||
public API / external implementation / dependency firewall / completeness passent
|
||||
cargo test -p ksp-program-api passe
|
||||
cargo test --workspace passe
|
||||
graphes Cargo inspectés
|
||||
documentation finale réconciliée
|
||||
```
|
||||
|
||||
## 16. Suite
|
||||
|
||||
Après `0.2.14`, la séquence active reste :
|
||||
|
||||
```text
|
||||
0.3.1 ksp-store-api + ksp-store-lib, RAW only
|
||||
0.3.2 ksp-interface-lib, wires génériques acquisition/CORE
|
||||
0.3.3 ksp-job-api + backfill
|
||||
0.3.4 application backfill/RAW
|
||||
```
|
||||
|
||||
Le payload DECODE, les materializers et la préparation d'exécution ne sont pas déplacés dans `0.3.1`; ils attendent les vertical slices qui démontreront leurs contrats réels.
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/000-README.md -->
|
||||
<!-- version: 29 -->
|
||||
<!-- version: 31 -->
|
||||
|
||||
# Validations KSP
|
||||
|
||||
@@ -25,3 +25,4 @@ Documents :
|
||||
- [`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 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.
|
||||
- [`017-V0_2_14_PROGRAM_API.md`](017-V0_2_14_PROGRAM_API.md) — matrice candidate finale de `0.2.14 — Program API foundation` : façade instruction-only ouverte, Recognition/Outcome, trait externe, Program Pubkey non enregistré, hardening adversarial, release completeness, firewall Core/Interface et gate technique `pre.006` intégralement vert.
|
||||
|
||||
346
docs/validation/017-V0_2_14_PROGRAM_API.md
Normal file
346
docs/validation/017-V0_2_14_PROGRAM_API.md
Normal file
@@ -0,0 +1,346 @@
|
||||
<!-- file: docs/validation/017-V0_2_14_PROGRAM_API.md -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Validation `0.2.14` — Program API foundation
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Cette matrice, ouverte par `0.2.14-pre.001`, est réconciliée par `pre.007` après fermeture intégralement verte du gate technique `pre.006`. Elle conserve l'historique des preuves par tranche et la surface candidate finale.
|
||||
|
||||
Le scope final reste une foundation instruction-only avec output associé à l'implémentation. Registry runtime, payload canonique D3 et `ProgramExecutionPreparer` sont explicitement reportés.
|
||||
|
||||
## 2. Gate `pre.001`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|----------------------------|---------|--------------------------------------------------------------------------------|
|
||||
| base stable `0.2.13` | PASS | Cargo `0.2.13`, `rel.001` et prompt 019 présents |
|
||||
| metadata Git/tag | N/A | archive opérateur sans metadata Git exploitable |
|
||||
| `ksp-interface-lib` stable | PASS | surface et canaris `0.2.13` relus |
|
||||
| `ksp-program-api` absent | PASS | aucun répertoire de crate sur la base |
|
||||
| `ksp-program-lib` absent | PASS | aucun répertoire de crate sur la base |
|
||||
| archive kbot3 disponible | PASS | archive historique réellement extraite et auditée |
|
||||
| règles Program/API relues | PASS | règles KSP/Dependencies/Workflow prescrites relues |
|
||||
| architecture durable relue | PASS | `002` à `010`, avec `006-WIRE_AND_PROGRAM.md` central |
|
||||
| audit Core + Interface | PASS | input `ProgramInstruction` jugé suffisant pour instruction-only |
|
||||
| matrice héritage kbot3 | PASS | `REPRENDRE / REDESSINER / REPORTER / REJETER` dans le plan 021 |
|
||||
| ownership matrix | PASS | Core/Interface/Program/CORE/Execution séparés dans le plan 021 |
|
||||
| API candidate | PASS | recognition + generic outcome + associated-output decoder |
|
||||
| payload canonique | REPORTÉ | aucune représentation D3 inventée en `0.2.14` |
|
||||
| registry runtime | REPORTÉ | aucune composition dyn hétérogène dans la release |
|
||||
| execution preparer | REPORTÉ | attend un intent technique réel de vertical slice |
|
||||
| dependency graph | PASS | cible Core + Interface uniquement |
|
||||
| threat/API model | PASS | payload, Debug, open-world, externe hostile, exactness et scope creep couverts |
|
||||
| stratégie de tests | PASS | unit/public/external/firewall/completeness, aucun live smoke |
|
||||
| sizing | PASS | release réduite à decoder instruction-only et couloirs de fermeture séparés |
|
||||
|
||||
## 3. Décisions API à prouver par le code
|
||||
|
||||
| Contrat | Décision `pre.001` | Gate futur |
|
||||
|--------------------------------------------|---------------------------------------------------------|--------------------------------|
|
||||
| `ProgramInstructionRecognition` | `NoMatch / ProgramMatch / ExactMatch`, non exhaustif | PASS `pre.003` |
|
||||
| `ProgramInstructionDecodeOutcome<Decoded>` | `Decoded(Decoded) / Unsupported`, non exhaustif | PASS `pre.003` |
|
||||
| decoder failure | `ksp_core_lib::Result`, aucun statut `Failed` parallèle | `pre.003` / `pre.004` |
|
||||
| `ProgramInstructionDecoder` | `Send + Sync`, associated `Decoded` | PASS `pre.004` |
|
||||
| input | `&ProgramInstruction` | PASS `pre.004` |
|
||||
| Program IDs déclarés | `&[Pubkey]`, opaque et open-world | PASS `pre.004` |
|
||||
| output | type concret de l'implémentation | PASS `pre.004` |
|
||||
| registry dyn | absent | completeness `pre.005` |
|
||||
| identity/version/coverage | absents | completeness `pre.005` |
|
||||
| Program Account/Event/ReturnData decoder | absents | completeness `pre.005` |
|
||||
| ProgramExecutionPreparer | absent | completeness `pre.005` |
|
||||
| serde/JSON/codec | absents | firewall `pre.002` / `pre.005` |
|
||||
| runtime/logging | absents | firewall `pre.002` / `pre.005` |
|
||||
|
||||
## 4. External implementation canary
|
||||
|
||||
La preuve matérialisée en `pre.004` utilise une crate d'intégration consommatrice séparée et vérifie :
|
||||
|
||||
```text
|
||||
implementation de ProgramInstructionDecoder
|
||||
associated output défini hors KSP
|
||||
Program Pubkey absent du registry Core
|
||||
construction de ProgramInstruction via la facade publique retenue
|
||||
recognition ProgramMatch ou ExactMatch déterministe
|
||||
decode vers Decoded(external value)
|
||||
aucun ksp-program-lib
|
||||
aucun module privé
|
||||
```
|
||||
|
||||
Ce canari remplace toute affirmation documentaire non exécutable d'extensibilité. Son gate opérateur `pre.004` est confirmé intégralement vert.
|
||||
|
||||
## 5. Dependency firewall cible
|
||||
|
||||
Graphe normal attendu :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
├── ksp-core-lib
|
||||
│ └── solana-pubkey
|
||||
└── ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Interdits :
|
||||
|
||||
```text
|
||||
Transport
|
||||
Store
|
||||
Wallet
|
||||
Materializer
|
||||
Config
|
||||
Tauri
|
||||
ksp-program-lib
|
||||
ksp-logging-lib
|
||||
serde / serde_json
|
||||
borsh / wincode / bincode
|
||||
solana-instruction
|
||||
reqwest / tokio / tonic
|
||||
tracing
|
||||
```
|
||||
|
||||
## 6. Threat/API gates futurs
|
||||
|
||||
| Gate | Attendu | Statut initial |
|
||||
|---------------------------|--------------------------------------------------------------------------|----------------|
|
||||
| unknown Program Pubkey | utilisable sans registry Core | PASS `pre.004` |
|
||||
| max Interface input | decoder consomme l'input déjà borné sans nouvelle allocation obligatoire | PASS `pre.005` |
|
||||
| malformed program payload | `Err` ou `Unsupported`; aucun echo n'est ajouté par le contrat | PASS `pre.005` |
|
||||
| Debug recognition | aucun payload | PASS |
|
||||
| Debug outcome | contenu `Decoded` non rendu automatiquement | PASS |
|
||||
| default methods | aucun default method susceptible de masquer panic/policy | PASS `pre.004` |
|
||||
| closed-world enum | aucun inventaire central de Program kinds | PASS `pre.004` |
|
||||
| serde accidental | aucune dependency/derive | PASS `pre.004` |
|
||||
| runtime creep | aucun réseau, wallet, store, logging ou UI | PASS `pre.004` |
|
||||
| external output | type tiers accepté sans `Any`/JSON central | PASS `pre.004` |
|
||||
| dyn claim | aucune assertion d'object-safety hétérogène dans cette release | PASS `pre.004` |
|
||||
|
||||
## 7. Gates de fermeture
|
||||
|
||||
### Gate technique final
|
||||
|
||||
Le gate technique dédié `pre.006` est fermé intégralement vert. Les commandes de référence étaient :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.2.14
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-program-api
|
||||
cargo test -p ksp-logging-lib --test ownership
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-program-api --edges normal
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
### Réconciliation documentaire
|
||||
|
||||
`pre.007` ferme :
|
||||
|
||||
```text
|
||||
ksp-program-api README/USAGE
|
||||
plan 021
|
||||
validation 017
|
||||
indexes/références durables concernées
|
||||
```
|
||||
|
||||
Sans `CHANGELOG.md`, `ROADMAP.md` ni prompt suivant.
|
||||
|
||||
### Préparation de publication
|
||||
|
||||
Doit rester limitée à :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompt de démarrage 0.3.1
|
||||
delta de la prerelease
|
||||
```
|
||||
|
||||
## 8. Gate opérateur `pre.002`
|
||||
|
||||
Le gate fourni le 28 août 2026 est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 170 tables / 119 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 4 tests d'intégration
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté, inventaire workspace observé
|
||||
```
|
||||
|
||||
Ce gate autorise l'ouverture de `pre.003`.
|
||||
|
||||
## 9. État préparé `pre.003`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|--------------------------------------|--------|----------------------------------------------------------------------|
|
||||
| `ProgramInstructionRecognition` | PASS | enum non exhaustif `NoMatch / ProgramMatch / ExactMatch` |
|
||||
| `ProgramInstructionDecodeOutcome<T>` | PASS | enum non exhaustif `Decoded(T) / Unsupported` |
|
||||
| absence de `Failed` / `Ignored` | PASS | échec réservé au futur `Result`; aucun statut parallèle |
|
||||
| Debug recognition | PASS | enum sans payload; Debug dérivé |
|
||||
| Debug outcome | PASS | implémentation manuelle sans `T: Debug`, valeur `Decoded` non rendue |
|
||||
| dépendances normales | PASS | manifest inchangé : `ksp-core-lib` + `ksp-interface-lib` |
|
||||
| module public | PASS | aucun `pub mod`; exports crate-root uniquement |
|
||||
| `ProgramInstructionDecoder` | ABSENT | réservé à `pre.004` |
|
||||
| registry / descriptor / payload D3 | ABSENT | hors scope maintenu |
|
||||
| serde / codec / logging / runtime | ABSENT | dependency firewall maintenu |
|
||||
|
||||
Le gate opérateur `pre.003` est confirmé intégralement vert : audits Rust/Markdown, check, Clippy, tests ciblés, workspace complet et graphes Cargo passent.
|
||||
|
||||
## 10. Gate opérateur `pre.003`
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 171 tables / 120 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 8 tests Rust
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté, inventaire workspace observé
|
||||
```
|
||||
|
||||
Ce gate autorise l'ouverture de `pre.004`.
|
||||
|
||||
## 11. État préparé `pre.004`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|------------------------------------|--------|----------------------------------------------------------------------|
|
||||
| `ProgramInstructionDecoder` | PASS | trait public `Send + Sync` |
|
||||
| associated `Decoded` | PASS | type sans bound imposé, possédé par l'implémentation |
|
||||
| `program_ids` | PASS | `&[Pubkey]`, aucune validation registry dans l'API |
|
||||
| `recognize` | PASS | input `&ProgramInstruction`, outcome `ProgramInstructionRecognition` |
|
||||
| `decode` | PASS | `Result<ProgramInstructionDecodeOutcome<Self::Decoded>>` |
|
||||
| default methods | ABSENT | toutes les méthodes sont obligatoires |
|
||||
| external implementation canary | PASS | test d'intégration downstream-style séparé |
|
||||
| Program Pubkey non enregistré | PASS | assertion `ksp_core_lib::find_program_pubkey(...) == None` |
|
||||
| output externe concret | PASS | `ExternalDecodedInstruction` défini dans le consumer canary |
|
||||
| `ksp-program-lib` | ABSENT | aucune dépendance ni implémentation officielle |
|
||||
| registry / descriptor / payload D3 | ABSENT | hors scope maintenu |
|
||||
| serde / codec / logging / runtime | ABSENT | dependency firewall inchangé |
|
||||
|
||||
Le canari d'implémentation consomme la façade `ksp_program_api` pour le trait, les types et les outcomes. Le registry Core n'est utilisé que par l'assertion de test négative et n'est pas réexporté par Program API. Le gate opérateur de `pre.004` est confirmé intégralement vert et autorise `pre.005`.
|
||||
|
||||
## 12. Gate opérateur `pre.004`
|
||||
|
||||
Le gate fourni le 28 août 2026 est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 172 tables / 121 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 11 tests Rust
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates exécuté, inventaire workspace observé
|
||||
```
|
||||
|
||||
Ce gate autorise l'ouverture de `pre.005`.
|
||||
|
||||
## 13. État préparé `pre.005`
|
||||
|
||||
| Critère | Statut | Preuve |
|
||||
|--------------------------------------|--------|----------------------------------------------------------------------|
|
||||
| exact crate-root export inventory | PASS | test `release_completeness` sur les 10 réexports |
|
||||
| exact production module inventory | PASS | `lib.rs`, decode vocabulary et decoder trait uniquement |
|
||||
| public enum inventory | PASS | Recognition + DecodeOutcome uniquement |
|
||||
| closed-world Program enum | ABSENT | aucun `ProgramKind`/inventaire public central |
|
||||
| registry / descriptors | ABSENT | aucune collection/runtime selection/identity-version-coverage |
|
||||
| `ProgramExecutionPreparer` | ABSENT | scope négatif maintenu |
|
||||
| serde / JSON / Any / codecs | ABSENT | manifest + source canaries |
|
||||
| logging / runtime / IO | ABSENT | aucune dépendance ou primitive runtime/FS/env/network |
|
||||
| max Interface input | PASS | 255 accounts + 10 240 bytes traversent le trait par référence |
|
||||
| malformed hostile payload | PASS | `Result::Err` Core reste sûr sans echo automatique du payload |
|
||||
| Debug outcome | PASS | valeur décodée jamais formatée |
|
||||
| associated `Decoded` implicit bounds | ABSENT | canari avec output `Rc<Cell<_>>`, donc non-`Send`/non-`Sync` accepté |
|
||||
| dyn heterogeneous claim | ABSENT | aucun `dyn ProgramInstructionDecoder`/registry |
|
||||
| dépendances normales | PASS | `ksp-core-lib` + `ksp-interface-lib` uniquement |
|
||||
|
||||
La sécurité des messages/contextes produits volontairement par une implémentation tierce reste sa responsabilité ; `ksp-program-api` garantit seulement qu'il n'ajoute aucun canal parallèle ni copie automatique du payload hostile.
|
||||
|
||||
Le gate opérateur de `pre.005` a révélé uniquement le faux positif cross-crate logging corrigé par `pre.005-fix.001`. Le gate du fix est désormais intégralement vert et autorise le gate technique final `pre.006`.
|
||||
|
||||
## 14. Gate opérateur `pre.005-fix.001`
|
||||
|
||||
Le gate fourni le 28 août 2026 est intégralement vert :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audit Rust général / exports / workspace PASS
|
||||
audit Markdown PASS — 173 tables / 123 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2/2
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Le faux positif `tracing` du canari `release_completeness.rs` est fermé sans ajout de dépendance, sans modification de production et sans affaiblissement du scanner logging workspace.
|
||||
|
||||
## 15. Gate technique final préparé `pre.006`
|
||||
|
||||
`pre.006` ne modifie aucun fichier de production ni de test. Le gate final doit confirmer la candidate suivante sans élargissement :
|
||||
|
||||
| Critère | Attendu `pre.006` |
|
||||
|--------------------------------------|-------------------------------------------|
|
||||
| API Program | exactement la surface fermée en `pre.005` |
|
||||
| tests `ksp-program-api` | 18 tests Rust PASS |
|
||||
| ownership Logging | 2 tests PASS |
|
||||
| workspace | PASS |
|
||||
| graphe normal `ksp-program-api` | Core + Interface uniquement |
|
||||
| registry / preparer / payload D3 | ABSENTS |
|
||||
| serde / codec / logging runtime / IO | ABSENTS |
|
||||
| README / USAGE | non réconciliés ici |
|
||||
| CHANGELOG / ROADMAP / prompt suivant | non modifiés |
|
||||
|
||||
Aucun smoke réseau/live n'est requis : `ksp-program-api` reste une API déclarative instruction-only sans I/O.
|
||||
|
||||
## 16. Gate technique final `pre.006`
|
||||
|
||||
Le gate opérateur fourni le 28 août 2026 confirme la candidate technique complète :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
audits Rust / export completeness / workspace PASS
|
||||
audit Markdown PASS — 174 tables / 124 fichiers
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS
|
||||
cargo test -p ksp-program-api PASS — 18 tests Rust
|
||||
cargo test -p ksp-logging-lib --test ownership PASS — 2/2
|
||||
cargo test --workspace PASS
|
||||
cargo tree -p ksp-program-api --edges normal PASS — Core + Interface uniquement
|
||||
cargo tree --duplicates inspecté
|
||||
```
|
||||
|
||||
Les duplicates observés sont ceux du workspace global et ne proviennent d'aucune dépendance ajoutée par Program API. Aucun smoke live n'est applicable à cette foundation déclarative sans I/O.
|
||||
|
||||
La validation technique de la release candidate est fermée.
|
||||
|
||||
## 17. 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-program-api/README.md` | PASS structurel | ownership, surface exacte, semantics, hardening, firewall et frontières |
|
||||
| `crates/ksp-program-api/USAGE.md` | PASS structurel | usage crate-root, implémentation externe, sélection, outcome et Debug sûr |
|
||||
| `docs/plans/002-FUNCTIONAL_RELEASE_SEQUENCE.md` | PASS structurel | contenu réel `0.2.14` + reports runtime/D3/preparer |
|
||||
| `docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md` | PASS structurel | gate `pre.006` fermé + lane documentaire finale |
|
||||
| `docs/validation/017-V0_2_14_PROGRAM_API.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 ne modifie aucun code/test/manifest de crate/dépendance et ne touche ni `CHANGELOG.md`, ni `ROADMAP.md`, ni le prompt `0.3.1`. Ces surfaces restent réservées à la préparation minimale de publication `pre.008`.
|
||||
|
||||
Le gate opérateur de `pre.007` doit rester déterministe : audits, check, Clippy, tests ciblés Program/Logging et workspace suffisent ; aucun smoke live ni nouveau `cargo tree` n'est requis si l'overlay documentaire est appliqué exactement.
|
||||
|
||||
1463
prompts/020-V0_3_1_START_PROMPT.md
Normal file
1463
prompts/020-V0_3_1_START_PROMPT.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user