Files
khadhroony-solana-project/docs/plans/021-V0_2_14_PROGRAM_API_PLAN.md
2026-08-28 16:16:15 +02:00

38 KiB
Raw Blame History

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 :

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 :

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 :

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 :

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 :

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à :

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 :

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 :

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 :

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 :

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é :

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 :

#[non_exhaustive]
pub enum ProgramInstructionRecognition {
    NoMatch,
    ProgramMatch,
    ExactMatch,
}

Sémantique :

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 :

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 :

#[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 :

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 :

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 :

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 :

instruction decoder uniquement

ProgramAccountDecoder est reporté : aucun input account Program-facing stable n'existe encore dans Interface/CORE.

Input

Retenu :

&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 :

ksp-program-api
├── ksp-core-lib
│   └── solana-pubkey
└── ksp-interface-lib
    └── ksp-core-lib

Dépendances de production interdites pour cette release :

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 :

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 :

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 à :

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.004ProgramInstructionDecoder + 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 nest 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 :

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 :

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 :

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 :

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 :

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 :

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 :

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 :

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é

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 :

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 :

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.