From 27d4cb1f362b0e508d0607816f7b02cda9de7191 Mon Sep 17 00:00:00 2001 From: SinuS Von SifriduS Date: Fri, 28 Aug 2026 14:10:49 +0200 Subject: [PATCH] v0.2.14-pre.003 --- Cargo.toml | 4 +- crates/ksp-program-api/README.md | 50 ++- crates/ksp-program-api/USAGE.md | 71 ++++- crates/ksp-program-api/src/lib.rs | 16 +- .../src/program_instruction_decode.rs | 50 +++ .../tests/dependency_boundary.rs | 36 ++- crates/ksp-program-api/tests/public_api.rs | 20 +- .../unit_tests/program_instruction_decode.rs | 41 +++ deltas/0.2.14/pre.003.md | 285 ++++++++++++++++++ docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md | 29 +- docs/validation/017-V0_2_14_PROGRAM_API.md | 54 ++-- 11 files changed, 588 insertions(+), 68 deletions(-) create mode 100644 crates/ksp-program-api/src/program_instruction_decode.rs create mode 100644 crates/ksp-program-api/unit_tests/program_instruction_decode.rs create mode 100644 deltas/0.2.14/pre.003.md diff --git a/Cargo.toml b/Cargo.toml index 6f8f709..5247e0f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,12 @@ # file: Cargo.toml -# version: 314 +# version: 315 [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-program-api", "crates/ksp-wallet-lib"] [workspace.package] -version = "0.2.14-pre.2" +version = "0.2.14-pre.3" edition = "2024" license = "MIT" repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project" diff --git a/crates/ksp-program-api/README.md b/crates/ksp-program-api/README.md index ba69777..aa2cc46 100644 --- a/crates/ksp-program-api/README.md +++ b/crates/ksp-program-api/README.md @@ -1,11 +1,11 @@ - + # ksp-program-api `ksp-program-api` est la façade publique ouverte du domaine Program KSP. Elle est destinée aux implémentations officielles futures comme aux crates Program externes et ne possède pas les implémentations concrètes. -La tranche initiale `0.2.14-pre.002` matérialise uniquement le scaffold et les types déjà possédés par les couches fondatrices. Aucun trait decoder n'est encore publié. +À partir de `0.2.14-pre.003`, la foundation expose les types Core/Interface retenus ainsi que le vocabulaire minimal de reconnaissance et d'outcome de décodage. Le trait decoder reste réservé à la tranche suivante. ## Ownership @@ -35,11 +35,43 @@ ProgramAccountMeta ProgramInstruction ``` -`ksp-program-api` les réexporte depuis son crate-root pour offrir une façade de consommation stable sans dupliquer leurs types ni transférer leur ownership. +Program API possède désormais : -## Surface de scaffold +```text +ProgramInstructionRecognition +ProgramInstructionDecodeOutcome +``` -La façade `pre.002` expose exactement : +`ksp-program-api` réexporte l'ensemble depuis son crate-root pour offrir une façade de consommation stable sans dupliquer les types Core/Interface ni transférer leur ownership. + +## Recognition + +`ProgramInstructionRecognition` est `#[non_exhaustive]` et possède trois états : + +```text +NoMatch l'implémentation ne revendique pas l'instruction +ProgramMatch le Program ou la famille correspond, sans reconnaissance exacte +ExactMatch l'implémentation affirme un match instruction-local exact +``` + +Cette reconnaissance ne contient aucun score, priorité, proof, confidence, discriminator textuel ou inventaire central de Programs. + +## Decode outcome + +`ProgramInstructionDecodeOutcome` est également `#[non_exhaustive]` : + +```text +Decoded(Decoded) valeur typée possédée par l'implémentation +Unsupported instruction connue mais non supportée par cette capability +``` + +Un futur `decode(...)` utilisera le `Result` Core : une erreur de validation/décodage restera donc `Err`, sans variante parallèle `Failed`. + +Le `Debug` de l'outcome n'impose pas `Decoded: Debug` et n'affiche jamais la valeur `Decoded`. Il produit uniquement le nom sûr de l'état (`Decoded` ou `Unsupported`). + +## Surface actuelle + +La façade `pre.003` expose : ```text Error @@ -49,16 +81,16 @@ Result Pubkey ProgramAccountMeta ProgramInstruction +ProgramInstructionRecognition +ProgramInstructionDecodeOutcome ``` Aucun module interne n'est public. -Les contrats suivants restent réservés aux tranches suivantes : +Le contrat suivant reste réservé à `pre.004` : ```text -ProgramInstructionRecognition pre.003 -ProgramInstructionDecodeOutcome pre.003 -ProgramInstructionDecoder pre.004 +ProgramInstructionDecoder ``` ## Frontières diff --git a/crates/ksp-program-api/USAGE.md b/crates/ksp-program-api/USAGE.md index 452d63d..f17192f 100644 --- a/crates/ksp-program-api/USAGE.md +++ b/crates/ksp-program-api/USAGE.md @@ -1,9 +1,9 @@ - + # Usage de ksp-program-api -Cette page décrit le scaffold public disponible à partir de `0.2.14-pre.002`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable. +Cette page décrit la surface publique disponible à partir de `0.2.14-pre.003`. Utiliser uniquement les exports du crate-root ; aucun module interne ne fait partie du contrat consommable. ## Construire un input Program avec la façade @@ -23,9 +23,61 @@ assert!(instruction.is_ok()); `Pubkey`, `ProgramAccountMeta` et `ProgramInstruction` conservent leur ownership Core/Interface. Program API fournit seulement une façade cohérente aux futures implémentations de capability Program. +## Représenter une reconnaissance + +```rust +let recognition = ksp_program_api::ProgramInstructionRecognition::ProgramMatch; + +match recognition { + ksp_program_api::ProgramInstructionRecognition::NoMatch => {} + ksp_program_api::ProgramInstructionRecognition::ProgramMatch => {} + ksp_program_api::ProgramInstructionRecognition::ExactMatch => {} + _ => {} +} +``` + +Le wildcard est volontaire : l'enum est `#[non_exhaustive]` afin de ne pas transformer la foundation en vocabulaire fermé pour toujours. + +## Représenter un outcome de décodage + +Le type décodé reste possédé par l'implémentation : + +```rust +struct ExternalDecodedInstruction { + opcode: u8, +} + +let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded( + ExternalDecodedInstruction { opcode: 7_u8 }, +); + +match outcome { + ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(value) => { + assert_eq!(value.opcode, 7_u8); + } + ksp_program_api::ProgramInstructionDecodeOutcome::Unsupported => {} + _ => {} +} +``` + +Aucun `Any`, JSON ou enum centrale n'est nécessaire pour transporter ce type. + +## Debug sûr + +`ProgramInstructionDecodeOutcome` possède un `Debug` volontairement opaque sur la valeur décodée : + +```rust +struct SecretDecoded; + +let outcome = ksp_program_api::ProgramInstructionDecodeOutcome::Decoded(SecretDecoded); +assert_eq!(std::format!("{outcome:?}"), "Decoded"); +``` + +`SecretDecoded` n'a même pas besoin d'implémenter `Debug`. Cela empêche un diagnostic générique de rendre accidentellement un payload externe. + ## Utiliser le contrat d'erreur commun -Les types d'erreur Core sont également disponibles depuis la façade : +Les types d'erreur Core restent disponibles depuis la façade : ```rust fn forward_result( @@ -35,21 +87,20 @@ fn forward_result( } ``` -Aucun type d'erreur Program spécifique n'est nécessaire au scaffold. +Le futur `decode(...)` utilisera ce `Result`. Une erreur sera donc `Err(...)`, tandis que `Unsupported` signifie une instruction connue volontairement non prise en charge. -## Ce que `pre.002` ne fournit pas +## Ce que `pre.003` ne fournit pas Il n'existe encore aucun : ```text -recognize(...) -decode(...) -ProgramInstructionRecognition -ProgramInstructionDecodeOutcome ProgramInstructionDecoder +program_ids(...) +recognize(...) sur un trait +decode(...) sur un trait registry de decoders payload générique JSON/Any execution preparer ``` -Ces éléments ne doivent pas être simulés côté consumer. Les contrats de recognition/outcome puis le trait decoder seront introduits dans leurs tranches dédiées. +Ces éléments ne doivent pas être simulés côté consumer. Le trait decoder et la preuve d'implémentation externe sont réservés à `pre.004`. diff --git a/crates/ksp-program-api/src/lib.rs b/crates/ksp-program-api/src/lib.rs index 0b300a3..97000ab 100644 --- a/crates/ksp-program-api/src/lib.rs +++ b/crates/ksp-program-api/src/lib.rs @@ -1,5 +1,5 @@ // file: crates/ksp-program-api/src/lib.rs -// version: 1 +// version: 2 #![warn(missing_docs)] #![deny(unreachable_pub)] @@ -7,11 +7,17 @@ //! Open Program contracts shared by KSP and external Program implementations. //! -//! This initial scaffold exposes only the Core and Interface types selected by -//! the `0.2.14` API model. Decoder behavior, recognition, decode outcomes, -//! registries, codecs, runtime logging and execution preparation are added only -//! by later contracts when their ownership is justified. +//! The foundation exposes Core/Interface types plus the minimal instruction +//! recognition and decode-outcome vocabulary. Decoder behavior, registries, +//! codecs, runtime logging and execution preparation are added only by later +//! contracts when their ownership is justified. +mod program_instruction_decode; + +/// 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; /// 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. diff --git a/crates/ksp-program-api/src/program_instruction_decode.rs b/crates/ksp-program-api/src/program_instruction_decode.rs new file mode 100644 index 0000000..3ffa32b --- /dev/null +++ b/crates/ksp-program-api/src/program_instruction_decode.rs @@ -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 { + /// The instruction was decoded into the implementation-owned output type. + Decoded(Decoded), + /// The instruction is known but unsupported by this decode capability. + Unsupported, +} + +impl std::fmt::Debug for ProgramInstructionDecodeOutcome { + 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; diff --git a/crates/ksp-program-api/tests/dependency_boundary.rs b/crates/ksp-program-api/tests/dependency_boundary.rs index 8fbbf78..db45419 100644 --- a/crates/ksp-program-api/tests/dependency_boundary.rs +++ b/crates/ksp-program-api/tests/dependency_boundary.rs @@ -1,7 +1,7 @@ // file: crates/ksp-program-api/tests/dependency_boundary.rs -// version: 1 +// version: 2 -//! Dependency and declarative-surface canaries for the Program API scaffold. +//! Dependency and declarative-surface canaries for the Program API foundation. #[test] fn pre_002_manifest_has_exact_core_and_interface_runtime_dependencies() { @@ -46,23 +46,27 @@ fn pre_002_manifest_has_exact_core_and_interface_runtime_dependencies() { } #[test] -fn pre_002_crate_root_is_facade_only_without_decoder_runtime_surface() { +fn pre_003_crate_root_adds_only_recognition_and_decode_outcome() { let crate_root = include_str!("../src/lib.rs"); - for required in ["Error", "ErrorCode", "ErrorContext", "Pubkey", "Result", "ProgramAccountMeta", "ProgramInstruction"] { + for required in [ + "ProgramInstructionDecodeOutcome", + "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 ", - "ProgramInstructionRecognition", - "ProgramInstructionDecodeOutcome", - "ProgramInstructionDecoder", - "ProgramExecutionPreparer", - "TRACING_TARGET", - "ksp_logging_lib", - "serde", - "Any", - ] { - assert!(!crate_root.contains(forbidden), "forbidden pre.002 Program API surface detected: {forbidden}"); + for forbidden in ["pub mod ", "ProgramInstructionDecoder", "ProgramExecutionPreparer", "TRACING_TARGET", "ksp_logging_lib", "serde", "Any"] { + assert!(!crate_root.contains(forbidden), "forbidden pre.003 Program API surface detected: {forbidden}"); + } + 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; diff --git a/crates/ksp-program-api/tests/public_api.rs b/crates/ksp-program-api/tests/public_api.rs index d7f1055..5466a34 100644 --- a/crates/ksp-program-api/tests/public_api.rs +++ b/crates/ksp-program-api/tests/public_api.rs @@ -1,7 +1,7 @@ // file: crates/ksp-program-api/tests/public_api.rs -// version: 1 +// version: 2 -//! Integration canaries for the public `ksp-program-api` scaffold. +//! Integration canaries for the public `ksp-program-api` foundation. fn consume_result(value: ksp_program_api::Result) -> ksp_program_api::Result { return value; @@ -31,3 +31,19 @@ fn public_pre_002_scaffold_does_not_require_private_modules() { 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::::Unsupported; + assert_eq!(std::format!("{unsupported:?}"), "Unsupported"); + return; +} diff --git a/crates/ksp-program-api/unit_tests/program_instruction_decode.rs b/crates/ksp-program-api/unit_tests/program_instruction_decode.rs new file mode 100644 index 0000000..3eaa235 --- /dev/null +++ b/crates/ksp-program-api/unit_tests/program_instruction_decode.rs @@ -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::::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::::Unsupported), "Unsupported"); + return; +} diff --git a/deltas/0.2.14/pre.003.md b/deltas/0.2.14/pre.003.md new file mode 100644 index 0000000..ba49d9a --- /dev/null +++ b/deltas/0.2.14/pre.003.md @@ -0,0 +1,285 @@ + + + +# 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 +``` + +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` 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` 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> +external implementation canary avec Pubkey non enregistré +``` + +Registry runtime, payload canonique D3 et `ProgramExecutionPreparer` resteront hors scope. diff --git a/docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md b/docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md index 374a02a..f13de3a 100644 --- a/docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md +++ b/docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md @@ -1,5 +1,5 @@ - + # Plan `0.2.14` — Program API foundation @@ -541,7 +541,7 @@ Baseline, règles/architecture, héritage, ownership, API candidate, dependency ### `pre.002` — Scaffold `ksp-program-api` + façade + firewall -**Statut : matérialisé ; gate opérateur à confirmer.** +**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. @@ -549,7 +549,9 @@ Aucun trait decoder, recognition, outcome, registry, codec, runtime logging ou e ### `pre.003` — Recognition + outcome minimal -Introduire `ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome` avec invariants et Debug sûr. Aucun descriptor/registry. +**Statut : matérialisé ; gate opérateur à confirmer.** + +`ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome` 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 @@ -599,6 +601,27 @@ dependency firewall canary présent `pre.003` reste limité à `ProgramInstructionRecognition` et `ProgramInstructionDecodeOutcome` 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 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 passage à `pre.004` reste conditionné au gate opérateur de cet overlay. + ## 14. Hors périmètre confirmé ```text diff --git a/docs/validation/017-V0_2_14_PROGRAM_API.md b/docs/validation/017-V0_2_14_PROGRAM_API.md index 00be8c7..d86ff5e 100644 --- a/docs/validation/017-V0_2_14_PROGRAM_API.md +++ b/docs/validation/017-V0_2_14_PROGRAM_API.md @@ -1,5 +1,5 @@ - + # Validation `0.2.14` — Program API foundation @@ -37,8 +37,8 @@ Le scope validé par `pre.001` est une foundation instruction-only avec output a | Contrat | Décision `pre.001` | Gate futur | |--------------------------------------------|---------------------------------------------------------|--------------------------------| -| `ProgramInstructionRecognition` | `NoMatch / ProgramMatch / ExactMatch`, non exhaustif | `pre.003` | -| `ProgramInstructionDecodeOutcome` | `Decoded(Decoded) / Unsupported`, non exhaustif | `pre.003` | +| `ProgramInstructionRecognition` | `NoMatch / ProgramMatch / ExactMatch`, non exhaustif | PASS `pre.003` | +| `ProgramInstructionDecodeOutcome` | `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` | `pre.004` | | input | `&ProgramInstruction` | `pre.004` | @@ -105,8 +105,8 @@ tracing | unknown Program Pubkey | utilisable sans registry Core | PENDING | | max Interface input | decoder consomme l'input déjà borné sans nouvelle allocation obligatoire | PENDING | | malformed program payload | `Err` ou `Unsupported` selon contrat, sans payload dans l'erreur | PENDING | -| Debug recognition | aucun payload | PENDING | -| Debug outcome | contenu `Decoded` non rendu automatiquement | PENDING | +| Debug recognition | aucun payload | PASS | +| Debug outcome | contenu `Decoded` non rendu automatiquement | PASS | | default methods | aucun default method susceptible de masquer panic/policy | PENDING | | closed-world enum | aucun inventaire central de Program kinds | PENDING | | serde accidental | aucune dependency/derive | PENDING | @@ -157,25 +157,37 @@ prompt de démarrage 0.3.1 delta de la prerelease ``` -## 8. État préparé `pre.002` +## 8. Gate opérateur `pre.002` -Le scaffold matérialisé est : +Le gate fourni le 28 août 2026 est intégralement vert : ```text -workspace member PASS structurel -normal dependencies ksp-core-lib + ksp-interface-lib uniquement -crate-root facade Error/ErrorCode/ErrorContext/Result/Pubkey + Interface instruction types -public modules aucun -README / USAGE présents -public API canary présent -dependency firewall canary présent -ProgramInstructionRecognition absent par contrat pre.002 -ProgramInstructionDecodeOutcome absent par contrat pre.002 -ProgramInstructionDecoder absent par contrat pre.002 -registry / canonical payload / preparer absents -serde / codecs / runtime logging absents +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é ``` -Le gate opérateur `pre.001` fourni le 28 août 2026 est vert pour `cargo fmt --all`, audits Rust/Markdown, `cargo check --workspace` et Clippy workspace. +Ce gate autorise l'ouverture de `pre.003`. -Le passage à `pre.003` reste conditionné au gate opérateur de cet overlay. Les preuves recognition/outcome restent `PENDING` jusqu'à leur tranche dédiée. +## 9. État préparé `pre.003` + +| Critère | Statut | Preuve | +|--------------------------------------|--------|----------------------------------------------------------------------| +| `ProgramInstructionRecognition` | PASS | enum non exhaustif `NoMatch / ProgramMatch / ExactMatch` | +| `ProgramInstructionDecodeOutcome` | 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 | + +Les canaris unitaires et publics de `pre.003` doivent passer avant d'ouvrir `pre.004`. La preuve d'implémentation externe, le Program Pubkey open-world et l'associated output complet restent réservés au trait decoder de la tranche suivante.