v0.4.8
This commit is contained in:
117
docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md
Normal file
117
docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md
Normal file
@@ -0,0 +1,117 @@
|
||||
<!-- file: docs/validation/V0_4_8_METADATA_VALIDATION_REPORT.md -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Validation fonctionnelle — Metadata on-chain et clôture 0.4.8
|
||||
|
||||
## Périmètre
|
||||
|
||||
La version `0.4.8` ferme trois domaines Metadata on-chain strictement séparés :
|
||||
|
||||
- Solana Program Metadata `ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S` ;
|
||||
- Token-2022 Token Metadata via `spl-token-metadata-interface` ;
|
||||
- Metaplex Token Metadata `metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s`.
|
||||
|
||||
Elle couvre les contrats on-chain, décodeurs, matérialisateurs, exécuteurs lorsque applicables, orchestration stateful, scénarios réutilisables et validation desktop.
|
||||
|
||||
## Qualification réseau
|
||||
|
||||
### Solana Program Metadata
|
||||
|
||||
Les neuf opérations stables sont `confirmed` sur Devnet avec simulation, soumission, confirmation, lectures stateful, replay canonique et matérialisation.
|
||||
|
||||
### Token-2022 Token Metadata
|
||||
|
||||
Les cinq opérations de l’interface sont `confirmed` sur Devnet :
|
||||
|
||||
- `Initialize` ;
|
||||
- `UpdateField` ;
|
||||
- `Emit` ;
|
||||
- `RemoveKey` ;
|
||||
- `UpdateAuthority`.
|
||||
|
||||
### Metaplex Token Metadata
|
||||
|
||||
La matrice Devnet courante des vingt opérations est close :
|
||||
|
||||
- 15 `confirmed` ;
|
||||
- 5 `unavailable` ;
|
||||
- 0 `not_run`.
|
||||
|
||||
Les cinq opérations indisponibles restent explicitement bornées par les observations runtime documentées pendant `0.4.8-pre.013` ; elles ne sont jamais promues depuis une validation synthétique.
|
||||
|
||||
## Desktop Metadata
|
||||
|
||||
`kb-app-demo-desktop` sépare les trois domaines Metadata et appelle les scénarios réutilisables de `kb-pipeline-demo-scenarios`.
|
||||
|
||||
La validation finale couvre notamment :
|
||||
|
||||
- synchronisation du profil Devnet ;
|
||||
- campagnes spécialisées Metaplex ;
|
||||
- campagne Token-2022 Token Metadata ;
|
||||
- campagne Solana Program Metadata ;
|
||||
- JsonViewer pour les résultats structurés ;
|
||||
- accordéons de préflight, simulation/confirmation et postconditions/preuves ;
|
||||
- carte des exigences dans la colonne de résultats ;
|
||||
- journal d’exécution sur toute la largeur.
|
||||
|
||||
## Conformité finale du workspace
|
||||
|
||||
La campagne finale du 9 août 2026 est conforme :
|
||||
|
||||
- `cargo fmt --all` réussi ;
|
||||
- `cargo check --workspace` réussi ;
|
||||
- `cargo clippy --all-targets` réussi sans warning ;
|
||||
- `python3 scripts/audit_rust_workspace_rules.py` : audit Rust général propre, export completeness à zéro candidat et audit Khadhroony propre ;
|
||||
- `cargo test --workspace` réussi sur toutes les crates, tous les tests d’intégration et toutes les doctests.
|
||||
|
||||
Les principales cibles unitaires observées comprennent :
|
||||
|
||||
- `kb-app-demo-desktop` : 144 tests ;
|
||||
- `kb-config` : 46 tests ;
|
||||
- `kb-core` : 2 tests ;
|
||||
- `kb-lib` : 706 tests, plus 9 tests d’intégration ;
|
||||
- `kb-logging` : 17 tests ;
|
||||
- `kb-onchain-transport` : 118 tests ;
|
||||
- `kb-pipeline` : 109 tests, plus 3 tests d’intégration Metadata ;
|
||||
- `kb-pipeline-demo-scenarios` : 105 tests bibliothèque, 1 test CLI et 1 test API externe ;
|
||||
- `kb-program-ids` : 6 tests ;
|
||||
- `kb-store` : 84 tests ;
|
||||
- `kb-wallet` : 6 tests.
|
||||
|
||||
## Build desktop de release
|
||||
|
||||
La validation frontend n’est pas exécutée par un `npm run build` autonome.
|
||||
|
||||
La commande de release utilisée est :
|
||||
|
||||
```bash
|
||||
cargo tauri build -c kb-app-demo-desktop/tauri.conf.json
|
||||
```
|
||||
|
||||
Tauri déclenche le `beforeBuildCommand`, qui exécute TypeScript puis Vite. La configuration validée utilise :
|
||||
|
||||
- `root: 'frontend'` et `build.outDir: '../../dist'` côté Vite ;
|
||||
- `frontendDist: '../dist'` côté Tauri.
|
||||
|
||||
Ces deux chemins convergent vers le même répertoire `dist` à la racine du workspace.
|
||||
|
||||
Le build de release a produit avec succès :
|
||||
|
||||
- `Khadhroony Bot3 Demo Desktop_0.4.8_amd64.deb` ;
|
||||
- `Khadhroony Bot3 Demo Desktop-0.4.8-1.x86_64.rpm` ;
|
||||
- `Khadhroony Bot3 Demo Desktop_0.4.8_amd64.AppImage`.
|
||||
|
||||
## Limites et reports
|
||||
|
||||
- aucun fetch HTTP/IPFS/Arweave n’est intégré au replay canonique ;
|
||||
- la couverture généraliste différée — programmes/interfaces SPL non prioritaires, compléments Metaplex et autres Program IDs non bloquants pour la séquence trading prioritaire — est reportée à `0.15.x` ;
|
||||
- `kb-offchain-transport` est reportée à `0.16.x+` après repriorisation du ROADMAP ;
|
||||
- le registre ElGamal reste sans preuve réseau réelle disponible.
|
||||
|
||||
## Traçabilité
|
||||
|
||||
Les audits, rapports de prerelease et le plan de travail `0.4.8` sont archivés sous `olddocs/archivekbot3/`. Ils conservent la chronologie détaillée mais ne sont plus normatifs.
|
||||
|
||||
## Statut
|
||||
|
||||
**Version fonctionnelle `0.4.8` clôturée et validée.**
|
||||
@@ -1,45 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_008_SOLANA_PROGRAM_METADATA_MAINNET_REPLAY_REPORT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Validation mainnet du replay Solana Program Metadata — `0.4.8-pre.008`
|
||||
|
||||
## Résultat
|
||||
|
||||
La campagne historique exécutée après `pre.008-fix-002` valide le parcours réel `backfill → Core extraction → decode replay → matérialisation` pour les instructions Solana Program Metadata observées.
|
||||
|
||||
```text
|
||||
dispatched = 132
|
||||
decoded = 132
|
||||
failed = 0
|
||||
processingErrors = 0
|
||||
materializedOutputs = 132
|
||||
materializationRefused = 0
|
||||
```
|
||||
|
||||
## Répartition observée
|
||||
|
||||
| Opération | Observée | Décodée | Matérialisée |
|
||||
|----------------|---------:|--------:|-------------:|
|
||||
| `Write` | 88 | 88 | 88 |
|
||||
| `Allocate` | 15 | 15 | 15 |
|
||||
| `Initialize` | 11 | 11 | 11 |
|
||||
| `SetAuthority` | 7 | 7 | 7 |
|
||||
| `Close` | 5 | 5 | 5 |
|
||||
| `SetData` | 5 | 5 | 5 |
|
||||
| `SetImmutable` | 1 | 1 | 1 |
|
||||
| `Trim` | 0 | 0 | 0 |
|
||||
| `Extend` | 0 | 0 | 0 |
|
||||
|
||||
Les sept opérations rencontrées sont validées sur données mainnet réelles. `Trim` et `Extend` restent validées synthétiquement mais non observées dans cet échantillon. Elles doivent être exercées par les scénarios Devnet de `pre.009` et `pre.010`.
|
||||
|
||||
## Anomalies non liées
|
||||
|
||||
Quatre entrées Loader v4 ont été classées `Unsupported` sans échec de traitement. Elles proviennent de transactions déjà échouées avec `ProgramAccountNotFound` et ne concernent pas `ProgM6…`.
|
||||
|
||||
## Preuve conservée
|
||||
|
||||
- archive : `docs/validation/evidence/v0.4.8/pre.008/mainnet/mainnet_research_v0.4.8-pre.008-01.zip` ;
|
||||
- SHA-256 : `16b3722d4b75afdef304f7b16af4baa3b51713d87a74e9e4a7aac0c0f0411335` ;
|
||||
- manifeste : `docs/validation/evidence/v0.4.8/pre.008/mainnet/SHA256SUMS`.
|
||||
|
||||
Cette archive est une preuve documentaire immuable. Le code, les tests et les runners ne doivent jamais en dépendre.
|
||||
@@ -1,59 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_010_SOLANA_PROGRAM_METADATA_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Validation Devnet Solana Program Metadata — `0.4.8-pre.010`
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Ce rapport clôt la validation réseau de l’intégration Solana Program Metadata livrée entre `0.4.8-pre.009` et `0.4.8-pre.010`.
|
||||
|
||||
La preuve brute est conservée sous [`evidence/v0.4.8/pre.010/devnet/`](evidence/v0.4.8/pre.010/devnet/README.md).
|
||||
|
||||
## 2. Environnement observé
|
||||
|
||||
- cluster : Solana Devnet ;
|
||||
- endpoint : profil `local_devnet` ;
|
||||
- autorité opérateur : wallet temporaire persistant du profil ;
|
||||
- programme : `ProgM6JCCvbYkfKqJYHePx4xxSUSqJp7rh8Lyv7nk7S` ;
|
||||
- mode : simulation obligatoire, soumission contrôlée, confirmation, lecture stateful et postcondition.
|
||||
|
||||
Le nom source de l’archive indiquait `mainnet_research`, mais son contenu utilise Devnet. Elle est donc classée comme preuve Devnet.
|
||||
|
||||
## 3. Campagnes exécutées
|
||||
|
||||
Deux fixtures indépendantes ont été préparées. Chaque campagne a exécuté :
|
||||
|
||||
1. deux transferts de préfinancement ;
|
||||
2. le parcours Buffer `Allocate → Extend → Write → SetAuthority → Trim → Close` ;
|
||||
3. le parcours Metadata `Initialize → SetData → SetImmutable`.
|
||||
|
||||
Le corpus contient ainsi :
|
||||
|
||||
- 2 campagnes complètes ;
|
||||
- 22 transactions confirmées ;
|
||||
- 18 opérations Solana Program Metadata ;
|
||||
- 18 postconditions `Confirmed` ;
|
||||
- 0 fichier d’erreur non vide ;
|
||||
- 0 réponse HTTP ou JSON-RPC `429` observée.
|
||||
|
||||
## 4. Résultats par opération
|
||||
|
||||
| Opération | Exécutions confirmées | Postconditions confirmées |
|
||||
|----------------|----------------------:|--------------------------:|
|
||||
| `Allocate` | 2 | 2 |
|
||||
| `Extend` | 2 | 2 |
|
||||
| `Write` | 2 | 2 |
|
||||
| `SetAuthority` | 2 | 2 |
|
||||
| `Trim` | 2 | 2 |
|
||||
| `Close` | 2 | 2 |
|
||||
| `Initialize` | 2 | 2 |
|
||||
| `SetData` | 2 | 2 |
|
||||
| `SetImmutable` | 2 | 2 |
|
||||
|
||||
`Close` est validée par l’absence finale du compte. Les autres opérations sont validées par une lecture stateful et une projection cohérente avec la postcondition attendue.
|
||||
|
||||
## 5. Conclusion
|
||||
|
||||
La couverture exécutable des neuf instructions stables Solana Program Metadata est validée sur Devnet, y compris `Extend` et `Trim`, qui n’avaient pas été observées dans l’échantillon historique mainnet de `pre.008`.
|
||||
|
||||
La surface Solana Program Metadata peut être considérée comme complète pour `0.4.8`, sous réserve des réconciliations transversales et documentaires prévues avant la clôture finale de la version.
|
||||
@@ -1,86 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_012_TOKEN_2022_METADATA_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.012` — Token-2022 Token Metadata
|
||||
|
||||
## Statut
|
||||
|
||||
**Confirmée sur Devnet le 7 août 2026.**
|
||||
|
||||
La campagne complète a été exécutée sur un mint Token-2022 frais. Les cinq opérations prévues ont produit une transaction confirmée et une postcondition `Confirmed`.
|
||||
|
||||
## Program ID
|
||||
|
||||
```text
|
||||
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb
|
||||
```
|
||||
|
||||
## Fixture
|
||||
|
||||
```text
|
||||
mint=EHrx1evxgXLEgjb1sgc5dVTktXX1LiovXR9YFsZS3d4k
|
||||
preparation_signature=2yYciRNoTTNSGuuaBFE6925FPjSj4fXp8usSkpLhgEPuhQMJYdsEzkAzxBdjDhpPHCT3db9bLz9Ud4BU5QSQZzQ5
|
||||
initial_authority=J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH
|
||||
final_authority=3RVXUmVvY7quUUEVsDKh5EcenVygwv3mo1iagPa4Pmq7
|
||||
```
|
||||
|
||||
La préparation crée `MetadataPointer` avant `InitializeMint2`, le fait pointer vers le mint lui-même et vérifie statefully l'absence initiale de `TokenMetadata`.
|
||||
|
||||
## Transactions confirmées
|
||||
|
||||
| Scénario | Opération canonique | Signature | Slot | Postcondition |
|
||||
|----------------------------------------|--------------------------------------------------|--------------------------------------------------------------------------------------------|----------:|---------------|
|
||||
| `token_2022_metadata_initialize` | `spl.token_2022.initialize_token_metadata` | `48kzJR5VW1ZYSRkVrg6qyNmuHdAUu7NXcnzaNsSmH7SSmRXK1X6RQdCeeSQi6LhrrkgRFRGVnxkwXPtkiqG6EgnY` | 481804441 | `Confirmed` |
|
||||
| `token_2022_metadata_update_field` | `spl.token_2022.update_token_metadata_field` | `JrdB9EqePS1FVWLo55w1Vhv2eTCTfCpXZgMvPCocW3m3iu4nk3BFBBRHoe2Nbcpq1rmnZoFrhnag5fG2WwmJrYs` | 481804454 | `Confirmed` |
|
||||
| `token_2022_metadata_emit` | `spl.token_2022.emit_token_metadata` | `3TKdBCJhM1VEZ9ti6EYR9gSLJnH5ni6FjW4kvoqwdYK1u14jdY6hS8hf2VGeLi21PbX5CWiyzjthJZERK5KHroWH` | 481804464 | `Confirmed` |
|
||||
| `token_2022_metadata_remove_key` | `spl.token_2022.remove_token_metadata_key` | `3kDBV7pDFgoCQVJ9DYYuxvHFbCJzyA6J2rLg6ndGCETEhhFBZ1ipRQ52X2hZfwNPfdJwEFFBmbyMU6kFGnVXJNrm` | 481804473 | `Confirmed` |
|
||||
| `token_2022_metadata_update_authority` | `spl.token_2022.update_token_metadata_authority` | `5aBpQsm6mAHA5xSN5tZ1ubALbfghGa7JScjXn9NGhg9agzEdjXydH6jgmn6UmxinGHmMvtqaGRLk9dgjmmz4HpU2` | 481804482 | `Confirmed` |
|
||||
|
||||
## Preuves spécialisées
|
||||
|
||||
### `Initialize`
|
||||
|
||||
Le snapshot final confirme les champs initiaux du `TokenMetadata` et une matérialisation instructionnelle est observée.
|
||||
|
||||
### `UpdateField`
|
||||
|
||||
La paire additionnelle `campaign=0.4.8-pre.012` est présente dans le snapshot autoritatif et une matérialisation instructionnelle est observée.
|
||||
|
||||
### `Emit`
|
||||
|
||||
La simulation retourne **202 octets** de `returnData`. Le runner décode la valeur complète et exige son égalité avec le `TokenMetadata` relu depuis le TLV du mint. La politique n'exige pas de matérialisation instructionnelle pour cette opération non mutante.
|
||||
|
||||
### `RemoveKey`
|
||||
|
||||
La paire `campaign` est absente du snapshot final et une matérialisation instructionnelle est observée.
|
||||
|
||||
### `UpdateAuthority`
|
||||
|
||||
L'autorité finale du snapshot TLV est :
|
||||
|
||||
```text
|
||||
3RVXUmVvY7quUUEVsDKh5EcenVygwv3mo1iagPa4Pmq7
|
||||
```
|
||||
|
||||
Elle correspond exactement à l'autorité fraîche préparée avant la campagne.
|
||||
|
||||
## Matrice machine-readable
|
||||
|
||||
`test-fixtures/contract-matrices/SPL_TOKEN_2022_METADATA_DEVNET_VALIDATION_MATRIX.json` porte désormais les cinq scénarios au statut `confirmed` et conserve toutes les catégories de preuve requises.
|
||||
|
||||
## Validations locales
|
||||
|
||||
Avant et après la campagne :
|
||||
|
||||
```text
|
||||
cargo fmt --all réussi
|
||||
cargo check --workspace réussi
|
||||
cargo clippy --all-targets réussi
|
||||
python3 scripts/audit_rust_workspace_rules.py clean
|
||||
cargo test -p kb-pipeline-demo-scenarios 69 + 1 + 1 tests réussis
|
||||
cargo test --workspace réussi
|
||||
```
|
||||
|
||||
## Conclusion
|
||||
|
||||
La campagne `0.4.8-pre.012` fournit une preuve Devnet complète pour les cinq instructions de `spl-token-metadata-interface` intégrées à Token-2022. Aucune des cinq lignes de la matrice ne reste `not_run`.
|
||||
@@ -1,139 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_COLLECTION_VERIFY_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — collection Metaplex `Verify -> Unverify`
|
||||
|
||||
## Statut
|
||||
|
||||
**Confirmé sur Devnet — `Verify` et `Unverify` qualifiés avec transition collection complète.**
|
||||
|
||||
Le rerun après `pre.013-delta-fix-018` termine le parcours `Verify(CollectionV1) -> Unverify(CollectionV1)` de bout en bout. Les deux opérations passent simulation exacte, confirmation, hydratation canonique, extraction Core, decode replay, matérialisation instructionnelle, snapshots stateful et seconde passe idempotente. La matrice Devnet v3 les promeut donc à `confirmed` sur la famille `collection`.
|
||||
|
||||
## Première tentative réseau après `fix-017`
|
||||
|
||||
La transaction `Verify(CollectionV1)` est confirmée sur Devnet :
|
||||
|
||||
- signature : `2kR1VeWdCW3FcKRZdNuKMMc3kGUmWRBXxXX8W1NNi2rhWfZYTg9zsDvJHx7WvebgUfc2K382J14i66E2qPEnjsqR` ;
|
||||
- slot confirmé : `481931061` ;
|
||||
- hydratation canonique : réussie ;
|
||||
- extraction Core : réussie ;
|
||||
- snapshots stateful : `3` ;
|
||||
- replay : `selected=1`, `started=1`, `completed=1`, `failed_inputs=1`, `decoded=0` ;
|
||||
- matérialisation instructionnelle : absente à cause de l’échec du décodeur ;
|
||||
- `Unverify` : non atteint.
|
||||
|
||||
Le diagnostic est local au replay. L’autorité de collection est également le fee payer : le message Solana la projette donc `signer + writable`, alors que l’AccountMeta `Verify` courant exige seulement `signer`. Le décodeur comparait encore les flags de façon exacte au lieu de traiter les privilèges transactionnels comme des sur-ensembles. Le même audit révèle que `Unverify` était artificiellement borné à 8 positions alors que le wrapper courant en construit 7. `fix-018` corrige ces deux défauts sans promouvoir la preuve partielle.
|
||||
|
||||
## Rerun réussi après `fix-018`
|
||||
|
||||
### `Verify(CollectionV1)`
|
||||
|
||||
- signature : `39JwUoxF2WWYWvEEWzFxSmKZVwoqXD1wH78sgGaoXv2vZKYUsXDNNnKikeuyQcfCqDftEMHSKFDHnTeSQ3bRpFcJ` ;
|
||||
- simulation context slot : `481936725` ;
|
||||
- confirmation slot : `481936730` ;
|
||||
- simulation : succès, `5` logs ;
|
||||
- message hash : `9o3WH8iWDcpoTuwx582MGPHAYiRmy36SRm1579Zrh9tw` ;
|
||||
- fee : `5000` lamports ;
|
||||
- snapshots avant/après : `3 / 3` ;
|
||||
- hydratation canonique, extraction Core, decode replay, matérialisation et idempotence : réussis ;
|
||||
- matérialisations instructionnelles : `1` ; snapshots matérialisés : `3`.
|
||||
|
||||
### `Unverify(CollectionV1)`
|
||||
|
||||
- signature : `4Kfv42BGZtuBEwqTie5RWwdQ772hyxKiU9d3F3gfRnwVNrxCs2iZMvwL17Rwmuyr3XCVoHdaJVgaqCwv8y7bKoZY` ;
|
||||
- simulation context slot : `481936738` ;
|
||||
- confirmation slot : `481936742` ;
|
||||
- simulation : succès, `4` logs ;
|
||||
- message hash : `HcrUFoW8i7oRVxbmyt8cpHpwgL2nSTaH9WuPsLEYfSKT` ;
|
||||
- fee : `5000` lamports ;
|
||||
- snapshots avant/après : `3 / 3` ;
|
||||
- hydratation canonique, extraction Core, decode replay, matérialisation et idempotence : réussis ;
|
||||
- matérialisations instructionnelles : `1` ; snapshots matérialisés : `3`.
|
||||
|
||||
### Transition autoritative observée
|
||||
|
||||
- membre : `collection.verified = false -> true -> false` ;
|
||||
- parent : `CollectionDetails::V1.size = 0 -> 1 -> 0`.
|
||||
|
||||
Ces preuves remplissent les seize dimensions réseau exigées par opération dans la matrice v3.
|
||||
|
||||
## Contrat de fixture
|
||||
|
||||
Le parcours prépare deux actifs frais :
|
||||
|
||||
1. un Collection NFT parent avec `CollectionDetails::V1 { size: 0 }`, Master Edition et supply `1` ;
|
||||
2. un NFT membre avec une relation `collection = { key: <parent mint>, verified: false }`, Master Edition et supply `1`.
|
||||
|
||||
Les deux actifs passent d’abord par le runner qualifié `Create -> Mint`. Le parcours spécialisé refuse donc de commencer `Verify` si le membre n’est pas explicitement non vérifié ou si la taille du parent n’est pas exactement `0`.
|
||||
|
||||
## Opérations qualifiées par le runner
|
||||
|
||||
Le runner spécialisé exécute ensuite exactement :
|
||||
|
||||
1. `metadata.metaplex_token_metadata.verify` avec `VerificationArgs::CollectionV1` ;
|
||||
2. `metadata.metaplex_token_metadata.unverify` avec `VerificationArgs::CollectionV1`.
|
||||
|
||||
`Verify` reçoit le mint, la metadata et la Master Edition du parent. `Unverify` reçoit le mint et la metadata du parent conformément au wrapper courant `mpl-token-metadata 5.1.1`.
|
||||
|
||||
## Postconditions obligatoires
|
||||
|
||||
Le runner lit après chaque confirmation :
|
||||
|
||||
- la Metadata PDA du membre ;
|
||||
- la Metadata PDA du parent ;
|
||||
- la Master Edition PDA du parent.
|
||||
|
||||
Les transitions attendues sont fermées :
|
||||
|
||||
| État | `collection.verified` membre | `CollectionDetails::V1.size` parent |
|
||||
|------------------|-----------------------------:|------------------------------------:|
|
||||
| avant `Verify` | `false` | `0` |
|
||||
| après `Verify` | `true` | `1` |
|
||||
| après `Unverify` | `false` | `0` |
|
||||
|
||||
La taille est validée comme état dérivé du programme ; le runner n’utilise pas l’opération obsolète `SetCollectionSize` pour fabriquer la postcondition.
|
||||
Le snapshot stateful provient de `serde_json::to_value(mpl_token_metadata::accounts::Metadata)` ; le champ lu est donc exactement `collection_details.V1.size`, conformément au nom Rust sérialisé par le SDK 5.1.1.
|
||||
|
||||
Chaque opération doit également démontrer :
|
||||
|
||||
- simulation exacte réussie ;
|
||||
- confirmation `Confirmed` ou `Finalized` avec slot ;
|
||||
- hydratation canonique ;
|
||||
- extraction Core ;
|
||||
- decode replay Metaplex ;
|
||||
- au moins une matérialisation instructionnelle ;
|
||||
- snapshots stateful matérialisés ;
|
||||
- seconde passe idempotente sans nouvel output ni refus.
|
||||
|
||||
## Commande opérateur
|
||||
|
||||
```bash
|
||||
KB_DEVNET_METAPLEX_COLLECTION_VERIFY_CAMPAIGN_TEST=1 \
|
||||
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
|
||||
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
|
||||
cargo test -p kb-pipeline-demo-scenarios \
|
||||
optional_devnet_metaplex_collection_verify_campaign_from_env \
|
||||
-- --nocapture
|
||||
```
|
||||
|
||||
`KB_DEVNET_PROFILE` et `KB_DEVNET_CONFIG_PATH` restent optionnels comme pour les autres campagnes Devnet.
|
||||
|
||||
## Sortie à conserver
|
||||
|
||||
Une exécution réussie imprime :
|
||||
|
||||
```text
|
||||
METAPLEX_COLLECTION_VERIFY_FIXTURE ...
|
||||
METAPLEX_COLLECTION_VERIFY_STEP operation=metadata.metaplex_token_metadata.verify ...
|
||||
METAPLEX_COLLECTION_VERIFY_STEP operation=metadata.metaplex_token_metadata.unverify ...
|
||||
METAPLEX_COLLECTION_VERIFY_STATE verified_before=false verified_after_verify=true verified_after_unverify=false size_before=0 size_after_verify=1 size_after_unverify=0
|
||||
METAPLEX_COLLECTION_VERIFY_EVIDENCE verify={...} unverify={...}
|
||||
```
|
||||
|
||||
Les objets de la dernière ligne conservent les mêmes dimensions machine-readable que la campagne `Create -> Mint` : genesis hash, slot/logs de simulation, message hash, fee, signature, statut/slot de confirmation, snapshots, hydratation, Core, replay, matérialisation et idempotence.
|
||||
|
||||
## Promotion de matrice
|
||||
|
||||
`Verify` et `Unverify` sont désormais `confirmed` sur la famille `collection`, avec un bundle `familyEvidence` de seize preuves chacun. Avec `Create` et `Mint`, la matrice compte donc `4` opérations courantes confirmées et `16` opérations `not_run`.
|
||||
|
||||
La prochaine campagne spécialisée est `Print -> Burn`; aucune preuve de cette campagne n’est promue avant une exécution Devnet complète terminée par `ok`.
|
||||
@@ -1,268 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_CREATE_MINT_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 12 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — Metaplex `Create -> Mint`
|
||||
|
||||
## Statut
|
||||
|
||||
**Campagne multi-famille `Create -> Mint` fermée : NFT, SFT, fungible, collection et pNFT sont confirmés sur Devnet.**
|
||||
|
||||
Le 7 août 2026, une première campagne NFT a atteint la post-validation de `Create` puis s’est arrêtée sur un diagnostic agrégé. Après `fix-007`, la seconde tentative localise une borne stateful incompatible avec le transport ; `fix-008` l’aligne sur `65536` octets. La troisième tentative franchit alors la lecture stateful, l’hydratation canonique et l’extraction Core : `Create` est réellement confirmée avec la signature `51MXdFFFNY7UTS23cmfCQBfrDKC99uk5Trtw2gkptvEug9aWJ2R1cE9Ta5QHbe4kS1NYgRUSSMmmdbqdhyxxnR4Y` au slot `481882374`, puis `fix-009` corrige le replay executor -> decoder. Les quatrième et cinquième tentatives atteignent ensuite une postcondition SPL qui exigeait à tort que l’autorité opérateur survive à `Create` pour un NFT Master Edition. `fix-011` corrige cette attente vers le PDA Master Edition. La sixième tentative termine enfin la campagne : `Create` est confirmé au slot `481904731` avec une matérialisation, puis `Mint` au slot `481904744` avec une matérialisation et la transition SPL exacte supply/amount `0 -> 1`. `fix-012` promeut donc les deux opérations à `confirmed` sur la famille NFT dans la matrice opérationnelle. La campagne SFT suivante réussit également de bout en bout : `Create` est confirmé au slot `481908028`, `Mint` au slot `481908039`, chaque étape produit une matérialisation, et la supply ainsi que l’amount passent de `0` à `10`. `fix-013` conserve donc `Create` et `Mint` comme seules opérations `confirmed`, désormais observées sur NFT et SFT ; les 18 autres opérations restent `not_run` et fungible/collection/pNFT restent à exécuter. La campagne fungible suivante réussit à son tour : `Create` est confirmé au slot `481910724`, puis `Mint` au slot `481910734`, avec une matérialisation par étape et la transition brute supply/amount `0 -> 1_000_000_000` sur un mint à 9 décimales. `fix-014` ajoute donc `fungible` aux bundles de preuves de `Create` et `Mint`. La campagne collection suivante réussit également de bout en bout : `Create` est confirmé au slot `481911942`, puis `Mint` au slot `481911955`, avec une matérialisation instructionnelle par étape, deux snapshots stateful et la transition supply/amount `0 -> 1`. `fix-015` ajoute `collection` aux bundles de preuves, corrige la régression du test de matrice resté figé sur NFT/SFT et laisse pNFT comme dernière variante `Create -> Mint` à exécuter.
|
||||
|
||||
## Première tentative NFT
|
||||
|
||||
Contrôles locaux avant réseau : `cargo fmt --all`, `cargo check --workspace`, audit workspace et tests de crate réussis ; `cargo clippy --all-targets` ne signalait qu'un warning `cloned_ref_to_slice_refs`, corrigé dans `fix-007`. La campagne réseau a ensuite échoué avec :
|
||||
|
||||
```text
|
||||
metaplex_create_mint_post_execution_incomplete:
|
||||
Metaplex create did not complete canonical replay and materialization
|
||||
```
|
||||
|
||||
Ce message ne permettait pas d'identifier le sous-état fautif. Aucune promotion de matrice n'est autorisée à partir de cette tentative.
|
||||
|
||||
|
||||
## Seconde tentative NFT
|
||||
|
||||
La validation locale de `fix-007` réussit avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, l'audit workspace, 78 tests unitaires `kb-pipeline-demo-scenarios` et 135 tests desktop. La nouvelle campagne NFT échoue ensuite avec le diagnostic exact :
|
||||
|
||||
```text
|
||||
canonical_inserted=false, core_extracted=false, decode_replayed=false, materialized=false,
|
||||
materialization_rows=0, materialized_snapshots=0,
|
||||
diagnostics=["Metaplex stateful postcondition read failed: configuration error: getAccountInfo complete data limit must be between 1 and 65536 bytes"]
|
||||
```
|
||||
|
||||
L'échec précède donc hydratation, extraction et replay : il provient du contrat de lecture stateful, pas d'une preuve que `Create` aurait échoué on-chain. La constante pipeline historique de `1 MiB` dépassait la borne du transport. `fix-008` remplace cette borne par `kb_onchain_transport::MAX_COMPLETE_ACCOUNT_DATA_BYTES`.
|
||||
|
||||
## Troisième tentative NFT
|
||||
|
||||
La validation locale de `fix-008` réussit avec `cargo check --workspace`, `cargo clippy --all-targets`, 106 tests unitaires `kb-pipeline`, 78 tests unitaires `kb-pipeline-demo-scenarios` et 135 tests desktop. La campagne produit ensuite :
|
||||
|
||||
```text
|
||||
signature=51MXdFFFNY7UTS23cmfCQBfrDKC99uk5Trtw2gkptvEug9aWJ2R1cE9Ta5QHbe4kS1NYgRUSSMmmdbqdhyxxnR4Y
|
||||
slot=481882374
|
||||
canonical_inserted=true
|
||||
core_extracted=true
|
||||
decode_replayed=false
|
||||
materialized=false
|
||||
materialization_rows=0
|
||||
materialized_snapshots=2
|
||||
```
|
||||
|
||||
La transaction `Create` est donc confirmée et les deux snapshots stateful sont disponibles, mais le décodeur instructionnel refuse encore le replay. Le réaudit du contrat local montre que `validate_accounts("create")` imposait historiquement le mint signer et l’update authority signer, alors que l’exécuteur courant expose respectivement `mint_as_signer` et `update_authority_as_signer`. La fixture utilise volontairement `mint_as_signer=false` car le mint est créé dans la transaction de préparation. De plus, authority, payer et update authority partagent le même wallet : leurs flags visibles dans le replay sont des privilèges globaux de transaction et peuvent donc être des sur-ensembles des metas positionnelles. Le même problème aurait touché `Mint`, où token owner, authority et payer partagent également le wallet opérateur.
|
||||
|
||||
`fix-009` remplace pour `Create` et `Mint` l’égalité stricte des flags par des minima de privilèges requis, tout en conservant writable obligatoire sur les comptes optionnels réellement présents. Il ajoute aussi les compteurs détaillés du premier replay au diagnostic. Cette correction doit être validée localement puis la campagne NFT rejouée avant toute promotion de matrice.
|
||||
|
||||
## Frontière de la campagne
|
||||
|
||||
Une invocation couvre une seule famille afin de limiter le nombre de transactions et de rendre les diagnostics attribuables :
|
||||
|
||||
- `nft` ;
|
||||
- `sft` ;
|
||||
- `fungible` ;
|
||||
- `collection` ;
|
||||
- `programmable_nft` ou `pnft`.
|
||||
|
||||
Chaque invocation exécute trois transactions au maximum : préparation native du mint + ATA, `Create`, puis `Mint`.
|
||||
|
||||
## Preuves exigées
|
||||
|
||||
Pour `Create` et `Mint` :
|
||||
|
||||
- simulation réussie liée au message exact ;
|
||||
- signature et confirmation Devnet ;
|
||||
- slot de confirmation ;
|
||||
- `after_state` Metaplex relu avec `minContextSlot >= confirmation_slot` ;
|
||||
- hydratation canonique de la transaction ;
|
||||
- extraction Core ;
|
||||
- replay du décodeur Metaplex ;
|
||||
- matérialisation instructionnelle ;
|
||||
- seconde passe de replay sans nouvel output ;
|
||||
- snapshot metadata et master edition lorsqu’elle est requise ;
|
||||
- token record après `Mint` pour pNFT ;
|
||||
- supply du mint et amount de l’ATA à zéro après `Create` ;
|
||||
- supply du mint et amount de l’ATA exactement égaux à `mint_amount_raw` après `Mint`.
|
||||
|
||||
## Commande initiale — NFT
|
||||
|
||||
```bash
|
||||
KB_DEVNET_METAPLEX_CREATE_MINT_CAMPAIGN_TEST=1 \
|
||||
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
|
||||
KB_DEVNET_METAPLEX_CREATE_MINT_FAMILY=nft \
|
||||
KB_POSTGRES_TEST_URL='postgresql://…' \
|
||||
cargo test -p kb-pipeline-demo-scenarios \
|
||||
optional_devnet_metaplex_create_mint_campaign_from_env \
|
||||
-- --nocapture
|
||||
```
|
||||
|
||||
`KB_DEVNET_PROFILE` et `KB_DEVNET_CONFIG_PATH` restent disponibles lorsque le profil par défaut n’est pas celui à utiliser.
|
||||
|
||||
## Sortie attendue
|
||||
|
||||
La campagne imprime :
|
||||
|
||||
```text
|
||||
METAPLEX_CREATE_MINT_FIXTURE ...
|
||||
METAPLEX_CREATE_MINT_STEP operation=metadata.metaplex_token_metadata.create ...
|
||||
METAPLEX_CREATE_MINT_STEP operation=metadata.metaplex_token_metadata.mint ...
|
||||
```
|
||||
|
||||
Les cinq chemins NFT, SFT, fungible, collection et pNFT sont désormais qualifiés dans les bundles `familyEvidence` de `Create` et `Mint`. La campagne multi-famille `Create -> Mint` est donc fermée ; les opérations spécialisées suivantes restent qualifiées séparément.
|
||||
|
||||
## Quatrième tentative NFT — mismatch d’autorité initialement mal interprété
|
||||
|
||||
La tentative suivant `fix-009` observe `3RJXuBF6xB3j47EeAHEBbcwvV66rJrkhmJvYNr36jz8x` comme mint authority et freeze authority au lieu de l’opérateur `J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH`. Cette sortie a d’abord été interprétée comme une réutilisation de fixture. `pre.013-delta-fix-010` a donc rendu la préparation fresh-only avec `TemporaryWalletStore::create`, absence on-chain préalable et relectures liées au slot confirmé. Ce durcissement reste souhaitable, mais l’interprétation « stale fixture » était incomplète.
|
||||
|
||||
Le réaudit du chemin exact montre que ce contrôle d’autorité est exécuté seulement après `validate_confirmed_execution("create", ...)`. Le mismatch est donc postérieur à `Create`, et non antérieur à toute instruction Metaplex.
|
||||
|
||||
## Cinquième tentative NFT — pipeline `Create` complet, postcondition SPL incorrecte
|
||||
|
||||
Après `fix-010`, la validation locale confirme 701 tests unitaires `kb-lib`, 106 tests unitaires `kb-pipeline`, 78 tests unitaires de scénarios et 135 tests desktop ; un unique warning `dead_code` subsiste pour `read_token_account`. La campagne fresh-only observe ensuite `KsjdBdmUUM3r8Mw6cQESkXJfxmnPXSmR482963gmsyo` comme mint authority et freeze authority après `Create`, face à l’attente opérateur `J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH`.
|
||||
|
||||
Cette erreur intervient après `validate_confirmed_execution("create", ...)`. Par construction, `Create` a donc déjà franchi simulation, confirmation, hydratation canonique, extraction Core, replay, matérialisation instructionnelle, snapshots stateful et seconde passe idempotente. La campagne ne copiait cependant pas signature + slot dans cette erreur SPL, donc la preuve n’est pas encore exploitable pour promouvoir `Create` dans la matrice.
|
||||
|
||||
Le contrat officiel Token Metadata explique la mutation : lors de la création d’un NFT avec Master Edition, mint authority et freeze authority sont transférées au PDA Edition/Master Edition. `pre.013-delta-fix-011` attend donc ce PDA pour NFT, collection et pNFT, et conserve l’opérateur pour SFT et fungible. Il maintient cette attente après `Mint`, ajoute signature + slot aux erreurs SPL post-confirmation et supprime le helper mort.
|
||||
|
||||
## Sixième tentative NFT — campagne complète confirmée
|
||||
|
||||
Après application de `pre.013-delta-fix-011`, la campagne NFT fresh-only termine les deux étapes et imprime les preuves suivantes :
|
||||
|
||||
```text
|
||||
fixture family=Nft
|
||||
mint=J6pDBZR4nWpM8Mj61fEdwQXH3KLZE8RuKSEsyNofC7bp
|
||||
metadata=7JLnovNwuatxAessRcWCEuKb5jg2H93KVpmyHNzx4euG
|
||||
master_edition=GxUFL8ZfosThA4hUVGPKDT8Zvcc2b2VmdjEiw6WQQYNx
|
||||
token_account=9LBJCDFkJghjVDDeccTe4vjZH3dDNpzsWVXqyTKs81To
|
||||
preparation_signature=2u4sdcFhmoeeYiAe8X761AmCnWyPLHSxYwzwwocLYkfVCan9W5i13ipvK4v3dWRe9E4iJRqBCHHFRh8MwR2o8FLh
|
||||
|
||||
Create:
|
||||
signature=okwkuQFp7yVguYW7GEY9Chv6ochM8TWBEeCGV1gu5Waku9wQvMfrKjkig6JxXBwpKoFTECignzJ8HFf8dLtpsvS
|
||||
slot=481904731
|
||||
materializations=1
|
||||
|
||||
Mint:
|
||||
signature=3hSizfdvezyFpfhqX4Za4wmhdMHhSPAisFvYjFAxpRzYcUXhryxCzc9qpwod3Yjm6GmijXTGjjDUuVksfpBzLwz1
|
||||
slot=481904744
|
||||
materializations=1
|
||||
supply_before=0
|
||||
supply_after=1
|
||||
token_before=0
|
||||
token_after=1
|
||||
```
|
||||
|
||||
Le test ne peut retourner `ok` qu’après simulation réussie, confirmation, hydratation canonique, extraction Core, replay Metaplex, matérialisation instructionnelle, snapshots stateful et seconde passe idempotente pour chacune des deux transactions. La postcondition SPL vérifie en plus que la supply et l’ATA restent à zéro après `Create`, puis deviennent exactement `1` après `Mint`. Cette sortie constitue donc la première preuve complète de `pre.013`.
|
||||
|
||||
`METAPLEX_TOKEN_METADATA_DEVNET_EXECUTION_MATRIX.json` passe en version 2 afin de conserver les familles observées et les preuves réellement qualifiantes. `Create` et `Mint` sont `confirmed` avec `observedFamilies=["nft"]`. Les 18 autres opérations restent `not_run`. Les valeurs de télémétrie qui n’étaient pas imprimées par `fix-011` sont explicitement marquées comme telles au lieu d’être inventées.
|
||||
|
||||
`fix-012` ajoute enfin une ligne `METAPLEX_CREATE_MINT_EVIDENCE` contenant, pour les prochaines familles, le genesis hash, le slot de simulation, le message hash, le fee, la signature, le statut/slot de confirmation et les états du pipeline. Les campagnes fungible, collection et pNFT pourront ainsi être reportées sans nouvelle perte de preuve ; la campagne SFT utilise déjà ce format machine-readable.
|
||||
|
||||
## Campagne SFT confirmée
|
||||
|
||||
Après application de `fix-012`, la campagne SFT termine sans erreur. La fixture fraîche utilise le mint `UhymxTPkMQJW3rzTa5Ff1FMhxgB4dPNRzqZM2ghgwZD`, la metadata PDA `47jQ8Smucco7QjSRa1gzR8pF7RXiugZW69eF2825svjt` et l’ATA opérateur `EF2epsY37WqXrGPuqB4VKCyMGMYcN1wVSkDZ2JNqQuJt`. La préparation native est confirmée par `53w14jG5KDEcDTfCAd2GDKmoJG1pRcVp9a9JZgzQ9DgFyPV8v5iYEGLdfAhS8jmhT8DaVodjDc4AqnrA6H7Fc5XM`.
|
||||
|
||||
### `Create` SFT
|
||||
|
||||
- genesis hash : `EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG` ;
|
||||
- simulation context slot : `481908023` ;
|
||||
- logs de simulation : `12` ;
|
||||
- message hash : `6zv9nc8ARRfKx29LhiwAfzME8a5LSQ6AF4BUYdy1D3WE` ;
|
||||
- fee : `5000` lamports ;
|
||||
- signature : `2s81m6k9HYDLmCy7oXKaqBvtb62iyX4bJmij2f2VjHuoRQBBA6YqRuAsjyaM7JCaJXasbU3WCfiko91cZcDLLdxV` ;
|
||||
- statut : `Confirmed` ;
|
||||
- slot : `481908028` ;
|
||||
- matérialisation instructionnelle : `1` ;
|
||||
- snapshots : `0 -> 1` ;
|
||||
- hydratation canonique, extraction Core, replay et seconde passe idempotente : réussis.
|
||||
|
||||
### `Mint` SFT
|
||||
|
||||
- simulation context slot : `481908034` ;
|
||||
- logs de simulation : `7` ;
|
||||
- message hash : `65VBkcnKtZdxLZgwTu669Voz57PqYJbQ8iAUe5jWUKJ6` ;
|
||||
- fee : `5000` lamports ;
|
||||
- signature : `4pAemhEJewuLAeqLkqwzPvVmsCRbkyLiN6uAUWBA5RMsofaEDt5Xr8YGiBEvLWQM7Qvxnd81mmCHpandmfmWuyAm` ;
|
||||
- statut : `Confirmed` ;
|
||||
- slot : `481908039` ;
|
||||
- matérialisation instructionnelle : `1` ;
|
||||
- snapshots : `1 -> 1` ;
|
||||
- supply : `0 -> 10` ;
|
||||
- amount ATA : `0 -> 10` ;
|
||||
- hydratation canonique, extraction Core, replay et seconde passe idempotente : réussis.
|
||||
|
||||
La validation locale qui suit est propre : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, audit workspace, 79 tests unitaires `kb-pipeline-demo-scenarios` et 135 tests desktop.
|
||||
|
||||
## Matrice v3 — preuves par famille
|
||||
|
||||
La campagne SFT montre qu’une simple liste `evidence` par opération n’est plus suffisante : NFT et SFT ont leurs propres signatures, slots, message hashes et états. `fix-013` passe donc la matrice en version 3 et ajoute un bundle `familyEvidence` complet pour chaque entrée de `observedFamilies`. Une opération `confirmed` est refusée si une famille observée n’a pas exactement son bundle de preuves de simulation et de soumission. L’ancien champ `evidence` reste réservé aux états non familiaux comme `unavailable`.
|
||||
|
||||
À ce stade, `Create` et `Mint` sont `confirmed` sur `nft` et `sft`. Les familles `fungible`, `collection` et `programmable_nft` restent à qualifier.
|
||||
|
||||
## Consolidation `pre.013-delta-fix-014` — qualification fungible
|
||||
|
||||
La campagne fungible `Create -> Mint` est confirmée de bout en bout sur Devnet. La fixture fraîche prépare le mint `8jBAXGfU95qVRSVeW67NxmuR6RaQxcRrqrDWF1kKn8u7` à 9 décimales et l’ATA opérateur `HHY3zXSjcmH4dkzNzE83NWrknGqWX4DFSPj8UeSNMLYT` avec supply et amount nuls ; la préparation native est confirmée par `39DyQvbnbgKaQxb36f4S1rjEuhH385jNAFe8CWH8j3dCgwSjgdkQMPJv2bzGLFLPet6GuC352QNGQLZ5vGhRT7wg`.
|
||||
|
||||
`Create` est simulé au slot `481910719` avec 12 logs, message hash `Ddpy6aTtWL4X1zvxmDxrU8W4uwBZMzLTs3AM5am5Wj9g` et fee `5000`, puis confirmé avec la signature `3J1Ebq9DVkupVFQmqQ84QaNeztwMuRwbtXj7CiyUWwZPj4KCAJpKLAbPvpYss5cdiY33foXXScWWZE98H7tvbZed` au slot `481910724`. La metadata PDA `J6W5PF4SESMvCoTw9H4uAoUvn6tZBWjiG9QWN3CZLyRE` est validée sans Master Edition, comme attendu pour cette famille. Hydratation canonique, extraction Core, replay, matérialisation et seconde passe idempotente sont propres.
|
||||
|
||||
`Mint` est simulé au slot `481910730` avec 7 logs, message hash `8SqHD12gMuaLXHcYLDx72eA2GVokTDDNnnxnuJPfaACh` et fee `5000`, puis confirmé avec `2GKiY9foLmioYtUHttA2D6nCSmsftRL1JDKxENHmCnb5w38FGSxwBiRNMfF7mH8htv3G45irmge6DVtr6VN359j2` au slot `481910734`. Une matérialisation instructionnelle et un snapshot stateful sont observés ; supply et amount ATA passent exactement de `0` à `1_000_000_000`, et le second replay est idempotent.
|
||||
|
||||
La matrice v3 conserve donc `Create` et `Mint` comme seules opérations `confirmed`, avec trois bundles familiaux indépendants `nft`, `sft` et `fungible`. Les 18 autres opérations restent `not_run`; les variantes `collection` et `programmable_nft` restent à exécuter avant les fixtures spécialisées.
|
||||
## Consolidation `pre.013-delta-fix-015` — qualification collection
|
||||
|
||||
La campagne collection `Create -> Mint` est confirmée de bout en bout sur Devnet. La fixture fraîche prépare le mint `AhUDoidUMXy1aqMDQWBGTbdA8SFurXSfU665NbdyMoMZ`, la metadata PDA `D2BFXXDC3p9uy4YEaoRiPq65cu6XrSsVjZccJrxzqYFm`, la Master Edition PDA `HmqeFdeVPmetDRiscWnSfQT7QpJ7cQs4GbJJUfH6Jou8` et l'ATA opérateur `B12BbbZoeDjbJnTn8vods5ZSc9tPiUPuny3yjNV6Vj2b`. La préparation native est confirmée par `4MMxFf1c9crksnr1npyWp4u88TCWgABitS7HQcKbmejfhiBDL6Sacaum8UMUoj3iNdrp61abBoVWjhDRKw6iGK5J`.
|
||||
|
||||
`Create` est simulé au slot `481911937` avec 27 logs, message hash `GxWcLJaiA2zTMQBp6NuKCgHbnC1taCyAjuDH5n2375Ci` et fee `5000`, puis confirmé avec la signature `3jpxyWuxQVyBtbvqDnV1oahLyxCXMw1zQQZBGCKgQSfn2TNcBaUdfvJ6kFa8zL3XJLMpM6tahQTnu8AUsTkYc3Dy` au slot `481911942`. Une matérialisation instructionnelle et deux snapshots stateful sont observés ; metadata et Master Edition sont validées, la supply et l'amount ATA restent à zéro, et le second replay est idempotent.
|
||||
|
||||
`Mint` est simulé au slot `481911950` avec 7 logs, message hash `JCx6XUnQ7e7Veh4K8xtN8KrGFHafdQMRxAK9jej7nNZs` et fee `5000`, puis confirmé avec la signature `4WEciqZA5vmtrh1ZeSbqcgVnezUy7qT6B6utySfkg7dbAmhH6SMwwY862zGbzPW3nBVFzMjFVGPEhnTt6TcAiEe2` au slot `481911955`. Une matérialisation instructionnelle et deux snapshots stateful sont observés ; supply et amount ATA passent exactement de `0` à `1`, et le second replay est idempotent.
|
||||
|
||||
La matrice v3 conserve donc `Create` et `Mint` comme seules opérations `confirmed`, avec quatre bundles familiaux indépendants `nft`, `sft`, `fungible` et `collection`. Les 18 autres opérations restent `not_run`; seule la variante `programmable_nft` reste à exécuter avant les fixtures spécialisées.
|
||||
|
||||
## Première tentative pNFT — `Mint` confirmé, postcondition SPL trop stricte
|
||||
|
||||
La campagne `programmable_nft` confirme `Mint` avec la signature `Gkg5A6ehuSzkU1N318kYoRHm5RdxV2yBRpaK9Gwyt6vN1ToYwAS6Vzpk2rQYWS9NJz1rnUpypLCn7DqWFzQzxFc` au slot `481913765`. Après confirmation, le compte token classique relu contient exactement le mint `Ecn3v1u21DKNhpFX1tqKvieVn5CkhMMukxWgoN59Hf2E`, l’owner `J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH`, `amount=1` et `state=2`. Le test échoue uniquement parce que la postcondition commune attendait encore `state=1`.
|
||||
|
||||
`state=2` est `Frozen` dans le contrat SPL Token et correspond au comportement attendu d’un pNFT : les opérations passent par Token Metadata et son Token Record au lieu de permettre les mutations SPL directes. `pre.013-delta-fix-016` exige donc `Initialized(1)` avant `Mint`, `Frozen(2)` après `Mint` uniquement pour pNFT, et conserve `Initialized(1)` pour NFT/SFT/fungible/collection.
|
||||
|
||||
La sortie machine-readable ajoute `tokenAccountStateBeforeMint` et `tokenAccountStateAfterMint`. Le rerun pNFT doit retourner `ok`, prouver la présence du Token Record et produire `1 -> 2` avant ajout du bundle `programmable_nft` à la matrice v3.
|
||||
|
||||
|
||||
## Deuxième tentative pNFT — campagne complète confirmée
|
||||
|
||||
Après `pre.013-delta-fix-016`, le rerun `programmable_nft` termine sans erreur et ferme la qualification des cinq familles. La fixture fraîche utilise :
|
||||
|
||||
- mint : `4tu87iUVr8hyGGRTVkYMGww7HLMZRuLLFn7MLXxzkmXA` ;
|
||||
- metadata : `Hvjpj78kPgWb14xoEuLPzqckYbjPRJaBxVRNDNX3qMBL` ;
|
||||
- Master Edition : `cVJELihnvgWeRmwQ3HHJAoXyrTPtZjpMZjwWMsJPzAx` ;
|
||||
- ATA opérateur : `BP8AAcqfAM4bKAZxnifKpTQM29QKXmkiDBoAYLT69ahS` ;
|
||||
- Token Record : `Ejp6LTUMxXTFPDDM7iZGsutnCUriQBnArofikMsc97op` ;
|
||||
- préparation native : `gHNtnEwTdw8Uyb32Fjkg9rdJ6ET9mg6Svnc1vXSZjBLYk7upcJUUBXu7VbtvXqYttGbvKQgnGEC2aLDkosvDjxw`.
|
||||
|
||||
### `Create` pNFT
|
||||
|
||||
- simulation context slot : `481921975` ;
|
||||
- logs de simulation : `27` ;
|
||||
- message hash : `4v1opnPoD8YRYr5ti5dFXjSBGbZ6gWCLfg4DwCErwtee` ;
|
||||
- fee : `5000` lamports ;
|
||||
- signature : `515t45UC5KPpGocEHtAuDf2qEqzeJt9TUrbUD1zhAFaXRHnefcu3MHAZTc1JqjSuscDgDSYFVTBX3AKJLk1G8fsN` ;
|
||||
- statut : `Confirmed` ;
|
||||
- slot : `481921980` ;
|
||||
- matérialisation instructionnelle : `1` ;
|
||||
- snapshots : `0 -> 2` ;
|
||||
- hydratation canonique, extraction Core, replay et seconde passe idempotente : réussis.
|
||||
|
||||
### `Mint` pNFT
|
||||
|
||||
- simulation context slot : `481921989` ;
|
||||
- logs de simulation : `19` ;
|
||||
- message hash : `86raN9VfGwk1BymXf2wfkeQmMxnyPTyx49s3gxYoRH6b` ;
|
||||
- fee : `5000` lamports ;
|
||||
- signature : `2kYgd9zpY5xjWSfpoDzvLkjy6KhKFNPsXWfxK4jFrnD15z2BaVUgaxKNpJNiJXP275YgR8LAEzn32Lc7qPq9GdH8` ;
|
||||
- statut : `Confirmed` ;
|
||||
- slot : `481921994` ;
|
||||
- matérialisation instructionnelle : `1` ;
|
||||
- snapshots : `2 -> 3` ;
|
||||
- supply : `0 -> 1` ;
|
||||
- amount ATA : `0 -> 1` ;
|
||||
- état ATA : `Initialized(1) -> Frozen(2)` ;
|
||||
- Token Record absent avant `Mint`, présent et validé après `Mint` ;
|
||||
- hydratation canonique, extraction Core, replay et seconde passe idempotente : réussis.
|
||||
|
||||
`pre.013-delta-fix-017` ajoute donc `programmable_nft` comme cinquième bundle `familyEvidence` de `Create` et `Mint`. Les deux opérations restent les seules entrées `confirmed`, mais leur qualification multi-famille est désormais complète `5/5`. Les 18 autres opérations restent `not_run`.
|
||||
@@ -1,81 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_ESCROW_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — Token Owned Escrow
|
||||
|
||||
## Statut
|
||||
|
||||
**Qualifié sur Devnet — les trois opérations escrow sont `confirmed`.**
|
||||
|
||||
Le rerun du 8 août 2026 après `pre.013-delta-fix-032` termine entièrement la campagne et les checks/tests locaux annoncés restent sans régression. La correction du compte terminal `authority=None` permet aux builders escrow de produire les formes officielles sans faux signer.
|
||||
|
||||
La matrice passe de 11 `confirmed`, 1 `unavailable`, 8 `not_run` à **14 `confirmed`, 1 `unavailable`, 5 `not_run`**.
|
||||
|
||||
## Fixture qualifiée
|
||||
|
||||
```text
|
||||
parent_mint=7Sib8Ugxi3urHBRAWCqdGGXD24em7QN3Vdp69f2RJNRM
|
||||
parent_metadata=8rg9f1wt9wbqNsVBwv4PPiUSLFgsLrLPSzs6cddPhtyo
|
||||
parent_edition=5j7kV9eFuFzXaAzqF6Gb6pG2sLG9iAsWq2YSMUn1kUGJ
|
||||
parent_token=EEGchyQPrimCWs2DyQq7BDRYvrsVs5ctMa4sTjZu6erk
|
||||
attribute_mint=C5e4ecUGoo1y94uXDNVTDfmiMGjGtir27YtLxnv8kfKU
|
||||
attribute_token=2kPTg6P48zgDbefZKWMSpmVjXXv2aH61ah2DRZwpsne1
|
||||
escrow=274ZJGXGVZ1ra2tkUvewtB21kNxSmALaHdHg8K35tVof
|
||||
escrow_attribute_token=3bnvR635UFZm52DA38VXXjZzQ547f4kWzp47d9VBV6q6
|
||||
```
|
||||
|
||||
Préparation SPL confirmée :
|
||||
|
||||
- ATA attribut escrow : `51K4hDTvyBCTZ1MNXhU7WZzgZiRbQyZbdbHAdVs1WfADB7PMhVszCeKqxGUvx3vEatXGJs2r15tHZ7T1ubxGoU1v`, slot `482147222` ;
|
||||
- dépôt d’une unité brute : `37B86chCnjWXPEbjExHry8XELn7UC8VbuTQnYe4KeKeYDikwXHZF4dPhNS27NSGXpzCJZjzUWyuJeRccz6DJWV2E`, slot `482147239`.
|
||||
|
||||
## Preuves Metaplex
|
||||
|
||||
### `CreateEscrowAccount`
|
||||
|
||||
- simulation : slot `482147200`, 13 logs, succès ;
|
||||
- message hash : `E1V2rLgFqjxpyBVu1dkp32VNkZ3V3iTdBTPv4j8mmwSj` ;
|
||||
- frais : `5000` lamports ;
|
||||
- signature : `Yy7NEvme3obuiGRBbBjpuk3dv4aPMPBQ2ns7KmbY4K5EtyAimaaM8qN5SQzEqr9SPbRu1VDCFkNpAjnRGW4JYuj` ;
|
||||
- confirmation : `Confirmed`, slot `482147206` ;
|
||||
- hydratation canonique, extraction Core, decode replay, matérialisation et idempotence : réussies ;
|
||||
- matérialisation : 1 ligne instructionnelle et 2 snapshots.
|
||||
|
||||
### `TransferOutOfEscrow`
|
||||
|
||||
- simulation : slot `482147246`, 10 logs, succès ;
|
||||
- message hash : `FnDRr8JPNPzyECSYjzgN1ABuhyS88iQNxcrS7M4L21WD` ;
|
||||
- frais : `5000` lamports ;
|
||||
- signature : `4yJcSvnZJqihfZTE7nxN3o7H7zBCacpdZdwNQ1ueWQMmQZxR7KRb99C7rfrXX2AyezfSStMdqqTYL3oEWgwRhFi3` ;
|
||||
- confirmation : `Confirmed`, slot `482147252` ;
|
||||
- hydratation canonique, extraction Core, decode replay, matérialisation et idempotence : réussies ;
|
||||
- matérialisation : 1 ligne instructionnelle et 2 snapshots.
|
||||
|
||||
### `CloseEscrowAccount`
|
||||
|
||||
- simulation : slot `482147262`, 4 logs, succès ;
|
||||
- message hash : `8y6uvagE6Z1k2adnR7Vrk8MDQDPCPx1jY9fQ9TMyb95L` ;
|
||||
- frais : `5000` lamports ;
|
||||
- signature : `3GuwmGf9JEK7rHE3tudnxskvruyML9AGVXQimxii3uHdXqNEF4ScpmDXwhU3y2eaUnTbBPPhVkhRfLwJr9jbGJBo` ;
|
||||
- confirmation : `Confirmed`, slot `482147267` ;
|
||||
- hydratation canonique, extraction Core, decode replay, matérialisation et idempotence : réussies ;
|
||||
- matérialisation : 1 ligne instructionnelle et 1 snapshot.
|
||||
|
||||
## Postconditions stateful
|
||||
|
||||
```text
|
||||
deposit_amount=1
|
||||
operator_before=1000000000
|
||||
operator_after_deposit=999999999
|
||||
escrow_after_deposit=1
|
||||
operator_after_transfer_out=1000000000
|
||||
escrow_attribute_closed=true
|
||||
escrow_closed=true
|
||||
parent_amount_after_close=1
|
||||
```
|
||||
|
||||
Le Token Owned Escrow est donc créé avec son parent NFT, reçoit indirectement l’unité SPL via son ATA, restitue exactement cette unité, ferme l’ATA devenue vide, puis se ferme lui-même sans modifier la possession du NFT parent.
|
||||
|
||||
## Décision
|
||||
|
||||
`CreateEscrowAccount`, `TransferOutOfEscrow` et `CloseEscrowAccount` sont promus à `confirmed` pour la famille `nft`. La campagne escrow n’est plus un blocant de `pre.013`.
|
||||
@@ -1,74 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_FINAL_VALIDATION_REPORT.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Validation finale `0.4.8-pre.013` — Metaplex Token Metadata
|
||||
|
||||
## Statut
|
||||
|
||||
**Terminée et validée.**
|
||||
|
||||
La prerelease ferme le réaudit fonctionnel et réseau de Metaplex Token Metadata. La matrice canonique `test-fixtures/contract-matrices/METAPLEX_TOKEN_METADATA_DEVNET_EXECUTION_MATRIX.json` contient les 20 opérations courantes et ne possède plus aucune ligne `not_run`.
|
||||
|
||||
| Statut | Nombre |
|
||||
|---------------|-------:|
|
||||
| `confirmed` | 15 |
|
||||
| `unavailable` | 5 |
|
||||
| `not_run` | 0 |
|
||||
| total | 20 |
|
||||
|
||||
## Opérations `confirmed`
|
||||
|
||||
Les opérations suivantes disposent de preuves Devnet qualifiantes avec simulation, confirmation, hydratation canonique, extraction Core, replay, matérialisation et idempotence selon leur parcours :
|
||||
|
||||
- `Create` et `Mint` sur NFT, SFT, fungible, collection et pNFT ;
|
||||
- `Verify` et `Unverify` sur collection parent-membre ;
|
||||
- `Print` et `Burn` sur NFT imprimable ;
|
||||
- `Delegate`, `Revoke`, `Lock`, `Unlock` et `Transfer` sur lifecycle pNFT ;
|
||||
- `CreateEscrowAccount`, `TransferOutOfEscrow` et `CloseEscrowAccount` sur Token Owned Escrow ;
|
||||
- `Update` sur NFT, avec `primary_sale_happened: false -> true`.
|
||||
|
||||
Les signatures, slots, message hashes et postconditions détaillés restent enregistrés dans la matrice et les rapports de campagne spécialisés de `docs/validation/`.
|
||||
|
||||
## Opérations `unavailable`
|
||||
|
||||
Les cinq statuts négatifs sont issus de preuves runtime réelles et ne sont pas des suppositions :
|
||||
|
||||
- `Use` : simulation Devnet rejetée par `InvalidInstructionData`; aucune soumission ;
|
||||
- `Resize` : `Custom(201)` / compte déjà redimensionné sur le layout courant ; une réussite positive exige un état legacy sous-dimensionné contrôlé ;
|
||||
- `Migrate` : `Custom(75)` / instruction retirée ;
|
||||
- `Collect` : `Custom(7)` avec l'opérateur contrôlé ; la surface exige l'autorité Metaplex fixe de collecte ;
|
||||
- `CloseAccounts` : `Custom(188)` avec l'opérateur contrôlé ; la surface exige l'autorité Metaplex ownerless-close fixe.
|
||||
|
||||
Aucune simulation négative n'est soumise. Aucun actif tiers ni aucune autorité réservée n'est imité pour fabriquer une validation positive.
|
||||
|
||||
## Validation locale finale
|
||||
|
||||
Après `pre.013-delta-fix-036`, l'état réel du workspace fourni par l'opérateur a produit :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
cargo check --workspace OK
|
||||
cargo clippy --all-targets OK, aucun warning
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
General Rust rule audit clean
|
||||
Rust export completeness audit 0 candidate(s)
|
||||
Khadhroony workspace rule audit clean
|
||||
cargo test -p kb-pipeline-demo-scenarios
|
||||
unitaires 105 passed
|
||||
CLI 1 passed
|
||||
API externe 1 passed
|
||||
```
|
||||
|
||||
La campagne maintenance opt-in a également terminé `ok` avec `Update` confirmé et les quatre probes négatifs aux codes attendus.
|
||||
|
||||
## Frontières conservées
|
||||
|
||||
- Metaplex Token Metadata reste distinct de Token-2022 Token Metadata et de Solana Program Metadata ;
|
||||
- les opérations historiques, remplacées ou dépréciées ne sont pas réinterprétées comme opérations courantes ;
|
||||
- les statuts réseau ne sont jamais promus depuis une preuve synthétique ;
|
||||
- le fetch off-chain reste hors périmètre de `0.4.8` ;
|
||||
- les campagnes Devnet restent réexécutables pour détecter une régression ou un changement de runtime, mais ne constituent plus des tâches ouvertes de `pre.013`.
|
||||
|
||||
## Passage à `0.4.8-pre.014`
|
||||
|
||||
Le prochain développement non-fix peut ouvrir `0.4.8-pre.014`, consacré à la finalisation desktop metadata. Il doit réutiliser les contrats et statuts désormais fermés de `pre.013` sans rouvrir une campagne Metaplex fondamentale sauf régression observée.
|
||||
@@ -1,91 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_MAINTENANCE_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 5 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — maintenance Metaplex finale
|
||||
|
||||
## Statut
|
||||
|
||||
**Qualifiée — aucune opération courante ne reste `not_run`.**
|
||||
|
||||
Le rerun `fix-035` ferme les cinq dernières lignes de maintenance. La matrice Devnet Metaplex Token Metadata contient désormais **15 opérations `confirmed`, 5 `unavailable` et 0 `not_run`**.
|
||||
|
||||
## Fixture qualifiante
|
||||
|
||||
- mint NFT : `66RQj9bF5MhzE7ZBwxvxpPTj9yaGMLmBAbTmysjrsDix` ;
|
||||
- Metadata : `9e3wJgmRQnZGogM5c8yPSB5kNtg9EYYaCfqjaMB1vzXn` ;
|
||||
- Master Edition : `3sCz28QcwqwrN5h5siJ617JbDCk7PwSDBUWgcpgXPTaM` ;
|
||||
- token account opérateur : `12aMBDfAUvoPXA6qKY7p5nHb6Tck63TUSxZ4zKoCjnuw`.
|
||||
|
||||
## `Update` — `confirmed`
|
||||
|
||||
L'opération courante `metadata.metaplex_token_metadata.update` est exécutée sur le NFT frais et prouve la transition bornée `primary_sale_happened: false -> true`.
|
||||
|
||||
- simulation : succès au slot `482162408`, 5 logs ;
|
||||
- message hash : `EakKCkQNhGyGivUcaeuSJx5F9PFVSpJY4JBsDFKNvRo8` ;
|
||||
- fee : `5000` lamports ;
|
||||
- signature : `4hxxBnsCA1JBJPNHgXRDeq1W7rXbFj2yySscWJKxU1VTMDcPzPfoWy7QzANHSDsbQfxxcwuAQNDLqEukgsug6qoZ` ;
|
||||
- confirmation : `Confirmed`, slot `482162413` ;
|
||||
- hydratation canonique, extraction Core, replay et matérialisation : réussis ;
|
||||
- matérialisation : 1 instruction et 1 snapshot ;
|
||||
- seconde passe idempotente : propre.
|
||||
|
||||
`Update` passe donc à `confirmed` sur la famille `nft`.
|
||||
|
||||
## `Resize` — `unavailable`
|
||||
|
||||
La simulation au slot `482162417` atteint `IX: Resize`, consomme `14643` CU et retourne :
|
||||
|
||||
```text
|
||||
InstructionError[0] = Custom(201)
|
||||
Program log: Account has already been resized
|
||||
```
|
||||
|
||||
Les comptes créés par l'API actuelle sont déjà au layout cible. Une confirmation positive demanderait un compte legacy sous-dimensionné contrôlé ; la campagne ne fabrique pas artificiellement un compte program-owned et ne revendique pas un actif tiers. Aucune transaction `Resize` n'est soumise.
|
||||
|
||||
## `Migrate` — `unavailable`
|
||||
|
||||
La simulation au slot `482162422` consomme `7614` CU et retourne `Custom(75)` :
|
||||
|
||||
```text
|
||||
This instruction was deprecated in a previous release and is now removed
|
||||
```
|
||||
|
||||
L'opération est retirée du runtime courant. Aucune transaction n'est soumise.
|
||||
|
||||
## `Collect` — `unavailable`
|
||||
|
||||
La simulation au slot `482162426` consomme `2286` CU et retourne `Custom(7)` / `UpdateAuthorityIncorrect` :
|
||||
|
||||
```text
|
||||
Update Authority given does not match
|
||||
```
|
||||
|
||||
La surface courante est réservée à l'autorité de collecte Metaplex fixe. Le scénario contrôlé n'essaie pas de l'usurper et ne soumet aucune transaction.
|
||||
|
||||
## `CloseAccounts` — `unavailable`
|
||||
|
||||
La simulation au slot `482162430` consomme `4625` CU et retourne `Custom(188)` / `InvalidCloseAuthority` :
|
||||
|
||||
```text
|
||||
IX: Close Accounts
|
||||
The close authority needs to be revoked by the Utility Delegate
|
||||
```
|
||||
|
||||
La surface courante exige l'autorité ownerless-close fixe. Le scénario ne l'usurpe pas et ne soumet aucune transaction.
|
||||
|
||||
## Validation locale observée
|
||||
|
||||
Le même état de travail a produit :
|
||||
|
||||
- `cargo fmt --all` : OK ;
|
||||
- `cargo check --workspace` : OK ;
|
||||
- `cargo clippy --all-targets` : OK, aucun warning ;
|
||||
- `python3 scripts/audit_rust_workspace_rules.py` : `General Rust rule audit: clean`, `Rust export completeness audit: 0 candidate(s)`, `Khadhroony workspace rule audit: clean` ;
|
||||
- `cargo test -p kb-pipeline-demo-scenarios` : 105 unitaires, 1 CLI et 1 test API externe, tous réussis ;
|
||||
- campagne maintenance opt-in : réussie intégralement.
|
||||
|
||||
## Conclusion
|
||||
|
||||
La matrice des 20 opérations courantes est fermée : **15 `confirmed`, 5 `unavailable`, 0 `not_run`**. Les statuts `unavailable` restent explicitement qualifiés par leur cause : divergence runtime pour `Use`, besoin d'un état legacy contrôlé pour `Resize`, retrait runtime pour `Migrate`, et autorités Metaplex réservées pour `Collect` et `CloseAccounts`.
|
||||
|
||||
La consolidation documentaire et de conformité de `0.4.8-pre.013` est désormais effectuée. Le prochain développement non-fix peut ouvrir `0.4.8-pre.014` pour la finalisation desktop metadata ; aucune campagne Metaplex fondamentale supplémentaire n'est requise par l'état courant.
|
||||
@@ -1,202 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_PNFT_LIFECYCLE_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 7 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — cycle pNFT delegates
|
||||
|
||||
## Statut
|
||||
|
||||
**Qualifié sur Devnet — le rerun `fix-028` termine les six exécutions, toutes les postconditions stateful et le bundle pipeline/idempotence. `Delegate`, `Revoke`, `Lock`, `Unlock` et `Transfer` sont promus par `pre.013-delta-fix-029`.**
|
||||
|
||||
La validation locale de `fix-023` n'avait exécuté aucune transaction pNFT : `cargo check --workspace` passait, mais `cargo clippy --all-targets` et `cargo test -p kb-pipeline-demo-scenarios` échouaient pendant la compilation du bloc `#[cfg(test)]`. `fix-024` a corrigé ce harness sans modifier le graphe.
|
||||
|
||||
Le premier rerun Devnet de `fix-024` atteint ensuite une vraie transaction `Create` pNFT :
|
||||
|
||||
- signature : `PNkQAnykFoHVsREkhDbTW9eccyJoQvQbRZ2MJ4FsFRXyXint9fj6FT9PW45W5R3yi9HJ2aiSZXssH6B6pmyCcEz` ;
|
||||
- slot confirmé : `482096529` ;
|
||||
- mint frais : `DtBji9AYCqLRB48LFEFir427Kwy4Ehie6Pc8S87aQ6Rb` ;
|
||||
- Master Edition : `HmCuW752ukBChVTbXtKJphUwJTJDdSycrgs6SrU2nT4B`.
|
||||
|
||||
La transaction est confirmée mais le bundle de post-validation s'arrête avant hydratation/replay/matérialisation complets, sur `MetaplexTokenMetadataAccountKind::Edition`: le décodeur rejette la Master Edition compacte pNFT avec `metadata account layout is invalid`.
|
||||
|
||||
Le diagnostic officiel est exact : `MAX_MASTER_EDITION_LEN=20`, les 18 premiers octets portent la sérialisation Borsh maximale, l'avant-dernier octet est réservé au fee flag et le dernier au `TokenStandard`. `Create` écrit explicitement `ProgrammableNonFungible` dans ce dernier byte pour une pNFT. `fix-021` avait à tort soumis ces deux octets au contrôle générique de padding nul. `fix-025` sépare donc le padding réservé du trailer sémantique et valide ce dernier de manière bornée.
|
||||
|
||||
Le rerun `fix-025` valide ensuite localement l’ensemble du workspace (`cargo check`, Clippy, audit, `kb-lib` 705/705, `kb-pipeline` 107/107, scénarios 96/96 et desktop 135/135) et franchit complètement `Create -> Mint`. La première opération lifecycle est alors soumise et confirmée :
|
||||
|
||||
- opération : `Delegate(StakingV1)` ;
|
||||
- signature : `4S2uDrVU6ci59eKeGtGeXoUCbsUr4WxzSa7uYhmBxLtjKfNwpBkZRqm59V9cfbD99oE9AugMYppiQqnMbV2Hy1p7` ;
|
||||
- slot confirmé : `482106293` ;
|
||||
- hydratation canonique : réussie ;
|
||||
- extraction Core : réussie ;
|
||||
- replay : `failed_inputs=1`, aucune observation décodée ;
|
||||
- matérialisation : non atteinte.
|
||||
|
||||
Le défaut est la même frontière conceptuelle que celle déjà corrigée pour `Create`, `Mint`, `Print`, `Verify` et `Unverify` : les flags du Core replay sont les privilèges globaux du message, pas une copie stricte des `AccountMeta` de l’instruction. Dans cette campagne, l’autorité pNFT est aussi le fee payer ; la position `Delegate.authority`, officiellement signer readonly, apparaît donc signer+writable dans le replay. `fix-026` valide uniquement les minima obligatoires et conserve writable obligatoire pour les comptes optionnels réellement mutés.
|
||||
|
||||
Le même correctif est appliqué préventivement à `Lock/Unlock` : leur `token_owner` est le wallet opérateur et donc également le fee payer, ce qui lui donne légitimement des privilèges globaux signer+writable alors que l’AccountMeta positionnel est readonly.
|
||||
|
||||
Le rerun `fix-026` valide ensuite entièrement la base locale :
|
||||
|
||||
```text
|
||||
cargo fmt --all : ok
|
||||
cargo check --workspace : ok
|
||||
cargo clippy --all-targets : ok
|
||||
audit_rust_workspace_rules.py : clean
|
||||
kb-lib : 706/706
|
||||
kb-pipeline : 107/107 + 2 API externes
|
||||
kb-pipeline-demo-scenarios : 96/96 + CLI + API externe
|
||||
kb-app-demo-desktop : 135/135
|
||||
```
|
||||
|
||||
La campagne franchit alors `Delegate(StakingV1)` beaucoup plus loin que lors du run précédent. `validate_confirmed_execution("delegate-staking", ...)` réussit, ce qui prouve pour cette nouvelle transaction : simulation réussie, confirmation avec slot, hydratation canonique, extraction Core, replay décodé, matérialisation, snapshots stateful et seconde passe idempotente propre. La sortie échoue seulement ensuite sur la postcondition du TokenRecord :
|
||||
|
||||
```text
|
||||
expected state=Unlocked
|
||||
expected delegate=Some("CPZBygeMzo6WVXiHoc4xarkFP3xo92hD1tuDZU4SCG5t")
|
||||
expected role=Some("Staking")
|
||||
observed state=Some("Unlocked")
|
||||
observed delegate=None
|
||||
observed role=Some("Staking")
|
||||
```
|
||||
|
||||
La nouvelle signature et son slot ne sont pas imprimés avant cette erreur terminale ; ils ne sont donc pas inventés ni utilisés pour une promotion. La signature `4S2uDr...` au slot `482106293` reste la preuve partielle du run `fix-025`, pas celle du rerun `fix-026`.
|
||||
|
||||
Le programme Metaplex courant écrit pourtant `token_record.delegate = Some(delegate)` et `token_record.delegate_role = Some(role)` ensemble pour les token delegates pNFT. Le défaut est local à notre projection : `DcMetadataMtmTokenRecordAccountSnapshot` calcule déjà `delegate` et `locked_transfer` comme chaînes base58, mais son `payload_json` était obtenu indépendamment par `serde_json::to_value(&mpl_token_metadata::accounts::TokenRecord)`. La couche stateful republie ce JSON brut ; la campagne cherche ensuite `payload_json["delegate"].as_str()`. Cette dépendance à la représentation Serde interne de `Pubkey` est incorrecte.
|
||||
|
||||
`fix-027` construit donc explicitement le JSON canonique du TokenRecord à partir des champs normalisés : `state`, `delegate`, `delegate_role`, `locked_transfer`, `rule_set_revision` et `bump`. Les adresses optionnelles deviennent des chaînes base58 ou `null`. La régression `token_record_decodes_programmable_state_delegate_and_exact_pda` vérifie désormais aussi les valeurs JSON `delegate`, `delegate_role` et `locked_transfer`. La postcondition lifecycle reste stricte : elle exige toujours l’adresse exacte du delegate et ne transforme pas cet incident de projection en tolérance fonctionnelle.
|
||||
|
||||
À l’issue du rerun `fix-026`, la campagne cible toujours cinq opérations courantes `not_run` : `Delegate`, `Revoke`, `Lock`, `Unlock` et `Transfer`. `Delegate(StakingV1)` possède alors une preuve de confirmation partielle mais ne peut pas être promu avant un bundle final imprimé ; les quatre autres opérations ne sont pas encore atteintes à ce stade historique.
|
||||
|
||||
Le rerun `fix-027` franchit ensuite la projection TokenRecord corrigée et poursuit toute la campagne jusqu’au `Transfer`. L’erreur terminale est désormais :
|
||||
|
||||
```text
|
||||
source pNFT token account is invalid after Transfer:
|
||||
expected amount=0 and state=Frozen;
|
||||
observed amount=0 and state=1 (Initialized)
|
||||
```
|
||||
|
||||
Cette erreur survient après `validate_confirmed_execution("transfer", ...)` et après validation du TokenRecord destination `Unlocked` sans delegate. Elle prouve donc que les étapes `Delegate(Staking)`, `Lock`, `Unlock`, `Revoke(Staking)`, `Delegate(Transfer)` et `Transfer` ont toutes franchi leur exécution et leur pipeline post-exécution interne lors de ce run. Les signatures et slots ne sont cependant imprimés qu’après construction complète du résumé ; l’échec final empêche donc encore l’émission du bundle `METAPLEX_PNFT_LIFECYCLE_STEP/EVIDENCE` et aucune promotion n’est effectuée.
|
||||
|
||||
Le comportement observé est celui du programme Metaplex courant : `frozen_transfer` thaw le compte source, effectue le transfert SPL, puis freeze uniquement le compte destination. Il n’existe pas de second freeze du compte source. Après transfert intégral d’une pNFT, l’état attendu est donc :
|
||||
|
||||
```text
|
||||
source ATA amount = 0
|
||||
source ATA state = Initialized
|
||||
destination ATA amount = 1
|
||||
destination ATA state = Frozen
|
||||
```
|
||||
|
||||
`fix-028` corrige uniquement cette postcondition et expose explicitement les deux états token dans `METAPLEX_PNFT_LIFECYCLE_STATE`.
|
||||
|
||||
## Graphe de campagne
|
||||
|
||||
```text
|
||||
Create pNFT -> Mint pNFT
|
||||
|
|
||||
v
|
||||
Delegate(StakingV1)
|
||||
|
|
||||
v
|
||||
Lock -> Unlock
|
||||
|
|
||||
v
|
||||
Revoke(StakingV1)
|
||||
|
|
||||
v
|
||||
Delegate(TransferV1)
|
||||
|
|
||||
v
|
||||
Transfer(delegate -> fresh destination)
|
||||
```
|
||||
|
||||
Le Staking delegate et le Transfer delegate sont volontairement deux rôles successifs : le premier qualifie le cycle lock/unlock, le second le transfert délégué.
|
||||
|
||||
## Postconditions requises
|
||||
|
||||
Token Record source :
|
||||
|
||||
```text
|
||||
after Mint : Unlocked, no delegate
|
||||
after Delegate Staking : Unlocked, delegate=<fresh>, role=Staking
|
||||
after Lock : Locked, delegate=<fresh>, role=Staking
|
||||
after Unlock : Unlocked, delegate=<fresh>, role=Staking
|
||||
after Revoke : Unlocked, no delegate
|
||||
after Delegate Transfer : Unlocked, delegate=<fresh>, role=Transfer
|
||||
```
|
||||
|
||||
Après `Transfer` :
|
||||
|
||||
```text
|
||||
source ATA amount = 0
|
||||
destination ATA amount = 1
|
||||
source ATA state = Initialized
|
||||
destination ATA state = Frozen
|
||||
destination TokenRecord = Unlocked
|
||||
destination delegate = none
|
||||
```
|
||||
|
||||
Chaque étape doit aussi fournir simulation réussie, signature, confirmation, hydratation canonique, extraction Core, replay, au moins une matérialisation, snapshots stateful et seconde passe idempotente.
|
||||
|
||||
## Commande opérateur
|
||||
|
||||
```bash
|
||||
KB_DEVNET_METAPLEX_PNFT_LIFECYCLE_CAMPAIGN_TEST=1 \
|
||||
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
|
||||
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
|
||||
cargo test -p kb-pipeline-demo-scenarios \
|
||||
optional_devnet_metaplex_pnft_lifecycle_campaign_from_env \
|
||||
-- --nocapture
|
||||
```
|
||||
|
||||
Une exécution complète doit produire :
|
||||
|
||||
```text
|
||||
METAPLEX_PNFT_LIFECYCLE_FIXTURE ...
|
||||
METAPLEX_PNFT_LIFECYCLE_STEP ... x6
|
||||
METAPLEX_PNFT_LIFECYCLE_STATE ...
|
||||
METAPLEX_PNFT_LIFECYCLE_EVIDENCE ...
|
||||
```
|
||||
## Qualification finale `fix-028`
|
||||
|
||||
Le rerun final retourne `ok` avec la fixture suivante :
|
||||
|
||||
```text
|
||||
mint = 9oEszJo4wT4Qodyrq7D3wD723ZFckiqYL4yB3JcJXFYc
|
||||
metadata = AWQwkdHkqjRiJ3Mz3CzmHgBwEUK7BSmpLTLr47S5799H
|
||||
master edition = E2QV5v91hvHnYDgnwQ3dh6deWYt5CtEMEYYEUsGAqZoN
|
||||
source token = 8ityw4e6phC1mdHYrvG2rrwTRmXa47W3e1tpXTfz2JcB
|
||||
source token record = FkbrKCQMejNwXVfuAqkfcM6Cw2LDsGJ5nYPUs2GEUhgp
|
||||
delegate = GcfXJhbS4fKaANtqt7pAuiFTR4S3jRAFGXv83bqbbWcQ
|
||||
destination owner = ForoAqqvXENKD7GStMb9kEpe2dKGeHCZBxRkcmSaSiui
|
||||
destination token = HbrpZbTu9MzQJrmnv3DYJQRXEkNMKNDFQCRxHxhzePEb
|
||||
destination token record = 3FcpMMmLUAyHW7duEqPFQiYCuSiLtvWkbBcZtfYGyaLo
|
||||
```
|
||||
|
||||
Les six exécutions réelles sont :
|
||||
|
||||
| Étape | Signature | Simulation | Confirmation |
|
||||
|------------------------|--------------------------------------------------------------------------------------------|-----------:|-------------:|
|
||||
| `Delegate(StakingV1)` | `mFpH2SUipx4E5fJod1kgypRBrD5HE7M6ZJen5T3KYvXPqNcU64KiAktSakZ7tB8oezrAiZTn6FdUkx48aheZN5N` | 482113797 | 482113803 |
|
||||
| `Lock` | `676sMvUwBg3G2JZK9gWYFgoHfRJ3sSyVR5Luk3AqtqgQeLnFvQZptqdUSG27Np1qiVj8vB2XncjfLCJ3hzCQN2EZ` | 482113807 | 482113812 |
|
||||
| `Unlock` | `4suhVVV6QwdSW1P1BX3NBMpRF4Yd7xVEUQ9KnvSLEUVygs4Yb4K5psKgxpod6m3Q4S28KAjPTp575ERRVbovYSTr` | 482113816 | 482113822 |
|
||||
| `Revoke(StakingV1)` | `4Av8nq4QNTjqGGLAwGe9Syn6YVtpvNbjJ1JGfrK8CGyweG8mt5N9Ua5WFFwYGYcj3Nbu1pCu7bVCJ8hiopiuMKfk` | 482113826 | 482113831 |
|
||||
| `Delegate(TransferV1)` | `KR44kRqhN8rS8bktvFDSjJnKDFGUwr6hmtTTocMBfhvuqXP8aeCQ78jTPXvianbi4wPRxQig2fFNt1ffqDTKhx1` | 482113836 | 482113840 |
|
||||
| `Transfer` | `35ABd7yhmtL6YiA4UHoxM3TvGsJu1nZDvHXy2geLyNPj25ASaE7918SswSfEKRMMNLQ8TvagQehzR8F4Z4R8JHXa` | 482113845 | 482113850 |
|
||||
|
||||
Chaque étape possède `simulationSuccess=true`, `canonicalHydration=true`, `coreExtraction=true`, `decodeReplay=true`, `materialized=true`, exactement une matérialisation instructionnelle, un snapshot matérialisé et `idempotenceReplayClean=true`. Les fees observés sont 5000 lamports pour les deux `Delegate` et `Revoke`, puis 10000 lamports pour `Lock`, `Unlock` et `Transfer`.
|
||||
|
||||
La transition finale est :
|
||||
|
||||
```text
|
||||
initial = Unlocked
|
||||
staking role = Staking
|
||||
after Lock = Locked / Staking
|
||||
after Unlock = Unlocked / Staking
|
||||
after Revoke = no delegate
|
||||
transfer role = Transfer
|
||||
source ATA after Transfer = amount 0 / Initialized
|
||||
destination ATA after Transfer = amount 1 / Frozen
|
||||
destination TokenRecord = Unlocked / no delegate
|
||||
```
|
||||
|
||||
Cette preuve ferme le lot pNFT et autorise la promotion des cinq opérations canoniques `Delegate`, `Revoke`, `Lock`, `Unlock` et `Transfer` sur la famille `programmable_nft`. La matrice Devnet passe ainsi de 6/20 à 11/20 opérations confirmées.
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_PRINT_BURN_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — Metaplex `Print -> Burn`
|
||||
|
||||
## Statut
|
||||
|
||||
**Qualifié sur Devnet.**
|
||||
|
||||
Le rerun suivant `pre.013-delta-fix-022` termine `ok` et fournit les preuves complètes de `Print` et `Burn`. La matrice Devnet v3 peut promouvoir les deux opérations sur la famille `nft`.
|
||||
|
||||
## Fixture qualifiée
|
||||
|
||||
```text
|
||||
master_mint = EjKZta4BpT1r9p8ECcANdxi7XQ6pjCBjuRpRp69EDCRc
|
||||
master_metadata = GHiG8W9eBbBQpw7efLX59wLnKwyMTSLJ7xPZ8x1ZDWr5
|
||||
master_edition = ARfpaZm4avbTRsFKFCHvr2xQQNepHV3QQ5uoR7hG1A86
|
||||
master_token_account = 375W7k6uMhwQKJTywyi5tSdaGD1hJvzZWScVoEYqQ1qi
|
||||
edition_mint = 5ZNDeUKSWRbWTppEk5v3Rk6pd5ETrgjCzKbM55JfM1nU
|
||||
edition_metadata = BHPfP3RJqfw8jYXm8uoKz2QpHqs9tpj6apC6bZeVgoWt
|
||||
edition = Cb7m21Kok8tWrzymtbY87T6WP6x2Eo4yLmkkthGL7mQG
|
||||
edition_token = E94rbzWFgYRPXGEdmHXrLHnHXzHYyobzMKpgvchCf3vV
|
||||
edition_marker = 2fnAxCkT76N7XDd7eB8z5zJAPGtVA9ToXssh65ZuTmdT
|
||||
```
|
||||
|
||||
Le mint d’édition et son ATA sont tous deux absents avant `Print`.
|
||||
|
||||
## `Print`
|
||||
|
||||
```text
|
||||
cluster = devnet
|
||||
genesis hash = EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
|
||||
simulation slot = 482087795
|
||||
simulation success = true
|
||||
simulation logs = 61
|
||||
message hash = Hvue5NZTK2UauCHGcFmSLTBrLMioNwDWFMNhX8kCuPA9
|
||||
fee = 10000 lamports
|
||||
signature = REHAxUZrSdKDj8F8k27Amrg7hwuJFhVfstjc9xjn2XGfTX38fH4tFwPeNrF5zeMN5pc21PpUPSgaKXMMfTFd7TE
|
||||
confirmation = Confirmed
|
||||
confirmation slot = 482087799
|
||||
before snapshots = 2
|
||||
after snapshots = 5
|
||||
instruction materialized = 1
|
||||
materialized snapshots = 5
|
||||
canonical hydration = true
|
||||
core extraction = true
|
||||
decode replay = true
|
||||
idempotence replay clean = true
|
||||
```
|
||||
|
||||
Postconditions :
|
||||
|
||||
```text
|
||||
MasterEdition.supply : 0 -> 1
|
||||
max_supply : 1
|
||||
printed mint supply : 0 -> 1
|
||||
printed ATA amount : 0 -> 1
|
||||
Edition.edition : 1
|
||||
Edition Marker bit : false -> true
|
||||
```
|
||||
|
||||
## `Burn`
|
||||
|
||||
```text
|
||||
cluster = devnet
|
||||
genesis hash = EtWTRABZaYq6iMfeYKouRu166VU2xqa1wcaWoxPkrZBG
|
||||
simulation slot = 482087813
|
||||
simulation success = true
|
||||
simulation logs = 10
|
||||
message hash = 8YpMC3PdLYZAssqAsyt6GzqjNnZFPVqAEErFo8gZ9dwF
|
||||
fee = 5000 lamports
|
||||
signature = 4cNUxGGSWifuAtqdPJAtM3Cjpi4JATitRDqrvEAe85NLpMWcgWmC27bsfjNUmK6sEBDovNPtkPV3wDH1LpfGbhd1
|
||||
confirmation = Confirmed
|
||||
confirmation slot = 482087818
|
||||
before snapshots = 5
|
||||
after snapshots = 2
|
||||
instruction materialized = 1
|
||||
materialized snapshots = 2
|
||||
canonical hydration = true
|
||||
core extraction = true
|
||||
decode replay = true
|
||||
idempotence replay clean = true
|
||||
```
|
||||
|
||||
Postconditions finales :
|
||||
|
||||
```text
|
||||
MasterEdition.supply : 1 -> 0
|
||||
MasterEdition.max_supply : 1
|
||||
printed mint supply : 1 -> 0
|
||||
printed ATA : absent
|
||||
printed Edition : absente
|
||||
Edition Marker : absent
|
||||
printed Metadata RPC : présente
|
||||
printed Metadata fee tombstone : true
|
||||
printed Metadata semantic closed : true
|
||||
```
|
||||
|
||||
Le compte Metadata restant est exactement le tombstone officiel attendu : owner Token Metadata, non exécutable, lamports résiduels positifs, `space=1`, donnée `[0x00]`. Il ne s’agit pas d’une Metadata active.
|
||||
|
||||
## Qualification
|
||||
|
||||
Les deux opérations satisfont les 16 preuves réseau requises par famille : simulation, contexte réseau, message/fee, signature, confirmation, états avant/après, hydratation canonique, extraction Core, decode replay, matérialisation et idempotence.
|
||||
|
||||
La matrice après promotion est :
|
||||
|
||||
```text
|
||||
confirmed : 6
|
||||
not_run : 14
|
||||
|
||||
Create : confirmed
|
||||
Mint : confirmed
|
||||
Verify : confirmed
|
||||
Unverify : confirmed
|
||||
Print : confirmed
|
||||
Burn : confirmed
|
||||
```
|
||||
@@ -1,86 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_013_METAPLEX_USE_DEVNET_VALIDATION_REPORT.md -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Validation Devnet `0.4.8-pre.013` — disponibilité `Use`
|
||||
|
||||
## Statut
|
||||
|
||||
**Indisponible au runtime Devnet avec la surface courante du programme.**
|
||||
|
||||
Le probe réel du 8 août 2026 a préparé un NFT classique frais avec `Uses::Multiple { remaining: 2, total: 2 }`, terminé le chemin qualifié `Create -> Mint`, puis simulé l'instruction courante `Use` de discriminant 51 sans soumettre de transaction.
|
||||
|
||||
La simulation a été exécutée et refusée par Token Metadata :
|
||||
|
||||
```text
|
||||
simulated = true
|
||||
success = false
|
||||
cluster = devnet
|
||||
blockhash_kind = latest
|
||||
blockhash_age_slots = 1
|
||||
units_consumed = 12085
|
||||
estimated_fee_lamports = 5000
|
||||
error = {"InstructionError":[0,"InvalidInstructionData"]}
|
||||
```
|
||||
|
||||
Logs observés :
|
||||
|
||||
```text
|
||||
Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s invoke [1]
|
||||
Program log: Error: InvalidInstructionData
|
||||
Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s consumed 12085 of 200000 compute units
|
||||
Program metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s failed: invalid instruction data
|
||||
```
|
||||
|
||||
Aucune signature `Use` n'a été produite et aucune soumission n'a été tentée.
|
||||
|
||||
## Interprétation
|
||||
|
||||
Le client Rust généré expose bien `Use`, mais le routeur du programme courant ne possède pas de branche nouvelle API correspondante. La surface legacy conserve `Utilize`, qui est une instruction distincte. La réponse Devnet confirme donc la divergence client/runtime : l'instruction actuelle est rejetée avant exécution avec `InvalidInstructionData`.
|
||||
|
||||
La matrice `METAPLEX_TOKEN_METADATA_DEVNET_EXECUTION_MATRIX.json` classe désormais `Use` comme `unavailable`, avec la raison runtime et les logs observés. Cette classification ne doit pas être transformée en `confirmed` et ne doit pas être confondue avec `not_run`.
|
||||
|
||||
## Correction du probe
|
||||
|
||||
Le premier probe a terminé le processus de test en erreur parce que la readiness générale exigeait encore une simulation réussie avant même de retourner le résumé en mode `submit=false`.
|
||||
|
||||
`pre.013-delta-fix-030` distingue désormais les deux contrats :
|
||||
|
||||
- une simulation exacte échouée peut être retournée comme donnée lorsque `submit=false`, afin d'alimenter un probe de disponibilité ;
|
||||
- une soumission reste strictement impossible tant que la simulation exacte n'a pas réussi ;
|
||||
- `send_authorized` reste donc faux pour toute simulation négative.
|
||||
|
||||
Le probe `Use` peut ainsi imprimer proprement `status=runtime_unavailable` et terminer `ok` sans affaiblir la politique simulation-first de soumission.
|
||||
|
||||
## Commande de contrôle
|
||||
|
||||
```bash
|
||||
KB_DEVNET_METAPLEX_USE_PROBE_TEST=1 \
|
||||
KB_DEVNET_METAPLEX_OPERATOR_CONFIRMED=1 \
|
||||
KB_POSTGRES_TEST_URL='postgres://solana:solana@localhost:5432/solana_test' \
|
||||
cargo test -p kb-pipeline-demo-scenarios \
|
||||
optional_devnet_metaplex_use_probe_from_env \
|
||||
-- --nocapture
|
||||
```
|
||||
|
||||
Après `fix-030`, la sortie attendue pour la surface runtime observée est :
|
||||
|
||||
```text
|
||||
METAPLEX_USE_PROBE_FIXTURE ...
|
||||
METAPLEX_USE_PROBE_SIMULATION success=false ...
|
||||
METAPLEX_USE_PROBE_STATUS status=runtime_unavailable ...
|
||||
METAPLEX_USE_PROBE_LOGS [...]
|
||||
```
|
||||
## Rerun qualifiant après correction du probe
|
||||
|
||||
Le rerun `fix-030` du 8 août 2026 confirme le contrat sans erreur d’orchestration. La fixture observée est :
|
||||
|
||||
```text
|
||||
mint = G9cXdhB1MjmbKk4Ari9Y9kposL7JJfDaQEWomz8xxfpM
|
||||
metadata = D1snmEtU8BroQHV2fVBfw7CcWVqT4BhqBD8MQTyfSciY
|
||||
master_edition = 8pV6JRefP5QQB4UYLSwaJCzEkHFfU8mLGjEb8i5TDR7z
|
||||
token = BfEGL81HW9KMVodVf4oXeK4mX6KMNTAZaYqCsb4NF3BW
|
||||
uses_before = 2
|
||||
simulation_context_slot = 482133665
|
||||
```
|
||||
|
||||
La simulation reste `success=false`, conserve exactement quatre logs et `InstructionError[0]=InvalidInstructionData`. La ligne `METAPLEX_USE_PROBE_STATUS` expose `status=runtime_unavailable`, `uses_after=null` et la raison complète ; aucune ligne de soumission n’est produite. Le test opt-in termine `ok`. Les autres checks et suites de tests rejoués localement restent sans régression.
|
||||
@@ -1,209 +0,0 @@
|
||||
<!-- file: docs/validation/V0_4_8_PRE_014_DESKTOP_METADATA_VALIDATION_REPORT.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Validation desktop Metadata `0.4.8-pre.014`
|
||||
|
||||
## 1. Objet
|
||||
|
||||
Ce rapport consolide la première validation réelle du panneau `demo_execution_metadata` après l’ouverture de `0.4.8-pre.014`, puis motive le correctif de câblage Metaplex du delta suivant.
|
||||
|
||||
Il ne remplace pas les matrices réseau spécialisées. Il qualifie uniquement l’intégration desktop et la correspondance entre l’UI Tauri et les campagnes réutilisables déjà validées.
|
||||
|
||||
## 2. Contrôles locaux
|
||||
|
||||
Le 8 août 2026, après application du premier delta `pre.014`, les contrôles suivants réussissent :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
cargo check --workspace OK
|
||||
cargo clippy --all-targets OK, aucun warning
|
||||
scripts/audit_rust_workspace_rules.py clean
|
||||
kb-pipeline-demo-scenarios 105 unitaires + 1 CLI + 1 API externe
|
||||
kb-app-demo-desktop 139 unitaires
|
||||
cargo tauri dev démarrage OK
|
||||
```
|
||||
|
||||
La validation visuelle confirme :
|
||||
|
||||
- trois accordéons distincts pour Metaplex Token Metadata, Token-2022 Token Metadata et Solana Program Metadata ;
|
||||
- synchronisation du profil sélectionné entre les trois domaines ;
|
||||
- journal d’exécution placé sous la grille et utilisant toute la largeur disponible.
|
||||
|
||||
## 3. Token-2022 Token Metadata
|
||||
|
||||
Les logs fournis montrent une campagne desktop complète sur Devnet, sans entrée dans les fichiers `error*.jsonl`.
|
||||
|
||||
| Opération | Signature | Slot |
|
||||
|-------------------|--------------------------------------------------------------------------------------------|------------:|
|
||||
| `Initialize` | `23aXutFc25Ncn4XPSGdaaEzvUpe9s57gYunmMq1asmFRK9xe1tAYVCnV3dePUn2a7qqq51JDsPKp5ep5d1DLypNv` | `482188064` |
|
||||
| `UpdateField` | `Uws9Laene33LxYet4562LKXMkKjAhW5FPweQSnFJv7NG6s4u7LqB7zbppQgQgaNFE52d9UVZKLmjZoK9zb4xdHK` | `482188079` |
|
||||
| `Emit` | `2uNggBbSvvj7Cqdddt1KtFgFhTJ9jsyvobeGUaAU6kPNY9o4hJ6BVHEhpELe1sRSyrMrgbeGLoRiWAMU2UrisMcE` | `482188091` |
|
||||
| `RemoveKey` | `3xUUnjQvWzSkMQPe2VFDyYX14K3STxBzFjzWEawrK28UsoJzXTPYA61nzkL5JvLwCfhNRg7YpBcsSSjhTJqtqNYT` | `482188102` |
|
||||
| `UpdateAuthority` | `2U9zrLL9NusrhpW9Dx15SqZ8c4d6zbcgSyM4hBcewr1Ar7JwLYwvBduLKs4HKEgZP9i5YQQ9cyTC977mjJGLWqXW` | `482188113` |
|
||||
|
||||
Les traces `kb-pipeline` et `kb-lib` montrent le décodage Token-2022, la matérialisation `materializer.metadata.token_2022` et la seconde passe de replay/idempotence. La fixture a été préparée auparavant par la signature `LNwzGfvCgZdumbYXfAecCxU6hfHYGa6XRwC7E71jc4JTDUj5QyVBVV5Sd9KLWmX2t72XfKBiYUEV6WYCvPqC4wd`, slot `482188053`.
|
||||
|
||||
**Statut desktop : validé.**
|
||||
|
||||
## 4. Solana Program Metadata
|
||||
|
||||
La campagne desktop `ProgM6…` traverse les deux parcours complets après préparation des PDA frais `buffer=6bs5XpPsNUqw8FatFJTJu81ZAUBCvxmyxptNyUY4RnDU` et `metadata=7fTTM3KCtFMjxmTaWa6xJ3nSbK9Yi7MdVXP3dSa8ahPB`.
|
||||
|
||||
Les neuf opérations atteignent toutes l’état `Confirmed` dans les contrôles post-exécution :
|
||||
|
||||
```text
|
||||
Buffer : Allocate -> Extend -> Write -> SetAuthority -> Trim -> Close
|
||||
Metadata : Initialize -> SetData -> SetImmutable
|
||||
```
|
||||
|
||||
Signatures observées :
|
||||
|
||||
```text
|
||||
Allocate Je6SLx7wfNqEJ8Huo64r177Sm9bda4uFXUPwuxfZG89jvb1zKMKLnzTJEL5DFHxftMq38FsLNF3TZ14kaWSZ7Hb
|
||||
Extend LYgf8ac4CKYdY2xkw9bCS8J9cvkphWA8ueCUJ5CBKZ11jEdS2NZLykF4jwmSA5AnVYWxzNABeXhGV4d1dFvzMnM
|
||||
Write 4p7XEXeGgWQjJkWTfrBB5rL9XwDadxzoCPreLfaB3fBGACyrPqZYmnBGqVYVgyR9zDZNxuKhimEwMtmiGdJseKa2
|
||||
SetAuthority 5kPi3eBqbq92kV5ZFWPur9afAokGxhgr84PPQh7s5btyQYayC3TDuaH9TCcspxbd4YEYDD4icFYnSWX2Ej9XdLgA
|
||||
Trim 5YG7Yp6x1waZZKoRjb37q7QUNJL5CMEUgu8gs7ehDwHUx1TXvV5BaeUJFT1Pb58z4hSo4woey2qaKQggAzaNtYEG
|
||||
Close 2jyZzegSM2v7LJ15nF3r9zXsLXd7ZDsWsCEWHLXQdoBrLkrbuSuwVrGx1jTqYejw195FVhWHeJQYY6BaN98s5R6
|
||||
Initialize 2kzvpRi8KwRhaQPiwtR8PCQGTuQ3e3kUNSi7EVsMXqJzhQkZanjNwxsL2sGeB8Xs56N22TaaYbS6LJimQpHZWk6J
|
||||
SetData 3WZHzYno9M6uHLMiXsNBtBHoN3yAp7ftd3pSNWpuj2jATk1g29nvUccgUu6wuRijv9oBo2Vi1dHKury2DFfDQ1ib
|
||||
SetImmutable XTAj5NNVXRkhKe4DxsXGm2xtxocrwHwkkpEun4ib6h4qs6DX5f2K6gfgQ2jppkTWoC83MyoPgrpvdKes1b72gbJ
|
||||
```
|
||||
|
||||
**Statut desktop : validé.**
|
||||
|
||||
## 5. Metaplex Token Metadata : écart constaté
|
||||
|
||||
Les logs de la même session ne montrent pas une campagne Metaplex spécialisée. Le desktop prépare uniquement une fixture classique avec :
|
||||
|
||||
```text
|
||||
operation = metadata.metaplex_token_metadata.prepare_native_mint_and_ata
|
||||
signature = 5YdSQHZ5T3VV8zefmQS4GVHNXPbvCijiLyHdgwvqcmGMMpobAJcM4HvdeQ7vex9qDqcYtAVUtj4U3bDCeQ2Hfzvv
|
||||
slot = 482188642
|
||||
```
|
||||
|
||||
Aucune séquence qualifiée `Create -> Mint`, collection, Print/Burn, lifecycle pNFT, escrow, maintenance ou Use ne suit cette préparation avant la fin des logs.
|
||||
|
||||
La cause est un écart de câblage desktop : le panneau utilisait encore le workflow générique `scénario -> étape -> intent JSON`, alors que `pre.013` a qualifié des campagnes spécialisées cohérentes et indivisibles.
|
||||
|
||||
## 6. Correctif `pre.014-delta-fix-001`
|
||||
|
||||
Le correctif conserve les scénarios synthétiques pour l’inspection de contrats mais remplace le parcours Devnet principal par 11 campagnes spécialisées :
|
||||
|
||||
1. `Create -> Mint` NFT ;
|
||||
2. `Create -> Mint` SFT ;
|
||||
3. `Create -> Mint` fungible ;
|
||||
4. `Create -> Mint` collection ;
|
||||
5. `Create -> Mint` pNFT ;
|
||||
6. collection `Verify -> Unverify` ;
|
||||
7. `Print -> Burn` ;
|
||||
8. lifecycle pNFT ;
|
||||
9. Token Owned Escrow ;
|
||||
10. maintenance ;
|
||||
11. probe Use.
|
||||
|
||||
Maintenance et Use conservent les opérations `unavailable` comme probes simulation-only ; elles ne sont pas converties en soumissions isolées.
|
||||
|
||||
La carte **Exigences** est également déplacée en bas de la colonne droite, après **Postconditions et preuves**. Le journal reste en pleine largeur sous la grille.
|
||||
|
||||
## 7. Validation de `fix-001`
|
||||
|
||||
Après application de `fix-001` :
|
||||
|
||||
- les 11 campagnes Metaplex sont bien exposées par le nouveau contrat desktop ;
|
||||
- les contrôles statiques `fmt`, `check`, Clippy et audit workspace sont propres ;
|
||||
- `kb-pipeline-demo-scenarios` conserve 105 tests unitaires + 1 CLI + 1 API externe réussis ;
|
||||
- `kb-app-demo-desktop` exécute 144 tests, avec 143 réussites et un échec du test historique qui cherche encore les anciens IDs de contrôles supprimés ;
|
||||
- deux tentatives réelles de `Create -> Mint — NFT` provoquent un arrêt brutal du processus pendant la post-validation du `Create`.
|
||||
|
||||
## 8. Correctif `pre.014-delta-fix-002`
|
||||
|
||||
Après application de `fix-001`, deux essais successifs de `Create -> Mint — NFT` provoquent un arrêt brutal de l'application au même endroit. Le second essai est effectué après purge des logs.
|
||||
|
||||
Le journal réseau prouve que la fixture SPL classique est créée, puis que l'opération Metaplex `Create` est simulée, envoyée et confirmée :
|
||||
|
||||
```text
|
||||
fixture signature : 64kLtKRiCewywr1CdNbcznHZS7PtNnfh5vxzZLte2VoUexkoyGtRdVozMxsATpP97Sp1fjv2fmPwGUj9hM6VFH8d
|
||||
fixture slot : 482323101
|
||||
Create signature : NAXZephC3aPqe8KA4Ly81o56xkhUEEMMLdZKnYEqiifvRGuQmf997nM29EtWZESyC97qu75v4UzyRWt4aqxRN1d
|
||||
Create slot : 482323110
|
||||
```
|
||||
|
||||
Le dernier événement écrit est le lancement de l'hydratation canonique de cette signature puis l'envoi de `getTransaction`. Aucun panic Rust, aucune erreur applicative structurée et aucune erreur JSONL ne sont enregistrés avant la disparition du processus. Le défaut n'est donc pas classé comme un échec Metaplex de la transaction : il appartient à l'intégration desktop/runtime du nouveau dispatch de campagnes.
|
||||
|
||||
`fix-002` :
|
||||
|
||||
- conserve les campagnes réutilisables intactes ;
|
||||
- boxe explicitement le futur du dispatch Metaplex avant l'attente Tauri, afin d'éviter de conserver le gros state machine des onze branches directement dans le futur de commande ;
|
||||
- journalise `campaign_start`, `campaign_completed` et `campaign_failed` ;
|
||||
- réaligne le test frontend historique sur les contrôles de campagne qualifiés introduits par `fix-001`.
|
||||
|
||||
La validation Tauri doit reprendre par `Create -> Mint — NFT`. Si un arrêt brutal subsiste, les nouveaux marqueurs et la dernière étape réseau permettront de distinguer un défaut du runtime desktop d'un défaut d'hydratation HTTP.
|
||||
|
||||
## 9. Validation réelle de `fix-002`
|
||||
|
||||
La validation locale du 9 août 2026 est propre :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
cargo check --workspace OK
|
||||
cargo clippy --all-targets OK, aucun warning
|
||||
scripts/audit_rust_workspace_rules.py clean
|
||||
kb-app-demo-desktop 144 tests unitaires, tous OK
|
||||
cargo tauri dev démarrage OK
|
||||
```
|
||||
|
||||
Le bundle de logs du second essai confirme que le boxing du dispatch Metaplex supprime l’arrêt brutal observé avec `fix-001`. Les onze campagnes exposées par le desktop ont toutes un marqueur `campaign_start` suivi d’un marqueur `campaign_completed`, sans `campaign_failed` :
|
||||
|
||||
| Campagne | Exécutions/probes projetés | Statut desktop |
|
||||
|--------------------------------|---------------------------:|---------------------------------------------|
|
||||
| `create_mint_nft` | 2 | terminé |
|
||||
| `create_mint_sft` | 2 | terminé |
|
||||
| `create_mint_fungible` | 2 | terminé |
|
||||
| `create_mint_collection` | 2 | terminé |
|
||||
| `create_mint_programmable_nft` | 2 | terminé |
|
||||
| `collection_verify` | 6 | terminé |
|
||||
| `print_burn` | 4 | terminé |
|
||||
| `pnft_lifecycle` | 8 | terminé |
|
||||
| `escrow` | 7 | terminé |
|
||||
| `maintenance` | 7 | terminé, dont 4 indisponibilités qualifiées |
|
||||
| `use_probe` | 3 | terminé, dont 1 indisponibilité qualifiée |
|
||||
|
||||
Les journaux UI confirment notamment `maintenance : confirmed=3, unavailable=4, evidence=7` et `use_probe : confirmed=2, unavailable=1, evidence=3`. Les fichiers `error*.jsonl` du bundle fourni sont tous vides.
|
||||
|
||||
**Statut desktop Metaplex : validé pour les onze campagnes qualifiées.**
|
||||
|
||||
## 10. Consolidation structurelle `fix-003`
|
||||
|
||||
Le correctif suivant ne change aucune campagne réseau. Il simplifie seulement le desktop :
|
||||
|
||||
- `demo_execution_metadata_metaplex_campaign.rs` est fusionné dans `demo_execution_metadata_metaplex_token_metadata.rs` ;
|
||||
- les commandes Tauri et les contrats TS-RS restent inchangés ;
|
||||
- Metaplex suit désormais le même modèle de module unique que Token-2022 Token Metadata et Solana Program Metadata ;
|
||||
- les trois blocs de résultats deviennent un accordéon Bootstrap commun, sur le modèle de `demo_execution_spl` ;
|
||||
- la carte **Exigences** reste sous l’accordéon dans la colonne droite ;
|
||||
- le journal d’exécution reste pleine largeur sous la grille.
|
||||
|
||||
Après application, la validation requise est locale (`fmt`, `check`, Clippy, audit, 144 tests desktop) puis visuelle dans Tauri pour l’ouverture/fermeture des trois JsonViewer. Aucune nouvelle campagne Devnet n’est requise pour requalifier Metaplex.
|
||||
|
||||
## 11. Clôture de `pre.014`
|
||||
|
||||
La validation finale confirme que `fix-003` ne réintroduit aucune régression :
|
||||
|
||||
```text
|
||||
cargo fmt --all OK
|
||||
cargo check --workspace OK
|
||||
cargo clippy --all-targets OK, aucun warning
|
||||
scripts/audit_rust_workspace_rules.py clean
|
||||
kb-app-demo-desktop 144 tests unitaires, tous OK
|
||||
```
|
||||
|
||||
La vérification visuelle Tauri confirme également :
|
||||
|
||||
- les trois accordéons de résultats s’ouvrent et se ferment correctement ;
|
||||
- les JsonViewer restent lisibles dans les accordéons ;
|
||||
- la carte **Exigences** reste sous les résultats dans la colonne droite ;
|
||||
- le journal d’exécution reste en pleine largeur sous la grille ;
|
||||
- les trois domaines Metaplex Token Metadata, Token-2022 Token Metadata et Solana Program Metadata restent distincts.
|
||||
|
||||
Les campagnes réseau ayant déjà été qualifiées avant le refactor structurel de `fix-003`, aucun rerun Devnet supplémentaire n’est requis. **Statut de `0.4.8-pre.014` : terminé et validé.**
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/evidence/v0.4.8/pre.008/mainnet/README.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Preuve mainnet `0.4.8-pre.008`
|
||||
|
||||
@@ -13,6 +13,6 @@ Ce répertoire conserve la preuve binaire de la campagne historique ayant valid
|
||||
- usage : preuve documentaire et diagnostic reproductible ;
|
||||
- chargement applicatif : aucun.
|
||||
|
||||
L’archive ne doit pas être extraite dans l’arbre source. Elle est référencée par le rapport `docs/validation/V0_4_8_PRE_008_SOLANA_PROGRAM_METADATA_MAINNET_REPLAY_REPORT.md`.
|
||||
L’archive ne doit pas être extraite dans l’arbre source. Elle est référencée par le rapport `olddocs/archivekbot3/docs/validation/V0_4_8_PRE_008_SOLANA_PROGRAM_METADATA_MAINNET_REPLAY_REPORT.md`.
|
||||
|
||||
Un contrôle avant archivage n’a trouvé ni fichier de wallet, ni keypair, ni `.env`, ni marqueur d’URL ou d’autorisation dans les contenus textuels. Cette vérification ne remplace pas une revue humaine avant publication hors du dépôt privé.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/validation/evidence/v0.4.8/pre.010/devnet/README.md -->
|
||||
<!-- version: 1 -->
|
||||
<!-- version: 2 -->
|
||||
|
||||
# Preuve Devnet `0.4.8-pre.010`
|
||||
|
||||
@@ -14,4 +14,4 @@ L’archive a été renommée lors de son intégration : son nom source contenai
|
||||
|
||||
Cette preuve est documentaire. Aucun test, runner ou composant runtime ne la charge.
|
||||
|
||||
Le rapport associé est [`V0_4_8_PRE_010_SOLANA_PROGRAM_METADATA_DEVNET_VALIDATION_REPORT.md`](../../../../V0_4_8_PRE_010_SOLANA_PROGRAM_METADATA_DEVNET_VALIDATION_REPORT.md).
|
||||
Le rapport associé est `olddocs/archivekbot3/docs/validation/V0_4_8_PRE_010_SOLANA_PROGRAM_METADATA_DEVNET_VALIDATION_REPORT.md`.
|
||||
|
||||
Reference in New Issue
Block a user