Files
khadhroony-bot3/docs/rules/RULES_SPECIFIC_KHADHROONY.md
2026-08-10 11:21:07 +02:00

40 KiB
Raw Permalink Blame History

Règles spécifiques à khadhroony-bot3

Ce fichier contient uniquement les règles darchitecture, de nomenclature et dexploitation 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_case lorsque c'est applicable.
  • Les bibliothèques généralistes Khadhroony Solana utilisent le préfixe Cargo ks- et lidentifiant Rust ks_; les applications et futures crates réellement propres au domaine Bot utilisent kb- / kb_.
  • Les décodeurs, matérialisateurs et exécuteurs sont des modules de ks-lib, pas des crates séparées.
  • Le crate de journalisation s'appelle ks-logging.
  • Les réexports sont regroupés par visibilité : le bloc pub use précède le bloc séparé pub(crate) use, sans ligne vide interne à un bloc ; leur ordre naturel doit rester compatible avec cargo fmt.
  • Les familles de symboles consolidées dans ks-lib utilisent les préfixes DC_/Dc/decoder_ pour les décodeurs, MT_/Mt/materializer_ pour les matérialisateurs, EX_/Ex/executor_ pour les exécuteurs et MD_/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 sappliquent aux constantes, types, traits et fonctions libres exposés à la crate ou hors de la crate.
  • Les constantes temporaires *_LEGACY_CRATE, *_MIGRATION_STATUS et *_MIGRATION_BOUNDARIES doivent disparaître dune 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 TS avec use ts_rs::TS; puis dériver TS.
  • 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/bindings ou #[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.
  • Dans létat courant, les crates généralistes ks-* ne possèdent ni dépendance ts-rs, ni dérivation/export TS-RS, ni dossier de bindings générés. Une exception future exige un contrat TypeScript générique indépendant de Tauri, explicitement documenté et ajouté à laudit workspace.
  • Les types source/runtime de ks-config susceptibles de contenir des secrets ou valeurs internes ne dérivent ni serde::Serialize ni Debug. Une surface publique ou diagnostic est construite champ par champ dans lapplication propriétaire ; il est interdit de sérialiser un runtime complet puis de le redacter a posteriori.
  • Corriger le type Rust/TS-rs source puis régénérer les bindings ; ne pas considérer une modification manuelle isolée dun fichier généré comme un correctif durable.
  • kb-app-demo-desktop/src/tauri.rs contient les attributs #[tauri::command], lenregistrement des commandes et des wrappers privés minces ; la logique complète doit vivre dans le module fonctionnel correspondant sous une fonction pub(crate) testable.
  • Un wrapper Tauri ne doit effectuer que ladaptation des handles/states/arguments, lappel 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.rs sont autorisés lorsquils mutualisent exclusivement une adaptation Tauri, par exemple louverture, laffichage, 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

Couverture des décodeurs

  • Les décodeurs ne dépendent pas de PostgreSQL, SQLite, RPC, Tauri, wallet, stratégie ou matérialisateurs.
  • Pour chaque programme Solana, quelle que soit sa famille, le décodeur doit couvrir maximalement tout wire officiellement identifiable : historique, courant, déprécié, expérimental, en développement ou publié avant son déploiement généralisé.
  • Le statut historique, déprécié, expérimental, en développement ou non encore déployé partout ne constitue jamais à lui seul un motif pour omettre un discriminant, un layout de compte ou une variante de wire officiellement documentée.
  • Lorsqu'un wire officiel est identifiable mais pas encore interprétable complètement, le décodeur doit produire une classification bornée et explicite, conserver les preuves disponibles et refuser toute interprétation inventée.
  • Les discriminants, layouts et variantes inconnus doivent échouer de manière bornée et diagnostiquée ; ils ne doivent pas être assimilés silencieusement à une variante connue.
  • 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.
  • La matrice contractuelle et les tests doivent distinguer explicitement les variantes courantes, historiques, dépréciées, expérimentales, en développement et inconnues.

