Files
khadhroony-bot3/docs/DECODER_MATERIALIZATION_CONTRACTS.md
2026-07-24 14:23:58 +02:00

180 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- file: docs/DECODER_MATERIALIZATION_CONTRACTS.md -->
<!-- version: 17 -->
# Contrats communs de décodage et de matérialisation
## Objet
La version `0.4.0` introduit linfrastructure backend-agnostique utilisée par les futurs décodeurs Solana Core, SPL et protocolaires. Elle ne cherche pas encore à décoder maximalement un protocole précis.
Le flux commun est :
```text
core instruction contextualisée
-> dispatch déterministe
-> observation décodée versionnée
-> persistance atomique decode + couverture + ledger
-> matérialisation optionnelle explicitement autorisée
-> persistance atomique mat + ledger
```
## Input contextualisé
`MdCoreInstructionReplayInput` reste lunique contrat dentrée commun. Son contrat passe à la version `2` dans `0.4.1-pre.014`. Il contient la signature, le slot, le statut et lerreur on-chain, le chemin stable de linstruction, le program ID, les comptes résolus dans leur ordre original, le payload brut déterministe et son hash, toutes les instructions outer ordonnées par index numérique, les inner instructions descendantes, les logs reliés prudemment, les changements de balances et la version du contrat core.
`outer_instructions_json` est un tableau stable dont chaque entrée contient `instructionIndex`, `instructionPath`, `programId`, `payloadJson` et `payloadHash`. Linstruction cible est incluse. Cette projection provient des tables core existantes et ne nécessite aucune migration SQL.
Le hash de replay est calculé à partir de la sérialisation JSON canonique de cet input. Le skip exige la même étape, le même processor, la même version, la même clé dentrée, le même hash et un statut ledger réussi.
Le passage au contrat `2` modifie légitimement les hashes existants, car les payloads outer participent désormais à la sérialisation. Le pipeline reste en version `1` : la version du contrat core et le nouveau contexte suffisent à invalider les anciens skips. Un force replay est requis après mise à niveau.
## Contrat de décodeur
`DcApiInstructionDecoder` expose :
- une identité stable `name/version` ;
- les programmes et surfaces supportés ;
- une matrice de couverture déclarée ;
- une reconnaissance déterministe ;
- un résultat terminal `decoded`, `ignored`, `unsupported` ou `failed` ;
- zéro ou plusieurs observations typées uniquement pour `decoded` ;
- une preuve, une confiance et des diagnostics structurés.
Le dispatch est ordonné par compatibilité exacte, priorité déclarée, surface, code dentrée et identité stable. Il ne dépend ni du nom de la crate ni de lordre denregistrement implicite.
Avant la lecture du store, le pipeline calcule le périmètre effectif des programmes à partir de lunion des `program_id` déclarés par les décodeurs activés. Lorsque lopérateur fournit un filtre explicite, ce filtre doit être un sous-ensemble exact de ces programmes ; une valeur incompatible est refusée avant toute sélection SQL. Cette règle empêche un décodeur natif de consommer par défaut des instructions SPL ou protocolaires et évite de rejouer indéfiniment le même lot `unmatched` sans rapport avec les processors choisis.
Une instruction inconnue dun programme reconnu doit être classée sans produire de faux événement. Un `unmatched` reste possible lorsque le program ID est supporté mais que la reconnaissance contextuelle refuse linput ; il ne modifie pas globalement le lifecycle de linstruction pour ne pas empêcher un autre décodeur futur de la traiter.
## Transactions on-chain échouées
Une transaction échouée reste décodable lorsquun input structurel existe. Toute observation conserve :
```text
transaction_failed
transaction_error
observation_committed
```
`observation_committed` doit être faux lorsque la transaction a été annulée. Ces observations peuvent décrire une instruction tentée, un événement loggé avant lerreur, une classification déchec, une consommation de compute ou une surface appelée.
Elles ne peuvent pas produire automatiquement un trade réussi, une modification de liquidité réussie, un changement confirmé de catalogue ou une candle normale. `MtApiEventMaterializer` applique une politique explicite par famille. Les familles `trade`, `liquidity` et `lifecycle` sont refusées avant lappel au matérialiseur lorsque la source est échouée ou non commitée. Une seconde barrière valide ensuite les familles de sortie et nautorise, dans ce contexte, que les matérialisations daudit ou de risque.
## Persistance
Les tables actives sont :
- `kb_sol_decode_events` ;
- `kb_sol_decode_coverage_declarations` ;
- `kb_sol_decode_coverage_observations` ;
- `kb_sol_mat_events` ;
- `kb_sol_ops_processing_ledger`.
Aucun schéma PostgreSQL applicatif explicite nest créé. Les payloads et preuves JSONB utilisent des colonnes suffixées par `_jsonb`.
Le décodage persiste dans une transaction unique les observations, la couverture, létat lifecycle de linstruction et le ledger. La matérialisation persiste également ses sorties et son ledger dans une transaction unique. Un rollback à la dernière étape doit donc supprimer toutes les écritures précédentes de la même tentative.
Toute exécution non skippée remplace atomiquement les sorties du même processor, de la même version et de la même clé dentrée. Le force replay contourne uniquement le skip version/hash ; il ne supprime jamais les sorties dun autre processor, dune autre version ou dune autre clé. Les versions antérieures restent disponibles pour laudit.
Lorsquun force replay contient une liste explicite de signatures, le pipeline retire le filtre de lifecycle pour cette sélection bornée. Le même contournement est autorisé sans signatures uniquement lorsque lopérateur active explicitement le mode « toutes les signatures » ; la sélection reste alors limitée par les programmes compatibles, les instruction paths, les slots éventuels et la limite. Sans signatures ni cette autorisation explicite, la requête est refusée.
Les déclarations de couverture sont synchronisées comme un snapshot du couple processor/version. Le résultat de persistance distingue les lignes réellement insérées, modifiées, supprimées du snapshot ou strictement inchangées ; une déclaration identique est comptée comme `skipped`, pas comme une nouvelle insertion.
## Couverture
La couverture compare les entrées déclarées et observées, puis agrège :
- reconnaissance ;
- décodage ;
- matérialisation ;
- erreurs ;
- inconnues ;
- transactions réussies ;
- transactions échouées.
Une surface ne peut pas être considérée comme clôturée tant que toutes les instructions, événements et discriminants connus, y compris historiques et non liés au trading, ne sont pas classifiés.
## Traçabilité structurée
Chaque campagne reçoit un `campaign_id` process-local stable, propagé de la démo jusquaux décisions de dispatch, de ledger, de décodage, de matérialisation et de persistance. Des spans imbriqués de campagne, input et processor transmettent aussi ce contexte aux événements émis par les décodeurs et les stores sans modifier leurs contrats. Elle doit permettre de reconstruire précisément les décisions prises sans requête SQL libre. Les événements `debug` utilisent un champ `action` stable et conservent au minimum, selon létape :
- le nombre de signatures, un échantillon borné et la sélection normalisée ;
- les filtres demandés puis les `program_id` et états effectivement appliqués ;
- la signature, le slot, linstruction path, le program ID et la clé dinput ;
- le processor et sa version ;
- le hash déterministe pertinent ;
- la décision de dispatch, y compris lorsque `recognize` nest pas appelé à cause dun program ID incompatible ;
- le résultat de reconnaissance et de décodage ;
- le contrôle du ledger, le motif exact du skip ou son contournement par force replay ;
- le début et la validation de la persistance PostgreSQL ;
- le statut terminal et les compteurs par processor.
Les targets stables sont :
```text
kb_app_demo.demo_decode_replay
kb_app_demo.frontend.demo_decode_replay
kb_pipeline.decode_replay
kb_store_pg.decode_pipeline
kb_decoder_solana_core
```
Les signatures, slots, paths et program IDs sont des identifiants publics on-chain. Les listes complètes de signatures ne sont pas répétées à chaque couche : les événements de campagne conservent un compteur et un petit échantillon, tandis que les événements par input conservent la signature exacte. Les traces ne doivent pas enregistrer de DSN, secret, clé privée ni payload brut complet. Le payload dinstruction est représenté par son hash déterministe.
## Orchestration
`kb_pipeline::execute_decode_replay` fournit :
- sélection bornée par signatures, états, slots, program IDs et instruction paths ;
- zéro, un ou plusieurs décodeurs compatibles selon la politique choisie ;
- concurrence bornée ;
- arrêt coopératif ;
- skip version/hash ;
- force replay ;
- résumé par processor et statut ;
- matérialisation optionnelle après succès de la persistance decode.
La fenêtre Tauri `demo_decode_replay` ne contient aucune logique SQL libre. Elle construit une requête typée, appelle le pipeline et affiche les diagnostics read-only.
## Projections natives actives
`kb_materializer_lifecycle::LifecycleMaterializer` est enregistré dans `demo_decode_replay` à partir de `0.4.1-pre.003`. Son applicabilité est filtrée par surface, entrée et paramètres avant toute consultation du ledger ou application de politique. `pre.017` étend ses familles acceptées à `Lifecycle`, `Admin` et `Audit`, mais uniquement pour des observations exactes qui produisent réellement une mutation lifecycle. `pre.018` ajoute linitialisation/la fermeture des rapports Slashing sous `slashing_violation_report`, sans transformer le rapport en pénalité de stake. Il applique toujours `SuccessfulCommittedOnly`.
Les sorties stables actives sont :
- `address_lookup_table:<operation>:0` pour les cinq mutations ALT ;
- `program_loader:<surface>:<operation>:0` pour les mutations loader stables ;
- `feature_gate:revoke_pending_activation:0` pour la révocation Feature Gate ;
- `durable_nonce_account:<operation>:0` pour initialize, advance, authorize, upgrade et withdraw du System Program ;
- `zk_proof_context:<operation>:0` pour linitialisation dun contexte ZK ElGamal demandée par une vérification réussie et pour sa fermeture.
`authorize_nonce_account` reste décodé en famille `Admin`, mais sa mutation dautorité durable est promue en sortie `Lifecycle`. Les vérifications ZK ElGamal restent des événements `Audit`; elles ne sont acceptées par le matérialiseur que lorsque `contextStateRequested = true`. Une preuve sans contexte nest jamais proposée au matérialiseur.
Le retrait dun nonce account conserve une sémantique conditionnelle. Le runtime détruit le compte lorsque la totalité du solde est retirée ; linstruction seule ne suffit pas à reconstruire de manière certaine létat final transactionnel du compte. La projection décrit donc lopération commitée, conserve le montant demandé et indique explicitement que létat final nest pas capturé. Les deltas SOL ne sont pas dupliqués.
La création dun contexte ZK conserve le compte cible, son autorité et le type de preuve, sans matérialiser les octets de preuve. La fermeture conserve le compte, la destination des lamports et lautorité, puis décrit le reset vers le System Program. Lancien ZK Token Proof Program nest jamais matérialisé : son runtime actuel est un stub sans effet et sa sémantique historique nest pas attribuable à une transaction sans preuve de version.
Le hash dentrée matérialiseur reste dérivé de lobservation décodée complète. Le ledger conserve séparément les processors `solana_native_lifecycle`, `solana_native_admin` et `solana_native_compliance_audit`, leur version, la clé dinput et le hash. Une transaction échouée ou une observation non commitée est refusée avant toute sortie mutable.
`pre.020` répartit les responsabilités : create/allocate System restent dans lifecycle ; assignations System, Config `store` et changements dautorité Loader appartiennent à `kb_materializer_admin` ; writes/copies de bytecode Loader appartiennent à `kb_materializer_compliance_audit`. Les transferts SOL ne sont pas rematérialisés, car les balance changes core en sont la source canonique.
## Projections natives restantes
La couverture maximale dun décodeur nimplique pas une matérialisation systématique. Une projection nest ajoutée que lorsquelle possède une identité stable, un état cible explicite, une politique didempotence et suffisamment de contexte pour ne pas reconstruire une mutation fictive.
Les prochaines projections sont réparties par propriétaire :
- `kb_materializer_lifecycle` : créations et allocations System, sans dupliquer les deltas SOL ;
- `kb_materializer_admin` : assignations System, écritures Config opaques commitées et changements dautorité Loader ;
- `kb_materializer_compliance_audit` : écritures et copies de bytecode Loader, avec hash et préfixe borné sans payload complet ;
- `kb_materializer_staking` : intentions/transitions Stake et Vote commitées. `pre.021` active des projections instructionnelles pour comptes Stake/Vote, autorités, lockup, vote state, retraits et rewards ; un snapshot final exige toujours létat antérieur/suivant du compte, les crédits cumulés et les sysvars ;
- un matérialiseur transactionnel Compute Budget : profil fusionnant toutes les instructions Compute Budget du message.
Les surfaces suivantes restent volontairement en decode/audit :
- précompiles de signature, qui décrivent une vérification runtime sans état métier durable ;
- preuves ZK sans compte de contexte, qui nont pas de mutation persistante à projeter ;
- ancien ZK Token Proof Program, dont le runtime Agave `v4.1.1` est un stub sans effet.
Chaque ajout futur doit indiquer le matérialiseur propriétaire, la source détat et la politique de transaction, au lieu détendre automatiquement `solana_native_lifecycle`.