v0.5.2-pre.007

This commit is contained in:
2026-08-11 15:15:03 +02:00
parent 56572cec40
commit 279fd67cc0
27 changed files with 1151 additions and 143 deletions

View File

@@ -1,10 +1,45 @@
<!-- file: CHANGELOG.md -->
<!-- version: 17 -->
<!-- version: 18 -->
# CHANGELOG — khadhroony-bot3
Ce changelog décrit les évolutions fonctionnelles globales du projet. Il ne recense pas les prereleases, les correctifs `fix` ni le détail de chaque delta. Ces informations appartiennent aux changelogs des crates concernées.
## 0.5.2 — `ks-wallet` multi-wallet et stockage natif protégé
### Wallet natif et sécurité
- introduction du conteneur binaire versionné `<alias>.kswallet`, protégé par Argon2id v19 + XChaCha20-Poly1305 et publié atomiquement/no-clobber avec permissions privées ;
- séparation entre `WalletIdentity`, `WalletPassword`, `WalletFileHandle` et `UnlockedWallet`, sans getter public des bytes privés ;
- création, scan, lookup, inspection externe, unlock, signature et changement de mot de passe avec conservation exacte de la keypair/pubkey ;
- séparation des wallets persistants sous `wallets/` et des fixtures/keypairs temporaires sous `wallets/temporary/**` ;
- durcissement des erreurs, logs et `Debug` afin de ne pas exposer secret, password ou chemin local inutile.
### Migration et compatibilité
- migration non destructive du keypair JSON Solana legacy vers `.kswallet` ;
- inspection publique d'un fichier keypair externe sans import, avec retour limité à la pubkey et au format ;
- import/export testés de `SolanaCliJson` et du Base58 du keypair complet de 64 octets ;
- authentification obligatoire du mot de passe avant tout export secret ;
- refus des collisions d'alias/pubkey, symlinks, permissions ouvertes et écrasements silencieux ;
- exports opérateur du desktop confinés sous `data/wallets/` ;
- matrice documentée des formats Phantom, Solflare, Backpack, Trust Wallet et Base/Coinbase, avec Base58 comme seul adaptateur tiers de cette version.
### Configuration, scénarios et desktop
- `wallet_alias` optionnel/nullable par profil dans `ks-config`, sans mot de passe ni matériau secret ;
- résolution explicite d'un signer `.kswallet` dans les démos Devnet System/SPL/Metadata, sans fallback temporaire lorsqu'un alias persistant est choisi ;
- sélection session-only du wallet d'exécution depuis la fenêtre Wallets, indépendante de la configuration persistée et authentifiée côté backend ;
- inventaire/création/inspection/import/export des wallets et explorateur public SOL/tokens/historique par profil RPC dans `kb-app-demo-desktop`, via DTO applicatifs sûrs ;
- ajout de `ks-wallet-demo-scenarios`, consommateur externe réutilisable de `ks-wallet`, avec validation ordonnée A → B → rejet de A → ouverture/signature avec B → restauration vers A.
### Validation et suite
- `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, audit workspace et `cargo test --workspace` validés sur la base `0.5.2-pre.006 + fix-010` ;
- validation runtime du signer persistant dans les démos Devnet avec `persistence="persistent"` et exports JSON/Base58 sous `data/wallets/` ;
- l'inventaire/migration des fixtures historiques et la régression de chargement de fixture Token-2022 sont explicitement reportés à `0.5.4` ;
- `0.5.3` est consacré à l'audit et la normalisation de `ks-store`.
## 0.5.1 — namespaces Khadhroony Solana et configuration sûre
### Namespace et ownership

View File

@@ -1,5 +1,5 @@
# file: Cargo.toml
# version: 64
# version: 65
[workspace]
resolver = "3"
@@ -19,7 +19,7 @@ members = [
]
[workspace.package]
version = "0.5.2-pre.6"
version = "0.5.2-pre.7"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-bot3"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md -->
<!-- version: 25 -->
<!-- version: 26 -->
# Khadhroony Bot3
@@ -26,6 +26,8 @@ La série `0.5.x` prépare la séparation explicite entre le domaine applicatif
Depuis `0.5.1`, les contrats de configuration source/runtime susceptibles de contenir des secrets restent backend-only et ne sont ni sérialisables ni `Debug` par défaut. Les crates `ks-config` et `ks-lib` ne génèrent plus de bindings TS-RS ; les surfaces TypeScript/Tauri sont possédées par les applications via des DTO explicites.
Depuis `0.5.2`, `ks-wallet` gère plusieurs wallets persistants `.kswallet` protégés par mot de passe, la migration/import/export de keypairs Solana et une capacité de signature sans exposition du secret. Les validations réutilisables du cycle de mot de passe sont isolées dans `ks-wallet-demo-scenarios`. Le guide opérationnel est [`docs/guides/WALLETS.md`](docs/guides/WALLETS.md).
Références :
- [`docs/architecture/ARCHITECTURE.md`](docs/architecture/ARCHITECTURE.md) ;

View File

@@ -1,5 +1,5 @@
<!-- file: ROADMAP.md -->
<!-- version: 39 -->
<!-- version: 43 -->
# ROADMAP — khadhroony-bot3
@@ -96,31 +96,48 @@ Les préfixes SQL historiques `kb_sol_*` restent volontairement inchangés jusqu
### 0.5.2 — `ks-wallet`
- auditer et normaliser les frontières identité, secret, déverrouillage et signature ;
- consolider les besoins multi-wallets et multi-profils ;
- revoir import/export, chiffrement, verrouillage, sauvegarde et restauration lorsque ces capacités sont retenues ;
- définir explicitement la migration du format keypair JSON `0.4.8` si un nouveau format persistant est adopté ;
- empêcher toute fuite de secret vers la configuration, les logs, Tauri ou les DTO publics ;
- conserver une API de signature réutilisable par les futurs exécuteurs sans couplage à un protocole particulier.
- isoler les validations intégrées réutilisables dans `ks-wallet-demo-scenarios`, en commençant par le cycle de mot de passe A → B → rejet de A → ouverture/signature avec B → restauration vers A, puis réutiliser cette crate pour les futurs scénarios dimport/export et migration.
Version clôturée fonctionnellement : la frontière wallet Solana générale est désormais séparée entre identité publique, secret persistant, mot de passe et capacité de signature.
### 0.5.3 — audit et normalisation de `ks-store`
- plusieurs `.kswallet` persistants sont découverts et sélectionnés par alias dans `wallets/`, tandis que les fixtures/keypairs temporaires restent sous `wallets/temporary/**` ;
- le format natif v1 est binaire, versionné, protégé par Argon2id v19 + XChaCha20-Poly1305 et publié atomiquement/no-clobber avec permissions privées ;
- `WalletPassword` et `UnlockedWallet` bornent respectivement l'acquisition du mot de passe et la capacité de signature, tandis que `ks-lib` continue de dépendre uniquement d'une capacité `Signer` ;
- le changement de mot de passe conserve exactement la même keypair/pubkey et son cycle A → B → rejet de A → B → A est validé par `ks-wallet-demo-scenarios` ;
- le legacy Solana CLI JSON peut être inspecté ou migré sans destruction vers `.kswallet` ;
- `SolanaCliJson` et `SolanaPrivateKeyBase58` disposent d'import/export testés, tout export secret exigeant un mot de passe valide ;
- les exports opérateur issus du desktop sont confinés sous `data/wallets/` ;
- `ks-config` ne transporte qu'un `wallet_alias` optionnel et aucun secret ;
- `kb-app-demo-desktop` peut sélectionner en session un `.kswallet` par profil Devnet, prioritaire sur l'alias configuré, et les logs runtime ont confirmé `persistence="persistent"` avec le signer choisi ;
- les chemins locaux inutiles sont retirés des logs/erreurs/`Debug` du store legacy et les collisions concurrentes de création native sont couvertes ;
- les détails normatifs restent dans `docs/NATIVE_FORMAT.md`, `docs/WALLET_FORMAT_COMPATIBILITY.md`, `docs/guides/WALLETS.md` et `docs/validation/V0_5_2_WALLET_VALIDATION_REPORT.md`.
- auditer DTO, entités, repositories, migrations, index, requêtes, idempotence et provenance ;
- vérifier les champs temporels et séparer explicitement le temps blockchain du temps de persistance ;
- distinguer notamment `slot`, `block_time` ou timestamp de transaction des timestamps d'acquisition, d'insertion et de mise à jour en base ;
- normaliser la structure de `ks-store` avant l'arrivée des matérialisations trading ;
- migrer les tables Solana du préfixe historique `kb_sol_*` vers `k_sol_*` ;
- réserver `kb_*` aux éventuelles tables dont la responsabilité appartient réellement au domaine applicatif Bot ;
- profiter de la fenêtre pré-`0.6.x` pour reconstruire ou migrer proprement les bases Devnet/Mainnet au lieu de conserver des alias historiques sans valeur durable ;
- préparer les index et contrats nécessaires aux faits de création de pools, liquidité, réserves, swaps, évolution de prix et séries temporelles ;
- préparer le terrain pour routing, multi-pools et analyse croisée sans introduire prématurément des tables spécifiques à un DEX ;
- permettre des extractions et analyses efficaces pour les futurs consommateurs de trading et de recherche historique.
### 0.5.3 — audit, gel de schéma et abstraction de `ks-store`
Aucune table trading spécifique à Meteora, Raydium, Pump, Orca ou Jupiter n'est inventée avant définition des faits stables produits par les futurs matérialisateurs.
- conserver `ks-store` comme frontière de persistance **généraliste Solana** pour les faits matérialisés par `ks-lib`; le trading est la priorité court terme, pas le périmètre exclusif du stockage ;
- migrer les tables Solana du préfixe historique `kb_sol_*` vers `k_sol_*` et réserver `kb_*` au domaine réellement Bot ;
- auditer DTO, models, repositories, migrations, index, requêtes, idempotence et provenance ;
- vérifier table par table que le contrat structurel est complet **avant gel** : colonnes, types, nullabilité, clés, contraintes, provenance, replay et temporalités ;
- corriger pendant `0.5.3` les omissions structurelles déjà identifiées, notamment la conservation du temps on-chain/`block_time` lorsqu'il existe et qu'il est pertinent ;
- considérer après clôture les tables stabilisées comme des contrats à ne plus remodeler : les nouvelles fonctionnalités doivent préférer de nouvelles tables reliées aux anciennes ;
- distinguer explicitement `slot`, `block_time` ou timestamp de transaction des timestamps d'acquisition, d'insertion, de mise à jour et de matérialisation ;
- mettre `ks-store` aux conventions du workspace avant l'extension massive des matérialisations ;
- supprimer des autres crates toute dépendance aux fonctions/modules/types PostgreSQL : elles consomment uniquement les DTO/models et opérations génériques de `ks-store` ;
- encapsuler dans `ks-store` la sélection du backend, l'interprétation des paramètres de connexion, la création des pools/connexions et les implémentations spécifiques ;
- conserver PostgreSQL comme backend opérationnel actuel tout en définissant une frontière réimplémentable plus tard avec MySQL, SQLite, RocksDB, Oracle ou un autre moteur sans modifier les consommateurs ;
- profiter de la fenêtre pré-`0.6.x` pour reconstruire ou migrer proprement les bases Devnet/Mainnet avant de figer les contrats ;
- auditer les modèles canoniques par **nature de fait** : core/transactions, comptes/balances/lifecycle, token/SPL, metadata, staking/vote, administration/autorités, programmes, audit/compliance, risques, trading/marchés et autres domaines justifiés par les Program IDs couverts ;
- faire des matérialiseurs la frontière de normalisation des comptes/événements/champs/unités spécifiques à chaque programme vers les DTO/models canoniques de `ks-store` ;
- pour la priorité trading, préparer les contrats canoniques nécessaires aux marchés/paires, pools de liquidité/AMM, order books lorsque leurs invariants ne peuvent pas être unifiés proprement, réserves, positions, swaps/trades, prix, volumes et séries temporelles ;
- autoriser de nouvelles tables génériques futures, par exemple candles/OHLC ou des tables dédiées par concept `liquidity_pool` / `order_book`, lorsque leur contrat est suffisamment durable ;
- conserver le Program ID/protocole/version comme provenance sans en faire le propriétaire par défaut du schéma ;
- permettre des extractions et analyses efficaces pour les futurs consommateurs de trading, metadata, recherche historique et autres usages Solana.
Le schéma ne doit pas être organisé en familles de tables par protocole ou Program ID. `meteora_*`, `raydium_*`, `pump_*`, `orca_*`, `jupiter_*`, etc. illustrent ce qui doit être évité : les différences protocolaires sont normalisées par les matérialiseurs. Lorsqu'une séparation est nécessaire, elle est définie par un concept/fait réellement distinct et durable, qu'il concerne le trading, les metadata, le staking ou un autre domaine.
### 0.5.4 — scénarios, exécuteurs et validations
- diagnostiquer et corriger la régression observée dans `demo_execution_spl_token_2022` lors du chargement de fixture (`unable to read configured Token-2022 fixture`) après séparation des racines wallet/fixtures ;
- inventorier non destructivement les keypairs historiques sous `wallets/temporary/**`, extraire les pubkeys des formats supportés et préparer une migration sélective des seuls signers devant devenir persistants ;
- garder toute classification on-chain éventuelle chez le consommateur/scénario, à partir de la pubkey et du profil réseau, sans dépendance `ks-wallet -> ks-onchain-transport` ni rôle métier inventé depuis les bytes du secret ;
- auditer les scénarios encore déclarés ou assemblés directement dans `kb-app-demo-desktop` ;
- déplacer toute logique de scénario réutilisable vers `ks-pipeline-demo-scenarios` et laisser le desktop comme adaptateur UI/Tauri ;
- comparer les décodeurs existants aux exécuteurs disponibles et identifier les exécuteurs réellement manquants ;

View File

@@ -1,5 +1,5 @@
<!-- file: docs/README.md -->
<!-- version: 36 -->
<!-- version: 37 -->
# Documentation active de Khadhroony Bot3
@@ -92,13 +92,15 @@ Les douze crates possèdent `README.md`, `TODO.md`, `USAGE.md` et `CHANGELOG.md`
- [RPC, backfill et WebSocket](guides/RPC_BACKFILL_AND_WEBSOCKET.md) ;
- [Extraction Core, replay et matérialisation](guides/REPLAY_CORE_EXTRACTION_AND_MATERIALIZATION.md) ;
- [PostgreSQL et stockage](guides/POSTGRES_STORAGE.md) ;
- [Validation Devnet](guides/DEVNET_VALIDATION.md).
- [Validation Devnet](guides/DEVNET_VALIDATION.md) ;
- [Wallets, sécurité et opérations](guides/WALLETS.md).
## 9. Rapports de validation actifs
- [Validation Metaplex Token Metadata 0.4.7](validation/V0_4_7_METAPLEX_TOKEN_METADATA_VALIDATION_REPORT.md) ;
- [Validation Metadata on-chain et clôture 0.4.8](validation/V0_4_8_METADATA_VALIDATION_REPORT.md) ;
- [Validation de fondation et clôture 0.5.1](validation/V0_5_1_FOUNDATION_VALIDATION_REPORT.md) ;
- [Validation wallet et clôture 0.5.2](validation/V0_5_2_WALLET_VALIDATION_REPORT.md) ;
- [`validation/WEBSOCKET_MAINNET_RESEARCH_VALIDATION_REPORT.md`](validation/WEBSOCKET_MAINNET_RESEARCH_VALIDATION_REPORT.md) ;
- [`validation/MAINNET_RESEARCH_BACKFILL_VALIDATION_SCENARIO.md`](validation/MAINNET_RESEARCH_BACKFILL_VALIDATION_SCENARIO.md).
@@ -106,10 +108,10 @@ Les preuves détaillées de `0.4.8-pre.*` restent accessibles sous `../olddocs/a
## 10. Plans de version actifs
Les plans temporaires `0.5.0` et `0.5.1` sont clôturés et archivés sous `../olddocs/archivekbot3/docs/plans/`.
Les plans temporaires `0.5.0`, `0.5.1` et `0.5.2` sont clôturés et archivés sous `../olddocs/archivekbot3/docs/plans/`.
Le plan temporaire détaillé de `0.5.2` est actif sous [`plans/V0_5_2_KS_WALLET_RESTRUCTURING_PLAN.md`](plans/V0_5_2_KS_WALLET_RESTRUCTURING_PLAN.md) et sera archivé lors de la dernière prerelease de `0.5.2`.
Le plan détaillé de `0.5.3` sera créé par `0.5.3-pre.001` après audit de `ks-store`.
## 11. Prompt de reprise
- [`Prompt actif 0.5.2`](../prompts/031_v0_5_2_ks_wallet_restructuring.md).
- [`Prompt actif 0.5.3`](../prompts/032_v0_5_3_ks_store_normalization.md).

View File

@@ -1,5 +1,5 @@
<!-- file: docs/WALLET_FORMAT_COMPATIBILITY.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Compatibilité import/export des wallets Solana
@@ -104,3 +104,13 @@ Les adaptations suivantes sont volontairement reportées vers une version ultér
- ajouter d'autres wallets uniquement à partir d'un format privé explicitement documenté et testable.
Ces reports ne bloquent pas `0.5.2` : le format Solana CLI obligatoire et l'adaptateur tiers Base58 de référence sont couverts dans `pre.005`.
## Emplacement des exports de démonstration
`ks-wallet` accepte un chemin de destination explicite fourni par son consommateur. La démo desktop `0.5.2` borne volontairement ses exports opérateur au répertoire :
```text
data/wallets/
```
Cette convention appartient à `kb-app-demo-desktop`; elle ne devient pas une dépendance ou une constante générale de `ks-wallet`.

324
docs/guides/WALLETS.md Normal file
View File

@@ -0,0 +1,324 @@
<!-- file: docs/guides/WALLETS.md -->
<!-- version: 2 -->
# Wallets, sécurité et opérations
## 1. Objet
Ce guide décrit le contrat opérationnel de `ks-wallet` à partir de `0.5.2`.
`ks-wallet` possède :
- le stockage local des wallets Solana persistants ;
- la protection par mot de passe ;
- l'ouverture authentifiée ;
- la capacité de signature ;
- les imports/exports de formats secrets explicitement supportés.
Il ne possède pas :
- la politique d'autorisation d'une transaction ;
- les plafonds de dépense ;
- le routage RPC ;
- la classification on-chain d'une pubkey ;
- les DTO frontend d'une application Tauri.
## 2. Modèle de données
### 2.1 Identité publique
Une identité publique contient uniquement :
- alias ;
- pubkey ;
- persistance temporaire ou persistante.
Une identité publique ne contient jamais le secret, le mot de passe, le ciphertext ou un chemin local.
### 2.2 Wallet temporaire
`TemporaryWallet::generate()` crée un keypair en mémoire. Il ne nécessite ni mot de passe ni fichier.
Cette surface reste adaptée aux tests synthétiques et signers jetables. Les fixtures/keypairs persistées uniquement pour les campagnes historiques restent sous `wallets/temporary/**`; elles ne doivent pas être confondues avec les `.kswallet` persistants de `wallets/`.
### 2.3 Wallet persistant
Le format natif est :
```text
<alias>.kswallet
```
Le layout exact est défini dans [`../NATIVE_FORMAT.md`](../NATIVE_FORMAT.md).
Le store automatique de `WalletManager` :
- scanne uniquement son répertoire configuré ;
- ne descend pas récursivement ;
- ignore les extensions étrangères ;
- refuse symlinks et fichiers non réguliers ;
- exige des permissions privées sous Unix ;
- valide le conteneur complet avant de retourner un handle.
## 3. Protection cryptographique
Le format v1 utilise :
| Élément | Contrat v1 |
| ----------------- | ---------------------------------- |
| KDF | Argon2id v19 |
| Profil d'écriture | 64 MiB, 3 passes, 4 lanes |
| Sel | 16 octets |
| Clé dérivée | 32 octets |
| AEAD | XChaCha20-Poly1305 |
| Nonce | 24 octets |
| Plaintext | keypair Solana exacte de 64 octets |
| Ciphertext + tag | 80 octets |
| AAD | header + alias + sel + nonce |
Les paramètres lus sont bornés avant l'exécution du KDF.
La pubkey présente dans le header n'est pas considérée comme authentifiée avant l'unlock. Après déchiffrement, `ks-wallet` reconstruit le keypair et vérifie que sa pubkey correspond exactement au header avant de produire une capacité de signature.
## 4. Mot de passe et cycle de vie
`WalletPassword` :
- prend possession de sa chaîne ;
- n'est pas clonable ;
- n'est pas sérialisable ;
- possède un `Debug` redacted ;
- zéroïse la valeur qu'il possède à la destruction.
`WalletManager::create()` crée un wallet natif et retourne `UnlockedWallet`.
`WalletManager::unlock()` ouvre un wallet du store par alias.
`WalletManager::unlock_file()` ouvre un `WalletFileHandle` obtenu par inspection explicite d'un fichier externe.
`UnlockedWallet` :
- possède le keypair authentifié ;
- n'est pas clonable ;
- expose `Signer` / `Signer + Sync` ;
- n'expose pas les 64 octets privés ;
- est verrouillé par consommation explicite avec `lock()` ou par fin de portée.
Un changement de mot de passe ne change pas la keypair. Il produit un nouveau sel et un nouveau nonce, puis reprotège exactement la même identité Solana.
Une `UnlockedWallet` déjà remise à un consommateur n'est pas révoquée rétroactivement par un changement de mot de passe. Son propriétaire doit la détruire ou appeler `lock()`.
## 5. Écriture et permissions
Les nouveaux `.kswallet` sont publiés sans écrasement silencieux.
Sous Unix :
- répertoire wallet : `0700` ;
- fichier `.kswallet` : `0600` ;
- exports secrets : `0600`.
Les écritures natives utilisent un fichier temporaire privé dans le même répertoire, `sync_all`, puis une publication atomique/no-clobber. Le changement de mot de passe remplace le fichier après authentification de l'ancien secret.
Les collisions concurrentes de création d'un même alias doivent produire exactement un gagnant et conserver une destination native valide.
## 6. Configuration
`wallet.config.json` contient une racine globale `wallets_directory` et des profils.
Un profil peut sélectionner :
```json
{
"wallet_alias": "operator"
}
```
ou laisser :
```json
{
"wallet_alias": null
}
```
L'alias est une sélection non sensible. Aucun mot de passe n'est stocké dans `ks-config`.
Lorsqu'un alias persistant est configuré, un consommateur ne doit pas retomber silencieusement sur un wallet temporaire : il doit acquérir explicitement le mot de passe et appeler l'API d'unlock.
## 7. Migration legacy
Le legacy historique est :
```text
<alias>.json
```
avec le tableau JSON des 64 octets du keypair Solana.
`WalletManager::migrate_legacy()` :
1. lit la source legacy privée ;
2. valide le keypair ;
3. crée `<alias>.kswallet` ;
4. vérifie que la pubkey est identique ;
5. conserve la source JSON intacte.
La suppression du legacy reste une décision explicite de l'opérateur après validation.
`TemporaryWalletStore` reste disponible pour les scénarios historiques. Ses erreurs, logs et `Debug` ne doivent pas projeter les chemins locaux, même si ses getters explicites `directory()` et `wallet_path()` restent nécessaires aux outils de fixtures.
## 8. Import et export
Les formats secrets actuellement supportés sont :
| Format | Import | Export | Mot de passe requis à l'export |
| ---------------------------------------------- | :----: | :----: | :----------------------------: |
| `WalletTransferFormat::SolanaCliJson` | oui | oui | oui |
| `WalletTransferFormat::SolanaPrivateKeyBase58` | oui | oui | oui |
La matrice détaillée est dans [`../WALLET_FORMAT_COMPATIBILITY.md`](../WALLET_FORMAT_COMPATIBILITY.md).
L'import refuse :
- source non régulière ou symlink ;
- permissions trop ouvertes sous Unix ;
- format invalide ;
- keypair de taille incorrecte ;
- alias déjà occupé ;
- pubkey déjà gérée sous un autre alias natif.
L'export authentifie d'abord le `.kswallet`, puis seulement après crée la destination. Il n'écrase jamais silencieusement un fichier existant.
## 9. Keypair, wallet, mint et authority
Une keypair Solana ne contient pas son rôle métier.
Le même type de secret Ed25519 peut servir comme :
- payer/opérateur ;
- mint authority ;
- freeze authority ;
- clé utilisée lors de la création d'un mint ;
- recipient possédant lui-même un signer ;
- autre authority ou signer de fixture.
Il est donc incorrect de décider « ce fichier est un mint et non un wallet » uniquement à partir du tableau JSON de 64 octets.
La future inspection de `wallets/temporary/**` prévue avec `0.5.4` doit produire un inventaire local factuel :
```text
format détecté
keypair valide / invalide / format non supporté
pubkey si valide
```
Un consommateur peut ensuite interroger un réseau donné avec cette pubkey et classifier l'état actuel de l'adresse, par exemple :
- compte absent ;
- compte système ;
- mint SPL Token ;
- mint Token-2022 ;
- compte token ;
- programme ou autre compte.
Cette classification reste réseau-dépendante et ne prouve pas tous les rôles historiques du signer.
`ks-wallet` ne doit pas dépendre de `ks-onchain-transport` pour réaliser cette classification.
## 10. Desktop de démonstration
`kb-app-demo-desktop` possède ses propres DTO Tauri et ne sérialise pas les types secrets de `ks-wallet`.
La fenêtre Wallets permet :
- inventaire des `.kswallet` de `wallets/` ;
- création d'un wallet natif avec un secret backend-only ;
- inspection d'un `.kswallet` externe ;
- inspection/import d'un keypair Solana CLI JSON ou Base58 sans exposer son secret au frontend ;
- export secret authentifié vers `data/wallets/` avec nom de fichier borné et sans chemin arbitraire côté frontend ;
- sélection explicite d'un profil RPC pour les lectures publiques ;
- consultation du solde SOL, des comptes SPL Token/Token-2022, des signatures récentes et du détail `getTransaction` ;
- sélection session-only du `.kswallet` utilisé par les démos Devnet.
Le mot de passe de démonstration est lu uniquement côté backend depuis :
```text
KB_SECRET_DEMO_WALLET_PASSWORD
```
La sélection runtime du wallet d'exécution est authentifiée avant activation et ne réécrit pas `wallet.config.json`. L'ordre de résolution est :
```text
override session demo_wallet
-> wallet_alias du profil
-> wallet temporaire uniquement si aucun alias persistant n'est sélectionné
```
Lorsqu'un alias persistant est effectif, les adaptateurs Devnet System/SPL/Metadata utilisent une capacité `UnlockedWallet` et ne retombent pas silencieusement sur le JSON temporaire. La validation opérateur `0.5.2` a observé `persistence="persistent"` avec la pubkey sélectionnée.
Le profil RPC choisi dans la fenêtre Wallets ne modifie ni le profil actif global ni le store wallet actif ; il borne uniquement les lectures on-chain de cette fenêtre.
### 10.1 Répertoires opérateur
La convention du desktop est :
```text
wallets/
<alias>.kswallet
temporary/<profil>/...
data/wallets/
<exports secrets explicites>
```
`wallets/` est la racine persistante native. `wallets/temporary/**` appartient aux fixtures/keypairs historiques. `data/wallets/` contient les exports explicites destinés à des outils externes et ne doit pas être rescanné automatiquement comme store natif.
### 10.2 Validation du changement de mot de passe
Le changement de mot de passe n'est volontairement pas exposé dans le frontend. La crate `ks-wallet-demo-scenarios` valide ce cycle comme consommateur externe de l'API publique :
```text
A -> B
A rejeté
B ouvre et signe
B -> A
A ouvre et signe
```
Le test utilise un `.kswallet` synthétique dans un répertoire temporaire privé et ne modifie aucun wallet réel de l'opérateur.
## 11. Non-divulgation
Ne jamais placer un secret wallet dans :
- `wallet.config.json` ;
- `KS_PUBLIC_*` ou `KB_PUBLIC_*` ;
- un payload Tauri ;
- un DTO TS-RS généraliste ;
- un log ;
- un message d'erreur normal ;
- un `Debug` automatique d'un type sensible.
Les chemins locaux ne sont pas des secrets cryptographiques, mais ils restent des informations internes et ne doivent pas apparaître inutilement dans les logs, erreurs et DTO fonctionnels.
## 12. Modèle de menace borné
`0.5.2` protège le secret persistant contre la lecture directe du fichier sans mot de passe et impose des permissions privées ainsi qu'un chiffrement authentifié.
Cette version ne prétend pas protéger contre :
- une machine déjà compromise pendant qu'un wallet est déverrouillé ;
- un processus disposant des mêmes droits utilisateur et capable de lire la mémoire ;
- la saisie volontaire du mot de passe dans un programme malveillant ;
- la copie volontaire d'un `.kswallet` et de son mot de passe vers une autre installation compatible ;
- hardware wallet, Ledger, KMS ou HSM.
## 13. Références
- [`../../ks-wallet/README.md`](../../ks-wallet/README.md)
- [`../../ks-wallet/USAGE.md`](../../ks-wallet/USAGE.md)
- [`../../ks-wallet-demo-scenarios/README.md`](../../ks-wallet-demo-scenarios/README.md)
- [`../NATIVE_FORMAT.md`](../NATIVE_FORMAT.md)
- [`../WALLET_FORMAT_COMPATIBILITY.md`](../WALLET_FORMAT_COMPATIBILITY.md)
- [`../validation/V0_5_2_WALLET_VALIDATION_REPORT.md`](../validation/V0_5_2_WALLET_VALIDATION_REPORT.md)

View File

@@ -0,0 +1,185 @@
<!-- file: docs/validation/V0_5_2_WALLET_VALIDATION_REPORT.md -->
<!-- version: 2 -->
# Validation `ks-wallet` — clôture 0.5.2
## 1. Périmètre
`0.5.2` transforme `ks-wallet` en frontière Solana réutilisable pour :
- wallets temporaires en mémoire ;
- plusieurs wallets persistants accessibles par alias ;
- conteneur natif `.kswallet` binaire, versionné et protégé par mot de passe ;
- capacité de signature sans exposition des bytes privés ;
- migration/inspection legacy ;
- import/export Solana CLI JSON et Base58 ;
- sélection non sensible depuis `ks-config` ;
- validation intégrée indépendante de Tauri via `ks-wallet-demo-scenarios` ;
- intégration opérateur desktop via DTO applicatifs sûrs.
La version ne transforme pas `ks-wallet` en client RPC et ne migre pas en masse les keypairs de fixtures sous `wallets/temporary/**`.
## 2. Organisation des données
La séparation validée est :
```text
wallets/
<alias>.kswallet
temporary/<profil>/...
data/wallets/
<exports JSON/Base58 explicites>
```
- `wallets/` : store natif persistant ;
- `wallets/temporary/**` : fixtures/keypairs historiques ou jetables ;
- `data/wallets/` : exports secrets explicites destinés à des outils externes.
Le desktop n'utilise pas `data/wallets/` comme store natif automatique.
## 3. Format natif et sécurité
Le format v1 validé utilise :
| Contrat | Valeur |
|-------------------|------------------------------------|
| Extension | `.kswallet` |
| Magic | `KSWALLET` |
| KDF | Argon2id v19 |
| Profil par défaut | 64 MiB / 3 passes / 4 lanes |
| AEAD | XChaCha20-Poly1305 |
| Sel | 16 octets |
| Nonce | 24 octets |
| Plaintext | keypair Solana exacte de 64 octets |
| Ciphertext + tag | 80 octets |
| AAD | header + alias + sel + nonce |
| Répertoire Unix | `0700` |
| Fichier Unix | `0600` |
Le codec rejette versions/algorithmes inconnus, réserves non nulles, troncatures, suffixes, longueurs incorrectes et paramètres KDF hors bornes. La pubkey du header n'est considérée authentifiée qu'après déchiffrement et comparaison avec la pubkey réellement dérivée du keypair.
La prerelease de clôture retire également les chemins locaux inutiles du `Debug`, des logs et des erreurs du `TemporaryWalletStore` legacy et ajoute un canari externe de non-divulgation.
## 4. Cycle de vie du mot de passe
Les surfaces validées comprennent :
- création native ;
- unlock par alias ;
- unlock d'un fichier externe inspecté explicitement ;
- signature avec `UnlockedWallet` ;
- `lock()` par consommation ;
- changement de mot de passe avec conservation exacte de l'alias/pubkey ;
- refus de l'ancien mot de passe ;
- altération des données authentifiées refusée avant capacité de signature ;
- refus d'écrasement natif ;
- test concurrent de création d'un même alias avec un seul gagnant et une destination valide.
`ks-wallet-demo-scenarios` valide le cycle ordonné suivant dans un seul test indépendant de Tauri :
```text
A -> B
A doit échouer
B ouvre et signe
B -> A
A restauré ouvre et signe
```
La fixture est synthétique et temporaire ; aucun wallet réel de l'opérateur n'est modifié.
## 5. Migration et transferts
Les tests externes valident :
- migration legacy `<alias>.json` non destructive ;
- conservation exacte de la pubkey ;
- inspection d'un fichier de transfert sans import ;
- import/export `SolanaCliJson` ;
- import/export `SolanaPrivateKeyBase58` ;
- refus des sources invalides ;
- collision de pubkey ;
- export impossible avec un mauvais mot de passe ;
- permissions privées ;
- absence d'écrasement silencieux.
Aucune recovery phrase n'est synthétisée depuis une keypair arbitraire.
La validation opérateur a confirmé les exports :
```text
data/wallets/local-devnet-operator2.json
data/wallets/local-devnet-operator2.txt
```
## 6. Configuration et signer Devnet
`wallet.config.json` sépare `wallets_directory` de `profile.directory` :
```text
wallet_dir = wallets
temporary_wallet_dir = wallets/temporary/<profil>
```
Un profil peut définir `wallet_alias`, sans mot de passe. Le desktop peut aussi définir un override session-only par profil Devnet. La résolution effective est runtime override -> alias configuré -> temporaire seulement lorsqu'aucun alias persistant n'est sélectionné.
La validation opérateur a confirmé que les démos Devnet utilisent bien le `.kswallet` sélectionné avec une trace `persistence="persistent"`, au lieu du JSON temporaire.
## 7. Desktop Wallets
La fenêtre Wallets couvre : inventaire, création, inspection externe, inspection/import de keypairs, export borné sous `data/wallets/`, sélection de profil RPC, balance SOL, comptes SPL Token/Token-2022, signatures récentes, détail de transaction et sélection session-only du wallet d'exécution.
Les secrets restent backend-only via `KB_SECRET_DEMO_WALLET_PASSWORD`; aucun password n'entre dans HTML, TypeScript ou les DTO Tauri.
## 8. Validation workspace — base `0.5.2-pre.006 + fix-010`
L'opérateur a validé :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --all-targets
python3 scripts/audit_rust_workspace_rules.py
cargo test --workspace
```
Résultats :
- `cargo check --workspace` : succès ;
- `cargo clippy --all-targets` : succès sans warning ;
- audit Rust général : clean ;
- export completeness : `0 candidate(s)` ;
- audit Khadhroony workspace : clean ;
- `cargo test --workspace` : succès sur toutes les crates et doc-tests ;
- `kb-app-demo-desktop` : 185 tests ;
- `ks-config` : 35 tests ;
- `ks-lib` : 606 tests ;
- `ks-logging` : 25 tests ;
- `ks-onchain-transport` : 124 tests ;
- `ks-pipeline` : 109 tests ;
- `ks-pipeline-demo-scenarios` : 109 tests + 2 tests CLI ;
- `ks-program-ids` : 6 tests ;
- `ks-store` : 84 tests ;
- `ks-wallet` : 22 unitaires + 7 legacy + 3 password natif + 2 API publique + 6 transfert ;
- `ks-wallet-demo-scenarios` : 1 test d'intégration password ;
- doc-tests : succès.
La `pre.007` ajoute seulement les canaris de non-divulgation legacy, le test concurrent natif et la clôture documentaire ; elle doit donc être rejouée avec la campagne standard avant le passage à `0.5.2` final.
## 9. Reports explicites
### `0.5.4`
- diagnostiquer/réparer la régression `unable to read configured Token-2022 fixture` observée après la séparation des racines wallet/fixtures ;
- scanner/inventorier bornément `wallets/temporary/**` ;
- extraire format/validité/pubkey sans inventer de rôle métier ;
- migrer sélectivement les signers devant devenir persistants ;
- laisser toute classification on-chain au consommateur, sans dépendance `ks-wallet -> ks-onchain-transport`.
### Version ultérieure non déterminée
- nouveaux formats Backpack, Trust Wallet, Solflare Keystore ou autres uniquement lorsqu'un wire suffisamment spécifié peut être validé et testé.
## 10. Statut
**Base fonctionnelle `0.5.2-pre.006 + fix-010` validée. `0.5.2-pre.007` est la prerelease de clôture à valider avant la release finale `0.5.2`.**

View File

@@ -1,11 +1,10 @@
<!-- file: kb-app-demo-desktop/TODO.md -->
<!-- version: 19 -->
<!-- version: 20 -->
# TODO — kb-app-demo-desktop
## Évolutions générales
- [ ] `0.5.2` — valider sur Devnet la sélection session-only dun `.kswallet` dans `demo_wallet`, confirmer `persistence="persistent"` dans les logs puis retrouver les signatures produites depuis lexplorateur.
- [ ] `0.5.4` — réduire les panneaux d'exécution à l'adaptation UI/Tauri en déplaçant toute orchestration de campagne encore réutilisable vers `ks-pipeline-demo-scenarios`.
- [ ] UX — empêcher les doubles déclenchements pendant une préparation, simulation ou soumission active.
- [ ] Observabilité — afficher explicitement les comptes relus et les projections matérialisées.

View File

@@ -1,10 +1,11 @@
<!-- file: ks-pipeline-demo-scenarios/TODO.md -->
<!-- version: 45 -->
<!-- version: 46 -->
# TODO — ks-pipeline-demo-scenarios
## Évolutions générales
- [ ] `0.5.4` — diagnostiquer et corriger la régression `unable to read configured Token-2022 fixture` observée dans `demo_execution_spl_token_2022` après séparation des répertoires persistants et temporaires ; réconcilier le chargement de fixtures avec `temporary_wallet_dir`.
- [ ] `0.5.4` — inventorier/classifier les keypairs de fixtures historiques sous `wallets/temporary/**` et préparer leur migration sélective lorsque leur rôle doit devenir persistant.
- [ ] `0.5.4` — centraliser les dispatchs, compositions decoder/materializer et critères de complétion encore réutilisables depuis le desktop.
- [ ] `0.5.4` — produire la matrice active decoder/materializer/executor/scénario/preuve sans transformer les surfaces réservées en dettes implicites.

View File

@@ -1,8 +1,13 @@
<!-- file: ks-wallet-demo-scenarios/CHANGELOG.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# CHANGELOG — ks-wallet-demo-scenarios
## `0.5.2-pre.007`
- clôt le scénario password `0.5.2` après validation workspace complète ;
- conserve la crate indépendante de Tauri et reporte les futurs scénarios d'import/export/migration aux versions qui ajouteront effectivement de nouveaux formats ou besoins de preuve.
## `0.5.2-pre.006-delta-fix-010`
- crée la crate réutilisable `ks-wallet-demo-scenarios` sans dépendance vers Tauri ou le desktop ;

View File

@@ -1,5 +1,5 @@
<!-- file: ks-wallet-demo-scenarios/README.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# ks-wallet-demo-scenarios
@@ -9,7 +9,7 @@
La crate nimplémente ni stockage de secret, ni chiffrement, ni codec `.kswallet`. Elle dépend uniquement de lAPI publique de `ks-wallet` et orchestre des séquences vérifiables autour des invariants wallet.
La première surface couvre le cycle de mot de passe natif :
La surface validée en `0.5.2` couvre le cycle de mot de passe natif :
1. changement du mot de passe A vers B avec conservation de lidentité publique ;
2. vérification explicite que A est rejeté ;

View File

@@ -1,19 +1,11 @@
<!-- file: ks-wallet-demo-scenarios/TODO.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# TODO — ks-wallet-demo-scenarios
## `0.5.2`
## Versions ultérieures
- [x] créer une crate de scénarios indépendante de Tauri et consommatrice exclusive de lAPI publique `ks-wallet` ;
- [x] ajouter une étape réutilisable de rotation de mot de passe avec conservation stricte de lalias et de la pubkey ;
- [x] ajouter une étape qui exige le rejet de lancien mot de passe par le code dauthentification natif attendu ;
- [x] ajouter une étape douverture authentifiée et de signature dun challenge non vide ;
- [x] composer un test externe ordonné A → B → rejet de A → ouverture/signature avec B → B → A → ouverture/signature avec A restauré.
## Version ultérieure non déterminée
- [ ] ajouter des scénarios de round-trip pour chaque nouveau format dimport/export supporté par `ks-wallet` ;
- [ ] ajouter des scénarios de round-trip pour chaque nouveau format d'import/export supporté par `ks-wallet` lorsque cela apporte une preuve distincte des tests de codec ;
- [ ] ajouter des scénarios de migration legacy vers `.kswallet` lorsque plusieurs formats sources doivent être comparés ;
- [ ] ajouter des scénarios douverture explicite hors store si une validation opérateur supplémentaire devient utile ;
- [ ] najouter une CLI que si une validation manuelle hors tests apporte une valeur distincte des consommateurs existants.
- [ ] ajouter des scénarios d'ouverture explicite hors store si une validation opérateur supplémentaire devient utile ;
- [ ] n'ajouter une CLI que si une validation manuelle hors tests apporte une valeur distincte des consommateurs existants.

View File

@@ -1,5 +1,5 @@
<!-- file: ks-wallet-demo-scenarios/USAGE.md -->
<!-- version: 1 -->
<!-- version: 2 -->
# Utilisation de ks-wallet-demo-scenarios

View File

@@ -1,8 +1,15 @@
<!-- file: ks-wallet/CHANGELOG.md -->
<!-- version: 20 -->
<!-- version: 21 -->
# CHANGELOG — ks-wallet
## `0.5.2-pre.007`
- retire les chemins locaux inutiles du `Debug`, des logs et des erreurs du `TemporaryWalletStore` legacy tout en conservant les getters explicites nécessaires aux fixtures ;
- ajoute un canari externe garantissant que les erreurs/`Debug` legacy ne divulguent pas le répertoire local ;
- ajoute un test concurrent de création native confirmant qu'un seul créateur publie un alias et que la destination `.kswallet` reste valide ;
- clôt la documentation `0.5.2`, archive le plan de version et reporte explicitement l'inventaire de `wallets/temporary/**` à `0.5.4`.
## `0.5.2-pre.006-delta-fix-004`
- ajoute `WalletTransferFormat::supported()`, `code()`, `label()` et `default_extension()` afin que les consommateurs puissent présenter exactement les formats réellement compilés ;

View File

@@ -1,13 +1,13 @@
<!-- file: ks-wallet/README.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# ks-wallet
`ks-wallet` fournit la frontière wallet Solana générale du workspace Khadhroony.
## État actuel
## Contrat `0.5.2`
En `0.5.2-pre.005`, la crate sait en plus migrer sans destruction un legacy Solana JSON, importer/exporter le format Solana CLI JSON et transférer un keypair complet via le format privé Base58 utilisé comme adaptateur tiers de référence pour Phantom. La dérivation Argon2id et le chiffrement authentifié XChaCha20-Poly1305 restent la protection du conteneur natif `.kswallet`.
`ks-wallet` constitue la frontière générale de stockage, authentification et signature des wallets Solana du workspace. Le format persistant recommandé est `.kswallet`; le JSON Solana historique reste une compatibilité legacy et une source d'import.
La crate fournit actuellement :
@@ -40,25 +40,11 @@ La crate fournit actuellement :
La persistance legacy écrit encore directement le contenu dans le chemin final : elle n'est pas une publication atomique crash-safe par fichier temporaire + renommage.
## Cible `0.5.2`
## Format natif et compatibilité
`ks-wallet` doit devenir capable de :
Le format `.kswallet` utilise Argon2id v19 pour la dérivation depuis le mot de passe et XChaCha20-Poly1305 pour le chiffrement authentifié. Le layout normatif est documenté dans [`../docs/NATIVE_FORMAT.md`](../docs/NATIVE_FORMAT.md). Le payload secret v1 est exactement la keypair Solana brute de 64 octets ; le header, l'alias, le sel et le nonce sont authentifiés comme AAD avant qu'une capacité `UnlockedWallet` puisse être produite. Changer le mot de passe ne change jamais la keypair/pubkey.
- découvrir dans le store les fichiers `<alias>.kswallet` valides et gérer plusieurs wallets persistants accessibles par alias ;
- conserver des wallets temporaires/jetables pour tests et scénarios ;
- stocker les wallets persistants dans un format natif binaire `<alias>.kswallet` ;
- protéger chaque wallet persistant par un mot de passe modifiable ;
- fournir une capacité de signature sans exposer les bytes privés ;
- importer le format legacy et d'autres formats explicitement supportés ;
- exporter volontairement vers des formats externes supportés ;
- exiger un mot de passe valide pour tout export contenant le secret ;
- préserver exactement la même keypair lors d'un changement de mot de passe ;
- importer et exporter obligatoirement le format keypair JSON des binaires Solana ;
- documenter les formats compatibles des principaux wallets Solana, implémenter un adaptateur tiers d'exemple et reporter les autres au TODO.
Le format `.kswallet` est propre à `ks-wallet`, mais sa protection cryptographique utilise des primitives établies : Argon2id v19 pour la dérivation depuis le mot de passe et XChaCha20-Poly1305 pour le chiffrement authentifié. Le layout normatif est documenté dans [`../docs/NATIVE_FORMAT.md`](../docs/NATIVE_FORMAT.md). Le payload secret v1 est exactement la keypair Solana brute de 64 octets ; avec le tag AEAD, le ciphertext est fixé à 80 octets. Le header, l'alias, le sel et le nonce sont authentifiés comme AAD avant qu'une capacité `UnlockedWallet` puisse être produite. Changer le mot de passe ne change jamais la keypair : une modification réelle du secret Ed25519 produirait une autre pubkey et donc un autre wallet. Le changement du mot de passe reprotège le fichier persistant ; il ne révoque pas une capacité `UnlockedWallet` déjà détenue par un consommateur, qui doit être explicitement `lock()`/dropée selon son propre cycle de vie.
Le scan automatique reste strictement borné au répertoire fourni à `WalletManager`. Un programme peut néanmoins demander l'inspection d'un autre fichier `.kswallet` choisi explicitement, par exemple via un file browser desktop, puis l'ouvrir avec `unlock_file()` et le mot de passe fourni. Ces opérations ne modifient pas le store et ne rendent pas le chemin public.
Le scan automatique reste strictement borné au répertoire fourni à `WalletManager`. Un programme peut inspecter explicitement un autre `.kswallet` puis l'ouvrir avec `unlock_file()` sans modifier le store. Les erreurs, logs et `Debug` du store JSON legacy ne projettent plus ses chemins locaux.
## Relations
@@ -77,5 +63,6 @@ Une application desktop doit projeter les informations autorisées dans ses prop
- [USAGE.md](USAGE.md)
- [TODO.md](TODO.md)
- [CHANGELOG.md](CHANGELOG.md)
- [plan temporaire `0.5.2`](../docs/plans/V0_5_2_KS_WALLET_RESTRUCTURING_PLAN.md)
- [Guide wallets](../docs/guides/WALLETS.md)
- [Rapport de validation 0.5.2](../docs/validation/V0_5_2_WALLET_VALIDATION_REPORT.md)
- [ROADMAP général](../ROADMAP.md)

View File

@@ -1,47 +1,19 @@
<!-- file: ks-wallet/TODO.md -->
<!-- version: 15 -->
<!-- version: 16 -->
# TODO — ks-wallet
## `0.5.2`
## `0.5.4` — réconciliation des keypairs de fixtures
- [x] caractériser par tests externes le format legacy `<alias>.json`, ses erreurs et ses permissions.
- [x] définir l'identité publique minimale d'un wallet et le lookup par alias.
- [x] introduire le manager, le scan borné et le lookup des `.kswallet` structurellement valides dans le store résolu.
- [x] conserver les wallets temporaires ou jetables purement en mémoire et leur frontière de signature actuelle.
- [x] permettre l'inspection explicite d'un `.kswallet` hors store sans mutation de la configuration ni exposition publique du chemin.
- [x] spécifier le format natif binaire v1 `<alias>.kswallet` et implémenter son décodage/validation stricts pour le scan.
- [x] `0.5.2-pre.004` — implémenter l'encodage de création et la publication atomique/no-clobber du conteneur natif.
- [x] sélectionner et documenter Argon2id v19 / XChaCha20-Poly1305 et leurs paramètres/bornes v1.
- [x] créer/ouvrir un wallet persistant avec mot de passe sans exposer les bytes privés.
- [x] permettre le changement de mot de passe en rechiffrant exactement la même keypair et donc en conservant la même pubkey.
- [x] préserver la frontière `solana_signer::Signer` compatible avec les consommateurs sans dépendance de `ks-lib` vers `ks-wallet`.
- [x] fournir cette même capacité depuis un wallet natif ouvert par mot de passe.
- [x] importer le legacy Solana JSON vers `.kswallet` avec écriture atomique, rollback et vérification de pubkey.
- [x] importer et exporter le format keypair JSON standard des binaires Solana.
- [x] produire une matrice documentée des formats Phantom, Solflare, Backpack, Trust Wallet, Coinbase/Base et autres wallets Solana pertinents.
- [x] implémenter dans `0.5.2` un seul adaptateur wallet tiers d'exemple : Base58 du keypair Solana complet, avec Phantom comme cible de référence documentée.
- [x] reporter les autres adaptateurs tiers faisables vers une version ultérieure non déterminée après validation de la matrice.
- [x] ne jamais synthétiser une recovery phrase supposée préserver une keypair arbitraire sans mnemonic/seed d'origine.
- [x] exiger le mot de passe valide pour tout export contenant le secret.
- [x] définir les collisions d'alias et de pubkey sans écrasement silencieux.
- [x] normaliser la sélection par alias dans `ks-config` sans secret.
- [x] adapter les consommateurs et le desktop uniquement via des surfaces non sensibles.
- [ ] retirer secrets et chemins locaux inutiles des logs, erreurs, diagnostics et DTO.
- [x] compléter les tests `pre.005` de migration non destructive, round-trip Solana CLI JSON/Base58, permissions privées, refus d'écrasement, collision de pubkey et export refusé avec mauvais mot de passe ; les tests de concurrence restent à réconcilier dans la finalisation selon les surfaces réellement utilisées.
- [ ] produire le guide de sécurité et la documentation finale avant clôture de `0.5.2`.
## Version ultérieure non déterminée — migration des keypairs de fixtures
- [ ] inventorier et classifier non destructivement les fichiers keypair JSON sous `wallets/temporary/**` avant toute conversion de masse : distinguer wallets/signers, autorités, mints, recipients et autres keypairs de fixtures ;
- [ ] proposer une migration sélective des seuls signers devant devenir persistants vers `.kswallet`, en préservant les fichiers JSON sources et les pubkeys ;
- [x] permettre l'inspection explicite d'un fichier keypair legacy compatible et l'extraction de sa pubkey publique sans conversion préalable en `.kswallet`.
- [ ] ajouter un scanner borné de répertoire pour inventorier plusieurs candidats legacy avant migration, sans conversion automatique ni classification métier inventée à partir du secret seul.
- [ ] ajouter un scanner borné de répertoire pour inventorier plusieurs candidats legacy sous `wallets/temporary/**`, sans conversion automatique ;
- [ ] produire uniquement des faits locaux vérifiables : format supporté/non supporté, keypair valide/invalide et pubkey lorsqu'elle est dérivable ;
- [ ] proposer une migration sélective des seuls signers devant devenir persistants vers `.kswallet`, en préservant les sources et les pubkeys ;
- [ ] laisser toute classification on-chain ou métier au consommateur/scénario, sans dépendance `ks-wallet -> ks-onchain-transport`.
## Version ultérieure non déterminée — adaptateurs de transfert
- [ ] caractériser le wire Solana exact accepté par l'import `Private key` de Backpack avant d'ajouter un codec de marque ou un alias de format.
- [ ] caractériser le wire d'import Solana de Trust Wallet depuis une documentation suffisamment précise avant implémentation.
- [ ] caractériser le format keystore Solflare et son mot de passe uniquement si son conteneur public est suffisamment stable et spécifié pour un round-trip testé.
- [ ] réévaluer Base app / ex-Coinbase Wallet si une documentation officielle expose un import direct de keypair Solana arbitraire ; ne jamais synthétiser une recovery phrase.
- [ ] caractériser le wire Solana exact accepté par l'import `Private key` de Backpack avant d'ajouter un codec de marque ou un alias de format ;
- [ ] caractériser le wire d'import Solana de Trust Wallet depuis une documentation suffisamment précise avant implémentation ;
- [ ] caractériser le format keystore Solflare et son mot de passe uniquement si son conteneur public est suffisamment stable et spécifié pour un round-trip testé ;
- [ ] réévaluer Base app / ex-Coinbase Wallet si une documentation officielle expose un import direct de keypair Solana arbitraire ; ne jamais synthétiser une recovery phrase ;
- [ ] ajouter d'autres adaptateurs wallets uniquement à partir d'un format secret officiellement documenté, strictement validable et testable.

View File

@@ -1,11 +1,11 @@
<!-- file: ks-wallet/USAGE.md -->
<!-- version: 13 -->
<!-- version: 14 -->
# Utilisation de ks-wallet
## Statut
En `0.5.2-pre.005`, le manager couvre aussi la migration non destructive du legacy, l'import/export du keypair JSON Solana CLI et le transfert Base58 d'une keypair Solana complète. Tout export secret repart d'un `.kswallet` authentifié avec son mot de passe.
Depuis `0.5.2`, le manager couvre la persistance native protégée, la migration non destructive du legacy, l'inspection de fichiers de transfert, l'import/export Solana CLI JSON et Base58, ainsi que le changement de mot de passe sans changement de pubkey. Tout export secret repart d'un `.kswallet` authentifié avec son mot de passe.
## Valider un alias
@@ -494,3 +494,13 @@ Phantom est la cible tierce de référence du Base58 et Solflare documente l'imp
- vérification des permissions Unix privées.
`pre.003` ajoute le décodage/validation v1 stricts et les bornes KDF/fichier. `pre.004` ajoute l'encodage, la publication atomique, le password, la dérivation/chiffrement effectifs, l'ouverture authentifiée et le changement de password. `pre.005` ajoute la migration legacy, les deux formats de transfert testés, les collisions d'alias/pubkey et la matrice de compatibilité. La tranche suivante couvre la configuration et les consommateurs.
## Validation réutilisable du mot de passe
La crate sœur `ks-wallet-demo-scenarios` valide le cycle A → B → rejet de A → ouverture/signature avec B → restauration B → A sans Tauri et sans toucher aux wallets réels de l'opérateur :
```bash
cargo test -p ks-wallet-demo-scenarios
```
Le guide opérationnel complet est [`../docs/guides/WALLETS.md`](../docs/guides/WALLETS.md).

View File

@@ -1,5 +1,5 @@
// file: ks-wallet/src/wallet.rs
// version: 11
// version: 12
//! Local wallet storage and signing primitives.
@@ -158,11 +158,17 @@ impl crate::TemporaryWallet {
}
/// Filesystem-backed store for development and integration-test wallets.
#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(Clone, Eq, PartialEq)]
pub struct TemporaryWalletStore {
directory: std::path::PathBuf,
}
impl std::fmt::Debug for crate::TemporaryWalletStore {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
return formatter.debug_struct("TemporaryWalletStore").finish();
}
}
impl crate::TemporaryWalletStore {
/// Creates a wallet store rooted at the supplied directory.
pub fn new(directory: impl std::convert::Into<std::path::PathBuf>) -> ks_core::Result<Self> {
@@ -193,7 +199,7 @@ impl crate::TemporaryWalletStore {
std::result::Result::Ok(exists) => std::result::Result::Ok(exists),
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
"wallet_file_exists_check_failed",
format!("{}: {error}", path.display()),
error.to_string(),
)),
};
}
@@ -218,7 +224,6 @@ impl crate::TemporaryWalletStore {
action = "create_temporary_wallet",
wallet_alias = alias.as_str(),
public_key = %keypair.pubkey(),
wallet_path = %path.display(),
"created persistent temporary wallet"
);
return std::result::Result::Ok(crate::TemporaryWallet {
@@ -240,7 +245,6 @@ impl crate::TemporaryWalletStore {
action = "load_temporary_wallet",
wallet_alias = alias.as_str(),
public_key = %keypair.pubkey(),
wallet_path = %path.display(),
"loaded persistent temporary wallet"
);
return std::result::Result::Ok(crate::TemporaryWallet {
@@ -279,7 +283,7 @@ async fn prepare_wallet_directory(directory: &std::path::Path) -> ks_core::Resul
std::result::Result::Err(error) => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_directory_create_failed",
format!("{}: {error}", directory.display()),
error.to_string(),
));
},
}
@@ -292,7 +296,7 @@ async fn prepare_wallet_directory(directory: &std::path::Path) -> ks_core::Resul
std::result::Result::Err(error) => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_directory_permissions_failed",
format!("{}: {error}", directory.display()),
error.to_string(),
));
},
}
@@ -335,10 +339,7 @@ async fn write_new_keypair(
} else {
"wallet_file_create_failed"
};
return std::result::Result::Err(ks_core::Error::new(
code,
format!("{}: {error}", task_path.display()),
));
return std::result::Result::Err(ks_core::Error::new(code, error.to_string()));
},
};
if let std::result::Result::Err(error) = file.write_all(encoded.as_slice()) {
@@ -346,7 +347,7 @@ async fn write_new_keypair(
let _ = std::fs::remove_file(&task_path);
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_write_failed",
format!("{}: {error}", task_path.display()),
error.to_string(),
));
}
encoded.zeroize();
@@ -354,7 +355,7 @@ async fn write_new_keypair(
let _ = std::fs::remove_file(&task_path);
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_sync_failed",
format!("{}: {error}", task_path.display()),
error.to_string(),
));
}
return std::result::Result::Ok(());
@@ -364,7 +365,7 @@ async fn write_new_keypair(
std::result::Result::Ok(result) => result,
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
"wallet_file_task_failed",
format!("{}: {error}", path.display()),
error.to_string(),
)),
};
}
@@ -379,7 +380,7 @@ async fn read_keypair(path: &std::path::Path) -> ks_core::Result<solana_keypair:
std::result::Result::Err(error) => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_read_failed",
format!("{}: {error}", path.display()),
error.to_string(),
));
},
};
@@ -390,7 +391,7 @@ async fn read_keypair(path: &std::path::Path) -> ks_core::Result<solana_keypair:
std::result::Result::Err(error) => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_keypair_json_invalid",
format!("{}: {error}", path.display()),
error.to_string(),
));
},
};
@@ -400,8 +401,7 @@ async fn read_keypair(path: &std::path::Path) -> ks_core::Result<solana_keypair:
return std::result::Result::Err(ks_core::Error::new(
"wallet_keypair_length_invalid",
format!(
"{} contains {length} bytes instead of {}",
path.display(),
"wallet keypair contains {length} bytes instead of {}",
crate::SOLANA_KEYPAIR_LENGTH
),
));
@@ -412,7 +412,7 @@ async fn read_keypair(path: &std::path::Path) -> ks_core::Result<solana_keypair:
std::result::Result::Ok(keypair) => std::result::Result::Ok(keypair),
std::result::Result::Err(error) => std::result::Result::Err(ks_core::Error::new(
"wallet_keypair_invalid",
format!("{}: {error}", path.display()),
error.to_string(),
)),
};
}
@@ -423,14 +423,14 @@ async fn validate_wallet_file_metadata(path: &std::path::Path) -> ks_core::Resul
std::result::Result::Err(error) => {
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_metadata_failed",
format!("{}: {error}", path.display()),
error.to_string(),
));
},
};
if metadata.file_type().is_symlink() || !metadata.is_file() {
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_type_invalid",
format!("{} must be a regular file and not a symlink", path.display()),
"wallet file must be a regular file and not a symlink",
));
}
#[cfg(unix)]
@@ -440,7 +440,7 @@ async fn validate_wallet_file_metadata(path: &std::path::Path) -> ks_core::Resul
if mode & 0o077 != 0 {
return std::result::Result::Err(ks_core::Error::new(
"wallet_file_permissions_too_open",
format!("{} has mode {mode:o}; expected no group or other access", path.display()),
format!("wallet file has mode {mode:o}; expected no group or other access"),
));
}
}

View File

@@ -1,5 +1,5 @@
// file: ks-wallet/tests/legacy_characterization.rs
// version: 1
// version: 2
//! External characterization tests for the legacy Solana JSON wallet format.
@@ -69,6 +69,31 @@ async fn legacy_missing_file_preserves_current_error_contract() {
assert_eq!(error.code(), "wallet_file_metadata_failed");
}
#[tokio::test]
async fn legacy_errors_and_debug_do_not_disclose_local_path() {
let directory = tempfile::tempdir()
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
let canary_directory = directory.path().join("wallet-path-canary");
std::fs::create_dir_all(&canary_directory)
.unwrap_or_else(|error| panic!("canary directory must be created: {error}"));
let store = ks_wallet::TemporaryWalletStore::new(&canary_directory)
.unwrap_or_else(|error| panic!("unexpected store error: {error}"));
let debug = format!("{store:?}");
assert!(!debug.contains("wallet-path-canary"));
assert!(!debug.contains(canary_directory.to_string_lossy().as_ref()));
let alias = ks_wallet::WalletAlias::parse("missing-canary")
.unwrap_or_else(|error| panic!("unexpected alias error: {error}"));
let error = store
.load(alias)
.await
.err()
.unwrap_or_else(|| panic!("missing legacy wallet must fail"));
let message = error.to_string();
assert_eq!(error.code(), "wallet_file_metadata_failed");
assert!(!message.contains("wallet-path-canary"));
assert!(!message.contains(canary_directory.to_string_lossy().as_ref()));
}
#[tokio::test]
async fn legacy_corrupted_json_and_short_keypair_are_distinct() {
let directory = tempfile::tempdir()

View File

@@ -1,5 +1,5 @@
// file: ks-wallet/tests/native_password.rs
// version: 1
// version: 2
//! External password-protected native wallet lifecycle tests.
@@ -137,6 +137,45 @@ async fn native_creation_is_private_and_refuses_overwrite() {
assert_eq!(handle.public_key(), public_key);
}
#[tokio::test]
async fn concurrent_native_creation_has_one_winner_and_preserves_valid_destination() {
let directory = tempfile::tempdir()
.unwrap_or_else(|error| panic!("temporary directory must exist: {error}"));
make_directory_private(directory.path());
let left_manager = ks_wallet::WalletManager::new(directory.path())
.unwrap_or_else(|error| panic!("left manager must be created: {error}"));
let right_manager = ks_wallet::WalletManager::new(directory.path())
.unwrap_or_else(|error| panic!("right manager must be created: {error}"));
let alias = ks_wallet::WalletAlias::parse("concurrent-create")
.unwrap_or_else(|error| panic!("alias must be valid: {error}"));
let left_alias = alias.clone();
let right_alias = alias.clone();
let left = left_manager.create(left_alias, password("left-password"));
let right = right_manager.create(right_alias, password("right-password"));
let (left_result, right_result) = tokio::join!(left, right);
let (winner, loser_error) = match (left_result, right_result) {
(std::result::Result::Ok(wallet), std::result::Result::Err(error)) => (wallet, error),
(std::result::Result::Err(error), std::result::Result::Ok(wallet)) => (wallet, error),
(std::result::Result::Ok(_), std::result::Result::Ok(_)) => {
panic!("concurrent creation must not publish two wallets for one alias");
},
(std::result::Result::Err(_), std::result::Result::Err(_)) => {
panic!("exactly one concurrent creation must succeed");
},
};
assert_eq!(loser_error.code(), "wallet_native_already_exists");
let public_key = winner.public_key();
winner.lock();
let verifier = ks_wallet::WalletManager::new(directory.path())
.unwrap_or_else(|error| panic!("verification manager must be created: {error}"));
let handle = verifier
.lookup(&alias)
.await
.unwrap_or_else(|error| panic!("published wallet lookup must succeed: {error}"))
.unwrap_or_else(|| panic!("published wallet must exist"));
assert_eq!(handle.public_key(), public_key);
}
#[tokio::test]
async fn authenticated_header_tampering_fails_before_signing_capability() {
let directory = tempfile::tempdir()

View File

@@ -1,5 +1,5 @@
<!-- file: olddocs/archivekbot3/001.README.md -->
<!-- version: 6 -->
<!-- version: 7 -->
# Archive documentaire de khadhroony-bot3
@@ -40,3 +40,7 @@ Le plan de fondation `0.5.0`, les audits `pre.002` et `pre.003` ainsi que le pro
## Clôture 0.5.1
Le plan de namespace/configuration `0.5.1` et le prompt de session `030` sont archivés sous `docs/plans/` et `prompts/`. Les décisions durables restent dans le ROADMAP, les guides de configuration, la politique de namespace et le rapport actif `docs/validation/V0_5_1_FOUNDATION_VALIDATION_REPORT.md`.
## Clôture 0.5.2
Le plan de restructuration `ks-wallet` `0.5.2` et le prompt de session `031` sont archivés sous `docs/plans/` et `prompts/`. Les décisions durables restent dans le ROADMAP, `docs/NATIVE_FORMAT.md`, `docs/WALLET_FORMAT_COMPATIBILITY.md`, `docs/guides/WALLETS.md` et le rapport actif `docs/validation/V0_5_2_WALLET_VALIDATION_REPORT.md`.

View File

@@ -153,10 +153,10 @@ Travail :
2. y reconstruire le miroir documentaire de bot2 en conservant les chemins relatifs : documents racine, `docs/`, `prompts/` et documents des anciennes crates ;
3. inclure les fichiers présentant une fonction documentaire démontrée, conformément à la politique de sélection, sans copier le code, les artefacts de build ou les données privées ;
4. appliquer [`decisions/DOCUMENT_ARCHIVE_SELECTION_POLICY.md`](decisions/DOCUMENT_ARCHIVE_SELECTION_POLICY.md) pour distinguer matrices, schémas, exemples et IDL documentaires des fixtures et configurations dexécution ;
4. créer `olddocs/archivekbot3/` ;
5. créer `docs/README.md` ;
6. créer larborescence utile sans fichiers factices ;
7. documenter la provenance, la non-normativité et lintégrité logique de larchive bot2.
5. créer `olddocs/archivekbot3/` ;
6. créer `docs/README.md` ;
7. créer larborescence utile sans fichiers factices ;
8. documenter la provenance, la non-normativité et lintégrité logique de larchive bot2.
Aucun document bot3 actif ne doit encore être supprimé.

View File

@@ -1,8 +1,8 @@
<!-- file: prompts/001.README.md -->
<!-- version: 5 -->
<!-- version: 6 -->
# Prompts actifs
Ce répertoire contient uniquement les prompts nécessaires aux prochaines versions fonctionnelles. Les prompts clôturés sont archivés sous `olddocs/archivekbot3/prompts/`.
- [`031_v0_5_2_ks_wallet_restructuring.md`](031_v0_5_2_ks_wallet_restructuring.md) : restructuration de `ks-wallet`, format persistant versionné, séparation identité/secret/signature, migration legacy et sécurité des futurs consommateurs.
- [`032_v0_5_3_ks_store_normalization.md`](032_v0_5_3_ks_store_normalization.md) : audit et normalisation de `ks-store`, temporalité/provenance/idempotence, migration `kb_sol_*` -> `k_sol_*` et préparation du stockage pour les futurs faits de trading.

View File

@@ -0,0 +1,392 @@
<!-- file: prompts/032_v0_5_3_ks_store_normalization.md -->
<!-- version: 4 -->
# Khadhroony Bot3 — `0.5.3` — audit et normalisation de `ks-store`
## Mission
Reprendre `khadhroony-bot3` après la clôture validée de `0.5.2` et auditer puis normaliser `ks-store` avant l'extension massive des décodages/matérialisations Solana et, à court terme, l'arrivée des surfaces Anchor/DEX nécessaires au trading. `ks-lib` reste généraliste : il doit pouvoir décoder et matérialiser le maximum de transactions, signatures, comptes et événements Solana issus de Program IDs multiples et évolutifs, qu'ils concernent le trading, les metadata, les tokens, le staking, l'administration, la conformité ou d'autres domaines.
`0.5.3` doit traiter comme un même chantier cohérent quatre objectifs structurants et leurs conséquences :
1. **renommer durablement les tables Solana** du préfixe historique `kb_sol_*` vers `k_sol_*` ;
2. **auditer puis figer le contrat structurel des tables existantes**, afin qu'une table déclarée stable ne doive plus recevoir ultérieurement de colonne oubliée, de changement de type, de nullabilité, de clé ou de sémantique ;
3. **mettre `ks-store` aux conventions du workspace** : frontières de modules, exports crate-root, DTO/models, erreurs, configuration, logging, tests, documentation et règles Rust ;
4. **rendre la frontière de stockage indépendante du moteur concret** : les autres crates consomment des contrats génériques de `ks-store` et ne doivent pas appeler les modules/fonctions PostgreSQL. `ks-store` reçoit la configuration du backend et possède seul la connexion, le routage et l'implémentation spécifique au moteur.
Ces quatre objectifs impliquent aussi l'audit des temporalités blockchain/persistance, de la provenance, de l'idempotence, des migrations, index et requêtes, ainsi que la préparation additive de faits canoniques Solana couvrant plusieurs domaines. Le trading est une priorité de court terme, pas la définition du périmètre de `ks-store`.
Cette version reste un chantier stockage. Elle ne doit pas ouvrir `0.5.4` sur la réconciliation générale des scénarios/exécuteurs, ni `0.6.x` sur Anchor, ni Meteora/Raydium/Pump/Orca/Jupiter.
## Base validée héritée de `0.5.2`
La base attendue possède notamment :
- onze crates Solana généralistes sous `ks-*` / `ks_*`, dont `ks-wallet-demo-scenarios`, plus `kb-app-demo-desktop` côté Bot ;
- `kb-app-demo-desktop` conservé côté Bot ;
- configuration spécialisée et composable, avec `KS_*` pour les contrats Solana et `KB_*` pour les contrats réellement applicatifs ;
- séparation source/runtime/public des données sensibles ;
- `ks-wallet` multi-wallet avec conteneur natif `.kswallet`, Argon2id + XChaCha20-Poly1305, sélection par alias, migration legacy, imports/exports secrets explicites et validation password réutilisable via `ks-wallet-demo-scenarios` ;
- `ks-lib` indépendant du stockage wallet et consommant uniquement une capacité `Signer` ;
- transport HTTP/WS généraliste dans `ks-onchain-transport` ;
- pipeline/replay/materialisation existants sur PostgreSQL via `ks-store` ;
- tables historiques encore préfixées `kb_sol_*`, volontairement laissées à `0.5.3` ;
- séparation entre faits Solana généralistes et futur domaine applicatif Bot.
Ne pas annuler les frontières de sécurité/configuration validées en `0.5.1`/`0.5.2` pour simplifier le stockage.
## Lectures obligatoires avant toute proposition
1. `README.md`, `ROADMAP.md`, `CHANGELOG.md`, `RULES.md` et ce prompt ;
2. toutes les règles actives sous `docs/rules/` ;
3. `docs/architecture/STORAGE_ARCHITECTURE.md`, `PIPELINE_ARCHITECTURE.md`, `ARCHITECTURE.md`, `CRATE_MAP.md` et `SURFACE_CRATE_MATRIX.md` ;
4. `ks-store/README.md`, `USAGE.md`, `TODO.md`, `CHANGELOG.md` et tout le code de `ks-store` ;
5. toutes les migrations SQL, constantes de noms de tables, repositories et requêtes ;
6. DTO persistés/relus par `ks-pipeline`, `kb-app-demo-desktop` et les tests d'API externe ;
7. scripts de validation, fixtures PostgreSQL, rapports Devnet/Mainnet et historiques de migrations pertinents ;
8. documents archivés `0.5.0`/`0.5.1` uniquement comme historique lorsque la décision actuelle n'est pas déjà portée par le ROADMAP ou l'architecture active.
Avant de renommer une table ou un champ, rechercher son usage dans tout le workspace, les migrations, requêtes, tests, fixtures, scripts et documentation.
## Principe de gel structurel des tables
`0.5.3` est la fenêtre prévue pour corriger **avant gel** les lacunes structurelles des tables déjà créées. L'exemple déjà identifié est l'absence de temps on-chain/block time là où cette information doit être conservée.
Pour chaque table existante, `0.5.3-pre.001` doit déterminer avant modification :
- son propriétaire fonctionnel et son rôle durable ;
- ses colonnes requises pour les usages actuels **et raisonnablement prévisibles** ;
- les temporalités nécessaires ;
- les clés primaires, étrangères, uniques et d'idempotence ;
- les types, nullabilités et unités ;
- la provenance nécessaire ;
- les besoins de replay et de rétention ;
- si elle doit être conservée, reconstruite, fusionnée, remplacée ou supprimée avant le gel.
Après clôture de `0.5.3`, une table marquée stable doit être considérée comme un **contrat append-only au niveau du schéma global** :
- pas d'ajout/suppression/renommage de colonne ;
- pas de changement de type ou de nullabilité ;
- pas de changement de clé primaire, clé étrangère ou contrainte métier ;
- pas de changement de sémantique d'une colonne existante.
Les nouvelles fonctionnalités doivent préférer **de nouvelles tables reliées aux contrats existants** plutôt qu'un remodelage d'une table gelée. Les objets physiques d'optimisation tels que les index doivent être distingués du contrat logique des tables dans le plan `pre.001`, et toute politique d'évolution après gel doit être explicitement documentée.
La règle ne signifie pas qu'il faut inventer toutes les tables futures : elle impose que chaque table déclarée stable ait été suffisamment auditée pour ne pas devoir être réparée fonctionnellement quelques versions plus tard.
## Première prerelease obligatoire : plan et audit
`0.5.3-pre.001` doit être un plan/brainstorm/audit. Elle ne doit pas commencer par renommer physiquement les tables.
Elle doit produire au minimum :
- inventaire exhaustif des tables et migrations actives ;
- inventaire des préfixes `kb_sol_*`, de leurs propriétaires et de leurs consommateurs ;
- matrice table -> DTO -> repository/query -> pipeline/desktop ;
- inventaire des colonnes temporelles et de leur sémantique réelle ;
- inventaire des champs de provenance, hash, version, processor, source/provider et états de traitement ;
- audit d'idempotence et des clés uniques ;
- audit des index existants versus requêtes réelles ;
- audit des limites/pagination et des conversions `u64` <-> PostgreSQL `BIGINT` ;
- classification des colonnes devant être corrigées **avant gel**, avec justification table par table ;
- matrice de gel structurel indiquant pour chaque table son état `à corriger`, `à remplacer`, `à supprimer` ou `stable/frozen` ;
- stratégie de migration/reconstruction des bases Devnet/Mainnet avant `0.6.x` ;
- stratégie explicite `kb_sol_* -> k_sol_*` ;
- audit des appels PostgreSQL hors `ks-store` et plan de suppression de toute dépendance backend-spécifique depuis les autres crates ;
- matrice API générique `DTO/model -> store contract -> backend implementation` ;
- stratégie de configuration du backend possédée par `ks-store` ;
- inventaire des domaines de faits Solana déjà matérialisés ou raisonnablement prévisibles : core/transactions, comptes et balances, token/SPL, metadata, lifecycle, staking, administration/autorités, audit/compliance, risques, programmes, trading/marchés et autres domaines justifiés par les Program IDs couverts ;
- identification des modèles canoniques suffisamment stables pour être créés de manière additive, sans supposer que tout doit entrer dans une table générique unique ;
- pour la priorité trading : pools de liquidité/AMM, order books si leur structure ne peut pas être unifiée proprement, marchés/paires, swaps/trades, liquidité, positions, réserves et séries temporelles ;
- matrice de normalisation `Program ID / source -> observation décodée -> matérialiseur -> DTO canonique -> table métier`, interdisant aux noms/champs spécifiques dun programme ou dun DEX de devenir par défaut le schéma public de stockage ;
- plan de prereleases borné jusqu'à la clôture `0.5.3` ;
- plan temporaire `docs/plans/V0_5_3_KS_STORE_NORMALIZATION_PLAN.md` à archiver dans la dernière prerelease.
Le plan doit être validé avant toute migration SQL massive.
## Temporalité à auditer explicitement
Ne pas utiliser un seul timestamp ambigu pour plusieurs concepts.
Distinguer selon les données réellement disponibles :
- `slot` ;
- `block_time` ou temps de transaction fourni par Solana ;
- temps d'observation/acquisition par le transport ;
- temps d'insertion en base ;
- temps de mise à jour/reprocessing ;
- temps éventuel de matérialisation.
Le plan doit dire pour chaque table quelles temporalités sont pertinentes, leur nullabilité et leur source de vérité.
Ne pas inventer un `block_time` lorsqu'il n'est pas présent dans la donnée canonique.
## Provenance
Chaque donnée persistée doit permettre de répondre, lorsque nécessaire, à :
- quelle transaction/signature/slot l'a produite ;
- quelle entrée canonique a été décodée ;
- quel décodeur/version a produit l'observation ;
- quel matérialiseur/version a produit le fait ;
- quel provider/transport a fourni la donnée brute lorsqu'il s'agit d'une donnée d'acquisition ;
- si le résultat est courant, supersédé, pending, failed ou replay-requested selon le domaine concerné.
Éviter de dupliquer la provenance dans toutes les tables si une relation canonique existante permet de la résoudre efficacement.
## Idempotence et replay
Auditer les contrats existants avant modification :
- clés d'idempotence ;
- hash d'input ;
- version de processor ;
- replacement/replay ;
- transaction atomique entre observation, couverture, ledger et matérialisation ;
- comportement en cas de reprise après erreur ;
- effets d'un replay forcé sur les lignes déjà présentes.
Une migration ne doit pas affaiblir les garanties actuelles simplement pour simplifier le schéma.
## Migration `kb_sol_* -> k_sol_*`
La cible durable des tables généralistes Solana est :
```text
k_sol_*
```
Le préfixe :
```text
kb_*
```
reste réservé aux données dont le propriétaire fonctionnel est réellement le domaine Bot.
Avant le renommage :
- inventorier toutes les tables `kb_sol_*` ;
- vérifier qu'elles sont bien généralistes Solana ;
- rechercher toutes les références SQL/textuelles ;
- décider migration incrémentale versus reconstruction propre des bases de développement ;
- définir le comportement des migrations sur une base existante et sur une base vide ;
- vérifier noms d'index, contraintes et séquences éventuelles ;
- ajouter des tests empêchant le retour de noms `kb_sol_*` actifs après clôture.
Ne pas renommer une table spécifique Bot en `k_sol_*` par simple proximité avec Solana.
## Index et requêtes
Les index doivent être justifiés par les requêtes actuelles ou par un besoin futur suffisamment stable.
Auditer notamment :
- recherche par signature ;
- slot/ranges ;
- program id ;
- processor/version/state ;
- address/account ;
- mint/token account lorsque ces clés existent déjà dans les faits ;
- pagination stable ;
- requêtes de replay ;
- futures extractions temporelles destinées au trading/research.
Éviter les index spéculatifs massifs sur des colonnes qui ne sont pas encore produites par les matérialisateurs.
## Préparation additive des faits canoniques Solana
`ks-store` ne doit pas être conçu comme une base de trading. Il est la frontière de persistance généraliste des faits Solana produits par les décodeurs et matérialiseurs de `ks-lib`. Le trading est la priorité fonctionnelle immédiate, mais seulement un domaine parmi d'autres.
Principe durable :
> Un Program ID ou un protocole est une **source de sémantique et de provenance**. Il ne devient pas automatiquement le propriétaire d'une table. Les tables sont définies par des faits/concepts canoniques suffisamment stables et réutilisables.
Les matérialiseurs portent la normalisation : ils convertissent comptes, événements, instructions, noms de champs, unités et conventions propres à chaque programme vers des DTO/models canoniques de `ks-store`. Une différence de nom, de wire format, de version de programme ou de représentation protocolaire ne justifie pas à elle seule une nouvelle table.
Le plan `0.5.3-pre.001` doit donc auditer le stockage par **domaines de faits**, notamment :
- transaction/core, instructions, comptes, balances et lifecycle ;
- tokens/SPL, mints, token accounts, autorités et extensions ;
- metadata on-chain et états associés ;
- programmes, loaders, administration et autorités ;
- staking/vote et autres états natifs ;
- audit, compliance, risques et annotations ;
- trading/marchés ;
- tout autre domaine durable découvert dans les Program IDs couverts par `ks-lib`.
Ces catégories ne sont pas une taxonomie rigide ni une obligation de table unique par domaine. `pre.001` doit déterminer ce qui peut être unifié et ce qui doit rester séparé **par nature du fait et invariants métier**, jamais par commodité liée au Program ID.
### Priorité court terme : faits de trading
Pour le trading, auditer au minimum des concepts canoniques comme :
- identité de marché/paire lorsque ce concept peut être partagé ;
- pools de liquidité / AMM ;
- order books lorsque leur état ne peut pas être représenté proprement par le même contrat que les pools ;
- réserves et états de liquidité ;
- positions/liquidité concentrée lorsqu'un modèle générique durable existe ;
- swaps/trades/exécutions ;
- prix, volumes et métriques dérivées ;
- séries temporelles/OHLC/candles ;
- relations de routing et graphes multi-pools/multi-marchés.
Meteora, Raydium, Pump, Orca, Jupiter ou tout autre DEX alimentent ces concepts via leurs décodeurs/matérialiseurs. Ils ne doivent pas créer des familles de tables par protocole. De la même manière, un programme de metadata ou de staking ne doit recevoir une table spécifique que si le **fait stocké** est réellement spécifique et durable, pas simplement parce que son Program ID est différent.
Par exemple, une table canonique commune de marché peut porter l'identité commune d'une paire, tandis que l'état d'un AMM/liquidity pool et celui d'un order book peuvent rester dans deux tables spécialisées si leurs invariants sont réellement incompatibles. Cette décision doit découler des faits à stocker, pas du nom du protocole.
Lorsque des concepts plus spécialisés apparaîtront plus tard (ticks, bins, positions, courbes, ordres, niveaux de carnet, états metadata particuliers, gouvernance, etc.), ils devront eux aussi être modélisés par concept réutilisable autant que possible. Une spécialisation est acceptable lorsqu'elle représente une structure métier réellement différente ; une spécialisation nommée d'après le protocole ou le Program ID ne l'est pas par défaut.
`0.5.3` **peut créer dès maintenant de nouvelles tables canoniques** pour une fonctionnalité pas encore consommée si leur contrat est suffisamment stable et backend-agnostique. Une table candles/OHLC ou une frontière canonique liquidity-pool/order-book sont des candidats à auditer, pas des obligations automatiques.
La décision doit respecter quatre règles :
1. ne pas modifier une table gelée pour y greffer plus tard une nouvelle fonctionnalité ;
2. préférer une table par fait/concept canonique à une table par protocole ou Program ID ;
3. faire porter aux matérialiseurs la traduction `programme/protocole -> modèle canonique`, tout en conservant la provenance permettant de retrouver le programme/source/version d'origine ;
4. ne pas sur-généraliser des concepts réellement distincts uniquement pour réduire le nombre de tables.
Il ne doit donc pas exister de stratégie de stockage fondée sur des familles `meteora_*`, `raydium_*`, `pump_*`, `orca_*`, `jupiter_*`, etc. Cette règle est un exemple du principe plus général : la provenance programme/protocole ne doit pas devenir le découpage primaire du schéma de stockage.
## Frontière générique de stockage
`ks-store` possède la frontière de persistance. Les autres crates ne doivent pas connaître le moteur concret utilisé derrière cette frontière.
À la clôture de `0.5.3` :
- `ks-pipeline`, `kb-app-demo-desktop` et toute autre crate consommatrice manipulent des DTO/models et des opérations génériques exposés par `ks-store` ;
- aucune crate externe à `ks-store` n'appelle une fonction, un module, un type de pool ou une requête nommé/spécifique `postgres` ;
- les types `sqlx::PgPool`, `sqlx::postgres::*` et équivalents backend-spécifiques ne traversent pas la frontière publique de `ks-store` ;
- les repositories/ports publics décrivent les opérations de stockage en termes fonctionnels, pas en termes SQL/PostgreSQL ;
- les implémentations PostgreSQL restent internes à `ks-store` ;
- `ks-pipeline` conserve l'orchestration des traitements et ne possède pas la connexion à la base ;
- `kb-app-demo-desktop` reste un consommateur/adaptateur et ne possède pas de logique PostgreSQL.
Le design doit permettre de réimplémenter plus tard la même frontière avec PostgreSQL, MySQL, SQLite, RocksDB, Oracle ou un autre moteur sans réécrire les consommateurs. **`0.5.3` n'a pas l'obligation d'implémenter tous ces backends** : PostgreSQL reste le backend opérationnel actuel, mais l'API publique ne doit plus l'imposer.
Le plan `pre.001` doit décider explicitement la forme de cette abstraction : traits/ports, store façade, repositories génériques, factories ou autre composition conforme aux règles du workspace. Ne pas introduire un `enum` backend géant dans toutes les crates consommatrices.
## Configuration et possession des connexions
La configuration du stockage appartient à `ks-store`/`ks-config` selon la frontière de configuration générale, mais **l'interprétation backend-spécifique et la création des connexions appartiennent à `ks-store`**.
Le contrat doit permettre de sélectionner un type de backend et de fournir les paramètres nécessaires au moteur choisi, par exemple :
```text
backend = postgres | mysql | sqlite | rocksdb | oracle | ...
```
Les détails concrets (`URL`/DSN, credentials, fichier SQLite, répertoire RocksDB, options de pool, timeouts, TLS, etc.) ne doivent pas remonter dans les DTO métier ni être interprétés par `ks-pipeline`.
Il faut auditer les fichiers `store.config.json`, schémas, exemples et composition existante pour déterminer la forme durable du contrat sans casser les conventions `KS_*`/`KS_SECRET_*`.
## PostgreSQL actuel et sécurité
PostgreSQL reste l'implémentation active et doit continuer à être entièrement testée pendant `0.5.3`. L'abstraction n'est pas une excuse pour réduire la couverture réelle du backend actuellement utilisé.
Aucun DSN, password, secret ou valeur de configuration sensible ne doit apparaître dans les erreurs/logs normaux.
Conserver le masquage des DSN et les frontières backend-only validées en `0.5.1`.
Les tests PostgreSQL optionnels continuent d'utiliser les variables d'environnement prévues et ne doivent jamais embarquer de credential réel dans une fixture versionnée.
## Tests minimums à prévoir
Le plan `pre.001` doit préciser les tranches, mais `0.5.3` devra couvrir au minimum :
- migration sur base vide ;
- migration/reconstruction depuis le schéma historique retenu ;
- absence de noms `kb_sol_*` actifs à la clôture ;
- cohérence des contraintes/index après migration ;
- idempotence et replay ;
- rollback transactionnel des graphes Core/decode ;
- pagination bornée ;
- limites `BIGINT` / slots ;
- provenance et temporalité, notamment conservation correcte du temps on-chain lorsqu'il existe ;
- requêtes critiques par signature/program/slot/state ;
- santé PostgreSQL ;
- canaris de frontière prouvant que les crates externes n'utilisent aucun type/fonction/module PostgreSQL ;
- API externe crate-root générique indépendante du backend ;
- canaris empêchant DSN/secret dans diagnostics et erreurs ;
- tests de configuration invalidant proprement un backend inconnu ou incomplet ;
- tests garantissant que les tables déclarées gelées correspondent exactement au contrat documenté.
## Validation standard
À chaque delta Rust ou SQL significatif :
```bash
cargo fmt --all
cargo check --workspace
cargo clippy --all-targets
python3 scripts/audit_rust_workspace_rules.py
cargo test --workspace
```
Les tests PostgreSQL réels seront activés lorsque la tranche le nécessite et avec les variables locales appropriées.
Le desktop n'est lancé avec :
```bash
cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
```
que lorsqu'une surface qu'il consomme réellement a changé.
Ne jamais demander de lancer directement `npm run build` ou `npm run dev` ; Tauri pilote Vite.
## Règles de développement à préserver
- Rust 2024 ;
- I/O async-first ;
- pas de `unsafe`, `unwrap`, `expect`, `panic` en production ;
- pas de `?` dans les commandes Tauri ;
- imports `use` réservés aux traits selon les règles du projet ;
- exports crate-root explicites ;
- pas de `pub mod` ;
- `missing_docs`, `unreachable_pub` et `forbid(unsafe_code)` préservés ;
- en-têtes `file:` / `version:` mis à jour à chaque modification ;
- Markdown en français pour la documentation projet ;
- changelogs ordonnés par ordre chronologique décroissant ;
- pas de `Cargo.lock` dans les archives delta.
## Cycle des prereleases
La première prerelease est le plan/audit détaillé.
Les prereleases intermédiaires réalisent les migrations par tranches bornées et validables.
Un correctif `delta-fix-XXX` ne fait jamais avancer le numéro de prerelease et son compteur repart à `fix-001` pour chaque prerelease.
La dernière prerelease de `0.5.3` doit obligatoirement :
- réconcilier les contrats et migrations ;
- exécuter les audits finaux ;
- mettre à jour README/USAGE/TODO/changelogs/guides ;
- supprimer les TODO terminés ;
- mettre à jour le ROADMAP ;
- produire/mettre à jour le rapport final de validation ;
- archiver le plan temporaire `0.5.3` et ce prompt `032` sous `olddocs/archivekbot3/` ;
- préparer le prompt de la session `0.5.4` consacrée aux scénarios, exécuteurs et validations.
## Hors périmètre de `0.5.3`
- nouvelle refonte fonctionnelle de `.kswallet` ;
- migration générale des keypairs de fixtures `wallets/temporary/**`, prévue avec `0.5.4` ;
- correction de la régression de chargement de fixture Token-2022 observée en clôture `0.5.2`, prévue avec la réconciliation des scénarios/fixtures de `0.5.4` ;
- centralisation générale des scénarios/exécuteurs (`0.5.4`) ;
- infrastructure Anchor (`0.6.x`) ;
- implémentation Meteora/Raydium/Pump/Orca/Jupiter (`0.7.x+`) ;
- hardware wallet/KMS/HSM ;
- renommage du workspace/repository `khadhroony-bot3`.
## Résultat attendu
À la fin de `0.5.3`, `ks-store` doit posséder :
- les tables généralistes Solana sous `k_sol_*` ;
- un contrat structurel audité et **gelé** pour chaque table stabilisée, incluant les temporalités on-chain nécessaires afin d'éviter des réparations fonctionnelles ultérieures ;
- une stratégie additive où les nouvelles fonctionnalités créent de nouvelles tables au lieu de remodeler les tables gelées ;
- une API publique conforme aux conventions du workspace et indépendante de PostgreSQL ;
- PostgreSQL comme implémentation active encapsulée dans `ks-store`, remplaçable ultérieurement par un autre backend sans réécriture de `ks-pipeline` ou des autres consommateurs ;
- une base suffisamment propre pour accueillir durablement les futurs faits Solana — trading prioritaire à court terme, mais aussi metadata, token, staking, administration, audit/compliance et autres domaines — sans dette historique de namespace ou de frontière de stockage.