Couverture des 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, les matérialisateurs doivent projeter maximalement tous les faits métier stables et prouvés par les sorties normalisées du décodage, y compris les états historiques, obsolètes, dépréciés, expérimentaux ou seulement rencontrables pendant un backfill.
  • Une instruction ou un compte decode-only peut et doit produire une matérialisation lorsque son observation prouve un fait stable relevant d'un propriétaire métier identifié.
  • Le statut historique interdit éventuellement 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.
  • Chaque matérialisateur concret possède un composant structuré avec une façade limitée aux déclarations de sous-modules et réexports, un constants.rs et un materializer.rs. Les fichiers spécialisés state.rs, account.rs ou équivalents sont ajoutés seulement lorsque leur responsabilité est distincte.
  • Lidentité runtime suit ks-lib-materializer.<domain>[.<subsystem>]. Le processorName persisté suit materializer.<domain>[.<subsystem>] et doit être exactement lidentité runtime sans le préfixe ks-lib-materializer. Le tracing target dun composant actif est identique à son identité runtime.
  • Les constantes dun composant utilisent le préfixe MT_<COMPONENT>_, résident dans son constants.rs, sont réexportées par chaque façade jusquà ks-lib/src/lib.rs et sont consommées par crate::, y compris dans les tests lorsquelles sont pub ou pub(crate).
  • Toute sortie persistée contient un processorName issu de la constante du composant et une projectionVersion explicite. Une correction de provenance persistée impose une nouvelle version de projection.
  • Une coquille réservée implémente MtMaterializer et MtApiEventMaterializer, expose une constante MT_*_ACCEPTED_FAMILIES vide, refuse tous les événements, retourne une liste legacy vide et un résultat contextuel Ignored. Elle ne doit jamais créer un faux événement de transition.
  • Un composant state-only peut exposer uniquement des APIs de snapshots sans implémenter MtApiEventMaterializer; ce statut doit être explicite et ne crée pas artificiellement un matérialisateur instructionnel.
  • Un wrapper public de compatibilité délègue vers le composant canonique et conserve exactement la même identité. Il ne constitue pas un second propriétaire de faits.

Couverture des exécuteurs

  • Pour chaque programme Solana, les exécuteurs doivent couvrir maximalement toutes les opérations officiellement constructibles ou appelables, y compris les opérations obsolètes qui restent techniquement constructibles.
  • Cette obligation couvre les opérations courantes, récentes, expérimentales, en développement et publiées avant leur déploiement généralisé dès lors que leur wire, leurs comptes, leurs signers et leurs garde-fous exacts sont prouvés.
  • Lorsqu'une chaîne de versions a été remplacée, seule la dernière version canonique de remplacement reçoit un builder public courant. Toutes les versions intermédiaires remplacées restent décodables et matérialisables, déclarent leur remplacement canonique final et ne reçoivent pas de builder public distinct.
  • Une opération obsolète sans remplacement canonique final doit rester exécutable lorsqu'elle est encore officiellement constructible. Son API Rust publique doit être marquée avec #[deprecated], sa matrice doit la déclarer ExecutableDeprecated et la surface runtime doit lidentifier explicitement comme dépréciée, et son exécution doit exiger une approbation opérateur explicite en plus des confirmations destructives ou sensibles éventuellement requises.
  • Une opération obsolète devenue techniquement impossible à construire peut rester decode-only, mais cette exception doit indiquer l'impossibilité contractuelle exacte et les sources qui la prouvent.
  • Une opération ne peut pas être exclue parce qu'elle n'a pas été arbitrairement retenue pour une version. Chaque opération officiellement connue doit recevoir un statut déterministe : Supported, ExecutableDeprecated, Unsupported(reason), DecodeOnlyHistorical, DecodeOnlyReplaced ou frontière de programme explicitement documentée.
  • Unsupported(reason) est réservé à une impossibilité technique ou contractuelle précise et vérifiable. Il ne doit jamais masquer un travail non réalisé, un choix de priorité ou une absence d'inventaire.
  • Le marquage Rust #[deprecated] avertit le développeur à la compilation ; l'approbation opérateur protège l'exécution au runtime. L'un ne remplace jamais l'autre.
  • Les opérations historiques ou remplacées restent décodables et matérialisables lorsqu'elles prouvent des faits. Elles ne sont pas exposées à l'exécution lorsqu'un remplacement canonique final existe, sauf surface de compatibilité historique explicitement isolée, justifiée et elle-même dépréciée.
  • Le déploiement sur un cluster, la disponibilité d'une fixture, la simulation réseau et l'autorisation d'envoi sont des niveaux de preuve distincts ; leur absence ne supprime pas un builder universel officiellement constructible.
  • Toute exclusion d'exécution doit être explicite dans la matrice contractuelle, les capacités runtime et la documentation publique de la surface.

