# 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.