26 KiB
Règles spécifiques à khadhroony-bot3
Ce fichier contient uniquement les règles d’architecture, de nomenclature et d’exploitation propres à khadhroony-bot3. Il est cumulatif avec RULES_GENERAL.md et RULES_RUST.md.
Toute divergence avec une règle générale doit être explicitement documentée et ne peut jamais affaiblir une interdiction de sécurité ou de qualité.
Règles de nommage
- Tous les noms de fichiers et de répertoires doivent être écrits en anglais.
- Les noms de fichiers et de répertoires ne doivent contenir aucun accent, espace ou caractère spécial inutile.
- Les noms internes doivent utiliser le format
snake_caselorsque c'est applicable. - Les packages Rust utilisent le préfixe
kb-; leur identifiant Rust correspondant utilise automatiquementkb_. - Les décodeurs, matérialisateurs et exécuteurs sont des modules de
kb-lib, pas des crates séparées. - Le crate de journalisation s'appelle
kb-logging. - Les réexports sont regroupés par visibilité : le bloc
pub useprécède le bloc séparépub(crate) use, sans ligne vide interne à un bloc ; leur ordre naturel doit rester compatible aveccargo fmt. - Les familles de symboles consolidées dans
kb-libutilisent les préfixesDC_/Dc/decoder_pour les décodeurs,MT_/Mt/materializer_pour les matérialisateurs,EX_/Ex/executor_pour les exécuteurs etMD_/Md/model_pour les modèles. - Les méthodes inhérentes et helpers strictement privés peuvent conserver un nom local court ; les préfixes s’appliquent aux constantes, types, traits et fonctions libres exposés à la crate ou hors de la crate.
- Les constantes temporaires
*_LEGACY_CRATE,*_MIGRATION_STATUSet*_MIGRATION_BOUNDARIESdoivent disparaître d’une famille dès que ses squelettes typés sont restaurés ; elles ne constituent jamais une API durable.
Règles Tauri et TypeScript
- Toute structure ou énumération Rust exposée au frontend TypeScript doit importer le trait
TSavecuse ts_rs::TS;puis dériverTS. - Les types Rust exportés vers TypeScript doivent utiliser des noms stables et explicites.
- Les bindings générés doivent être produits dans un dossier dédié, généralement
../frontend/ts/bindingsou#[ts(export, export_to = "../frontend/ts/bindings/MyStruct.ts")]. - Les types purement internes au backend ne doivent pas être exportés vers TypeScript par défaut.
- Corriger le type Rust/TS-rs source puis régénérer les bindings ; ne pas considérer une modification manuelle isolée d’un fichier généré comme un correctif durable.
kb-app-demo-desktop/src/tauri.rscontient les attributs#[tauri::command], l’enregistrement des commandes et des wrappers privés minces ; la logique complète doit vivre dans le module fonctionnel correspondant sous une fonctionpub(crate)testable.- Un wrapper Tauri ne doit effectuer que l’adaptation des handles/states/arguments, l’appel de la fonction de module et le retour du résultat ; toute validation métier, orchestration ou construction de payload doit rester hors de
tauri.rs. - Les helpers privés de
tauri.rssont autorisés lorsqu’ils mutualisent exclusivement une adaptation Tauri, par exemple l’ouverture, l’affichage, le focus ou l’émission vers une fenêtre ; ils ne doivent contenir aucune logique métier, requête SQL ou orchestration de pipeline.
Règles d'architecture
- Les décodeurs ne dépendent pas de PostgreSQL, SQLite, RPC, Tauri, wallet, stratégie ou matérialisateurs.
- Les matérialisateurs ne dépendent pas du RPC, du wallet, de Tauri ou des décodeurs spécifiques.
- Pour chaque programme Solana, quelle que soit sa famille, un décodeur doit couvrir maximalement tout wire officiellement identifiable de sa surface, qu'il soit historique, courant, récent, expérimental ou publié avant son déploiement généralisé. Ces statuts doivent rester explicites et ne constituent pas un motif pour supprimer le décodage.
- Une observation lisible issue d'une transaction échouée peut conserver une intention non commitée ; elle ne doit jamais être présentée comme une mutation réussie.
- Pour chaque programme Solana, les matérialisateurs doivent projeter maximalement tous les faits métier stables et prouvés par le décodage, y compris les états historiques, obsolètes, dépréciés ou seulement rencontrables pendant un backfill. Le statut historique interdit l'exécution, mais ne constitue jamais à lui seul un motif de non-matérialisation.
- Toute projection historique doit conserver explicitement son lifecycle, sa version de layout, sa provenance, son slot ou ordre d'observation lorsqu'ils sont connus, et ne doit jamais écraser silencieusement un état actif plus récent.
- Une même réalité métier doit avoir une seule projection canonique. Les snapshots de comptes sont la source autoritative de l'état final lorsqu'ils sont disponibles ; les instructions et événements corrélés restent des observations de mutation et ne doivent pas produire un doublon concurrent du même état.
- Les matérialisateurs doivent refuser les transactions non commitées pour les mutations d'état, tout en pouvant conserver séparément une intention non commitée lorsque le modèle métier le prévoit explicitement.
- Toute absence volontaire de projection doit être documentée avec une justification technique précise. Un matérialisateur ne doit inventer ni état final, ni montant, ni autorité, ni frais, ni agrégation que l'observation ne prouve pas.
- Pour chaque programme Solana, les exécuteurs doivent couvrir maximalement les opérations officiellement appelables et les opérations expérimentales publiées lorsque leurs contrats exacts et garde-fous sont prouvés. Les opérations historiques, dépréciées ou obsolètes doivent rester décodables et matérialisables, mais ne doivent jamais être exposées à l'exécution ; cette exclusion doit être explicite dans la matrice et le README.
kb-storepossède les contrats de persistance neutres et les adaptateurs de base de données.- PostgreSQL est l'adaptateur de production de
kb-store. - Un futur adaptateur SQLite doit rester interne à
kb-storeet limité aux tests, imports et corpus locaux. kb-walletreste isolé du reste du système.- Les transactions raw sont immuables et restent la source d'audit.
- Les replays doivent être ciblés par module, version, programme, surface, discriminator, slot ou signatures.
- La documentation active du projet ne doit pas présenter l'ancien workspace comme architecture courante. Les documents de migration et copies de référence peuvent le nommer explicitement.
Nomenclature métier
protocol_codedésigne la famille :pump,raydium,meteora,orca,jupiter, etc.surface_codedésigne la surface concrète :pump_swap,raydium_amm_v4,meteora_dlmm, etc.event_codesuit le format<surface_code>.<event_name>.- Les familles d'événements principales sont :
trade,liquidity,lifecycle,fee,admin,reward,orderbook,token_account,pool_state,routing,risk,audit,unknown.
Base de données
- Les schémas PostgreSQL cibles sont :
raw,core,obs,decode,mat,catalog,agg,ops,wallet. - Les colonnes JSONB doivent se terminer par
_jsonb. - Les montants bruts on-chain doivent se terminer par
_raw. - La transaction canonique raw reste la source rejouable et ne doit pas être supprimée après traitement sans politique de rétention explicite.
Nommage canonique des surfaces
Les nouvelles surfaces de programmes doivent utiliser un nom canonique basé sur la fonction réelle du programme :
<function_code>_<family_code>_<identifier_code>[_vN]
Les modules internes de décodage doivent utiliser la hiérarchie de fichiers :
kb-lib/src/decoder/<function_code>/<family_code>_<identifier_code>[_vN].rs
Exemples :
kb-lib/src/decoder/amm/raydium_cpmm.rs;kb-lib/src/decoder/clmm/raydium.rs;kb-lib/src/decoder/dlmm/meteora.rs;kb-lib/src/decoder/router/jupiter_aggregator_v6.rs;kb-lib/src/decoder/orderbook/openbook_v2.rs;kb-lib/src/decoder/metadata/metaplex_token_metadata.rs;kb-lib/src/decoder/nft/metaplex_bubblegum.rs.
Ces modules restent privés. Les consommateurs externes utilisent exclusivement les types et fonctions réexportés directement par kb_lib.
Les noms historiques ou issus d'IDL doivent être conservés dans le registre, mais ne doivent pas créer de nouveau module si un module canonique existe déjà.
Aucun renommage massif de modules n'est autorisé sans étape de contrôle dédiée et sans validation Cargo.
Règles de nommage des surfaces Solana
- Le nom canonique d'une surface doit commencer par une fonction réelle :
amm,clmm,dlmm,router,orderbook,launchpad,lending,vault,staking,bridge,perpetuals,oracle,nft,metadata,admin, etc. - Le préfixe
program_est interdit pour les nouveaux noms canoniques. - Les surfaces non classifiées doivent utiliser
unknown_*et ne doivent pas avoir de crate cible tant que leur fonction n'est pas validée. - Les programmes Solana/SPL primitifs doivent rester séparés des surfaces DEX/router dans la documentation de contrôle.
dammne doit pas être utilisé comme préfixe fonctionnel ; utiliseramm_meteora_damm_v1ouamm_meteora_damm_v2.
Registre des identifiants core
- Les identifiants Solana/SPL primitifs doivent être tenus à jour dans
registry/core_program_id_seed.toml. - Les sysvars et comptes natifs connus ne doivent pas être classés comme surfaces DEX/router.
spl_token,spl_token2022etassociated_token_accountrestent des surfaces spécialisées ; les noms historiques de crates externes conservent leur graphie officielle.stake_pooldoit être réservé à un futur crate spécialisé plutôt que mélangé avec le programmestake.
Index court de programme
- Les noms de modules ne doivent pas commencer par un index hexadécimal.
- Un champ
registry_codeoptionnel peut être ajouté au registre pour l'UI, PostgreSQL ou les matrices. - Le nom canonique reste la source principale : fonction + famille + identifiant + version.
Comptes non exécutables
- Une adresse de compte, de pool, de PDA ou de vault ne doit pas générer un module de décodeur.
- Le vrai
program_idpropriétaire doit être prouvé avant création d'une surface canonique.
Constantes Rust
- Les fichiers
program_ids.rssont interdits dans les nouveaux crates. Utiliserconstants.rs. - Les
program_idpublics doivent être réexportés depuislib.rs. - Dans une crate, les modules internes doivent appeler les constantes réexportées via
crate::CONSTANT_NAME. - Les discriminants, sélecteurs, longueurs Borsh et constantes internes futures doivent être placés dans
constants.rset resterpub(crate)sauf besoin d'API publique explicite.
Règles de tracing
- Une crate ou un composant de
kb-libest opérationnel lorsqu’il effectue des I/O, orchestre un pipeline, décode, matérialise, exécute, applique une politique runtime ou prend une décision mutable observable. - Toute crate opérationnelle ajoutée ou modifiée doit dépendre de
tracingdepuis le workspace et déclarer exactement unpub(crate) const TRACING_TARGETdanssrc/constants.rs. - Hors
kb-lib, la valeur canonique deTRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATAest le nom exact du package Cargo. - Dans
kb-lib, chaque composant opérationnel possède son propreconstants.rset un target hiérarchique stable fondé sur son identifiant de décodeur, matérialiseur ou exécuteur ; un target uniquekb-libne doit pas effacer l'identité du composant. - Les targets historiques
khbot.*et les targets de fenêtre sont interdits dans les nouvelles modifications. - Les macros
tracingdoivent utilisertarget: crate::TRACING_TARGETet des champs structurés stables. La granularité interne passe paraction,stage,window,campaign_id,signature,instruction_path,program_id,processor_name,processor_version,statuseterror_code. - Les crates passives de types, contrats, DTO, API sans exécution, registres ou constantes restent sans dépendance
tracing.kb-configreste une exception de bootstrap tant que sa validation précède l’installation du subscriber. - Il est interdit d’ajouter
tracingsans événement réel ou de conserver un faux target uniquement consommé parlet _target. - Une décision interne doit être journalisée par la crate responsable ;
kb-app-demo-desktopne journalise que les frontières Tauri/UI, les actions utilisateur et les résumés d’orchestration. - Tout input sélectionné sans décodeur compatible, tout résultat de décodage
failedouunsupported, tout résultat de matérialisationfailed, toute validation de résultat invalide et toute erreur de persistance doivent émettre un événementerroravant le retour ou la persistance terminale. - Une transaction Solana échouée mais correctement décodée n’est pas une erreur du logiciel. Une décision
ignored, un refus de matérialisation conforme à la politique ou une annulation coopérative ne doivent pas être promus artificiellement au niveauerror. - Les erreurs de décodage et de matérialisation doivent conserver au minimum, lorsque disponibles :
campaign_id,signature,slot,instruction_path,program_id, processor ou materializer avec version,input_key,input_hashou hash du payload, statut, code et diagnostic borné. - Les payloads complets, DSN non masqués, secrets, clés privées et données non bornées sont interdits dans les logs.
- Chaque profil doit router les événements vers les sorties globales
debug.log,info.log,error.jsonletapp.log, puis versdebug.log,info.logeterror.jsonldans un répertoire propre à chaque crate utilisanttracing. - L’ajout ou la suppression de
tracing.workspace = truedans une crate impose la mise à jour simultanée de la matrice de routes, de ses tests et dedocs/TRACING_CONTRACT.md. - Le contrat détaillé est défini dans
docs/TRACING_CONTRACT.md. - L’audit mécanique spécifique au projet est exécuté par
python3 scripts/audit_khadhroony_workspace_rules.py. Il couvre notammentTRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATAet l’usage obligatoire desolana_pubkey::Pubkeyà la place desolana_address::Address.
Règles de réutilisation des interfaces Solana et SPL
-
Les dépendances déclarées dans
[workspace.dependencies]forment un catalogue de versions et de features autorisées ; elles ne doivent être ajoutées à une crate consommatrice que lorsqu’un type, un encodeur, un décodeur ou un identifiant officiel est réellement utilisé. -
Dans un
Cargo.toml, placer dans[dependencies]toute crate référencée par le code de bibliothèque compilé en production. Réserver[dev-dependencies]aux références contenues exclusivement dans#[cfg(test)], les tests d’intégration, benches ou exemples. Une dépendance de test vers un décodeur ou matérialiseur concret est légitime lorsqu’elle sert uniquement à éprouver une orchestration générique fondée sur les traits API ; elle ne prouve pas qu’une capacité de production manque. Toute promotion dedev-dependenciesversdependenciesdoit être motivée par un appel runtime réel, et toute dépendance runtime inutilisée doit être supprimée. -
Les registres de composition runtime des applications doivent énumérer explicitement chaque décodeur et matérialiseur concret activé. Toute nouvelle surface instructionnelle dotée d’un
MtApiEventMaterializerdoit être ajoutée au registre applicatif et couverte par un test d’inventaire ordonné ; une crate présente dans le workspace ou danskb_pipelinen’est pas activée automatiquement. Les matérialiseurs exclusivement stateful qui n’implémentent pasMtApiEventMaterializerrestent routés par leurs APIs de snapshots dédiées. -
Les corrélations instruction/état doivent produire une issue explicite (
confirmed,contradictedounot_applicable) et ne doivent jamais transformer automatiquement une configuration observée en violation, score ou conclusion métier. -
Une interface officielle Solana ou SPL étroite doit être préférée à
solana-sdklorsque son contrat suffit. -
L’ordre de préférence des formats est : schéma officiel
wincode, schéma officiel Borsh, puis parseur local borné reproduisant exactement le runtime lorsque l’interface officielle n’expose quebincode. -
Aucun nouveau code ne doit dépendre directement de
bincode. Une interface officielle uniquement disponible derrière une featurebincodene justifie pas l’activation de cette feature ; le layout doit alors être prouvé depuis les sources officielles et implémenté localement avec des bornes et des tests. -
Les exécuteurs doivent utiliser les builders officiels disponibles, préserver l’ordre exact des metas, borner toute liste de comptes variable avant l’appel au builder et refuser les doublons lorsque leur répétition n’a pas de sémantique publiée.
-
Les features des interfaces doivent rester minimales et explicites. Une feature
serde,wincode,borsh,std,allocou équivalente n’est activée que si la crate consommatrice l’utilise réellement. -
Les crates applicatives ne doivent pas dépendre d’interfaces RPC ou transactionnelles uniquement pour relayer des types ; ces dépendances appartiennent à
kb_onchain_transport, aux modèles communs justifiés ou à la crate opérationnelle propriétaire. -
Toute exception et toute implémentation locale doivent être documentées dans
docs/SOLANA_INTERFACE_DEPENDENCIES.mdavec la raison, la source officielle et la stratégie de test. -
Tant que les types Solana consommés implémentent les traits de
wincode 0.5.x, le catalogue workspace conservewincode = "^0.5". LeCargo.locklocal du workspace doit résoudre exactementwincode 0.5.5avecsolana-wincode-varint 1.0.0afin d’éviter l’incompatibilité observée entre les familles transitiveswincode 0.5etwincode 0.6. Ce lockfile est un garde-fou local de résolution : il n’est ni versionné, ni inclus dans les archives. Une entrée inutilisée ne doit pas être ajoutée artificiellement aux dépendances d’une crate pour influencer le résolveur. L’audit spécifique du workspace refuse toute dérive de ce couple avant compilation lorsqu’unCargo.locklocal a été généré ou restauré.
Règles des exécuteurs
-
Les exécuteurs résident dans
kb_lib::executor. -
Une surface classifiée peut avoir un module décodeur et un module exécuteur distincts dans
kb-lib. -
Les exécuteurs ne doivent pas dépendre des décodeurs.
-
Les exécuteurs utilisent les contrats
ExApi*réexportés directement par la façadekb_lib. -
Un squelette d’exécuteur doit exposer un type
Ex*Executor, référencer uniquement des Program IDs dekb-program-ids, annoncerMaybepour sa surface et construire exclusivement un plan réservé à zéro instruction. -
La migration fonctionnelle d’un exécuteur doit remplacer ce comportement réservé par des capacités exactes
SupportedouUnsupported(reason); aucun statut temporaireLEGACY_CRATEouMIGRATION_STATUSne doit subsister. -
Les garde-fous communs doivent être placés dans les modules de sécurité partagés de
kb-lib. -
Aucun exécuteur ne doit envoyer de transaction sans simulation et validation explicite.
-
Les surfaces non classifiées ne doivent pas avoir de crate exécuteur.
-
Pour chaque programme Solana et contrairement aux décodeurs, les exécuteurs ne construisent pas les opérations obsolètes ou purement historiques. Ils couvrent uniquement les opérations courantes et expérimentales officiellement constructibles, avec un statut exact
SupportedouUnsupported(reason). -
Le statut expérimental, récent ou non encore déployé partout n'interdit pas un builder universel lorsqu'un wire officiel exact existe. Le déploiement, la simulation et l'autorisation d'envoi restent trois décisions séparées ; la bibliothèque ne doit pas imposer artificiellement un cluster.
-
Les champs JSON exposés à TypeScript ne doivent pas utiliser directement
serde_json::ValueavecTS-rs; utiliser une chaîne JSON sérialisée (std::string::String) ou un type Rust typé exportable. -
Les APIs qui gardent des payloads dynamiques doivent fournir des helpers explicites basés sur
serde_json::to_stringetserde_json::to_string_pretty.
Règles de configuration
- La configuration applicative commune doit passer par
kb-config. - Les fichiers JSON de configuration ne doivent pas contenir de commentaires.
- Les secrets ne doivent pas être écrits en clair dans le dépôt.
- Les valeurs sensibles doivent utiliser des variables d'environnement ou un stockage chiffré dédié.
- Les structures de configuration exposées à Tauri doivent dériver
TS.
Ordre de développement cible
kb-loggingdoit être stabilisé avant les logs avancés des autres crates.kb-configdoit être stabilisé avant les stores, RPC, wallet et applications.- Les contrats SQL et de matérialisation doivent être définis avant les gros décodeurs DEX.
- Les implémentations détaillées des matérialisateurs doivent suivre les sorties réelles des décodeurs correspondants.
kb-app-demo-desktopdoit fournir des validations live après chaque capacité majeure, sans créer une application Tauri séparée par crate.
Constantes des composants de kb-lib
- Chaque composant classifié avec un
program_iddoit avoir son propre fichierconstants.rs. constants.rscontient les discriminators, sélecteurs, opcodes, constantes Borsh et constantes de décodage quand elles sont connues.- Le module parent puis
kb-lib/src/lib.rsréexportent les constantes publiques nécessaires. - Les fichiers d'implémentation utilisent le chemin public le plus court réexporté par
kb-lib. - Les literals de
program_idne doivent pas rester dansprogram_ids(), sauf dans un fichierconstants.rs.
Identifiants de programmes
Les program_id connus doivent être définis une seule fois dans kb-program-ids. Les composants de décodeur, d’exécuteur, de store, d’application ou d’outil doivent référencer directement kb_program_ids::XXX_PROGRAM_ID. Les fichiers constants.rs locaux ne doivent pas redéfinir ces chaînes ; ils restent réservés aux constantes internes du module, par exemple discriminators, opcodes, seeds, index de comptes ou layouts.
Validation frontend Tauri
- Pour
kb-app-demo-desktop, ne jamais exécuternpm run build,npm --prefix kb-app-demo-desktop run buildni une commande équivalente de build frontend autonome. - L’installation manuelle d’une dépendance frontend est limitée aux commandes npm d’ajout nécessaires, notamment
npm i -D <package>pour une dépendance de développement ;node_modules/etpackage-lock.jsonrestent locaux, générés et non livrables. - La validation frontend de développement est réalisée uniquement par
cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json, qui démarre et pilote Vite selon la configuration Tauri.
Architecture khadhroony-bot3
- Les décodeurs, exécuteurs et matérialisateurs résident exclusivement dans
kb-lib. - Les modules peuvent posséder leur propre fichier de constantes.
- Toute API publique portée depuis une ancienne crate doit être réexportée au crate root de
kb-lib. kb-storeregroupe les contrats store-neutral et les adaptateurs de persistance, avec PostgreSQL comme adaptateur de production initial.kb-store/src/lib.rsreste une façade : les DTO, entités, traits, requêtes et implémentations résident dans des modules privés dédiés et toute API publique est réexportée au crate root.- Les modèles source-neutral partagés avec les décodeurs, notamment
MdCoreInstructionReplayInput, appartiennent àkb-lib;kb-storeles consomme et les réexporte sans les dupliquer. kb-libne dépend jamais dekb-store. Cette direction de dépendance évite tout cycle entre modèles, décodage et persistance.kb-storene dépend pas dekb-config. La frontière applicative transforme une configuration résolue en options de store explicitement validées.- Les adaptateurs concrets implémentent les mêmes traits neutres et ne font pas fuiter leurs types de connexion dans les contrats.
- Seul
kb-app-demo-desktopest conservé comme binaire pendant la migration initiale.
Nomenclature des identités et opérations persistées
- Les identités runtime,
processor_name,protocol_code,surface_code,operation_codeetevent_codesont des contrats persistés et utilisent des segments hiérarchiques séparés par.. - Chaque segment utilise
snake_case; un underscore ne remplace jamais un niveau hiérarchique. Exemples :solana.core.system.transfer,spl.memo.v4.add_memo,spl.token_2022.transfer_checked. - Les anciennes formes préfixées par
solana_core,solana_native,spl_memo,spl_token,spl_token_2022,spl_associated_token_accountoumetadata_metaplex_token_metadatasont interdites pour ces valeurs contractuelles. - Toute nouvelle surface ou opération doit respecter
docs/OPERATION_NAMING_CONVENTION.mdet être ajoutée àtest-fixtures/contract-matrices/OPERATION_NAMING_MATRIX.jsonavant son premier remplissage persistant. - Un renommage de ces valeurs après remplissage d’une base est une migration de données et exige une migration SQL ou une reconstruction explicite des tables dérivées.