Frontière des pipelines

  • ks-pipeline est le pipeline généraliste, réutilisable et indépendant d'un environnement de démonstration. Ses contrats doivent pouvoir être appelés depuis une application, un service, un worker, un CLI, des tests ou une autre orchestration, sur tout cluster compatible autorisé par la configuration.
  • ks-pipeline possède l'orchestration générique du backfill, de l'extraction Core, du replay, des corrélations stateful, du préflight, de la préparation, de la simulation, de la soumission autorisée, de la confirmation, de la postvalidation et de la matérialisation idempotente.
  • ks-pipeline ne doit contenir ni wallet, mint, compte, airdrop, autorité, adresse, séquence ou hypothèse codée en dur pour une démonstration Devnet ou Testnet.
  • ks-pipeline-demo-scenarios contient les fixtures, aides de campagne et tests automatisés spécifiques aux réseaux de test, actuellement Devnet ou Testnet.
  • Les fixtures, séquences, simulations/soumissions, postconditions et qualifications Devnet/Testnet réutilisables appartiennent à ks-pipeline-demo-scenarios, y compris lorsqu'elles sont déclenchées depuis le desktop.
  • kb-app-demo-desktop conserve l'adaptation UI/Tauri, l'état applicatif, la sélection opérateur, la progression/annulation et la présentation. Il ne doit pas maintenir une seconde implémentation d'une campagne réutilisable.
  • ks-pipeline-demo-scenarios peut préparer des wallets temporaires, demander des airdrops, créer des actifs de test, enchaîner plusieurs appels du pipeline généraliste et produire des preuves de validation réseau.
  • Le binaire ks-pipeline-demo-scenarios-cli reste un outil ciblé tant que son contrat public ne prévoit pas explicitement d'autres commandes. Son usage historique de préparation des fixtures SPL Token-2022 ne doit pas être généralisé implicitement à tous les scénarios.
  • ks-pipeline-demo-scenarios dépend de ks-pipeline ; la dépendance inverse est interdite.
  • Une primitive ou orchestration réellement réutilisable hors d'une campagne de validation précise doit être placée dans ks-pipeline, ks-pipeline-demo-scenarios ou la crate métier propriétaire selon sa responsabilité. Seuls les adaptateurs, états et séquences strictement propres à l'interaction UI restent dans le desktop.
  • Les scénarios Mainnet sans écriture, par exemple les validations de backfill ou de replay, relèvent du pipeline généraliste et de documents de validation dédiés ; ils ne justifient pas l'introduction d'une logique Mainnet spécifique dans la crate de scénarios Devnet/Testnet.

Autres frontières

  • ks-store possède les contrats de persistance neutres et les adaptateurs de base de données.
  • PostgreSQL est l'adaptateur de production de ks-store.
  • Un futur adaptateur SQLite doit rester interne à ks-store et limité aux tests, imports et corpus locaux.
  • ks-wallet reste 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_code désigne la famille : pump, raydium, meteora, orca, jupiter, etc.
  • surface_code désigne la surface concrète : pump_swap, raydium_amm_v4, meteora_dlmm, etc.
  • event_code suit 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 :

