Files
khadhroony-bot3/docs/DEVNET_EXECUTION_GUIDE.md
2026-08-11 22:22:40 +02:00

838 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- file: docs/DEVNET_EXECUTION_GUIDE.md -->
<!-- version: 28 -->
# Guide dexécution Devnet
## 1. Objet et ordre de validation
Ce guide décrit la campagne Devnet de `kb-app-demo-desktop` et `ks-pipeline-demo-scenarios`. Après une modification de nomenclature persistée ou une recréation de la base Devnet, reprendre les scénarios depuis le début dans lordre suivant :
1. préparation commune et base PostgreSQL propre ;
2. Solana Core — System Transfer ;
3. SPL Memo v4 ;
4. SPL Associated Token Account — mint Token classique ;
5. SPL Associated Token Account — mint Token-2022 ;
6. SPL Token classique ;
7. Token-2022 ;
8. registre ElGamal — reporté tant que sa fixture de preuve réelle manque ;
9. Metadata on-chain — Solana Program Metadata, Token-2022 Token Metadata et Metaplex Token Metadata dans `demo_execution_metadata`.
Les commandes réutilisables sont centralisées en section 4. Chaque scénario référence leur identifiant `Cxx` au lieu de les recopier.
## 2. Préconditions
- `.env` contient `KS_SECRET_POSTGRES_DEVNET_URL` et les secrets de transport requis ;
- `KS_SECRET_POSTGRES_DEVNET_URL`, `KS_SECRET_POSTGRES_MAINNET_URL` et `KS_SECRET_POSTGRES_TEST_URL` désignent des bases distinctes ;
- le profil sélectionné est Devnet et autorise explicitement lenvoi Devnet ;
- lenvoi Mainnet reste désactivé ;
- les plafonds de frais, de dépense et de rent sont contrôlés ;
- la politique reste `simulation-first` ;
- le wallet temporaire persistant nest jamais copié dans les logs ou les preuves ;
- le financement est réalisé par un faucet Web Devnet, pas par `solana airdrop`.
Depuis `0.5.3-pre.002`, le desktop ne lit plus une section PostgreSQL concrète. Le profil sélectionne `database.backend` et transporte ses paramètres dans `database.backend_options`, interprétés uniquement par `ks-store`. Lorsque loption backend `auto_initialize_schema` vaut `true`, louverture persistante du `Store` peut initialiser le schéma du backend actif. Lorsquelle vaut `false`, le modèle de stockage doit déjà être disponible.
## 3. Organisation des terminaux
La campagne utilise deux terminaux distincts. Les variables denvironnement exportées dans un terminal ne sont pas visibles dans lautre.
### Terminal A — application Tauri
Ce terminal reste occupé par `cargo tauri dev` pendant toute la campagne. Il affiche les logs Rust, Tauri, Vite, PostgreSQL et RPC.
### Terminal B — contrôles CLI et preuves
Ce terminal reste disponible pour les commandes Solana, PostgreSQL, balances, confirmations et captures avec `tee`.
Les commandes `C01` à `C05` doivent être exécutées dans le terminal B. Le terminal A doit exécuter `T01`, puis rester ouvert. Avant chaque scénario, le terminal B doit définir `KS_DEVNET_SCENARIO` avant dappeler `C06`.
## 4. Commandes communes
Les commandes suivantes sont exécutées depuis la racine du workspace dans un terminal interactif. Ne pas utiliser `set -e` ou `set -u` dans ce terminal : une commande de contrôle non satisfaite fermerait la session. `set -o pipefail` est suffisant pour fiabiliser les pipelines vers `tee`.
### T01 — Démarrer lapplication dans le terminal A
Premier lancement du workspace ou après modification des dépendances frontend :
```bash
cd ~/Projects/khadhroony-bot3; command -v cargo; command -v npm; command -v cargo-tauri || cargo install tauri-cli --locked; test -d kb-app-demo-desktop/node_modules || npm --prefix kb-app-demo-desktop i; cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
```
La commande `npm --prefix kb-app-demo-desktop i -D ...` installe ou réaligne explicitement les dépendances de développement déclarées par lapplication. `npm --prefix kb-app-demo-desktop i` reste nécessaire pour les dépendances runtime.
Installation ou réalignement conditionnel des dépendances de développement, uniquement après modification de `package.json`, suppression de `node_modules` ou erreur de dépendance frontend :
```bash
npm --prefix kb-app-demo-desktop i -D @tauri-apps/cli @types/bootstrap @types/markdown-it @types/node sass-embedded typescript vite
```
`npm run dev` est lancé automatiquement par Tauri via `beforeDevCommand`; il exécute le script `dev` du `package.json`, actuellement Vite. Il ne faut pas le lancer dans un troisième terminal.
La validation frontend de cette campagne est effectuée par `cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json`, qui lance Vite. Ne pas ajouter `npm --prefix kb-app-demo-desktop run build` à la procédure.
Lancements suivants, lorsque `cargo-tauri` et `node_modules` sont déjà présents :
```bash
cd ~/Projects/khadhroony-bot3; cargo tauri dev -c kb-app-demo-desktop/tauri.conf.json
```
Attendre avant tout scénario :
- le démarrage de Vite ;
- le lancement du binaire `kb-app-demo-desktop` ;
- louverture de la fenêtre ;
- le résumé store indiquant que le backend actif est joignable et que les modèles logiques attendus sont prêts ;
- la résolution correcte du profil `local_devnet`.
Ne pas exécuter les commandes `C06` ou `C07` dans ce terminal.
### T02 — Arrêter et redémarrer Tauri conditionnellement
Redémarrer Tauri après :
- recréation du schéma PostgreSQL si lapplication était déjà ouverte ;
- modification de `.env`, de la configuration ou du profil actif ;
- recompilation liée à une correction de code ;
- perte de connexion entre Vite et la fenêtre.
Arrêter avec `Ctrl+C`, puis relancer `T01`.
### C01 — Initialiser lenvironnement de validation
```bash
cd ~/Projects/khadhroony-bot3 && set -o pipefail && export KS_DEVNET_PROFILE="local_devnet" && export KS_DEVNET_RPC_URL="https://api.devnet.solana.com" && export KS_DEVNET_VALIDATION_DIR="/tmp/devnet-validation/current" && export KS_DEVNET_WALLET="$PWD/wallets/temporary/local_devnet/local-devnet-operator.json" && mkdir -p "$KS_DEVNET_VALIDATION_DIR" && printf 'Profil : %s\n' "$KS_DEVNET_PROFILE" && printf 'RPC Devnet : %s\n' "$KS_DEVNET_RPC_URL" && printf 'Preuves : %s\n' "$KS_DEVNET_VALIDATION_DIR" && printf 'Wallet : %s\n' "$KS_DEVNET_WALLET";
```
`KS_DEVNET_WALLET` reste ici un **fichier Solana CLI JSON explicite** utilisé par les commandes externes historiques. Un fichier natif `.kswallet` ne doit jamais être fourni directement à `solana-keygen`, `solana` ou `spl-token`. Lorsqu'un opérateur part d'un wallet natif, il doit produire volontairement un export `SolanaCliJson` via `ks-wallet`, l'utiliser pour la campagne bornée, puis gérer explicitement ce fichier privé. Aucun export automatique n'est déclenché par les scénarios.
### C02 — Capturer les versions CLI
```bash
command -v solana && command -v solana-keygen && command -v spl-token && { date --iso-8601=seconds; solana --version; solana-keygen --version; spl-token --version; } | tee "$KS_DEVNET_VALIDATION_DIR/00-cli-versions.txt";
```
Chaque campagne doit capturer les versions exactes des outils externes quelle utilise. Les fixtures Rust natives ne doivent pas dépendre implicitement de la configuration globale dune CLI.
### C03 — Vérifier lidentité du réseau
```bash
solana config set --url "$KS_DEVNET_RPC_URL" && { date --iso-8601=seconds; solana config get; solana cluster-version --url "$KS_DEVNET_RPC_URL"; solana genesis-hash --url "$KS_DEVNET_RPC_URL"; solana epoch-info --url "$KS_DEVNET_RPC_URL"; } | tee "$KS_DEVNET_VALIDATION_DIR/01-devnet-network.txt";
```
Le genesis hash Devnet attendu est :
```text
EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
```
### C04 — Vérifier le wallet opérateur
```bash
test -f "$KS_DEVNET_WALLET" && chmod 600 "$KS_DEVNET_WALLET" && export KS_PUBLIC_DEVNET_WALLET_ADDRESS="$(solana-keygen pubkey "$KS_DEVNET_WALLET")" && { date --iso-8601=seconds; printf 'wallet_path=%s\n' "$KS_DEVNET_WALLET"; printf 'wallet_pubkey=%s\n' "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/02-wallet.txt"
```
### C05 — Recréer la base Devnet
Cette commande est destructive. Elle ne doit viser que `KS_SECRET_POSTGRES_DEVNET_URL`. Elle supprime toutes les données et tous les objets du schéma `public`, puis laisse lapplication recréer son schéma lors de louverture dune fenêtre Devnet.
```bash
test -n "$KS_SECRET_POSTGRES_DEVNET_URL" && printf 'database_url=<configured>\n' && export KS_CONFIRM_DEVNET_DATABASE_RESET="YES_RESET_SOLANA_DEVNET" && test "$KS_CONFIRM_DEVNET_DATABASE_RESET" = "YES_RESET_SOLANA_DEVNET" && psql "$KS_SECRET_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
```
Après ouverture dune fenêtre Devnet, contrôler les tables :
```bash
psql "$KS_SECRET_POSTGRES_DEVNET_URL" -v ON_ERROR_STOP=1 -c "SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' ORDER BY tablename;" | tee "$KS_DEVNET_VALIDATION_DIR/03-devnet-schema.txt"
```
### C06 — Capturer le solde avant scénario
Définir `KS_DEVNET_SCENARIO` avant lappel.
```bash
test -n "${KS_DEVNET_SCENARIO:-}" && test -n "${KS_PUBLIC_DEVNET_WALLET_ADDRESS:-}" && test -n "${KS_DEVNET_RPC_URL:-}" && test -n "${KS_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nwallet=%s\n' "$KS_DEVNET_SCENARIO" "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-wallet-before.txt"
```
### C07 — Confirmer une signature et capturer le solde après scénario
Définir `KS_DEVNET_SCENARIO` et `KS_DEVNET_SIGNATURE` avant lappel.
```bash
test -n "${KS_DEVNET_SCENARIO:-}" && test -n "${KS_DEVNET_SIGNATURE:-}" && test -n "${KS_PUBLIC_DEVNET_WALLET_ADDRESS:-}" && test -n "${KS_DEVNET_RPC_URL:-}" && test -n "${KS_DEVNET_VALIDATION_DIR:-}" && { date --iso-8601=seconds; printf 'scenario=%s\nsignature=%s\n' "$KS_DEVNET_SCENARIO" "$KS_DEVNET_SIGNATURE"; solana confirm "$KS_DEVNET_SIGNATURE" --url "$KS_DEVNET_RPC_URL" --commitment finalized --verbose; solana balance "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" --url "$KS_DEVNET_RPC_URL" --commitment confirmed; } | tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-confirmation.txt"
```
### C08 — Préparer un mint SPL Token classique pour ATA
Cette commande crée uniquement un mint de test persistant. Elle ne crée aucun compte token associé : lATA doit être dérivé, simulé et créé par `kb-app-demo-desktop`.
Loption `--silent` est obligatoire afin que la phrase de récupération ne soit pas affichée dans le terminal, les captures ou lhistorique de validation.
La commande est idempotente au niveau du guide : si le compte du mint existe déjà sur Devnet, elle le réutilise.
```bash
export KS_PUBLIC_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KS_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && mkdir -p "$(dirname "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")" && { test -f "$KS_DEVNET_CLASSIC_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_CLASSIC_MINT_KEYPAIR"; }
```
```bash
export KS_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")" && { solana account "$KS_DEVNET_CLASSIC_MINT" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" create-token "$KS_DEVNET_CLASSIC_MINT_KEYPAIR" --decimals 9; } && printf 'classic_mint=%s\n' "$KS_DEVNET_CLASSIC_MINT" | tee "$KS_DEVNET_VALIDATION_DIR/30a-spl-ata-classic-mint.txt"
```
### C09 — Préparer un mint Token-2022 pour ATA
Cette commande crée uniquement un mint Token-2022 de test persistant, sans extension supplémentaire. Elle ne crée aucun ATA.
```bash
export KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID="TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" && export KS_DEVNET_TOKEN_2022_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-token-2022-mint.json" && mkdir -p "$(dirname "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { test -f "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR"; }
```
```bash
export KS_PUBLIC_DEVNET_TOKEN_2022_MINT="$(solana-keygen pubkey "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR")" && { solana account "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" create-token "$KS_DEVNET_TOKEN_2022_MINT_KEYPAIR" --decimals 9; } && printf 'token_2022_mint=%s\n' "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" | tee "$KS_DEVNET_VALIDATION_DIR/30b-spl-ata-token-2022-mint.txt"
```
### C10 — Préparer les comptes du scénario SPL Token classique
La fenêtre actuelle **Décodeur spl_token — TransferChecked** valide uniquement `TransferChecked`. Elle exige :
- un mint SPL Token classique ;
- un compte source appartenant au wallet opérateur et possédant un solde token suffisant ;
- un compte destination distinct pour le même mint ;
- lautorité simple du compte source, qui doit être le wallet opérateur.
Cette préparation réutilise le mint créé par `C08` et lATA classique créée pendant `S03A`.
1. Dériver lATA source avec la syntaxe exigée par `spl-token-cli 5.5.0` :
```bash
export KS_DEVNET_CLASSIC_SOURCE_ATA="$(spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_PUBLIC_DEVNET_WALLET_ADDRESS" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KS_DEVNET_CLASSIC_SOURCE_ATA" && printf 'source_ata=%s\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA"
```
2. Préparer un owner destinataire persistant :
```bash
export KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR="$PWD/wallets/temporary/local_devnet/recipients/spl-token-transfer-recipient.json" && mkdir -p "$(dirname "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")" && { test -f "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR" || solana-keygen new --no-bip39-passphrase --force --silent --outfile "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR"; } && export KS_DEVNET_CLASSIC_RECIPIENT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_RECIPIENT_KEYPAIR")"
```
3. Dériver puis créer lATA destination si elle nexiste pas :
```bash
export KS_DEVNET_CLASSIC_DESTINATION_ATA="$(spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" address --verbose --token "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_DEVNET_CLASSIC_RECIPIENT" | awk -F': ' '/Associated token address/ {print $2}')" && test -n "$KS_DEVNET_CLASSIC_DESTINATION_ATA" && { solana account "$KS_DEVNET_CLASSIC_DESTINATION_ATA" --url "$KS_DEVNET_RPC_URL" --output json >/dev/null 2>&1 || spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" create-account "$KS_DEVNET_CLASSIC_MINT" --owner "$KS_DEVNET_CLASSIC_RECIPIENT" --fee-payer "$KS_DEVNET_WALLET"; }
```
4. Créditer le compte source. Cette commande ajoute `10` tokens à chaque exécution ; ne la relancer que si le solde source est insuffisant :
```bash
spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" mint "$KS_DEVNET_CLASSIC_MINT" 10 "$KS_DEVNET_CLASSIC_SOURCE_ATA" --owner "$KS_DEVNET_WALLET" --fee-payer "$KS_DEVNET_WALLET"
```
5. Afficher les comptes par leur adresse. Avec cette version du CLI, utiliser `display` plutôt que `account-info <adresse>`, car largument positionnel de `account-info` est interprété comme un mint :
```bash
spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
```
6. Capturer la fixture :
```bash
{ printf 'mint=%s\n' "$KS_DEVNET_CLASSIC_MINT"; printf 'source=%s\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA"; printf 'destination=%s\n' "$KS_DEVNET_CLASSIC_DESTINATION_ATA"; printf 'authority=%s\n' "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"; printf 'amount_raw=1000000000\n'; printf 'decimals=9\n'; } | tee "$KS_DEVNET_VALIDATION_DIR/40-spl-token-fixture.txt"
```
La création du compte destination par CLI est acceptable ici : `S03A` et `S03B` ont déjà validé lexecutor ATA. `S04` doit isoler et valider lexecutor SPL Token `TransferChecked`.
### C11 — Créer ou réutiliser la fixture Token-2022
Le workspace fournit une commande idempotente qui prépare les comptes publics requis par les huit scénarios Token-2022 :
```bash
cargo run -p ks-pipeline-demo-scenarios --bin ks-pipeline-demo-scenarios-cli -- prepare-token-2022-fixture --rpc-url "$KS_DEVNET_RPC_URL" --wallet "$KS_DEVNET_WALLET" --wallet-dir "$PWD/wallets/temporary/local_devnet" --decimals 9 | tee "$KS_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-preparation.json"
```
Lorsque `--rpc-url` et `--wallet` sont omis, la commande utilise respectivement `KS_DEVNET_RPC_URL` et `KS_DEVNET_WALLET`. Lorsque `--wallet-dir` est omis, elle utilise le répertoire parent du wallet.
`--wallet` / `KS_DEVNET_WALLET` acceptent uniquement le fichier keypair compatible Solana CLI. La commande refuse explicitement l'extension `.kswallet` afin d'empêcher qu'un conteneur natif protégé soit traité comme un keypair CLI.
La commande :
- crée silencieusement les keypairs manquants avec des permissions `0600` ;
- crée ou réutilise un mint Token-2022 avec mint authority et freeze authority égales au wallet opérateur ;
- crée ou réutilise trois comptes Token-2022 distincts : source, destination et compte vide réservé à `CloseAccount` ;
- crée ou réutilise une pubkey delegate indépendante ;
- n'affiche jamais les phrases de récupération ni les octets privés ;
- écrit atomiquement la fixture publique attendue par l'application.
Les keypairs et la fixture sont conservés sous :
```text
wallets/temporary/local_devnet/spl_token_2022_validation/
```
La fixture publique est :
```text
wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env
```
Elle définit :
```text
KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID
KS_PUBLIC_DEVNET_TOKEN_2022_MINT
KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE
KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION
KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT
KS_PUBLIC_DEVNET_TOKEN_2022_DELEGATE
KS_PUBLIC_DEVNET_TOKEN_2022_AUTHORITY
KS_PUBLIC_DEVNET_TOKEN_2022_FREEZE_AUTHORITY
KS_PUBLIC_DEVNET_TOKEN_2022_DECIMALS
KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW
KS_PUBLIC_DEVNET_TOKEN_2022_TRANSFER_AMOUNT_RAW
KS_PUBLIC_DEVNET_TOKEN_2022_APPROVE_AMOUNT_RAW
KS_PUBLIC_DEVNET_TOKEN_2022_BURN_AMOUNT_RAW
KS_PUBLIC_DEVNET_WALLET_ADDRESS
```
Vérifier puis charger uniquement les valeurs publiques dans le terminal B :
```bash
export KS_DEVNET_TOKEN_2022_FIXTURE="$PWD/wallets/temporary/local_devnet/spl_token_2022_validation/fixture.env" && test -f "$KS_DEVNET_TOKEN_2022_FIXTURE" && sed -n '/^export [A-Z0-9_]*=/p' "$KS_DEVNET_TOKEN_2022_FIXTURE" | sed 's/=.*$/=<défini>/' | tee "$KS_DEVNET_VALIDATION_DIR/50-spl-token-2022-fixture-keys.txt" && source "$KS_DEVNET_TOKEN_2022_FIXTURE"
```
Afficher le mint et les trois comptes Token-2022 avec le Program ID explicite :
```bash
spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_SOURCE" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_DESTINATION" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_2022_PROGRAM_ID" display "$KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT"
```
Le compte `KS_PUBLIC_DEVNET_TOKEN_2022_CLOSE_ACCOUNT` doit rester vide jusqu'au scénario `CloseAccount`. Ne pas utiliser `account-info <adresse>` dans cette campagne : avec `spl-token-cli 5.5.0`, cette forme peut interpréter l'adresse comme un mint.
### C12 — Preuves applicatives communes
Pour chaque scénario, conserver depuis lapplication :
- profil et cluster résolus ;
- paramètres saisis ;
- `operation_code`, `program_id` et plan préparé ;
- signers requis et fee payer ;
- plafond de frais et plafond de dépense ;
- résultat et logs de simulation ;
- signature denvoi ;
- résultat de confirmation ;
- insertion canonique ;
- extraction Core ;
- Decode replay ciblé ;
- projections matérialisées ;
- second replay démontrant lidempotence ;
- diagnostics ou écarts observés.
Un scénario nest validé que si le replay ne produit ni échec fonctionnel ni erreur de traitement et si les projections attendues sont présentes et idempotentes.
## 5. Préparation initiale de la campagne
1. Dans le terminal B, exécuter `C01`, `C02`, `C03` et `C04`.
2. Dans le terminal B, exécuter `C05` pour repartir dune base propre.
3. Dans le terminal A, exécuter `T01`.
4. Attendre que le résumé store confirme la disponibilité des modèles logiques attendus, puis la disponibilité de la fenêtre.
5. Dans la fenêtre Configuration, vérifier que `local_devnet` utilise la base Devnet.
6. Dans le terminal B, exécuter le contrôle de tables de `C05`.
7. Financer la pubkey par un faucet Web Devnet si le solde est insuffisant.
8. Réexécuter `C04` dans le terminal B après financement.
9. Avant chaque scénario, définir `KS_DEVNET_SCENARIO` dans le terminal B, puis exécuter `C06`.
## 6. Scénario S01 — Solana Core System Transfer
### Objectif
Valider la chaîne complète : préparation, simulation, envoi, confirmation, stockage canonique, extraction Core et replay.
### Procédure
1. Définir puis exécuter `C06` :
```bash
export KS_DEVNET_SCENARIO="10-system-transfer"
```
2. Dans la fenêtre **Exécution Devnet — Solana Core** :
- générer un nouveau destinataire ;
- conserver sa pubkey ;
- saisir un montant borné ;
- vérifier `solana.core.system.transfer` ;
- simuler ;
- contrôler frais, spend et signer ;
- confirmer explicitement lenvoi.
3. Définir la signature et exécuter `C07`.
4. Capturer séparément le solde du destinataire :
```bash
export KS_DEVNET_RECIPIENT="COLLER_LE_DESTINATAIRE"
solana balance \
"$KS_DEVNET_RECIPIENT" \
--url "$KS_DEVNET_RPC_URL" \
--commitment confirmed \
| tee "$KS_DEVNET_VALIDATION_DIR/${KS_DEVNET_SCENARIO}-recipient-after.txt"
```
5. Exécuter les contrôles applicatifs `C08` sur la signature.
### Contrat derreur de linterface
Pour un nouveau destinataire inexistant, le montant doit être au moins égal au minimum de rent exemption indiqué par lapplication. Avec la valeur observée de `890880` lamports, une demande de `10000` lamports doit être refusée avant simulation.
Ce refus est attendu fonctionnellement, mais linterface doit afficher lerreur dans les panneaux de résultat :
- `Résumé` doit passer de `idle` à `error` ;
- `Plan exact` doit afficher léchec de préparation ou rester explicitement indisponible avec sa cause ;
- `Simulation exacte` doit indiquer quaucune simulation na été lancée à cause du préflight ;
- `Confirmation et replay` doit rester non exécuté, avec une raison explicite.
Un message uniquement présent dans le journal est insuffisant. Tant que les panneaux restent à `idle`, ne pas considérer le scénario comme validé et ne pas utiliser « Signer et envoyer ».
### Résultat historique de référence
La première campagne a validé la signature `3k8BaQJKwSn8r2pYdvfp1Q3VYrPEcDEuUunMFn7NDq1ZqsvryjoGsxeBBNJjc1123RgDCoykp7w9VrtZgsDw4ph3`, au slot `479589279`, avec `890880` lamports transférés, `5000` lamports de frais et `150` compute units. Cette preuve réseau reste historique ; les lignes PostgreSQL doivent être recréées dans la nouvelle base.
## 7. Scénario S02 — SPL Memo v4
### Objectif
Valider lopération exécutable `spl.memo.add_memo`, lévénement observé `spl.memo.v4.add_memo` et la projection dannotation.
### Procédure
1. Définir puis exécuter `C06` :
```bash
export KS_DEVNET_SCENARIO="20-spl-memo-v4"
```
2. Dans la fenêtre **Exécution Devnet — SPL** :
- sélectionner Memo v4 ;
- saisir un texte UTF-8 borné ;
- vérifier le Program ID `Memo4c2pN8afCj432Lb7RMVKi9PbQnnW7ewFFaV3oAH` ;
- vérifier le wallet signer ;
- simuler puis confirmer lenvoi.
3. Définir `KS_DEVNET_SIGNATURE` et exécuter `C07`.
4. Exécuter `C08` et vérifier précisément :
- `processor_name = materializer.transaction.annotations` ;
- `surface_code = spl.memo.v4` ;
- `event_code = spl.memo.v4.add_memo` ;
- une seule annotation matérialisée ;
- second replay ignoré/idempotent.
### Résultat historique de référence
La première campagne a validé la signature `3uYNASrHibwpnsFWwV2JHAxtnci96RhFYf6zbUSfGMbQQV37gfHizstk7atiHYYQCBm4jhmC6cT3G3CCPCV38Lpx`, au slot `479596483`, avec `5000` lamports de frais et `513` compute units. Après recréation de la base, cette signature peut être réingérée pour tester le replay, mais la campagne propre doit également produire une nouvelle preuve complète.
## 8. Scénario S03 — SPL Associated Token Account
Le scénario ATA est divisé en deux validations indépendantes. Une ATA dépend du triplet exact :
```text
owner + token_program + mint
```
Un même owner et deux mints appartenant à des Token Programs différents doivent donc produire deux dérivations et deux comptes distincts.
### S03A — ATA avec SPL Token classique
#### Objectif
Valider la dérivation et la création idempotente dune ATA dont le mint appartient au programme SPL Token classique.
#### Préparation dans le terminal B
1. Exécuter `C08`.
2. Définir le scénario et capturer le solde :
```bash
export KS_DEVNET_SCENARIO="30a-spl-ata-classic"
```
3. Exécuter `C06`.
4. Copier la valeur affichée par :
```bash
printf '%s\n' "$KS_DEVNET_CLASSIC_MINT"
```
#### Procédure dans lapplication
1. Ouvrir la fenêtre **SPL Associated Token Account**.
2. Utiliser :
- owner : wallet opérateur `KS_PUBLIC_DEVNET_WALLET_ADDRESS` ;
- mint : `KS_DEVNET_CLASSIC_MINT` ;
- token program : SPL Token classique ;
- payer : wallet opérateur.
3. Dériver lATA et conserver son adresse.
4. Vérifier que le Program ID sélectionné est `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`.
5. Simuler `spl.associated_token_account.create_idempotent`.
6. Contrôler le rent ceiling, le payer, lowner, le mint, le token program et ladresse ATA dérivée.
7. Confirmer explicitement lenvoi.
8. Définir `KS_DEVNET_SIGNATURE`, puis exécuter `C07`.
9. Exécuter `C12`.
10. Réexécuter la création idempotente et vérifier quelle ne produit ni fausse création ni duplication des projections.
### S03B — ATA avec Token-2022
#### Objectif
Valider la dérivation et la création idempotente dune ATA dont le mint appartient au programme Token-2022, puis démontrer quelle est distincte de lATA classique.
#### Préparation dans le terminal B
1. Exécuter `C09`.
2. Définir le scénario et capturer le solde :
```bash
export KS_DEVNET_SCENARIO="30b-spl-ata-token-2022"
```
3. Exécuter `C06`.
4. Copier la valeur affichée par :
```bash
printf '%s\n' "$KS_PUBLIC_DEVNET_TOKEN_2022_MINT"
```
#### Procédure dans lapplication
1. Utiliser :
- owner : le même wallet opérateur ;
- mint : `KS_PUBLIC_DEVNET_TOKEN_2022_MINT` ;
- token program : Token-2022 ;
- payer : wallet opérateur.
2. Dériver lATA et conserver son adresse.
3. Vérifier que le Program ID sélectionné est `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`.
4. Vérifier que ladresse dérivée diffère de lATA classique de S03A.
5. Simuler puis envoyer `spl.associated_token_account.create_idempotent`.
6. Définir `KS_DEVNET_SIGNATURE`, puis exécuter `C07`.
7. Exécuter `C12`.
8. Rejouer la création idempotente.
9. Vérifier séparément les faits parent ATA et les éventuels enfants CPI Token-2022, sans duplication.
### Critères communs S03A/S03B
- le mint existe et son owner on-chain correspond au Token Program choisi ;
- ladresse ATA est dérivée avec les graines dans lordre canonique `owner`, `token_program`, `mint` ;
- le compte créé a pour owner le Token Program attendu ;
- le premier envoi peut créer le compte ;
- le second envoi idempotent ne crée pas un second compte ;
- le replay et les projections restent idempotents ;
- aucune ATA classique nest confondue avec une ATA Token-2022.
## 9. Scénario S04 — SPL Token classique
### Portée réellement exposée
La fenêtre actuelle expose uniquement :
```text
spl.token.transfer_checked
```
Elle ne permet pas encore denchaîner depuis linterface `InitializeMint`, `MintToChecked`, `Approve`, `Revoke`, `BurnChecked` et `CloseAccount`. Ces opérations restent hors de ce scénario Devnet tant quelles ne sont pas exposées par la fenêtre.
### Préparation dans le terminal B
1. Réutiliser le mint classique de `C08` :
```bash
export KS_PUBLIC_SPL_TOKEN_PROGRAM_ID="TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" && export KS_DEVNET_CLASSIC_MINT_KEYPAIR="$PWD/wallets/temporary/local_devnet/mints/ata-classic-mint.json" && export KS_DEVNET_CLASSIC_MINT="$(solana-keygen pubkey "$KS_DEVNET_CLASSIC_MINT_KEYPAIR")"
```
2. Définir le scénario :
```bash
export KS_DEVNET_SCENARIO="40-spl-token"
```
3. Exécuter `C06`.
4. Exécuter `C10`.
5. Vérifier les comptes token avant lopération :
```bash
spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
```
### Valeurs à saisir dans lapplication
Dans **Décodeur spl_token — TransferChecked** :
| Champ | Valeur |
|--------------------|--------------------------------------------|
| Compte source | `$KS_DEVNET_CLASSIC_SOURCE_ATA` |
| Mint | `$KS_DEVNET_CLASSIC_MINT` |
| Compte destination | `$KS_DEVNET_CLASSIC_DESTINATION_ATA` |
| Autorité simple | `$KS_PUBLIC_DEVNET_WALLET_ADDRESS` |
| Montant brut exact | `1000000000` pour 1 token avec 9 décimales |
| Decimals | `9` |
Afficher les valeurs à copier :
```bash
printf 'source=%s\nmint=%s\ndestination=%s\nauthority=%s\namount_raw=1000000000\ndecimals=9\n' "$KS_DEVNET_CLASSIC_SOURCE_ATA" "$KS_DEVNET_CLASSIC_MINT" "$KS_DEVNET_CLASSIC_DESTINATION_ATA" "$KS_PUBLIC_DEVNET_WALLET_ADDRESS"
```
### Exécution
1. Cliquer **Préflight et simuler**.
2. Vérifier :
- owner des deux comptes = SPL Token classique ;
- mint identique sur les deux comptes ;
- decimals = `9` ;
- source suffisamment financée ;
- autorité simple = wallet opérateur ;
- montant brut conservé exactement.
3. Cocher la confirmation opérateur.
4. Cliquer **Signer et envoyer Token**.
5. Copier la signature dans :
```bash
export KS_DEVNET_SIGNATURE="SIGNATURE_SPL_TOKEN"
```
6. Exécuter `C07`, puis `C12`.
7. Vérifier les comptes après transfert :
```bash
spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_SOURCE_ATA" && spl-token --url "$KS_DEVNET_RPC_URL" --program-id "$KS_PUBLIC_SPL_TOKEN_PROGRAM_ID" display "$KS_DEVNET_CLASSIC_DESTINATION_ATA"
```
### Critères de validation
- simulation réussie ;
- transaction confirmée puis finalisée ;
- `operation_code = spl.token.transfer_checked` ;
- montant brut exact ;
- insertion canonique, extraction Core et replay réussis ;
- projection métier présente ;
- second replay idempotent ;
- aucun compte Token-2022 impliqué.
Le journal métier SPL Token peut rester à `empty` après une simulation seule. Il doit être actualisé après lenvoi confirmé, le replay et la matérialisation.
## 10. Scénario S05 — Token-2022
### Préparation
1. Définir le scénario et exécuter `C06` :
```bash
export KS_DEVNET_SCENARIO="50-spl-token-2022"
```
2. Exécuter `C11` pour créer ou réutiliser la fixture.
3. Contrôler le mint, la source, la destination et le compte réservé à la fermeture avec les commandes `display` de `C11`.
4. Dans lapplication, ouvrir **Exécution spl_token_2022 — scénarios publics**.
5. Cliquer **Charger la fixture Token-2022**.
6. Vérifier que le message indique le chemin de `fixture.env` et le Program ID Token-2022.
Le bouton lit le `fixture.env` produit par `ks-pipeline-demo-scenarios` et remplit automatiquement :
- compte source ou cible ;
- mint ;
- compte destination ou destination lamports ;
- delegate ;
- autorité ;
- freeze authority ;
- montant brut ;
- décimales.
Ne remplacer manuellement une valeur que pour un test négatif délibéré.
### Ordre des sous-scénarios
Exécuter les scénarios dans cet ordre, car certains modifient létat nécessaire aux suivants :
#### S05.1 — MintToChecked
Champs utilisés :
- source/cible : compte token à créditer ;
- mint : mint Token-2022 ;
- autorité : mint authority ;
- montant brut : `KS_PUBLIC_DEVNET_TOKEN_2022_MINT_AMOUNT_RAW` chargé depuis la fixture ;
- décimales : valeur de la fixture.
Avec la fixture par défaut, le mint initial est `10000000000` unités brutes, soit 10 tokens avec 9 décimales. Cette quantité couvre ensuite le transfert, l'approbation et le burn prévus.
Simuler, envoyer, exécuter `C07`, puis `C12`.
#### S05.2 — TransferChecked
Champs utilisés :
- source : compte financé par S05.1 ;
- mint ;
- destination : second compte Token-2022 ;
- autorité : owner du compte source ;
- montant brut et décimales.
Simuler, envoyer, confirmer et vérifier les balances source/destination.
#### S05.3 — ApproveChecked
Champs utilisés :
- source ;
- mint ;
- delegate ;
- autorité : owner du compte source ;
- montant brut ;
- décimales.
Après confirmation, vérifier la projection de délégation.
#### S05.4 — Revoke
Champs utilisés :
- source ;
- autorité : owner du compte source.
Le mint et le delegate ne sont pas requis par le formulaire pour cette opération. Vérifier que la délégation précédente est supprimée.
#### S05.5 — BurnChecked
Champs utilisés :
- source ;
- mint ;
- autorité : owner du compte source ;
- montant brut ;
- décimales.
Le compte source doit conserver un solde suffisant après le transfert.
#### S05.6 — FreezeAccount
Champs utilisés :
- source/cible ;
- mint ;
- freeze authority.
Vérifier que la fixture désigne une freeze authority réellement configurée sur le mint.
#### S05.7 — ThawAccount
Réutiliser le même compte cible et la même freeze authority. Ce scénario doit suivre FreezeAccount.
#### S05.8 — CloseAccount
À exécuter uniquement avec le compte de fermeture prévu par la fixture :
- source/cible : `closeAccount` chargé par lapplication ;
- destination : autorité/destination lamports chargée ;
- autorité : owner ou close authority.
Le compte doit être vide et satisfaire toutes les préconditions de fermeture.
### Pour chaque sous-scénario
1. sélectionner le scénario ;
2. laisser `applyToken2022Fixture` remplir les champs adaptés ;
3. cliquer **Préflight et simuler** ;
4. contrôler le plan, les owners, les autorités, le montant et les extensions ;
5. cocher la confirmation opérateur ;
6. envoyer ;
7. définir immédiatement `KS_DEVNET_SIGNATURE` avec la signature affichée pour cette sous-opération ;
8. vérifier qu'elle diffère de la signature du scénario précédent, puis exécuter `C07` ;
9. appliquer `C12` ;
10. conserver un fichier de preuve distinct en modifiant temporairement le préfixe, par exemple :
```bash
export KS_DEVNET_SCENARIO="50a-token-2022-mint-to-checked"
```
puis `50b`, `50c`, etc., avant chaque appel à `C07`.
### Critères de validation
- chaque opération disponible est simulée sur son message exact ;
- les comptes sont owned par Token-2022 ;
- les autorités correspondent à la fixture ;
- les montants bruts et décimales sont exacts ;
- les projections token account, admin, fee, metadata ou risk attendues sont présentes selon lopération ;
- aucun événement nest attribué au programme Token classique ;
- chaque replay est sans échec ;
- le second replay est idempotent.
## 11. Scénario S06 — Registre ElGamal — reporté
### Statut de la campagne de référence historique
Le registre ElGamal reste implémenté mais **non validé sur Devnet** dans cette campagne. Ce report ne remet pas en cause les validations S01 à S05.
Deux prérequis manquent :
- une fixture créant un compte de contexte de preuve `PubkeyValidity` valide et owned par le programme natif ZK ElGamal Proof ;
- le raccordement complet du panneau desktop : lecture des champs, handler du bouton **Construire le plan Registry**, commande Tauri, rendu du plan et affichage borné des erreurs.
Les champs envisagés sont :
- fee payer : wallet opérateur ;
- owner du registre : wallet opérateur ;
- opération initiale : `CreateRegistry` ;
- proof context state account : compte de contexte `PubkeyValidity` réel, jamais une adresse arbitraire.
Ne pas fabriquer une preuve de validation à partir dun compte quelconque. La future campagne S06 devra produire sa propre fixture, exécuter simulation et envoi, confirmer la signature, puis vérifier insertion canonique, extraction Core, replay, projection admin et idempotence.
## 12. Scénario S07 — Metadata on-chain
### Surface réellement exposée
La fenêtre `demo_execution_metadata` regroupe trois domaines on-chain distincts sans les fusionner :
- Solana Program Metadata, Program ID `ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S` ;
- Token-2022 Token Metadata, exécuté par le programme Token-2022 à partir du contrat `spl-token-metadata-interface` ;
- Metaplex Token Metadata, Program ID `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s`.
Le profil Devnet sélectionné est synchronisé entre les trois accordéons. Les résultats détaillés utilisent les trois accordéons **Préflight et opérations**, **Simulation et confirmation** et **Postconditions et preuves**. Le journal dexécution reste en pleine largeur sous la grille. Aucun bouton de fetch HTTP, IPFS ou Arweave nest exposé.
### Qualification courante
Les matrices réseau actives sont déjà qualifiées :
- Solana Program Metadata : neuf opérations `confirmed` par les deux campagnes `pre.010` ;
- Token-2022 Token Metadata : cinq opérations `confirmed` par la campagne `pre.012` (`Initialize`, `UpdateField`, `Emit`, `RemoveKey`, `UpdateAuthority`) ;
- Metaplex Token Metadata : 20 opérations courantes classées en `pre.013`, avec 15 `confirmed`, 5 `unavailable` et 0 `not_run`.
Les cinq indisponibilités Metaplex restent bornées par leurs preuves runtime : `Use`, `Resize`, `Migrate`, `Collect` et `CloseAccounts`. Une simulation négative ne doit jamais être transformée en autorisation de soumission.
### Revalidation depuis le desktop
Une revalidation complète nest pas requise à chaque changement documentaire. En cas de régression du runtime, du transport, de lorchestration ou du panneau :
1. démarrer Tauri avec `T01` et sélectionner un profil Devnet persistant ;
2. préparer la base depuis le panneau Metadata ;
3. conserver `simulation-first`, les limites de coût et la confirmation opérateur explicite ;
4. exécuter uniquement la campagne spécialisée concernée ;
5. vérifier la confirmation, lhydratation canonique, lextraction Core, le replay, la matérialisation, les postconditions et lidempotence ;
6. comparer le résultat à la matrice Devnet active du domaine avant toute modification de statut.
Pour Metaplex, utiliser les campagnes qualifiées du panneau (`Create -> Mint`, collection, `Print -> Burn`, lifecycle pNFT, escrow, maintenance et probe `Use`) plutôt que reconstruire manuellement un intent générique. Pour Token-2022 Token Metadata et Solana Program Metadata, utiliser leurs campagnes dédiées déjà exposées par le panneau.
### Critères de validation
- le Program ID et le domaine sélectionnés restent exacts ;
- les transactions soumises sont précédées dune simulation réussie du même message ;
- les opérations classées `unavailable` restent simulation-only ;
- les preuves canonical/Core/replay/materialization/postconditions restent cohérentes avec la matrice active ;
- les JsonViewer ne remplacent pas les preuves persistées ; ils les rendent seulement observables dans le desktop ;
- aucune résolution off-chain nest effectuée par le replay canonique ou par le panneau Metadata.
## 13. Critères de clôture de la campagne
La campagne est clôturable uniquement lorsque :
- tous les scénarios déclarés validables dans la campagne ont été rejoués depuis une base Devnet propre ;
- toutes les signatures des scénarios effectivement rejoués sont confirmées sur Devnet ;
- toute surface reportée est identifiée explicitement avec ses prérequis manquants ;
- les preuves S07 restent concordantes avec les matrices Metadata actives, sans imposer un rerun réseau en labsence de régression ;
- les identités persistées respectent la nomenclature canonique ;
- aucun ancien `processor_name`, `surface_code`, `operation_code` ou `event_code` ne subsiste ;
- le replay ciblé est sans échec ni erreur de traitement ;
- les projections sont présentes et idempotentes ;
- le présent guide reflète les commandes réellement exécutées.