v0.1.1-pre.001-fix.002

This commit is contained in:
2026-08-14 14:45:57 +02:00
parent 37a1480c72
commit 27a6715a3e
2 changed files with 439 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/003-V0_1_1_CORE_FOUNDATION_PLAN.md -->
<!-- version: 2 -->
<!-- version: 4 -->
# Plan KSP 0.1.1 — Core foundation
@@ -126,7 +126,9 @@ ksp_core_lib::ErrorContext
ksp_core_lib::Result
ksp_core_lib::Pubkey
ksp_core_lib::ProgramIdEntry
ksp_core_lib::ProgramIdFilter
ksp_core_lib::entries
ksp_core_lib::program_ids
ksp_core_lib::native_program_ids
ksp_core_lib::find_program_id
ksp_core_lib::declare_program_id!
@@ -250,11 +252,15 @@ Les well-known account IDs doivent rester explicitement séparés des Program ID
## Nomenclature des Program IDs
Chaque Program ID KSP possède deux représentations publiques partageant exactement le même suffixe :
La nomenclature des symboles et la taxonomie du registre sont deux contrats liés mais distincts.
Le nom Rust d'une constante doit privilégier une **identité stable** et ne doit pas embarquer toute la classification fonctionnelle, car une reclassification future ne doit pas obliger à renommer un symbole public.
La forme générale devient :
```text
PRGID_<DOMAIN>_<SUBDOMAIN?>_<NAME>_<VERSION?> -> &'static str Base58
PRGIDPK_<DOMAIN>_<SUBDOMAIN?>_<NAME>_<VERSION?> -> Pubkey
PRGID_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?> -> &'static str Base58
PRGIDPK_<NAMESPACE>_<PROGRAM_OR_FAMILY>_<VARIANT?>_<VERSION?> -> Pubkey
```
Règles :
@@ -262,10 +268,11 @@ Règles :
- `PRGID_` identifie toujours la représentation texte Base58 ;
- `PRGIDPK_` identifie toujours la représentation `Pubkey` ;
- le suffixe après le préfixe doit être identique entre les deux formes ;
- `DOMAIN` identifie le propriétaire/famille stable, par exemple `SOLANA`, `SPL`, `METAPLEX`, `RAYDIUM` ;
- `SUBDOMAIN` n'est utilisé que lorsqu'il clarifie réellement une famille interne ;
- `VERSION` n'est ajoutée que lorsque plusieurs Program IDs distincts correspondent réellement à des versions différentes ;
- la nomenclature privilégie propriétaire/famille puis fonction, afin d'éviter les anciens noms inversés difficiles à étendre.
- `NAMESPACE` identifie le namespace/propriétaire stable de l'identité, par exemple `SOLANA`, `SPL`, `METAPLEX`, `RAYDIUM`, `METEORA`, `GOOSEFX` ou `JUPITER` ;
- `PROGRAM_OR_FAMILY` et `VARIANT` décrivent l'identité publique utile du programme sans tenter de recopier mécaniquement tous les champs de `ProgramIdEntry` ;
- `VERSION` n'est ajoutée que lorsque le projet/protocole distingue réellement plusieurs générations d'une même lignée de programme ;
- un suffixe ressemblant à une année ou une version dans un nom officiel n'est pas automatiquement interprété comme `program_version` : `Token-2022` reste par exemple une identité de programme distincte et non une déduction automatique de version ;
- la valeur de version est un label KSP normalisé à partir de la génération publiquement reconnue (`V1`, `V2`, `V3`, `V4`, `V6`, `V0_5`, etc.), pas la version d'une crate ou d'une IDL.
Exemples de convention :
@@ -279,11 +286,29 @@ PRGIDPK_SOLANA_LOADER_BPF_V2
PRGID_SOLANA_PRECOMPILE_ED25519
PRGIDPK_SOLANA_PRECOMPILE_ED25519
PRGID_SPL_MEMO_V1
PRGIDPK_SPL_MEMO_V1
PRGID_SPL_MEMO_V3
PRGIDPK_SPL_MEMO_V3
PRGID_SPL_MEMO_V4
PRGIDPK_SPL_MEMO_V4
PRGID_METEORA_DAMM_V2
PRGIDPK_METEORA_DAMM_V2
PRGID_GOOSEFX_GAMMA
PRGIDPK_GOOSEFX_GAMMA
PRGID_GOOSEFX_SSL_V2
PRGIDPK_GOOSEFX_SSL_V2
```
`PRGID_SPL_MEMO_V3` est uniquement un exemple de nomenclature future pendant `0.1.1` ; SPL Memo reste hors scope fonctionnel de cette release.
Les exemples SPL/DEX définissent uniquement la convention future pendant `0.1.1` ; ces protocoles restent hors scope fonctionnel de cette release.
### Pourquoi `NAMESPACE` et non `DOMAIN` dans le symbole
Le mot `domain` est réservé à la taxonomie fonctionnelle du registre décrite plus bas. Une constante doit rester stable si la classification fonctionnelle d'un programme est affinée.
Par exemple, `PRGID_GOOSEFX_GAMMA` reste un bon identifiant public même si KSP affine plus tard sa classification AMM. Le nom de symbole ne doit donc pas être une sérialisation complète de `domain/family/protocol/subfamily`.
## Construction et ownership des constantes
@@ -335,26 +360,132 @@ native_well_known_account_ids()
find_registered_program_id()
```
Cette fonctionnalité doit être reprise et simplifiée/améliorée dans Core pour les IDs réellement possédés par Core.
Cette fonctionnalité doit être reprise et améliorée autour d'un **registre canonique unique**. Les vues spécialisées ne doivent pas maintenir des listes indépendantes et dupliquer les mêmes Program IDs.
Direction retenue :
### Axes de classification retenus
- `ProgramIdEntry` décrit une entrée canonique KSP sans porter de decoder/executor ;
- `entries()` expose toutes les entrées Program ID actuellement possédées par Core ;
- `native_program_ids()` expose le sous-ensemble runtime-native/loader/precompile/historique retenu par Core ;
- `find_program_id()` recherche une entrée par Program ID canonique ;
- une recherche directe par `Pubkey` peut être ajoutée si elle simplifie réellement l'usage sans dupliquer la logique ;
- `registered_program_ids()` de bot3 est considéré comme un alias redondant de `entries()` et n'est pas repris automatiquement ;
- les well-known accounts suivent un registre/naming distinct lorsqu'ils deviennent nécessaires.
L'audit de l'ancien registre bot3 et des IDLs archivées montre qu'un seul axe hiérarchique ne suffit pas. La taxonomie KSP doit séparer au minimum :
`ProgramIdEntry` doit au minimum pouvoir exposer :
- `domain` : domaine fonctionnel large ;
- `family` : famille fonctionnelle dans ce domaine ;
- `protocol` : protocole/projet auquel appartient le programme ;
- `subfamily` : branche, architecture ou produit interne optionnel dans une même famille/protocole ;
- `program_version` : génération publique optionnelle de la **lignée du programme on-chain** ;
- `kind` : classification technique nécessaire aux vues Core telles que les programmes natifs/loaders/précompiles ;
- le code KSP unique, la chaîne Base58 `PRGID_*` et le `Pubkey` `PRGIDPK_*` restent les identités de l'entrée.
- un code KSP stable lisible machine ;
- la représentation Base58 `PRGID_*` ;
- la représentation `Pubkey` `PRGIDPK_*` ;
- une classification minimale permettant de construire les sous-ensembles utiles sans dupliquer manuellement plusieurs registres.
Les vocabulaires exacts de `domain`, `family`, `protocol`, `subfamily` et `kind` doivent rester extensibles. Core ne doit pas créer une enum fermée contenant tous les futurs protocoles Solana. Des identifiants statiques/constantes KSP ou des newtypes légers peuvent être utilisés ; le choix syntaxique exact est finalisé en `pre.003`.
La structure Rust exacte et le nom exact de la classification sont finalisés avec les tests de `pre.003`. Cette classification reste descriptive et bornée aux catégories réellement nécessaires ; elle ne devient pas une enum générale de protocoles ou de capacités de décodage.
`family = amm` est retenu comme famille agrégatrice future pour les modèles AMM. Les variantes `cpmm`, `clmm`, `dlmm`, `damm`, `stable_swap`, `weighted_swap`, `gamma`, `ssl` ou équivalentes appartiennent au niveau `subfamily` lorsqu'elles représentent réellement une branche architecturale du protocole. Cela permettra à une future vue `amm_program_ids()` de retrouver l'ensemble de ces programmes au lieu de limiter la recherche à l'ancien préfixe bot3 `AMM_*`.
`subfamily` reste optionnelle : un programme unique peut supporter plusieurs courbes/mécanismes et ne doit pas être forcé artificiellement dans une seule sous-famille. L'AMM Aldrin constitue notamment un cas où le programme peut couvrir plusieurs types de courbes ; la famille `amm` suffit alors si aucune sous-famille unique n'est normative.
### `program_version` est distinct de `subfamily`
La version est un axe indépendant. Elle ne doit jamais être encodée comme une `subfamily` uniquement pour distinguer deux Program IDs.
Cas représentatifs audités :
| Cas | `domain`/`family`/`protocol` | `subfamily` | `program_version` |
|----------------------------|-------------------------------------------------------------------|-------------------|-------------------------------------------------------------|
| SPL Memo v1 / v3 / v4 | identiques entre les trois entrées | identique/absente | `v1` / `v3` / `v4` |
| Aldrin AMM v1 / v2 | identiques | identique/absente | `v1` / `v2` |
| Meteora DAMM v1 / v2 | identiques | `damm` | `v1` / `v2` |
| Meteora DLMM | même domaine/protocole AMM | `dlmm` | aucune si aucune génération normative n'est attachée à l'ID |
| GooseFX GAMMA | même domaine/famille/protocole GooseFX que les autres AMM GooseFX | `gamma` | aucune génération `v1` ne doit être inventée |
| GooseFX SSL v2 | même domaine/famille/protocole GooseFX | `ssl` | `v2` |
| Jupiter Aggregator v4 / v6 | identiques pour la lignée Aggregator | `aggregator` | `v4` / `v6` |
Cette séparation évite notamment de traiter GooseFX `GAMMA` comme « V1 » de GooseFX `SSL V2`, ce que les sources/IDLs ne justifient pas.
### Version du programme versus version d'IDL
`program_version` ne représente **jamais** la version de l'IDL, de la crate cliente, du SDK ou du schéma Anchor.
L'audit des IDLs archivées de bot3 démontre que ces nombres évoluent indépendamment du Program ID :
- l'IDL `jupiter_v6` porte une version d'IDL `0.1.0` alors que la génération publique du programme est `v6` ;
- l'IDL `goosefx_v2` porte une version d'IDL `0.3.0` alors que la génération publique est `v2` ;
- l'IDL GooseFX `gamma` porte une version de schéma `0.2.0` sans faire de GAMMA une hypothétique « v0.2 » du protocole ;
- l'IDL Meteora DAMM v2 peut porter une version de schéma différente de `v2`.
Une éventuelle provenance/version d'IDL appartient plus tard à la couche d'interface/decoder ou à ses métadonnées, pas à l'identité `ProgramIdEntry` de Core.
Le nom `protocol_version` n'est pas retenu : un même protocole peut posséder simultanément plusieurs composants/lignées versionnés indépendamment (par exemple un aggregator, un limit-order program, un vault ou un lending program). `program_version` borne correctement la version à l'entrée/lignée concernée.
### Recherches et vues
Direction de l'API :
```text
ProgramIdEntry
ProgramIdFilter
entries()
program_ids(filter)
native_program_ids()
find_program_id()
```
Le filtre générique doit pouvoir combiner les axes, au minimum :
```text
domain
family
protocol
subfamily
program_version
kind
```
Des helpers lisibles peuvent être exposés lorsque leur usage est réel :
```text
program_ids_by_domain(...)
program_ids_by_family(...)
program_ids_by_protocol(...)
native_program_ids()
```
Une future surface possédant des Program IDs AMM pourra ajouter :
```text
amm_program_ids()
```
Cette fonction devra être une vue de la classification canonique (`family = amm`) et non un second registre manuel. `0.1.1` ne crée pas un helper AMM vide puisque les Program IDs AMM restent hors scope de la release, mais son ajout futur ne doit nécessiter aucune refonte de `ProgramIdEntry`.
Les vues filtrées peuvent retourner un iterator/view au lieu d'un `&'static [ProgramIdEntry]` si cela évite de dupliquer des tableaux statiques. Le contrat exact de retour est décidé en `pre.003` en privilégiant une API stable et sans allocation inutile.
`registered_program_ids()` de bot3 reste considéré comme un alias redondant de `entries()` et n'est pas repris automatiquement. Les well-known accounts suivent un registre/naming distinct lorsqu'ils deviennent nécessaires.
### Invariants du registre
`ProgramIdEntry` doit permettre :
- recherche exacte par chaîne Base58 et, si utile, par `Pubkey` ;
- recherche par domaine ;
- recherche par famille ;
- recherche par protocole ;
- recherche par sous-famille lorsqu'elle existe ;
- recherche par génération de programme lorsqu'elle existe ;
- intersections de plusieurs critères sans créer un registre secondaire par combinaison ;
- production des vues spécialisées telles que `native_program_ids()` et, plus tard, `amm_program_ids()` ;
- unicité des codes et Program IDs canoniques.
La classification est descriptive. Elle ne porte aucun decoder, executor, IDL ou capability de dispatch et ne devient pas le registry fonctionnel de `ksp-program-lib`.
### Validation externe de la taxonomie pendant `pre.001-fix.002`
Le réaudit a confronté l'inventaire bot3 et ses IDLs à plusieurs sources externes actuelles :
- la source officielle Agave de chargement SPL distingue explicitement les Memo `1.0.0`, `3.0.0` et `4.0.0` avec trois Program IDs distincts ;
- l'interface SPL Memo actuelle expose séparément les modules `v1`, `v3` et `v4` ;
- Solana Explorer/Solscan exposent encore les Program IDs correspondants ;
- les sources GooseFX distinguent le programme GAMMA et la lignée SSL/V2 ;
- les sources Meteora distinguent DAMM v1, DAMM v2 et DLMM ;
- les sources Jupiter distinguent les générations de son Swap Aggregator, notamment v4 et v6.
Ces cas valident la séparation `family` / `subfamily` / `program_version` et invalident l'utilisation de `subfamily` comme simple conteneur de version.
## Primitives communes supplémentaires
@@ -399,7 +530,9 @@ Tests d'intégration pour vérifier :
- type exact des constantes `PRGID_*` et `PRGIDPK_*` ;
- égalité entre chaque chaîne Base58 possédée par KSP et sa représentation `Pubkey` compile-time ;
- unicité des codes, chaînes Base58 et `Pubkey` du registre ;
- cohérence de `entries()`, `native_program_ids()` et `find_program_id()` ;
- cohérence de `entries()`, `program_ids(...)`, `native_program_ids()` et `find_program_id()` ;
- filtres par `domain`, `family`, `protocol`, `subfamily`, `program_version` et `kind`, y compris leurs intersections ;
- absence de duplication des entrées entre registre canonique et vues spécialisées ;
- séparation entre Program IDs et well-known accounts ;
- conformité des valeurs avec les sources officielles Anza/Solana consultées par l'audit, sans dépendance `solana-sdk-ids`.
@@ -469,8 +602,10 @@ Objectifs :
- réexporter `Pubkey` ;
- implémenter `declare_program_id!` et la paire `PRGID_*` / `PRGIDPK_*` ;
- finaliser l'inventaire des Program IDs fondamentaux à partir des sources officielles actuelles ;
- implémenter `ProgramIdEntry`, `entries()`, `native_program_ids()` et `find_program_id()` ;
- ajouter les tests de conformité et d'unicité ;
- implémenter `ProgramIdEntry`, `ProgramIdFilter`, `entries()`, `program_ids(...)`, `native_program_ids()` et `find_program_id()` ;
- implémenter la taxonomie extensible `domain` / `family` / `protocol` / `subfamily` / `program_version` / `kind` sans enum centrale fermée des protocoles ;
- garantir que les futurs helpers spécialisés comme `amm_program_ids()` puissent être des vues du registre canonique sans duplication ;
- ajouter les tests de conformité, d'unicité et de filtrage ;
- confirmer l'absence totale de dépendance `solana-sdk-ids` ;
- auditer le graphe/features réels.