ks-lib/src/decoder/<function_code>/<family_code>_<identifier_code>[_vN].rs

Exemples :

  • ks-lib/src/decoder/amm/raydium_cpmm.rs ;
  • ks-lib/src/decoder/clmm/raydium.rs ;
  • ks-lib/src/decoder/dlmm/meteora.rs ;
  • ks-lib/src/decoder/router/jupiter_aggregator_v6.rs ;
  • ks-lib/src/decoder/orderbook/openbook_v2.rs ;
  • ks-lib/src/decoder/metadata/metaplex_token_metadata.rs ;
  • ks-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 ks_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.
  • damm ne doit pas être utilisé comme préfixe fonctionnel ; utiliser amm_meteora_damm_v1 ou amm_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_token2022 et associated_token_account restent des surfaces spécialisées ; les noms historiques de crates externes conservent leur graphie officielle.
  • stake_pool doit être réservé à un futur crate spécialisé plutôt que mélangé avec le programme stake.

Index court de programme

  • Les noms de modules ne doivent pas commencer par un index hexadécimal.
  • Un champ registry_code optionnel 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_id propriétaire doit être prouvé avant création d'une surface canonique.

Constantes Rust

  • Les fichiers program_ids.rs sont interdits dans les nouveaux crates. Utiliser constants.rs.
  • Les program_id publics doivent être réexportés depuis lib.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.rs et rester pub(crate) sauf besoin d'API publique explicite.

