v0.4.8-pre.013
This commit is contained in:
@@ -0,0 +1,333 @@
|
||||
<!-- file: docs/audits/V0_4_8_PRE_013_METAPLEX_COMPLETENESS_AND_DEVNET_AUDIT.md -->
|
||||
<!-- version: 30 -->
|
||||
|
||||
# Audit `0.4.8-pre.013` — Metaplex Token Metadata et campagnes Devnet
|
||||
|
||||
## Objet
|
||||
|
||||
Ce réaudit vérifie si la surface Metaplex Token Metadata doit encore être complétée avant de reprendre les campagnes Devnet. Il sépare strictement la complétude du code, la disponibilité d’une fixture et la preuve réseau observée.
|
||||
|
||||
## Sources contrôlées
|
||||
|
||||
- IDL historique conservé `metadata.metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s.metaplex_token_metadata.V1_14_0.from_github_mpl-token-metadata.json` ;
|
||||
- `METAPLEX_TOKEN_METADATA_MATRIX.json` ;
|
||||
- intents, builders, exécuteur, préflight et matérialiseurs Metaplex de `kb-lib` et `kb-pipeline` ;
|
||||
- inventaires synthétiques et Devnet de `kb-pipeline-demo-scenarios` ;
|
||||
- surface Rust actuelle `mpl-token-metadata ^5.1`, résolue à `5.1.1` dans la base validée.
|
||||
|
||||
## Fermeture de la surface
|
||||
|
||||
L’IDL contient exactement 58 instructions et la matrice d’exécution contient exactement 58 lignes. Leur partition est :
|
||||
|
||||
- 20 `executable_current` ;
|
||||
- 15 `executable_deprecated` ;
|
||||
- 22 `decode_only_replaced` ;
|
||||
- 1 `decode_only_bridge_boundary`, `BubblegumSetCollectionSize`, hors frontière du programme Metaplex Token Metadata.
|
||||
|
||||
Les 20 opérations courantes sont : `CreateEscrowAccount`, `CloseEscrowAccount`, `TransferOutOfEscrow`, `Burn`, `Create`, `Mint`, `Delegate`, `Revoke`, `Lock`, `Unlock`, `Migrate`, `Transfer`, `Update`, `Use`, `Verify`, `Unverify`, `Collect`, `Print`, `Resize` et `CloseAccounts`.
|
||||
|
||||
Le réaudit ne met en évidence aucune instruction courante du SDK actuel absente des intents ou de l’exécuteur. Une seconde passe d’exactitude des builders a toutefois révélé que `Print` et `Resize` utilisaient encore les account metas figées de l’IDL historique : `Print` ne déclarait pas `edition_mint` ni `master_token_account_owner` signataires et `Resize` ne déclarait pas `payer` signataire. `pre.013-delta-fix-003` migre ces deux opérations vers les builders officiels `mpl-token-metadata 5.1.1` et verrouille leurs flags de comptes par tests directs. Les formes remplacées restent volontairement non exécutables et les formes obsolètes restent séparées, exécutables uniquement sous approbation explicite. Aucun élargissement de la frontière programme n’est requis.
|
||||
|
||||
## Écart initial de validation réseau
|
||||
|
||||
Au début de `0.4.8-pre.013`, la matrice Devnet contenait les 20 opérations courantes mais aucune preuve réseau durable n'était conservée dans la base reprise : les 20 statuts ont donc été rouverts à `not_run`. Cette décision constitue le point de départ du réaudit, pas son état final ; la consolidation en fin de document ferme la matrice à 15 `confirmed`, 5 `unavailable` et 0 `not_run`.
|
||||
|
||||
À ce même point de départ, les cinq familles de parcours existantes — NFT, SFT, token fongible, collection et pNFT — décrivaient une cible cohérente, mais leur préparation Devnet réellement automatisée restait limitée à `Create` et `UpdateAsUpdateAuthorityV2`. Les opérations spécialisées exigeaient encore des graphes de comptes dédiés, notamment :
|
||||
|
||||
- édition maître, édition imprimée, `Print`, `Mint` et `Burn` ;
|
||||
- collection parent/membre pour `Verify` et `Unverify` ;
|
||||
- pNFT avec token records, delegates et rule set lorsque requis ;
|
||||
- uses, escrow et opérations de maintenance selon leurs préconditions stateful.
|
||||
|
||||
Aucune disponibilité de builder ni preuve synthétique n’est promue en preuve Devnet.
|
||||
|
||||
## Écart du runner corrigé
|
||||
|
||||
Le runner Metaplex construisait déjà une policy exigeant, après soumission, l’insertion canonique, l’extraction Core, le replay et éventuellement la matérialisation. Pourtant, son exécution s’arrêtait après confirmation, lectures stateful et snapshots de comptes.
|
||||
|
||||
`pre.013` aligne le comportement sur le contrat déclaré :
|
||||
|
||||
1. confirmation de la signature ;
|
||||
2. lectures stateful de postcondition ;
|
||||
3. hydratation canonique bornée de la transaction ;
|
||||
4. extraction Core de la signature ;
|
||||
5. replay du décodeur Metaplex avec les matérialiseurs du domaine ;
|
||||
6. lecture des matérialisations instructionnelles ;
|
||||
7. seconde passe de replay avec état matérialisé, qui doit produire un skip idempotent propre ;
|
||||
8. diagnostic post-exécution agrégé.
|
||||
|
||||
Le nombre de retries `getTransaction` est borné à 20. Le desktop est seulement adapté à ce contrat commun ; l’ajout des nouveaux parcours UI reste réservé à `pre.014`.
|
||||
|
||||
## État de la prerelease
|
||||
|
||||
Le réaudit de complétude est terminé et le défaut de post-validation du runner est corrigé dans le delta initial. La prerelease reste **en cours** tant que les fixtures spécialisées ne sont pas complétées et que les 20 opérations courantes ne sont pas qualifiées par des preuves Devnet réelles ou une indisponibilité explicitement démontrée.
|
||||
|
||||
## Correctif `pre.013-delta-fix-001`
|
||||
|
||||
La première validation locale du delta initial a mis en évidence deux erreurs de compilation, sans remettre en cause le réaudit ni la frontière fonctionnelle :
|
||||
|
||||
- le test Devnet opt-in appelait `PostgresStoreOptions::new` avec l'ancienne signature à trois paramètres et fournissait une `Duration` alors que le contrat courant attend `connect_timeout_ms: u64` puis `auto_initialize_schema: bool` ;
|
||||
- le desktop injectait directement `BackfillSummary`, `CoreExtractionSummary` et `DecodeReplaySummary` dans `serde_json::json!`, alors que ces summaries internes ne dérivent volontairement pas `Serialize`.
|
||||
|
||||
`pre.013-delta-fix-001` corrige le premier point avec `5_000` ms et `false`, puis projette explicitement les trois summaries en `serde_json::Value` dans l'adaptateur desktop. Aucun derive public supplémentaire n'est ajouté à `kb-pipeline` et aucun contrat de production n'est élargi.
|
||||
|
||||
La validation locale de `pre.013-delta-fix-001` est ensuite réussie : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets` et l'audit workspace sont propres ; `kb-pipeline-demo-scenarios` réussit 69 tests unitaires, 1 test CLI et 1 test d'API externe ; `kb-app-demo-desktop` réussit 135 tests unitaires.
|
||||
|
||||
## Correctif `pre.013-delta-fix-002` — cohérence des cinq fixtures Create
|
||||
|
||||
Le réaudit des cinq parcours Devnet a révélé un défaut latent indépendant du runner : le desktop adaptait le JSON `Create` à NFT, SFT, fungible, collection ou pNFT, tandis que `prepare_metaplex_create_fixture` préparait toujours un mint classique à zéro décimale. Cette séparation pouvait produire un parcours `Fungible` dont le `TokenStandard` annoncé ne correspondait pas aux décimales du mint réellement créé.
|
||||
|
||||
Le correctif déplace la spécialisation dans la fixture réutilisable :
|
||||
|
||||
- NFT, SFT, collection et pNFT préparent un mint classique à 0 décimale ;
|
||||
- fungible prépare un mint classique à 9 décimales ;
|
||||
- seules NFT, collection et pNFT demandent une master edition ;
|
||||
- SFT et fungible conservent `master_edition = null` et aucun `print_supply` ;
|
||||
- collection déclare `CollectionDetails::V1 { size: 0 }` ;
|
||||
- pNFT déclare `ProgrammableNonFungible` sans rule set pour le parcours de base ;
|
||||
- les cinq JSON produits sont vérifiés hors réseau par désérialisation vers `ExMetaplexTokenMetadataOperation::Create`.
|
||||
|
||||
Le desktop ne réécrit plus le contrat après préparation : le standalone Create reste NFT par défaut et chaque scénario transmet explicitement sa famille à la fixture commune.
|
||||
|
||||
La prerelease reste **en cours** : ce correctif ferme uniquement la cohérence des fixtures `Create`. Les token accounts/supply, éditions imprimées, collection parent-membre, token records pNFT, uses, escrow et la qualification réseau des 20 opérations restent à traiter.
|
||||
|
||||
## Correctif `pre.013-delta-fix-003` — exactitude `Print` et `Resize`
|
||||
|
||||
Le contrôle des graphes nécessaires aux éditions imprimées a mis en évidence un écart de builder avant même l’exécution Devnet. Le SDK `mpl-token-metadata 5.1.1` déclare pour `Print` `edition_mint`, `edition_mint_authority`, `payer` et `master_token_account_owner` comme signataires ; l’ancien builder issu de l’IDL ne déclarait que `edition_mint_authority` et `payer`. Pour `Resize`, le SDK courant déclare `payer` writable + signer, alors que l’ancien builder le rendait writable non signer.
|
||||
|
||||
Le correctif remplace uniquement ces deux constructions par `PrintBuilder` et `ResizeBuilder` du SDK officiel. Les types publics restent inchangés dans ce lot : les comptes actuellement obligatoires dans l’intent sont transmis aux comptes optionnels du SDK sous forme `Some(...)`. L’audit des optionalités courantes et des autres opérations encore construites depuis l’IDL brut reste explicitement ouvert avant leur qualification Devnet.
|
||||
|
||||
Deux tests de régression vérifient directement le discriminator, le nombre de comptes et les flags signer/writable critiques. Aucune ligne de la matrice Devnet n’est promue par ce correctif.
|
||||
|
||||
## Correctif `pre.013-delta-fix-004` — optionalités positionnelles courantes
|
||||
|
||||
La validation locale de `pre.013-delta-fix-003` a d’abord révélé deux violations `clippy::implicit-return` dans les deux closures ajoutées par ses tests. L’opérateur a ajouté les deux `return`, puis `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets` et l’audit workspace ont réussi ; les deux régressions `Print`/`Resize` passent et la suite complète `kb-lib` atteint 697 tests unitaires réussis sans échec. `fix-004` incorpore ces deux corrections afin que l’archive reproduise exactement cet état validé.
|
||||
|
||||
Le réaudit d’optionalité montre ensuite que le décodeur et la matrice conservaient déjà le contrat Kinobi courant, mais que plusieurs intents/exécuteurs imposaient encore des comptes que le SDK accepte comme positions optionnelles. Le correctif aligne donc :
|
||||
|
||||
- `CreateEscrowAccount.authority` et `TransferOutOfEscrow.authority` sur l’autorité optionnelle de fin de liste ;
|
||||
- `Mint.token_owner`, `master_edition`, `token_record`, `delegate_record`, `authorization_rules_program` et `authorization_rules` sur les six positions optionnelles du wrapper courant ;
|
||||
- `Migrate.authorization_rules_program` et `authorization_rules` sur les deux positions optionnelles finales ;
|
||||
- `Use.delegate_record`, `token`, `edition`, `spl_token_program`, `authorization_rules_program` et `authorization_rules` sur les positions optionnelles courantes ;
|
||||
- `Print.edition_token_record`, `Resize.authority` et `Resize.token` sur les comptes optionnels exposés par les builders officiels.
|
||||
|
||||
Les positions optionnelles absentes sont encodées avec le Program ID Metaplex readonly et non signer, ce qui préserve le nombre et l’ordre des comptes positionnels attendus par le programme et par le décodeur. Les comptes système, sysvar et programmes dont le builder propose seulement une valeur par défaut restent explicitement fournis lorsque la struct d’instruction courante les porte comme comptes requis : une commodité de builder n’est pas reclassée comme optionalité positionnelle.
|
||||
|
||||
Deux régressions supplémentaires couvrent les placeholders de `CreateEscrowAccount`, `Mint`, `Migrate` et `Use`, puis l’absence de `edition_token_record` pour `Print` et de `authority`/`token` pour `Resize`. Aucune ligne Devnet n’est promue par ce correctif. La validation locale de `fix-004` réussit ensuite avec `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets`, l’audit workspace, 699 tests unitaires `kb-lib`, 70 tests unitaires `kb-pipeline-demo-scenarios` et 135 tests desktop.
|
||||
|
||||
## Correctif `pre.013-delta-fix-005` — socle token accounts/supply
|
||||
|
||||
La préparation des campagnes `Mint` exigeait encore un compte token classique réellement utilisable. Le correctif étend donc la fixture `Create` sans préconsommer la preuve Metaplex :
|
||||
|
||||
- la transaction native de préparation crée le mint SPL classique, exécute `InitializeMint2`, puis crée l’ATA canonique de l’opérateur ;
|
||||
- la dépense déclarée du plan inclut les minima de rent du mint et du compte token ;
|
||||
- après confirmation, le mint doit rester initialisé avec supply nulle et l’ATA doit être un compte classique de 165 octets, lié au mint et à l’opérateur, avec amount nul et état initialisé ;
|
||||
- le résumé expose l’ATA et produit un intent Metaplex `Mint` typé par famille ;
|
||||
- NFT, collection et pNFT réservent un montant brut de 1, SFT un montant de 10 et le fungible à 9 décimales un montant de 1_000_000_000 ;
|
||||
- pour pNFT, le token-record PDA canonique est dérivé et transmis à `Mint`, mais n’est pas créé par la fixture native.
|
||||
|
||||
Cette séparation est intentionnelle : la fixture prépare les préconditions mais laisse `Mint` produire la supply et, pour pNFT, l’état programmable que la campagne Devnet devra observer. Les 20 lignes réseau restent `not_run` jusqu’à réception de preuves réelles.
|
||||
|
||||
## Correctif `pre.013-delta-fix-006` — première campagne réseau `Create -> Mint`
|
||||
|
||||
La validation locale de `fix-005` est acquise : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets` et l’audit workspace sont propres ; `kb-pipeline-demo-scenarios` réussit 72 tests unitaires, 1 test CLI et 1 test d’API externe, et `kb-app-demo-desktop` réussit 135 tests unitaires.
|
||||
|
||||
Le correctif ajoute une campagne Devnet volontairement bornée à une seule famille par invocation. Les valeurs acceptées sont NFT, SFT, fungible, collection et pNFT. La campagne :
|
||||
|
||||
1. prépare un mint SPL classique frais et l’ATA canonique opérateur avec supply/amount nuls ;
|
||||
2. exécute `Create` avec matérialisation et snapshots metadata/master edition selon la famille ;
|
||||
3. relit le mint et l’ATA au minimum au slot confirmé de `Create` et exige toujours supply=0/amount=0 ;
|
||||
4. exécute `Mint` avec les snapshots `Create` comme préflight confirmé ;
|
||||
5. relit les comptes Metaplex au slot confirmé de `Mint`, exige le token record pour pNFT et vérifie la transition SPL exacte vers `mint_amount_raw` ;
|
||||
6. exige pour les deux transactions hydratation canonique, extraction Core, premier replay, matérialisation instructionnelle et second replay idempotent.
|
||||
|
||||
Le runner générique est durci en parallèle : les requêtes de postcondition sont clonées après confirmation et leur `min_context_slot` devient le maximum entre la borne demandée et le slot confirmé. Une lecture `after_state` ne peut donc plus être satisfaite par un contexte antérieur à la transaction.
|
||||
|
||||
Aucune ligne de `METAPLEX_TOKEN_METADATA_DEVNET_EXECUTION_MATRIX.json` n’est promue par ce correctif. `Create` et `Mint` restent `not_run` jusqu’à réception de signatures et slots Devnet réels.
|
||||
|
||||
## Correctif `pre.013-delta-fix-007` — structure de crate et diagnostic de la première campagne NFT
|
||||
|
||||
La première tentative réelle `Create -> Mint` sur la famille NFT a été lancée après validation locale de `fix-006`. La suite hors réseau est propre avec 77 tests unitaires de `kb-pipeline-demo-scenarios` et 135 tests desktop. La campagne a ensuite atteint la validation post-exécution de `Create`, mais s'est arrêtée sur `metaplex_create_mint_post_execution_incomplete`. Le message de `fix-006` ne permettait pas de distinguer hydratation, extraction Core, replay, matérialisation instructionnelle ou snapshots manquants, et aucune signature n'a été imprimée avant le `panic`. Cette tentative ne constitue donc pas une preuve réseau durable et ne modifie aucun statut de matrice.
|
||||
|
||||
Le réaudit du chemin de matérialisation identifie en parallèle une sélection de preuve trop indirecte : les lignes matérialisées étaient retenues à partir du `source_decoder_name`, alors que la preuve recherchée appartient explicitement au matérialiseur Metaplex. `fix-007` sélectionne désormais les lignes par `processor_name`, dérivé directement de l'identité publique de `MtMetadataMetaplexTokenMetadataMaterializer`. Si aucune ligne n'est trouvée, le diagnostic post-exécution conserve le nom exact du matérialiseur et la signature concernée. La validation de campagne expose en outre les quatre drapeaux post-exécution, le nombre de lignes matérialisées, le nombre de snapshots et les diagnostics accumulés. Une nouvelle tentative pourra donc confirmer la correction ou localiser exactement l'étape encore défaillante sans interprétation implicite.
|
||||
|
||||
La même correction réorganise `kb-pipeline-demo-scenarios` avant l'ajout de nouvelles familles de fixtures. Les fichiers sont désormais groupés par domaine : `metadata/solana_program`, `metadata/metaplex_token_metadata`, `spl/associated_token_account`, `spl/memo`, `spl/token`, `spl/token_2022` et `spl/token_2022/metadata`. `solana.rs` conserve les primitives d'orchestration communes. Les exports publics restent au crate-root ; le refactor ne change donc pas le contrat externe de la crate.
|
||||
|
||||
## Correctif `pre.013-delta-fix-008` — borne RPC stateful Metaplex
|
||||
|
||||
La validation locale de `fix-007` réussit avec 78 tests unitaires de `kb-pipeline-demo-scenarios`, 135 tests desktop, `cargo check --workspace`, Clippy et l'audit workspace propres. La seconde tentative NFT localise ensuite l'échec avant hydratation : une lecture de postcondition transmet `MAX_METAPLEX_TOKEN_METADATA_ACCOUNT_BYTES = 1_048_576` à `GetAccountInfoConfig::new_with_data`, alors que le transport d'exécution borne une lecture complète à `MAX_COMPLETE_ACCOUNT_DATA_BYTES = 65536`.
|
||||
|
||||
`fix-008` aligne la constante stateful Metaplex sur cette borne de transport, valide la requête avant l'appel RPC et ajoute une régression analogue à celle déjà utilisée pour Solana Program Metadata. Les capacités propres aux décodeurs restent indépendantes pour des données déjà disponibles offline ou un futur lecteur par tranches. Le diagnostic de campagne inclut désormais aussi signature et slot lorsqu'une transaction confirmée échoue plus tard dans la post-validation.
|
||||
|
||||
Aucune ligne Devnet n'est promue par cette correction : la campagne doit être rejouée après validation locale.
|
||||
|
||||
## Correctif `pre.013-delta-fix-009` — compatibilité replay `Create` / `Mint`
|
||||
|
||||
La validation locale de `fix-008` est propre : `cargo check --workspace`, Clippy, 106 tests unitaires `kb-pipeline`, 78 tests unitaires `kb-pipeline-demo-scenarios` et 135 tests desktop réussissent. La troisième tentative NFT confirme ensuite réellement `Create` sur Devnet avec la signature `51MXdFFFNY7UTS23cmfCQBfrDKC99uk5Trtw2gkptvEug9aWJ2R1cE9Ta5QHbe4kS1NYgRUSSMmmdbqdhyxxnR4Y` au slot `481882374`. L’hydratation canonique et l’extraction Core réussissent, et deux snapshots stateful sont matérialisés. Le blocage restant est exclusivement instructionnel : `decode_replayed=false`, aucune ligne du matérialiseur Metaplex n’est produite et la seconde passe ne peut pas démontrer l’idempotence.
|
||||
|
||||
Le réaudit local identifie une incompatibilité entre l’exécuteur et son propre décodeur. `Create` permet officiellement de choisir si le mint et l’update authority signent, mais le décodeur imposait encore les deux signatures. La fixture prépare le mint dans une transaction antérieure et utilise donc légitimement `mint_as_signer=false`. En outre, les flags signer/writable de `MdCoreInstructionReplayInput` décrivent les privilèges globaux du message : lorsque authority, payer et update authority désignent le même wallet, un rôle readonly peut apparaître writable sans rendre l’instruction invalide. `Mint` présente la même propriété avec token owner, authority et payer.
|
||||
|
||||
`fix-009` valide donc pour `Create` et `Mint` uniquement les privilèges minimaux réellement requis, accepte les signataires dynamiques et les sur-ensembles transactionnels, tout en conservant writable obligatoire pour master edition/token record lorsqu’ils ne sont pas des placeholders Metaplex. Deux régressions verrouillent ces formes. Le runner ajoute aussi un diagnostic des compteurs par processor lorsque le premier replay n’est pas complet. Aucune ligne de matrice n’est promue avant un replay NFT complet avec matérialisation et idempotence.
|
||||
|
||||
## Correctif `pre.013-delta-fix-010` — fixture `Create -> Mint` fresh-only
|
||||
|
||||
La tentative suivant `fix-009` expose un mismatch entre l’autorité opérateur `J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH` et des mint/freeze authorities observées à `3RJXuBF6xB3j47EeAHEBbcwvV66rJrkhmJvYNr36jz8x`. L’interprétation initiale attribuait ce mismatch à une fixture persistante. `fix-010` durcit donc légitimement la préparation : alias à granularité nanoseconde, `TemporaryWalletStore::create` sans fallback de chargement, absence on-chain obligatoire avant préparation, puis relecture du mint et de l’ATA avec `minContextSlot` égal au slot confirmé de la transaction native.
|
||||
|
||||
Le réaudit complet effectué après la tentative suivante corrige toutefois l’interprétation causale : la validation qui produit ce message est exécutée après `validate_confirmed_execution("create", ...)`, donc après un `Create` confirmé et son pipeline post-exécution. Pour une famille NFT avec Master Edition, Token Metadata transfère normalement les mint/freeze authorities au PDA Master Edition. `fix-010` reste donc un durcissement fresh-only utile, mais il ne pouvait pas résoudre ce mismatch attendu.
|
||||
|
||||
## Correctif `pre.013-delta-fix-011` — postcondition d’autorité après `Create`
|
||||
|
||||
La tentative suivant `fix-010` reproduit le mismatch avec une nouvelle valeur fraîche `KsjdBdmUUM3r8Mw6cQESkXJfxmnPXSmR482963gmsyo`. La préparation fresh-only ayant été validée immédiatement avant `Create`, cette variation confirme qu’il ne s’agit pas d’un vieux mint réutilisé. Surtout, le chemin de code n’atteint cette vérification qu’après simulation, confirmation, hydratation canonique, extraction Core, replay, matérialisation, snapshots et seconde passe idempotente réussis pour `Create`. Signature et slot ne sont cependant pas imprimés à ce stade, donc cette tentative ne peut pas encore promouvoir la matrice.
|
||||
|
||||
`fix-011` applique la postcondition officielle : NFT, collection et pNFT attendent après `Create` le PDA Master Edition comme mint authority et freeze authority ; SFT et fungible continuent d’attendre l’autorité opérateur. La même attente est conservée après `Mint`. Les erreurs SPL postérieures à une exécution confirmée incluent désormais signature + slot, et le helper `read_token_account` devenu inutilisé est supprimé afin de retrouver un build sans warning.
|
||||
|
||||
## Correctif `pre.013-delta-fix-012` — première qualification opérationnelle confirmée
|
||||
|
||||
Après `fix-011`, la campagne NFT `Create -> Mint` termine enfin sans erreur. Le mint frais `J6pDBZR4nWpM8Mj61fEdwQXH3KLZE8RuKSEsyNofC7bp` utilise la metadata PDA `7JLnovNwuatxAessRcWCEuKb5jg2H93KVpmyHNzx4euG`, la Master Edition `GxUFL8ZfosThA4hUVGPKDT8Zvcc2b2VmdjEiw6WQQYNx` et l’ATA opérateur `9LBJCDFkJghjVDDeccTe4vjZH3dDNpzsWVXqyTKs81To`. La préparation native est confirmée par `2u4sdcFhmoeeYiAe8X761AmCnWyPLHSxYwzwwocLYkfVCan9W5i13ipvK4v3dWRe9E4iJRqBCHHFRh8MwR2o8FLh`.
|
||||
|
||||
`Create` est confirmé avec la signature `okwkuQFp7yVguYW7GEY9Chv6ochM8TWBEeCGV1gu5Waku9wQvMfrKjkig6JxXBwpKoFTECignzJ8HFf8dLtpsvS` au slot `481904731` et produit une matérialisation instructionnelle. `Mint` est confirmé avec la signature `3hSizfdvezyFpfhqX4Za4wmhdMHhSPAisFvYjFAxpRzYcUXhryxCzc9qpwod3Yjm6GmijXTGjjDUuVksfpBzLwz1` au slot `481904744`, produit une matérialisation instructionnelle et fait passer la supply du mint ainsi que l’amount de l’ATA de `0` à `1`. Le test retourne `ok` uniquement après les gardes de simulation, hydratation canonique, extraction Core, replay, matérialisation, snapshots stateful et seconde passe idempotente.
|
||||
|
||||
La matrice Devnet opérationnelle passe en version 2. Elle conserve désormais `observedFamilies` et une liste de preuves observées ; une ligne `confirmed` est refusée si elle ne couvre pas l’union de `requiredEvidence` et `submissionEvidence`. `Create` et `Mint` deviennent `confirmed` sur `nft`, tandis que les 18 autres opérations restent `not_run`. La largeur multi-famille n’est pas confondue avec cette qualification opérationnelle : SFT, fungible, collection et pNFT restent à exécuter pour confirmer que les variantes de comptes et d’arguments empruntent le même pipeline complet.
|
||||
|
||||
Pour éviter une nouvelle perte de télémétrie, le résumé d’exécution conserve aussi `simulation_context_slot` et le test opt-in imprime une ligne `METAPLEX_CREATE_MINT_EVIDENCE` machine-readable. Les futures campagnes peuvent ainsi fournir le genesis hash, le slot de simulation, le message hash, le fee, la confirmation et les compteurs de pipeline exacts sans nouvelle instrumentation.
|
||||
|
||||
## Correctif `pre.013-delta-fix-013` — qualification SFT et preuves par famille
|
||||
|
||||
La campagne SFT suivante termine également de bout en bout. `Create` est simulé au slot `481908023`, confirmé avec `2s81m6k9HYDLmCy7oXKaqBvtb62iyX4bJmij2f2VjHuoRQBBA6YqRuAsjyaM7JCaJXasbU3WCfiko91cZcDLLdxV` au slot `481908028`, puis matérialise une ligne. `Mint` est simulé au slot `481908034`, confirmé avec `4pAemhEJewuLAeqLkqwzPvVmsCRbkyLiN6uAUWBA5RMsofaEDt5Xr8YGiBEvLWQM7Qvxnd81mmCHpandmfmWuyAm` au slot `481908039`, matérialise une ligne et fait passer supply/amount de `0` à `10`. Les deux étapes conservent genesis hash, message hash, fee, hydratation canonique, extraction Core, replay et idempotence propres.
|
||||
|
||||
La seconde famille observée expose une faiblesse du schéma v2 : une seule liste `evidence` ne peut pas représenter proprement plusieurs signatures et slots tout en conservant des kinds uniques. La matrice passe donc en version 3 avec un bundle `familyEvidence` par famille observée. Le validateur exige une correspondance exacte entre `observedFamilies` et ces bundles, puis contrôle chaque bundle contre les six preuves de simulation et les dix preuves de soumission. `Create` et `Mint` restent les deux seules opérations `confirmed`, désormais sur NFT et SFT ; les 18 autres opérations restent `not_run`.
|
||||
|
||||
## Consolidation `pre.013-delta-fix-014` — troisième famille `Create -> Mint`
|
||||
|
||||
La campagne fungible confirme que le même pipeline fonctionne avec un mint SPL classique à 9 décimales et sans Master Edition. `Create` est confirmé avec `3J1Ebq9DVkupVFQmqQ84QaNeztwMuRwbtXj7CiyUWwZPj4KCAJpKLAbPvpYss5cdiY33foXXScWWZE98H7tvbZed` au slot `481910724`; `Mint` est confirmé avec `2GKiY9foLmioYtUHttA2D6nCSmsftRL1JDKxENHmCnb5w38FGSxwBiRNMfF7mH8htv3G45irmge6DVtr6VN359j2` au slot `481910734`. Les deux étapes terminent simulation exacte, confirmation, hydratation canonique, extraction Core, replay, matérialisation et idempotence. `Mint` fait passer supply et amount ATA de `0` à `1_000_000_000`.
|
||||
|
||||
La matrice v3 ajoute donc un troisième bundle `familyEvidence = fungible` à `Create` et `Mint`. Leur statut opérationnel reste `confirmed`; les 18 autres opérations courantes restent `not_run`. La couverture multi-famille de cette campagne n’est plus ouverte que pour collection et pNFT.
|
||||
|
||||
### Consolidation `pre.013-delta-fix-015`
|
||||
|
||||
La campagne collection `Create -> Mint` est confirmée avec `Create` signature `3jpxyWuxQVyBtbvqDnV1oahLyxCXMw1zQQZBGCKgQSfn2TNcBaUdfvJ6kFa8zL3XJLMpM6tahQTnu8AUsTkYc3Dy` slot `481911942`, puis `Mint` signature `4WEciqZA5vmtrh1ZeSbqcgVnezUy7qT6B6utySfkg7dbAmhH6SMwwY862zGbzPW3nBVFzMjFVGPEhnTt6TcAiEe2` slot `481911955`. Les deux étapes terminent le pipeline de preuve complet ; `Create` et `Mint` possèdent désormais quatre bundles indépendants `nft`, `sft`, `fungible` et `collection`. Le test de matrice est corrigé pour exiger ces quatre familles déjà qualifiées tout en autorisant l'ajout ultérieur de `programmable_nft` lorsqu'un bundle complet existe. pNFT reste la dernière variante `Create -> Mint` à exécuter.
|
||||
|
||||
## Correctif `pre.013-delta-fix-016` — état SPL pNFT après `Mint`
|
||||
|
||||
La première campagne `programmable_nft` franchit `Create`, puis confirme `Mint` avec la signature `Gkg5A6ehuSzkU1N318kYoRHm5RdxV2yBRpaK9Gwyt6vN1ToYwAS6Vzpk2rQYWS9NJz1rnUpypLCn7DqWFzQzxFc` au slot `481913765`. La relecture de l’ATA confirme le mint attendu `Ecn3v1u21DKNhpFX1tqKvieVn5CkhMMukxWgoN59Hf2E`, l’owner opérateur `J12WA6c42oqpWkLu1dFa4pCegkQJPpxabwc3RRCMSUuH` et `amount=1`, mais observe `state=2`. Le runner exigeait encore `state=1` pour toutes les familles et échoue donc après une transaction `Mint` déjà confirmée.
|
||||
|
||||
Le contrat SPL encode `Initialized=1` et `Frozen=2`. Pour un programmable NFT, Token Metadata conserve l’ATA SPL gelé tandis que le Token Record porte l’état programmable et les délégations. `fix-016` rend cette distinction explicite : pNFT exige `Frozen` après `Mint`, les quatre autres familles exigent `Initialized`, et le Token Record reste une postcondition Metaplex séparée. Le résumé de campagne conserve aussi les états SPL bruts avant/après afin de produire la preuve `1 -> 2`.
|
||||
|
||||
Aucun bundle `programmable_nft` n’est ajouté à la matrice sur la base de cette tentative interrompue : la campagne doit être rejouée et retourner `ok` avec sa ligne `METAPLEX_CREATE_MINT_EVIDENCE` complète avant promotion.
|
||||
|
||||
## `pre.013-delta-fix-017` — fermeture `Create -> Mint` et ouverture collection parent-membre
|
||||
|
||||
Le rerun pNFT après `fix-016` ferme la qualification des cinq familles `Create -> Mint`. `Create` est confirmé au slot `481921980` et `Mint` au slot `481921994`; le Token Record est créé, supply/amount passent `0 -> 1` et l’ATA passe `Initialized(1) -> Frozen(2)`. La matrice v3 peut donc conserver cinq bundles familiaux indépendants pour `Create` et `Mint`. Les 18 autres opérations restent `not_run`.
|
||||
|
||||
Le lot suivant est borné à la collection courante :
|
||||
|
||||
- parent Collection NFT avec `CollectionDetails::V1 { size: 0 }` ;
|
||||
- membre NFT créé avec `collection.key=<parent mint>` et `verified=false` ;
|
||||
- `Verify` courant avec `VerificationArgs::CollectionV1` et comptes parent mint/metadata/master-edition ;
|
||||
- `Unverify` courant avec `VerificationArgs::CollectionV1` ;
|
||||
- postconditions member `verified false -> true -> false` ;
|
||||
- postconditions parent `size 0 -> 1 -> 0` ;
|
||||
- aucune utilisation de `SetCollectionSize` pour fabriquer l’état attendu.
|
||||
|
||||
Le runner réutilise le chemin confirmé `Create -> Mint`, puis exige pour `Verify` et `Unverify` le même contrat de preuve complet : simulation, confirmation, hydratation canonique, Core extraction, replay, matérialisation, snapshots et seconde passe idempotente. Aucun statut réseau de `Verify`/`Unverify` n’est promu avant exécution réelle.
|
||||
|
||||
## `pre.013-delta-fix-018` — compatibilité replay `Verify` / `Unverify`
|
||||
|
||||
La première campagne collection spécialisée confirme `Verify(CollectionV1)` sur Devnet avec la signature `2kR1VeWdCW3FcKRZdNuKMMc3kGUmWRBXxXX8W1NNi2rhWfZYTg9zsDvJHx7WvebgUfc2K382J14i66E2qPEnjsqR` au slot `481931061`. L’hydratation canonique, l’extraction Core et trois snapshots stateful réussissent, mais le décodeur retourne `failed=1`, `decoded=0`.
|
||||
|
||||
Le défaut est le même que pour `Create`/`Mint` : les flags Core sont les privilèges globaux du message. L’autorité est aussi fee payer et devient donc writable au niveau transactionnel, même si `Verify` ne requiert localement que sa signature. `fix-018` remplace les égalités négatives par des minima de privilèges pour `Verify` et `Unverify`, conserve l’exigence writable de la metadata cible et de la collection metadata réellement fournie, et aligne `Unverify` sur ses 7 positions courantes. La matrice conserve `Verify` et `Unverify` à `not_run` jusqu’au rerun complet.
|
||||
|
||||
## `pre.013-delta-fix-019` — qualification collection et préparation `Print -> Burn`
|
||||
|
||||
Le rerun suivant `fix-018` ferme la campagne collection spécialisée. `Verify(CollectionV1)` est confirmé avec la signature `39JwUoxF2WWYWvEEWzFxSmKZVwoqXD1wH78sgGaoXv2vZKYUsXDNNnKikeuyQcfCqDftEMHSKFDHnTeSQ3bRpFcJ` au slot `481936730`, puis `Unverify(CollectionV1)` avec `4Kfv42BGZtuBEwqTie5RWwdQ772hyxKiU9d3F3gfRnwVNrxCs2iZMvwL17Rwmuyr3XCVoHdaJVgaqCwv8y7bKoZY` au slot `481936742`. Les deux étapes terminent simulation, confirmation, hydratation canonique, extraction Core, decode replay, matérialisation, trois snapshots stateful et seconde passe idempotente. Le membre suit `verified=false -> true -> false` et le parent `CollectionDetails::V1.size=0 -> 1 -> 0`. La matrice Devnet peut donc promouvoir `Verify` et `Unverify` sur `collection`; elle contient désormais 4 opérations `confirmed` et 16 `not_run`.
|
||||
|
||||
Le lot suivant prépare `Print -> Burn` sans réutiliser les anciens wrappers d’édition. Le master est créé par le chemin courant `Create -> Mint` avec `PrintSupply::Limited(1)`. Le mint d’édition est un compte SPL classique frais, decimals 0, supply 0, avec ATA opérateur vide ; le builder courant `Print` reste responsable de la création de l’édition, du mint du token imprimé et du transfert d’autorité du nouveau mint. Le runner dérive Metadata, Edition et Edition Marker pour l’édition 1 et ajoute une lecture stateful `EditionMarker` dédiée.
|
||||
|
||||
`Print` exige un `edition_mint` signataire distinct du wallet opérateur. La surface Devnet ajoute donc une variante explicite multi-signataires : aucun signataire supplémentaire n’est implicitement accepté, chacun doit être déclaré dans `additional_authorized_signers`, fourni au moment de la signature et rester dans la borne du runner. L’API historique conserve son comportement profile-wallet-only. Pour la fixture fraîche limitée à une seule édition et possédée par le même opérateur que le master, `Burn` doit aussi ramener `MasterEdition.supply` de `1` à `0`, effacer l’unique bit d’Edition Marker puis fermer ce marker devenu vide, en plus de fermer le token account et l'Edition imprimée et de fermer sémantiquement Metadata selon le comportement du programme courant. La matrice garde `Print` et `Burn` à `not_run` tant que cette nouvelle campagne n’a pas terminé `ok` avec preuves réseau complètes.
|
||||
|
||||
## `pre.013-delta-fix-020` — correction de la précondition `Print` observée sur Devnet
|
||||
|
||||
La première tentative `Print -> Burn` de `fix-019` atteint le programme Metaplex pendant la simulation exacte mais n’est pas soumise. `Print` retourne `MetadataError::NotEnoughTokens` (`0x20`). L’erreur est produite avant toute preuve réseau qualifiante ; `Print` et `Burn` restent donc `not_run`.
|
||||
|
||||
Le réaudit du processeur courant ferme le diagnostic. `fix-019` précréait un mint SPL d’édition et son ATA opérateur avec `amount=0`. Pour `Print`, si le mint d’édition est absent, le programme le crée ; si le token account d’édition est absent, il crée l’ATA puis frappe exactement un token. En revanche, lorsqu’un token account est déjà présent, le chemin de validation exige `amount=1` et retourne `NotEnoughTokens` si cette quantité n’est pas satisfaite. La fixture de `fix-019` sélectionnait donc mécaniquement le mauvais chemin avec un ATA existant vide.
|
||||
|
||||
`fix-020` corrige le contrat de fixture sans contourner le programme :
|
||||
|
||||
- création persistante du **keypair** `edition_mint` uniquement ;
|
||||
- refus si le compte mint correspondant existe déjà on-chain ;
|
||||
- dérivation de l’ATA canonique puis refus si cet ATA existe déjà ;
|
||||
- validation séparée de l’ATA master, qui doit contenir exactement un token avant `Print` ;
|
||||
- `edition_mint` reste un signataire supplémentaire explicitement déclaré et réellement fourni ;
|
||||
- après confirmation, les mêmes postconditions fortes restent exigées sur mint/ATA, Metadata, Edition, Edition Marker et Master Edition.
|
||||
|
||||
Le `E0599` local signalé en parallèle ne correspond pas au contenu du delta `fix-019` archivé : ce delta contient bien `MetaplexTokenMetadataAccountKind::EditionMarker`. Il démontre néanmoins qu’un overlay partiel peut laisser `print_burn_campaign.rs` plus récent que `kb-pipeline`. `fix-020` réembarque donc le fichier stateful, valide ses pubkeys de dérivation et ajoute un test d’intégration externe crate-root construisant réellement le variant `EditionMarker`.
|
||||
|
||||
## `pre.013-delta-fix-021` — compte `Edition` compact et futur Tauri `Send`
|
||||
|
||||
La tentative Devnet suivant `fix-020` franchit désormais `Print` : la transaction `2199PTvKyTAfnGRHVaaCceW4u8phdJSu5ULkceD9uJeQyjjenEupK9osRZu1Pzx2NuQaJnAwngSAXMvr5oNtf5y6` est confirmée au slot `482068400`. La campagne s’arrête toutefois pendant les lectures stateful post-confirmation, avant hydratation canonique, extraction Core, replay et matérialisation. `Burn` n’est donc pas atteint et aucune promotion de matrice n’est effectuée.
|
||||
|
||||
Le compte `Edition` fraîchement créé expose la frontière de compatibilité liée à la réduction de taille Metaplex : la structure `Edition` du SDK Rust sérialise 41 octets, tandis que l’allocation on-chain compacte courante utilise 42 octets et l’allocation historique 241 octets. Le décodeur utilisait à tort `Edition::LEN` comme taille de compte stricte. `fix-021` accepte uniquement la longueur sérialisée exacte ou les allocations Metaplex connues avec padding nul, et refuse les longueurs ou paddings inconnus. Une régression `kb-pipeline` matérialise explicitement un compte `Edition` compact de 42 octets. Les erreurs stateful incluent désormais l’adresse et le `kind` du compte visé.
|
||||
|
||||
La validation workspace de `fix-020` révèle en parallèle que `&dyn solana_signer::Signer` est conservé au travers du futur async multi-signataires. Comme le trait `Signer` ne garantit pas `Sync`, la commande Tauri ne satisfait plus son obligation `Future + Send`. Le keypair concret est `Send + Sync`; `fix-021` conserve donc `TemporaryWallet::as_signer()` et ajoute une vue `as_sync_signer()` dédiée, puis borne la nouvelle API multi-signataires à `Signer + Sync`. Les règles d’autorisation des signataires supplémentaires restent inchangées. Le warning Clippy `cloned_ref_to_slice_refs` observé dans le test de garde des signataires est également corrigé.
|
||||
|
||||
## `pre.013-delta-fix-022` — fermeture Metadata, future `Send` et régression `Print`
|
||||
|
||||
Le rerun suivant `fix-021` atteint désormais `Burn` après validation confirmée de son exécution. La dernière garde rapporte `token=false, metadata=true, edition=false, edition_marker=false` : seuls les tests d’existence brute font encore apparaître Metadata. Le processeur courant ferme bien Metadata, mais son helper `close_program_account` réserve un traitement à `MetadataV1` : seul le rent minimum est retiré, car des fees peuvent rester. Lorsqu’un solde résiduel subsiste, le compte est réalloué à un octet `0x00` et devient `Uninitialized` au lieu de disparaître. `fix-022` accepte donc comme fermeture uniquement l’absence du compte ou ce tombstone exact (`owner=Token Metadata`, non exécutable, lamports positifs, `space=1`, `data=[0]`). Token account, Edition et Edition Marker vide doivent toujours être réellement absents.
|
||||
|
||||
La validation workspace expose aussi l’effacement incomplet du marqueur `Sync` : bien que l’API de `fix-021` accepte `Signer + Sync`, elle recréait ensuite une `Vec<&dyn Signer>` qui survivait jusqu’aux `await` suivants et rendait le futur Tauri non-`Send`. `fix-022` confine cette conversion dans un helper synchrone qui signe immédiatement la transaction ; aucun trait object non-`Sync` n’est désormais stocké dans l’état du futur.
|
||||
|
||||
Enfin, le seul échec `kb-lib` de la validation locale (`703/704`) provient du test `modern_print_accepts_transaction_privilege_supersets` : il construisait un `edition_token_record` présent mais readonly, contrairement au builder courant qui exige ce compte writable lorsqu’il est fourni. Le test est corrigé ; le décodeur n’est pas assoupli. La matrice reste à 4 opérations `confirmed` et 16 `not_run` jusqu’au rerun complet et à l’émission des signatures/slots/evidences `Print -> Burn`.
|
||||
|
||||
## `pre.013-delta-fix-023` — qualification `Print/Burn` et préparation du cycle pNFT
|
||||
|
||||
La validation locale de `fix-022` est entièrement propre : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets` et l’audit workspace réussissent. `kb-lib` passe `704/704`, `kb-pipeline` `107/107` plus deux APIs externes, `kb-pipeline-demo-scenarios` `92/92` plus CLI/API externe et le desktop `135/135`.
|
||||
|
||||
La campagne Devnet `Print -> Burn` termine `ok`. `Print` est confirmé avec `REHAxUZrSdKDj8F8k27Amrg7hwuJFhVfstjc9xjn2XGfTX38fH4tFwPeNrF5zeMN5pc21PpUPSgaKXMMfTFd7TE` au slot `482087799`; `Burn` avec `4cNUxGGSWifuAtqdPJAtM3Cjpi4JATitRDqrvEAe85NLpMWcgWmC27bsfjNUmK6sEBDovNPtkPV3wDH1LpfGbhd1` au slot `482087818`. Les postconditions prouvent `MasterEdition.supply 0 -> 1 -> 0`, mint imprimé `0 -> 1 -> 0`, token `0 -> 1`, bit d’Edition Marker consommé, puis fermeture du token account, de l’Edition et du marker redevenu vide. Metadata subsiste uniquement comme tombstone fee exact et est donc sémantiquement fermée. Les preuves pipeline sont complètes et idempotentes. `Print` et `Burn` peuvent être promus : la matrice compte désormais 6 `confirmed` et 14 `not_run`.
|
||||
|
||||
Le sous-lot suivant prépare la campagne pNFT `Delegate(Staking) -> Lock -> Unlock -> Revoke(Staking) -> Delegate(Transfer) -> Transfer`. Cette séquence couvre cinq opérations courantes sans mélanger les rôles : le Staking delegate possède le droit de lock/unlock mais pas de transfer ; le Transfer delegate possède le droit de transfer mais pas le lock. Le runner vérifie à chaque étape le Token Record autoritatif et, après transfert, les deux ATA gelées ainsi que le Token Record destination sans delegate. Les cinq opérations restent `not_run` avant exécution réelle.
|
||||
|
||||
## `pre.013-delta-fix-029` — qualification du lifecycle pNFT et ouverture du probe `Use`
|
||||
|
||||
Le rerun `fix-028` ferme le cycle pNFT avec six transactions confirmées. `Delegate(StakingV1)` est confirmé au slot `482113803`, `Lock` au slot `482113812`, `Unlock` au slot `482113822`, `Revoke(StakingV1)` au slot `482113831`, `Delegate(TransferV1)` au slot `482113840` et `Transfer` au slot `482113850`. Les six étapes possèdent hydratation canonique, extraction Core, replay, matérialisation et idempotence propres. L’état suit `Unlocked -> Staking -> Locked -> Unlocked -> revoked -> Transfer`, puis le transfert laisse la source `amount=0/Initialized`, la destination `amount=1/Frozen` et le TokenRecord destination `Unlocked` sans delegate.
|
||||
|
||||
La matrice v3 promeut donc `Delegate`, `Revoke`, `Lock`, `Unlock` et `Transfer` sur `programmable_nft`. Le bilan devient **11 opérations `confirmed` et 9 `not_run`**.
|
||||
|
||||
Le réaudit de la source officielle courante impose une précaution avant `Use`. Le client Rust généré expose bien l’instruction `Use` (discriminant 51), avec authority/payer signataires, Metadata writable et comptes token/edition optionnels writable. En revanche, le routeur du programme courant n’expose pas de branche nouvelle API `Use`; `Migrate` est même explicitement routé vers `MetadataError::Removed`. Le code legacy conserve `Utilize`, qui n’est pas la même instruction. Cette divergence client/runtime ne doit être transformée ni en succès supposé ni en indisponibilité supposée.
|
||||
|
||||
`fix-029` prépare donc un probe Devnet borné : NFT classique frais, `Uses::Multiple { remaining: 2, total: 2 }`, `Create -> Mint`, puis simulation exacte de `Use`. Si la simulation est refusée, le probe retourne une classification `runtime_unavailable` avec erreur et logs sans soumettre. Si elle réussit, la transaction est soumise et doit prouver `remaining 2 -> 1`, token inchangé à `amount=1/Initialized`, pipeline complet et idempotence. `Use` reste `not_run` jusqu’à ce probe réel.
|
||||
|
||||
## `pre.013-delta-fix-030` — classification runtime de `Use`
|
||||
|
||||
Le probe Devnet réel de `Use` termine `Create -> Mint`, puis la simulation exacte de l'instruction courante de discriminant 51 est refusée par Token Metadata avec `InstructionError[0]=InvalidInstructionData`. Les logs contiennent `Program log: Error: InvalidInstructionData`; la simulation consomme `12085` compute units et estime les frais à `5000` lamports. Aucune transaction `Use` n'est soumise.
|
||||
|
||||
La classification canonique devient donc `unavailable`, et non `not_run` ni `confirmed`. La matrice contient désormais 11 opérations `confirmed`, 1 `unavailable` et 8 `not_run`. Le premier harness de probe remontait encore la simulation négative comme erreur de readiness ; `fix-030` corrige ce point en autorisant l'observation d'une simulation échouée uniquement pour `submit=false`, sans jamais autoriser l'envoi.
|
||||
|
||||
## `pre.013-delta-fix-033` — qualification escrow et bornage de la maintenance finale
|
||||
|
||||
Le rerun `fix-032` qualifie les trois opérations Token Owned Escrow. `CreateEscrowAccount` est confirmé au slot `482147206`, `TransferOutOfEscrow` au slot `482147252` et `CloseEscrowAccount` au slot `482147267`. Chacune termine hydratation canonique, extraction Core, replay, matérialisation et idempotence. Le dépôt contrôlé d’une unité brute est intégralement restitué, l’ATA du PDA est fermée lorsqu’elle devient vide, le compte escrow est fermé et le NFT parent reste à `amount=1`. La matrice passe à **14 `confirmed`, 1 `unavailable`, 5 `not_run`**.
|
||||
|
||||
Le dernier lot distingue ensuite les opérations selon leurs autorités réelles. `Update` et `Resize` peuvent être exercés par un NFT frais détenu par l’opérateur. `Migrate` est explicitement routé vers `Removed` dans le programme courant. `Collect` est réservé à `FEE_AUTHORITY=Levytx9LLPzAtDJJD7q813Zsm8zg9e1pb53mGxTKpD7`, et `CloseAccounts` à `OWNERLESS_CLOSE_AUTHORITY=C1oseLQExhuEzeBhsVbLtseSpVgvpHDbBj3PTevBCEBh`. La campagne de maintenance ne tente donc pas de contourner ces autorités : elle soumet seulement `Update`/`Resize` et simule les trois autres pour obtenir une classification runtime observable.
|
||||
|
||||
## `pre.013-delta-fix-034` — classification `Resize` sur comptes courants
|
||||
|
||||
Le premier run de maintenance après `fix-033` franchit la transaction `Update` et sa postcondition `primary_sale_happened false -> true`, puis la simulation de `Resize` atteint `IX: Resize` et s'arrête avec `Account has already been resized`, `Custom(201)`, après `14643` compute units. La politique simulation-first empêche toute soumission `Resize`. La sortie du test étant émise seulement après le résumé complet, la signature et le slot du `Update` déjà validé en interne ne sont pas disponibles et cette opération n'est pas encore promue.
|
||||
|
||||
Cette réponse est conforme à la fonction de `Resize` : les créations courantes sont déjà au layout cible et une exécution positive nécessite un compte legacy sous-dimensionné que le scénario ne peut pas fabriquer comme compte Token Metadata program-owned. `Resize` est donc classé `unavailable` pour la qualification contrôlée actuelle. La matrice passe à **14 `confirmed`, 2 `unavailable` et 4 `not_run`**. Le rerun final soumet uniquement `Update` et simule `Resize(201)`, `Migrate(75)`, `Collect(7)` et `CloseAccounts(188)`.
|
||||
|
||||
## Clôture fonctionnelle `pre.013-delta-fix-036`
|
||||
|
||||
Le dernier rerun maintenance ferme toutes les lignes encore ouvertes. `Update` est confirmé sur NFT avec simulation au slot `482162408`, confirmation au slot `482162413`, signature `4hxxBnsCA1JBJPNHgXRDeq1W7rXbFj2yySscWJKxU1VTMDcPzPfoWy7QzANHSDsbQfxxcwuAQNDLqEukgsug6qoZ`, replay, matérialisation, idempotence et transition `primary_sale_happened false -> true`.
|
||||
|
||||
Les quatre probes finaux sont tous négatifs avant soumission et correspondent au contrat courant : `Resize -> AccountAlreadyResized(201)` au slot `482162417`, `Migrate -> Removed(75)` au slot `482162422`, `Collect -> UpdateAuthorityIncorrect(7)` au slot `482162426`, `CloseAccounts -> InvalidCloseAuthority(188)` au slot `482162430`. `Resize` requiert un état legacy contrôlé absent des fixtures modernes ; `Migrate` est retiré ; `Collect` et `CloseAccounts` sont réservés à des autorités Metaplex fixes.
|
||||
|
||||
La matrice v3 est donc intégralement classée : **15 `confirmed`, 5 `unavailable`, 0 `not_run`**. Aucun statut `confirmed` n'est dérivé d'une preuve synthétique ou d'une simple simulation. Le travail fonctionnel de réaudit Metaplex de `pre.013` est terminé ; la suite est une consolidation documentaire et de conformité avant `pre.014`.
|
||||
|
||||
## `pre.013-delta-fix-037` — consolidation finale du réaudit Metaplex
|
||||
|
||||
La validation locale suivant `fix-036` ferme la prerelease sans nouvelle modification fonctionnelle : `cargo fmt --all`, `cargo check --workspace`, `cargo clippy --all-targets` et `python3 scripts/audit_rust_workspace_rules.py` sont propres. `cargo test -p kb-pipeline-demo-scenarios` réussit avec 105 tests unitaires, 1 test CLI et 1 test API externe. Le warning `if_same_then_else` observé avant `fix-036` a disparu sans suppression de lint.
|
||||
|
||||
La matrice Devnet reste la source de vérité opérationnelle et contient exactement **15 opérations `confirmed`, 5 `unavailable` et 0 `not_run`**. Les cinq indisponibilités sont bornées et distinctes : `Use` est rejeté par le runtime courant avec `InvalidInstructionData`; `Resize` retourne `AlreadyResized(201)` sur les comptes créés au layout courant et nécessiterait un état legacy contrôlé pour un succès positif; `Migrate` retourne `Removed(75)`; `Collect` exige l'autorité Metaplex fixe de collecte; `CloseAccounts` exige l'autorité Metaplex ownerless-close fixe. Aucune de ces quatre dernières surfaces n'est soumise après une simulation négative.
|
||||
|
||||
Les formulations d'usage encore restées au statut préparatoire sont réconciliées : collection `Verify/Unverify`, lifecycle pNFT et Token Owned Escrow sont décrits comme campagnes qualifiées, le guide documente la campagne maintenance finale, et le TODO retire les tâches `pre.013` terminées. Les mentions `not_run` conservées dans les sections chronologiques de cet audit et des rapports intermédiaires restent intentionnelles : elles décrivent l'état observé au moment de chaque delta et ne constituent pas le statut courant.
|
||||
|
||||
`0.4.8-pre.013` est donc **terminée et validée**. Le prochain développement non-fix peut ouvrir `0.4.8-pre.014` pour la finalisation desktop metadata, sans rouvrir les campagnes Metaplex sauf régression ou changement de contrat explicitement observé.
|
||||
Reference in New Issue
Block a user