# 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), 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>; } ``` 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>` 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` 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` 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 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> 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.