Règles de tracing

  • Une crate ou un composant de ks-lib est opérationnel lorsquil 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 tracing depuis le workspace et déclarer exactement un pub(crate) const TRACING_TARGET dans src/constants.rs.
  • Hors ks-lib, la valeur canonique de TRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATA est le nom exact du package Cargo.
  • Dans ks-lib, chaque composant opérationnel possède son propre constants.rs et un target hiérarchique stable fondé sur son identifiant de décodeur, matérialiseur ou exécuteur ; un target unique ks-lib ne 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 tracing doivent utiliser target: crate::TRACING_TARGET et des champs structurés stables. La granularité interne passe par action, stage, window, campaign_id, signature, instruction_path, program_id, processor_name, processor_version, status et error_code.
  • Les crates passives de types, contrats, DTO, API sans exécution, registres ou constantes restent sans dépendance tracing. ks-config reste une exception de bootstrap tant que sa validation précède linstallation du subscriber.
  • Il est interdit dajouter tracing sans événement réel, de conserver un tracing target déclaré mais inutilisé ou de consommer artificiellement un target avec let _target.
  • Une décision interne doit être journalisée par la crate responsable ; kb-app-demo-desktop ne journalise que les frontières Tauri/UI, les actions utilisateur et les résumés dorchestration.
  • Tout input sélectionné sans décodeur compatible, tout résultat de décodage failed ou unsupported, tout résultat de matérialisation failed, toute validation de résultat invalide et toute erreur de persistance doivent émettre un événement error avant le retour ou la persistance terminale.
  • Une transaction Solana échouée mais correctement décodée nest 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 niveau error.
  • 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_hash ou 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.jsonl et app.log, puis vers debug.log, info.log et error.jsonl dans un répertoire propre à chaque crate utilisant tracing.
  • Lajout ou la suppression de tracing.workspace = true dans une crate impose la mise à jour simultanée de la matrice de routes, de ses tests et de docs/TRACING_CONTRACT.md.
  • Le contrat détaillé est défini dans docs/TRACING_CONTRACT.md.
  • Laudit mécanique spécifique au projet est exécuté par python3 scripts/audit_khadhroony_workspace_rules.py. Il couvre notamment les conventions de composants et processorName des matérialisateurs, la pureté de leurs façades, la neutralité des coquilles réservées, TRACING_TARGET_DECODER_METADATA_METAPLEX_TOKEN_METADATA et lusage obligatoire de solana_pubkey::Pubkey à la place de solana_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 lorsquun 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 dintégration, benches ou exemples. Une dépendance de test vers un décodeur ou matérialiseur concret est légitime lorsquelle sert uniquement à éprouver une orchestration générique fondée sur les traits API ; elle ne prouve pas quune capacité de production manque. Toute promotion de dev-dependencies vers dependencies doit ê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 dun MtApiEventMaterializer doit être ajoutée au registre applicatif et couverte par un test dinventaire ordonné ; une crate présente dans le workspace ou dans ks_pipeline nest pas activée automatiquement. Les matérialiseurs exclusivement stateful qui nimplémentent pas MtApiEventMaterializer restent routés par leurs APIs de snapshots dédiées.

  • Les corrélations instruction/état doivent produire une issue explicite (confirmed, contradicted ou not_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-sdk lorsque son contrat suffit.

  • Lordre de préférence des formats est : schéma officiel wincode, schéma officiel Borsh, puis parseur local borné reproduisant exactement le runtime lorsque linterface officielle nexpose que bincode.

  • Aucun nouveau code ne doit dépendre directement de bincode. Une interface officielle uniquement disponible derrière une feature bincode ne justifie pas lactivation 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 lordre exact des metas, borner toute liste de comptes variable avant lappel au builder et refuser les doublons lorsque leur répétition na pas de sémantique publiée.

  • Les features des interfaces doivent rester minimales et explicites. Une feature serde, wincode, borsh, std, alloc ou équivalente nest activée que si la crate consommatrice lutilise réellement.

  • Les crates applicatives ne doivent pas dépendre dinterfaces RPC ou transactionnelles uniquement pour relayer des types ; ces dépendances appartiennent à ks_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.md avec 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 conserve wincode = "^0.5". Le Cargo.lock local du workspace doit résoudre exactement wincode 0.5.5 avec solana-wincode-varint 1.0.0 afin déviter lincompatibilité observée entre les familles transitives wincode 0.5 et wincode 0.6. Ce lockfile est un garde-fou local de résolution : il nest ni versionné, ni inclus dans les archives. Une entrée inutilisée ne doit pas être ajoutée artificiellement aux dépendances dune crate pour influencer le résolveur. Laudit spécifique du workspace refuse toute dérive de ce couple avant compilation lorsquun Cargo.lock local a été généré ou restauré.

Règles des exécuteurs

  • Les exécuteurs résident dans ks_lib::executor.

  • Une surface classifiée peut avoir un module décodeur et un module exécuteur distincts dans ks-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çade ks_lib.

  • Un squelette dexécuteur doit exposer un type Ex*Executor, référencer uniquement des Program IDs de ks-program-ids, annoncer Maybe pour sa surface et construire exclusivement un plan réservé à zéro instruction.

  • La migration fonctionnelle dun exécuteur doit remplacer ce comportement réservé par des capacités exactes Supported ou Unsupported(reason) ; aucun statut temporaire LEGACY_CRATE ou MIGRATION_STATUS ne doit subsister.

  • Les garde-fous communs doivent être placés dans les modules de sécurité partagés de ks-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.

  • La section « Couverture des exécuteurs » ci-dessus est normative pour chaque surface : la migration fonctionnelle doit fermer linventaire complet et ne peut pas sélectionner arbitrairement un sous-ensemble dopérations officiellement constructibles.

  • Les champs JSON exposés à TypeScript ne doivent pas utiliser directement serde_json::Value avec TS-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_string et serde_json::to_string_pretty.

Règles de configuration

  • La configuration commune Khadhroony Solana passe par ks-config, mais chaque binaire peut posséder un fichier de composition et une configuration dédiée sans rendre ks-config dépendant de ce binaire.
  • Le nom par défaut d'une composition binaire suit <binary>.default.config.json. Le desktop utilise config/kb-app-demo-desktop.default.config.json. Un consommateur qui accepte intégralement les defaults partagés ne doit pas créer une composition uniquement pour les répéter.
  • Les documents partagés actifs sont config/logging.config.json, config/transport.config.json, config/listeners.config.json, config/store.config.json, config/wallet.config.json et config/execution.config.json.
  • Chaque document partagé définit un default_profile. Une composition peut sélectionner un autre profil ; une référence explicite doit être validée par ks-config et doit désigner un profil existant.
  • Une composition ne recopie pas arbitrairement les paramètres dun document spécialisé. Les overrides de champ restent définis et validés par le contrat propriétaire (par exemple les overrides dun endpoint WebSocket) ; les valeurs globales explicitement prévues pour lenvironnement peuvent être remplacées via KS_*/KB_*.
  • Les valeurs qui ne varient pas par profil restent au niveau racine de leur document spécialisé. logs_directory appartient au logging et wallets_directory au wallet ; ils ne doivent pas être dupliqués dans les profils.
  • Les valeurs globales pouvant varier par installation doivent fournir un défaut versionné sûr et peuvent être remplacées par une variable d'environnement namespacée.
  • Les endpoints WebSocket doivent sélectionner une classe de defaults nommée ; leurs timeouts, capacités et politique auto_reconnect peuvent être remplacés explicitement au niveau de l'endpoint.
  • Les autorisations *_send_enabled appartiennent à la politique d'exécution, pas au contrat d'identité/stockage wallet.
  • Les schémas JSON actifs sont conservés exclusivement sous config/schemas/. Les documents source spécialisés possèdent chacun leur schéma ; resolved.app.config.schema.json décrit uniquement le contrat runtime transitoire reconstruit par ks-config.
  • Les exemples conformes résident exclusivement sous config/exemples/ avec un nom distinct des fichiers runtime. Les fixtures d'un contrat runtime résolu appartiennent à test-fixtures/ et ne doivent pas être chargées en production.
  • Les fichiers historiques config/app.config.json, config/example.app.config.json, config/schemas/app.config.schema.json, config/example.config.json, les fichiers config/example.*.config.json hors config/exemples/, config/schema.config.json et config/ks-pipeline-demo-scenarios.default.config.json sont interdits dans l'état courant.
  • Le chemin de composition desktop peut être remplacé par KB_APP_DEMO_DESKTOP_CONFIG_PATH. KS_DEVNET_CONFIG_PATH est uniquement un override facultatif vers une composition explicite pour les scénarios Devnet ; sans cet override, les scénarios utilisent les defaults partagés. KS_LOGGING_CONFIG_PATH reste un override explicite du document logging.
  • 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 variables possédées par les composants généralistes ks-* utilisent obligatoirement KS_SECRET_*, KS_PUBLIC_* ou KS_* ; les variables réellement spécifiques à kb-app-demo-desktop ou à de futures crates kb-* utilisent KB_SECRET_*, KB_PUBLIC_* ou KB_*.
  • Le namespace est déterminé par le propriétaire fonctionnel du contrat et non par son consommateur.
  • Les sous-préfixes SECRET sont toujours non exposables ; les sous-préfixes PUBLIC ne sont exposables que par une surface explicitement autorisée ; les autres variables du domaine sont internes.
  • La sensibilité dune valeur composée suit Secret > Internal > Public : une URL, un DSN ou toute autre chaîne incorporant un placeholder KS_SECRET_*/KB_SECRET_* hérite de la sensibilité Secret, quel que soit le nom du champ final.
  • Une valeur Secret ne doit jamais apparaître en clair dans une sérialisation, un Debug, une erreur, un log, un diagnostic, un payload Tauri ou lUI. Une valeur interne napparaît que dans un diagnostic explicitement borné et sémantiquement autorisé.
  • La section application dune composition est opaque pour ks-config; le binaire propriétaire définit et valide son propre schéma sous config/schemas/ avant usage.
  • Les bindings TS-RS sont une frontière d'application Tauri. Une crate ks-* ne conserve une dérivation/export TypeScript que si le type constitue un contrat externe générique explicitement justifié et audité ; sinon l'application définit un DTO/wrapper dédié.
  • Une commande Tauri ne retourne jamais directement un contrat ks-* susceptible de contenir des valeurs runtime ; elle retourne un DTO appartenant à lapplication et construit explicitement la projection autorisée.
  • Les snapshots/runtime transport contenant une URL résolue restent backend-only : ils ne sont pas sérialisables directement, leur Debug est sanitisé, les DTO Tauri ne contiennent pas endpoint_url, et les erreurs/logs de transport ne recopient ni corps HTTP non-success ni message JSON-RPC distant susceptible de réinjecter un credential.
  • Les chemins dérivés du stockage wallet sont internes ; un payload fonctionnel Tauri ne transporte pas un chemin de fixture. Seule une surface de diagnostic explicitement bornée peut exposer un chemin interne autorisé.

Ordre de développement cible

  • ks-logging doit être stabilisé avant les logs avancés des autres crates.
  • ks-config doit ê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-desktop doit fournir des validations live après chaque capacité majeure, sans créer une application Tauri séparée par crate.

Constantes des composants de ks-lib

  • Chaque composant classifié avec un program_id doit avoir son propre fichier constants.rs.
  • constants.rs contient les discriminators, sélecteurs, opcodes, constantes Borsh et constantes de décodage quand elles sont connues.
  • Le module parent puis ks-lib/src/lib.rs réexportent les constantes publiques nécessaires.
  • Les fichiers d'implémentation utilisent le chemin public le plus court réexporté par ks-lib.
  • Les literals de program_id ne doivent pas rester dans program_ids(), sauf dans un fichier constants.rs.

Identifiants de programmes

Les program_id connus doivent être définis une seule fois dans ks-program-ids. Les composants de décodeur, dexécuteur, de store, dapplication ou doutil doivent référencer directement ks_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écuter npm run build, npm --prefix kb-app-demo-desktop run build ni une commande équivalente de build frontend autonome.
  • Les commandes npm manuelles sont limitées à linstallation explicite de dépendances nécessaires, notamment npm i et npm i -D <package> ; node_modules/ et package-lock.json restent 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.
  • La validation frontend de release est réalisée uniquement par cargo tauri build -c kb-app-demo-desktop/tauri.conf.json ; Tauri déclenche alors son beforeBuildCommand et pilote TypeScript/Vite.
  • Lorsque Vite utilise root: 'frontend', son build.outDir et le frontendDist Tauri doivent résoudre explicitement vers le même répertoire physique. Pour la configuration 0.4.8, ../../dist côté Vite et ../dist côté Tauri désignent le dist situé à la racine du workspace.
  • Le répertoire dist/ est généré localement et ne doit jamais être inclus dans un delta source.

Architecture khadhroony-bot3

  • Les décodeurs, exécuteurs et matérialisateurs résident exclusivement dans ks-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 ks-lib.
  • ks-store regroupe les contrats store-neutral et les adaptateurs de persistance, avec PostgreSQL comme adaptateur de production initial.
  • ks-store/src/lib.rs reste 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 à ks-lib; ks-store les consomme et les réexporte sans les dupliquer.
  • ks-lib ne dépend jamais de ks-store. Cette direction de dépendance évite tout cycle entre modèles, décodage et persistance.
  • ks-store ne dépend pas de ks-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-desktop est 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_code et event_code sont 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_account ou metadata_metaplex_token_metadata sont interdites pour ces valeurs contractuelles.
  • Toute nouvelle surface ou opération doit respecter docs/OPERATION_NAMING_CONVENTION.md et être ajoutée à test-fixtures/contract-matrices/OPERATION_NAMING_MATRIX.json avant son premier remplissage persistant.
  • Un renommage de ces valeurs après remplissage dune base est une migration de données et exige une migration SQL ou une reconstruction explicite des tables dérivées.