Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3de0488cab | |||
| 2460162243 | |||
| 1b9104d64b | |||
| 80be36bfdd | |||
| e8d2382ac3 | |||
| 749e53edc2 | |||
| 7377a6f6cd | |||
| 45601ce386 | |||
| 7d490eb5d8 | |||
| ca018095bf | |||
| 0dd722ffca | |||
| 75e8030b07 | |||
| c24e4c48f8 |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,8 +1,20 @@
|
||||
<!-- file: CHANGELOG.md -->
|
||||
<!-- version: 23 -->
|
||||
<!-- version: 25 -->
|
||||
|
||||
# Changelog KSP
|
||||
|
||||
## 0.3.5 — Interface acquisition events partagés — 2026-08-31
|
||||
|
||||
`0.3.5` étend `ksp-interface-lib` avec deux familles passives d'acquisition réellement partagées, sans transformer Interface en runtime, en event bus ou en seconde couche RAW. `SlotLifecycleEvent` expose un `slot` et un `SlotLifecycleStage` non exhaustif limité à `Processed`, `FirstShredReceived`, `Completed`, `CreatedBank`, `Dead`, `OptimisticallyConfirmed` et `Rooted`. La normalisation conserve la sémantique commune : les notifications Solana `optimisticConfirmation` et Yellowstone `Confirmed` convergent vers `OptimisticallyConfirmed`, tandis que Solana `root` et Yellowstone `Finalized` convergent vers `Rooted`; les différences d'ordre, de complétude, de replay et de transport restent la responsabilité du producteur/Transport.
|
||||
|
||||
La seconde famille matérialise le fait minimal d'exécution transactionnelle partagé par plusieurs sources. `TransactionSignature` possède exactement 64 octets et un `Debug` redacted, `TransactionExecutionOutcome` distingue seulement `Succeeded` et `Failed`, et `TransactionExecutionEvent` transporte uniquement `slot + signature + outcome`. Les logs, erreurs provider détaillées, commitments, indexes, timestamps, filtres et payloads complets restent Transport-owned. Les snapshots HTTP `getSignatureStatuses`, les transitions one-shot `signatureSubscribe`, un éventuel `TransactionLogEvent`, les votes et les entrées Yellowstone ne sont pas fusionnés artificiellement dans ce contrat.
|
||||
|
||||
La frontière d'ownership reste stricte : les DTOs wire/provider demeurent dans `ksp-onchain-transport-lib`, les événements passifs provider-neutral sont Interface-owned, et les modèles persistants/replayables `RawTransaction` / `RawAccountState` restent `ksp-store-api`. `ksp-interface-lib` conserve exactement `ksp-core-lib` comme seule dépendance normale, sans feature propre, dev/build dependency, serde, codec, logging ou runtime. Les canaris publics, external consumer, inventaires exacts et hardening vérifient également qu'aucun second RAW, metadata source ou payload hostile n'entre dans la surface Interface.
|
||||
|
||||
Les gates de clôture passent audits Rust/Markdown, `cargo check --workspace`, Clippy all-targets, tests ciblés Interface/Program API, `cargo test --workspace` et graphes Cargo. `cargo tree -p ksp-interface-lib --edges normal` confirme le chemin `ksp-interface-lib -> ksp-core-lib -> solana-pubkey -> solana-address`; le graphe features ne montre aucune feature propre Interface et les doublons éventuels restent ceux du workspace global. La documentation durable a été réconciliée et `TransactionLogEvent` est conservé comme idée différée soumise à un nouveau gate consumer/bornes.
|
||||
|
||||
`prompts/025-V0_3_6_START_PROMPT.md` ouvre `0.3.6` sur le développement parallèle de `ksp-job-api` et `ksp-job-backfill-lib`. La release doit reprendre fonctionnellement le backfill historique kbot3 sans en copier le code : audit obligatoire de l'archive historique, `RawTransaction` par adresse via `getSignaturesForAddress` + `getTransaction`, directions/anchors et déduplication, hydratation/persistence via les façades KSP, frontier/checkpoint/reprise, cancellation/concurrency bornées, idempotence et distinctions missing/conflit. `ksp-job-api` doit en parallèle stabiliser lifecycle/progress/outcome et un contrat de notifications/listeners borné pour qu'une couche supérieure puisse visualiser l'état sans parser les logs. Le ROADMAP enchaîne ensuite l'app de backfill/inspection `0.3.7`, `ksp-worker-api` `0.3.8`, `ksp-worker-live-transactions-retriever-lib` `0.3.9` puis une application de monitoring/visualisation Jobs + Workers `0.3.10`, avec reprise du même pattern d'observabilité côté Worker sans fusionner les sémantiques Job/Worker/Store.
|
||||
|
||||
## 0.3.4 — Store/PostgreSQL RawAccountState + complétude RAW — 2026-08-31
|
||||
|
||||
`0.3.4` complète la seconde vertical slice RAW physique sur le couple `ksp-store-lib` / `ksp-store-postgres-lib` et ferme la conformance PostgreSQL des **10 capabilities** backend-agnostic de `ksp-store-api` : les six capabilities `RawTransaction*` acquises en `0.3.3` restent intactes et les quatre capabilities `RawAccountStateRead`, `RawAccountStateWrite`, `RawAccountObservationRead` et `RawAccountObservationWrite` sont désormais implémentées par `PostgresBackend` puis dispatchées par la façade `Store`. La séparation reste stricte : les consommateurs ordinaires passent par `ksp-store-lib`, le backend PostgreSQL conserve SQL/driver/pool/TLS/migrations privés, et la façade reste compilable/testable sans backend via `--no-default-features`.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
# file: Cargo.toml
|
||||
# version: 382
|
||||
# version: 392
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"
|
||||
|
||||
19
ROADMAP.md
19
ROADMAP.md
@@ -1,5 +1,5 @@
|
||||
<!-- file: ROADMAP.md -->
|
||||
<!-- version: 98 -->
|
||||
<!-- version: 100 -->
|
||||
|
||||
# Roadmap KSP
|
||||
|
||||
@@ -97,18 +97,21 @@ RAW -> STRUCTURAL -> DECODED -> DOMAIN
|
||||
- [X] `0.3.2` — `ksp-store-lib` + `ksp-store-postgres-lib` stables comme fondation runtime/backend PostgreSQL : feature `postgres` par défaut, `Store` lié à un unique `RawNetworkId`, Config `std.store` avec targets/bases `devnet`/`mainnet`/`testnet`, pool Deadpool borné, `tokio-postgres`, TLS Rustls `Disabled`/`VerifyFull`, moteur de migrations privé `V000` + SHA-256/advisory lock, health/readiness portable et close borné. Gate complet + PostgreSQL réel major 17 verts ; aucune table/capability `RawTransaction`/`RawAccountState` métier n'est encore ajoutée.
|
||||
- [X] `0.3.3` — Vertical slice PostgreSQL `RawTransaction` complète sur `ksp-store-lib` + `ksp-store-postgres-lib` : six capabilities transaction/observation/rétention, V001 physique liée à un réseau, acquisition canonical+observation atomique, idempotence/conflit, get/list keyset cursorisé, archive/purge/tombstone/ForceRehydrate, hardening des erreurs et du schéma, concurrence et rollback validés sur PostgreSQL 17.
|
||||
- [X] `0.3.4` — Vertical slice PostgreSQL `RawAccountState` complète sur `ksp-store-lib` + `ksp-store-postgres-lib` : quatre capabilities account ajoutées aux six transaction pour une conformance RAW 10/10, V002 additive de 32 ressources au-dessus de V000/V001 immuables, state+observation atomiques, idempotence/conflit exacts, metadata Yellowstone observation-only, get/list keyset `(slot,pubkey,state_hash)` avec cursor KSPA anti-replay, hardening cross-family et live validé sur PostgreSQL 17 sans rétention destructive account.
|
||||
- [ ] `0.3.5` — Étendre `ksp-interface-lib` uniquement avec les modèles passifs/event-only dont une matrice des surfaces HTTP/WS/Yellowstone/Helius démontre la sémantique réellement partagée et le besoin consumer ; auditer notamment logs, slot/root/slotsUpdates, transaction status et vote, sans dupliquer `RawTransaction`/`RawAccountState`, sans event bus et sans dépendance Interface vers Transport/Store.
|
||||
- [ ] `0.3.6` — Introduire `ksp-job-api` et un premier job de backfill historique concret consommant `ksp-store-lib`, avec policy/batch-size/progression possédés par le job et non par Store.
|
||||
- [ ] `0.3.7` — Introduire une application spécialisée de backfill/inspection RAW.
|
||||
- [ ] Compléter ensuite la couche RAW avec le worker/service live, son contrôle et les outils d’exploitation réellement nécessaires avant de passer à la couche de normalisation générique suivante.
|
||||
- [X] `0.3.5` — `ksp-interface-lib` étendu avec deux familles passives réellement partagées : `SlotLifecycleEvent` (`Processed`, `FirstShredReceived`, `Completed`, `CreatedBank`, `Dead`, `OptimisticallyConfirmed`, `Rooted`) et `TransactionExecutionEvent` (`slot + TransactionSignature[64] + Succeeded/Failed`). Interface reste Core-only, provider-neutral, sans serde/codec/runtime/event bus et sans duplication de `RawTransaction`/`RawAccountState`; les DTOs riches restent Transport-owned et les candidats non convergents restent différés.
|
||||
- [ ] `0.3.6` — Introduire en parallèle `ksp-job-api` et `ksp-job-backfill-lib` : reprendre fonctionnellement le backfill historique kbot3 sur les abstractions KSP actuelles (`ksp-onchain-transport-lib` + `ksp-store-lib`), fermer une première verticale `RawTransaction` historique par adresse avec directions/anchors, déduplication, hydratation, idempotence, frontier/checkpoint/reprise, cancellation et concurrency bornées, et stabiliser un lifecycle/progress/outcome avec notifications/listeners sûrs pour les couches supérieures.
|
||||
- [ ] `0.3.7` — Introduire une application spécialisée de backfill/inspection RAW consommant `ksp-job-api` : lancement/annulation contrôlés, état et progression live, compteurs, checkpoint/frontière, outcome terminal et inspection RAW sans parser les logs ni connaître les providers/backends physiques.
|
||||
- [ ] `0.3.8` — Introduire `ksp-worker-api` comme API générique de lifecycle/health/progression pour services continus, en reprenant le pattern de notifications/listeners stabilisé par Job tout en gardant les sémantiques Worker distinctes des jobs terminables et des wake-ups Store post-commit.
|
||||
- [ ] `0.3.9` — Introduire `ksp-worker-live-transactions-retriever-lib` pour l'acquisition continue `RawTransaction` via les surfaces live de `ksp-onchain-transport-lib`, persistence par `ksp-store-lib`, reprise/backpressure/idempotence et notifications `ksp-worker-api`, sans decode Program ni dépendance backend/provider directe.
|
||||
- [ ] `0.3.10` — Introduire une application de monitoring/visualisation Jobs + Workers : vue graphique des lifecycles, health/progression, rates/backpressure/retries sûrs, checkpoints et outcomes ; l'application consomme les APIs publiques Job/Worker et ne devient ni scheduler caché ni source de vérité du backlog.
|
||||
|
||||
### TODO/IDEAS — taxonomie N1, processing et rétention
|
||||
|
||||
- [ ] **TODO** — maintenir la matrice d’admission HTTP/WS/gRPC/provider lors de toute nouvelle famille N1 : plusieurs sources ne convergent vers un même struct que si elles satisfont la même sémantique sans perte.
|
||||
- [X] `RawAccountState` + observation — contrat commun stabilisé en `0.3.1` avec bytes complets + slot, provenance séparée et enrichissements source-specific optionnels ; la persistence PostgreSQL physique est complétée en `0.3.4` avec les quatre capabilities account et la conformance RAW 10/10.
|
||||
- [ ] **TODO** — `TransactionStatusObservation` : réauditer `signatureSubscribe`, `getSignatureStatuses`, Yellowstone TransactionStatus et extensions provider lorsqu’un consumer réel apparaît ; ne pas fusionner snapshot, transition et update dans un modèle Option-soup.
|
||||
- [ ] **TODO** — logs realtime : conserver `logMessages` dans `RawTransaction` jusqu’à la décomposition STRUCTURAL ; traiter `logsSubscribe` comme event-only candidat et décider son contrat passif dans `ksp-interface-lib`, sans table Store par défaut. Le format canonique d’un wake-up « donnée persistée disponible » reste distinct et appartient à `ksp-store-api` conformément à `KSP-NOTIFY-*`, mais ne sera matérialisé qu’avec un publisher/consumer réel.
|
||||
- [ ] **TODO** — slot/root/slotsUpdates et vote : ne créer un modèle passif commun que si un consumer realtime réel et une sémantique cross-ledger/provider justifient le contrat ; aucune persistence Store par défaut.
|
||||
- [ ] **TODO** — statut/commitment transactionnel restant : `0.3.5` couvre uniquement le fait passif d’exécution `slot + signature + outcome`; réauditer séparément `signatureSubscribe` et `getSignatureStatuses` lorsqu’un consumer de commitment/snapshot réel apparaît, sans fusionner snapshot, transition et execution update dans un modèle Option-soup.
|
||||
- [ ] **IDEA** — logs realtime enrichis : `logsSubscribe` alimente déjà la projection minimale `TransactionExecutionEvent`, mais un éventuel `TransactionLogEvent` portant les lignes de log reste différé dans `docs/IDEAS.md` jusqu’à démonstration d’un consumer et de bornes explicites. `logMessages` reste dans `RawTransaction` jusqu’à STRUCTURAL ; le wake-up post-commit reste distinct et Store API-owned conformément à `KSP-NOTIFY-*`.
|
||||
- [X] slot/root/slotsUpdates — `0.3.5` stabilise `SlotLifecycleEvent` pour l’intersection réellement partagée, sans persistence Store par défaut et sans promettre l’ordre/complétude du flux.
|
||||
- [ ] **TODO** — vote realtime : reste hors Interface tant qu’aucun consumer transversal et aucune sémantique provider-neutral suffisamment précise ne justifient un contrat partagé.
|
||||
- [ ] **IDEA** — `RawBlock` : ne rouvrir que si une information block-level non reconstructible devient nécessaire ; `getBlock` doit d’abord être traité comme source de `RawTransaction`, pas comme invitation à recopier le ledger en blocs.
|
||||
- [ ] **REJET ACTUEL** — Yellowstone `Entry` : trop bas niveau et aucune destination replay/decomposition/event métier justifiant un modèle KSP n’est identifiée.
|
||||
- [ ] **TODO** — processing ledger : reprendre l’idée kbot2/kbot3 `stage + processor identity/version + input identity/hash + terminal status`, sans faire d’un `processed: bool` la preuve durable unique ; prévoir force replay/version upgrades lorsque les processors seront ouverts.
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<!-- file: crates/ksp-interface-lib/README.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# ksp-interface-lib
|
||||
|
||||
`ksp-interface-lib` est la façade wire officielle KSP destinée aux contrats passifs partagés par les implémentations Program Solana officielles ou externes. La crate expose uniquement des structures de représentation/admission ; elle ne possède ni transport, ni exécution, ni persistence, ni comportement métier Program.
|
||||
`ksp-interface-lib` possède les contrats passifs KSP qui doivent être partagés entre plusieurs composants sans imposer leur runtime d'origine. Sa surface couvre actuellement deux familles distinctes : les contrats wire Program génériques et un petit ensemble de faits d'acquisition provider-neutral dont la sémantique commune a été démontrée.
|
||||
|
||||
La crate reste une façade de représentation. Elle ne possède ni transport réseau, ni event bus, ni worker/job, ni persistence, ni exécution, ni comportement métier Program.
|
||||
|
||||
## Ownership
|
||||
|
||||
@@ -15,9 +17,9 @@ Error / ErrorCode / Result
|
||||
Program IDs fondamentaux
|
||||
```
|
||||
|
||||
`Pubkey` est réexporté depuis le crate-root Interface afin qu'un consumer wire n'introduise aucun wrapper d'identité parallèle. Les Program IDs restent possédés et répertoriés par Core.
|
||||
`Pubkey` est réexporté depuis le crate-root Interface afin qu'un consumer n'introduise aucun wrapper d'identité parallèle. Les Program IDs restent possédés et répertoriés par Core.
|
||||
|
||||
La dependency direction candidate `0.2.13` reste strictement :
|
||||
Le graphe normal reste strictement :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
@@ -25,9 +27,11 @@ ksp-interface-lib
|
||||
└── solana-pubkey
|
||||
```
|
||||
|
||||
## Surface publique `0.2.13`
|
||||
La crate ne possède aucune feature Cargo, aucune `dev-dependency` et aucune `build-dependency` runtime propre.
|
||||
|
||||
La façade crate-root expose exactement :
|
||||
## Surface publique
|
||||
|
||||
La façade crate-root expose :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
@@ -36,10 +40,17 @@ MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
SlotLifecycleStage
|
||||
SlotLifecycleEvent
|
||||
TransactionSignature
|
||||
TransactionExecutionOutcome
|
||||
TransactionExecutionEvent
|
||||
```
|
||||
|
||||
Aucun module interne n'est public.
|
||||
|
||||
## Contrats Program passifs
|
||||
|
||||
### `ProgramAccountMeta`
|
||||
|
||||
`ProgramAccountMeta` représente un compte ordonné d'une instruction avec :
|
||||
@@ -68,16 +79,14 @@ data: Vec<u8>
|
||||
|
||||
Les cas vides sont valides et une `program_id` inconnue du registry KSP reste admissible.
|
||||
|
||||
## Bornes d'admission
|
||||
|
||||
Interface applique deux limites locales :
|
||||
### Bornes d'admission
|
||||
|
||||
| Limite | Valeur |
|
||||
|------------------------------------|----------|
|
||||
| `MAX_PROGRAM_INSTRUCTION_ACCOUNTS` | `255` |
|
||||
| `MAX_PROGRAM_INSTRUCTION_DATA_LEN` | `10_240` |
|
||||
|
||||
Ces valeurs sont des **bornes d'admission Interface**. Elles ne constituent pas une garantie qu'une instruction donnée tient dans toutes les contraintes d'une transaction Solana top-level. La limite CPI de comptes uniques n'est notamment pas transformée en règle artificielle sur la liste d'account metas.
|
||||
Ces valeurs sont des **bornes d'admission Interface**. Elles ne constituent pas une garantie qu'une instruction donnée respecte à elle seule toutes les contraintes d'une transaction Solana complète.
|
||||
|
||||
Un dépassement utilise le code commun :
|
||||
|
||||
@@ -89,21 +98,74 @@ Le contexte d'erreur est limité aux métadonnées sûres `field`, `actual_len`
|
||||
|
||||
Le `Debug` de `ProgramInstruction` est volontairement borné : il affiche `program_id`, `account_count` et `data_len`, jamais les accounts complets ni les octets du payload.
|
||||
|
||||
## Faits passifs d'acquisition
|
||||
|
||||
Les événements Interface sont des **projections provider-neutral supplémentaires**. Ils ne remplacent jamais les DTOs riches de `ksp-onchain-transport-lib` et ne deviennent jamais la source de vérité durable d'un backlog.
|
||||
|
||||
La conversion depuis un DTO HTTP/WS/gRPC/provider appartient à la composition ou au consumer qui connaît les deux contrats. `ksp-interface-lib` ne dépend donc pas de Transport.
|
||||
|
||||
### `SlotLifecycleEvent`
|
||||
|
||||
`SlotLifecycleEvent` conserve exactement :
|
||||
|
||||
```text
|
||||
slot: u64
|
||||
stage: SlotLifecycleStage
|
||||
```
|
||||
|
||||
Les stages actuellement représentés sont :
|
||||
|
||||
```text
|
||||
Processed
|
||||
FirstShredReceived
|
||||
Completed
|
||||
CreatedBank
|
||||
Dead
|
||||
OptimisticallyConfirmed
|
||||
Rooted
|
||||
```
|
||||
|
||||
`SlotLifecycleStage` est `#[non_exhaustive]` afin qu'un consumer externe traite explicitement l'évolution future de l'enum.
|
||||
|
||||
Parent, timestamp, diagnostics de slot mort, source/provider, filter/session metadata et autres détails Transport ne sont pas copiés dans ce contrat minimal.
|
||||
|
||||
### `TransactionExecutionEvent`
|
||||
|
||||
`TransactionExecutionEvent` conserve exactement :
|
||||
|
||||
```text
|
||||
slot: u64
|
||||
signature: TransactionSignature
|
||||
outcome: TransactionExecutionOutcome
|
||||
```
|
||||
|
||||
`TransactionSignature` contient exactement les 64 bytes canoniques déjà décodés d'une signature Solana. Son `Debug` ne rend pas les bytes.
|
||||
|
||||
`TransactionExecutionOutcome` distingue uniquement :
|
||||
|
||||
```text
|
||||
Succeeded
|
||||
Failed
|
||||
```
|
||||
|
||||
L'enum est `#[non_exhaustive]`. Le contrat ne contient aucun log, payload RAW, erreur provider, commitment, provenance, network id, source metadata ni détail d'exécution arbitraire. Une source ambiguë ou insuffisante doit rester dans son owner Transport au lieu de forcer un événement Interface.
|
||||
|
||||
## Codecs et runtime
|
||||
|
||||
La foundation `0.2.13` n'ajoute aucun codec par réflexe :
|
||||
La crate n'ajoute aucun codec ou runtime par réflexe :
|
||||
|
||||
```text
|
||||
serde / serde_json absents
|
||||
borsh absent
|
||||
wincode absent
|
||||
bincode absent
|
||||
solana-instruction absent
|
||||
borsh absent tant qu'aucun wire réel ne le requiert
|
||||
wincode absent tant qu'aucun wire réel ne le requiert
|
||||
bincode interdit pour les codecs wire KSP
|
||||
transport/runtime réseau absent
|
||||
logging runtime absent
|
||||
```
|
||||
|
||||
Des codecs/layouts/discriminants spécifiques pourront être ajoutés ultérieurement uniquement lorsqu'un vertical Program réel en démontre le besoin et que leur ownership wire appartient bien à Interface.
|
||||
Des codecs/layouts/discriminants spécifiques peuvent être ajoutés uniquement lorsqu'un protocole réel en démontre le besoin et que leur ownership wire appartient bien à Interface.
|
||||
|
||||
La crate ne produit aucun événement runtime. Elle ne dépend donc pas de `ksp-logging-lib` et ne possède ni `constants.rs` ni `TRACING_TARGET`. Si un futur comportement Interface exige réellement du logging, le runtime devra passer par la façade Logging KSP plutôt que par une dépendance directe à Tracing.
|
||||
Les événements passifs ne constituent pas un comportement runtime. La crate ne dépend donc pas de `ksp-logging-lib` et ne possède ni `constants.rs` ni `TRACING_TARGET`.
|
||||
|
||||
## Frontières
|
||||
|
||||
@@ -112,20 +174,20 @@ La crate ne produit aucun événement runtime. Elle ne dépend donc pas de `ksp-
|
||||
```text
|
||||
RPC / WebSocket / gRPC
|
||||
provider DTOs Transport
|
||||
wallet / signature
|
||||
sessions / reconnect / backpressure
|
||||
Config / environnement
|
||||
persistence / Store
|
||||
persistence / Store / cursor / retention
|
||||
notifications post-commit Store
|
||||
worker / job / scheduler / event bus
|
||||
Program decoding / recognition / proofs
|
||||
execution policy / signers
|
||||
transaction replay / CPI path / runtime logs
|
||||
lifecycle réseau
|
||||
RawTransaction / RawAccountState
|
||||
```
|
||||
|
||||
La foundation Program API est reportée à `0.2.14`. Les wires génériques d'acquisition/CORE restent reportés à `0.3.2+`.
|
||||
Les données persistantes/replayables restent dans `ksp-store-api`. Les notifications post-commit de données persistées restent un contrat Store API lorsqu'un publisher/consumer réel les justifie. Les faits réseau riches restent Transport-owned.
|
||||
|
||||
## Références
|
||||
|
||||
- [Usage public](USAGE.md)
|
||||
- [Plan `0.2.13`](../../docs/plans/020-V0_2_13_INTERFACE_PLAN.md)
|
||||
- [Validation `0.2.13`](../../docs/validation/016-V0_2_13_INTERFACE.md)
|
||||
- [Architecture Wire + Program](../../docs/architecture/006-WIRE_AND_PROGRAM.md)
|
||||
- [Architecture Acquisition/Workers/Jobs](../../docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md)
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!-- file: crates/ksp-interface-lib/USAGE.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Usage de ksp-interface-lib
|
||||
|
||||
Cette page décrit la façade publique matérialisée par `0.2.13`. Les modules internes ne font pas partie du contrat consommable : utiliser uniquement les exports du crate-root.
|
||||
Cette page décrit l'utilisation durable de la façade publique. Les modules internes ne font pas partie du contrat consommable : utiliser uniquement les exports du crate-root.
|
||||
|
||||
## Construire des account metas
|
||||
|
||||
@@ -52,9 +52,9 @@ match result {
|
||||
|
||||
L'ordre et les doublons des accounts sont conservés. Les octets `data` restent opaques : `ProgramInstruction` ne les sérialise, désérialise ni interprète.
|
||||
|
||||
Les `Vec` fournis à `try_new` sont consommés par la structure après validation des bornes ; aucun clone ou reformatage interne n'est requis par le contrat actuel.
|
||||
Les `Vec` fournis à `try_new` sont consommés par la structure après validation des bornes ; aucun clone ou reformatage interne n'est requis par le contrat.
|
||||
|
||||
## Bornes
|
||||
## Respecter les bornes Program
|
||||
|
||||
Les limites publiques sont :
|
||||
|
||||
@@ -63,9 +63,9 @@ assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
```
|
||||
|
||||
`255` account metas et `10_240` bytes de data sont admis. `256` account metas ou `10_241` bytes sont refusés par `try_new` avant création d'un `ProgramInstruction` valide.
|
||||
`255` account metas et `10_240` bytes de data sont admis. `256` account metas ou `10_241` bytes sont refusés par `ProgramInstruction::try_new`.
|
||||
|
||||
Ces limites sont des bornes locales Interface et ne promettent pas qu'une instruction admise respecte à elle seule toutes les contraintes de taille/account-set d'une transaction Solana complète.
|
||||
Ces limites sont locales à Interface et ne promettent pas qu'une instruction admise respecte à elle seule toutes les contraintes d'une transaction Solana complète.
|
||||
|
||||
## Observer une erreur de limite
|
||||
|
||||
@@ -92,31 +92,108 @@ maximum_len
|
||||
|
||||
Le contenu du payload et les account metas arbitraires ne sont pas projetés dans le diagnostic.
|
||||
|
||||
## Debug borné
|
||||
## Construire un événement de lifecycle de slot
|
||||
|
||||
Le `Debug` de `ProgramInstruction` contient uniquement :
|
||||
Un producer/composer qui a déjà établi la correspondance sémantique avec son DTO Transport peut construire le fait passif partagé :
|
||||
|
||||
```text
|
||||
program_id
|
||||
account_count
|
||||
data_len
|
||||
```rust
|
||||
let event = ksp_interface_lib::SlotLifecycleEvent::new(
|
||||
42,
|
||||
ksp_interface_lib::SlotLifecycleStage::Processed,
|
||||
);
|
||||
|
||||
assert_eq!(event.slot(), 42);
|
||||
assert_eq!(event.stage(), ksp_interface_lib::SlotLifecycleStage::Processed);
|
||||
```
|
||||
|
||||
Il ne faut donc pas attendre de ce rendu une sérialisation wire ou un dump du payload.
|
||||
Les stages actuellement disponibles sont :
|
||||
|
||||
```text
|
||||
Processed
|
||||
FirstShredReceived
|
||||
Completed
|
||||
CreatedBank
|
||||
Dead
|
||||
OptimisticallyConfirmed
|
||||
Rooted
|
||||
```
|
||||
|
||||
Un consumer externe doit traiter `SlotLifecycleStage` comme une enum évolutive `#[non_exhaustive]` et prévoir un fallback dans ses `match`.
|
||||
|
||||
Le type ne contient volontairement ni timestamp, ni parent, ni diagnostic, ni source/provider, ni identifiant de subscription.
|
||||
|
||||
## Construire un événement d'exécution de transaction
|
||||
|
||||
Une signature doit d'abord être disponible sous sa forme canonique de 64 bytes :
|
||||
|
||||
```rust
|
||||
let signature = ksp_interface_lib::TransactionSignature::new([7_u8; 64]);
|
||||
|
||||
let event = ksp_interface_lib::TransactionExecutionEvent::new(
|
||||
123,
|
||||
signature,
|
||||
ksp_interface_lib::TransactionExecutionOutcome::Succeeded,
|
||||
);
|
||||
|
||||
assert_eq!(event.slot(), 123);
|
||||
assert_eq!(event.signature().as_bytes(), &[7_u8; 64]);
|
||||
assert_eq!(
|
||||
event.outcome(),
|
||||
ksp_interface_lib::TransactionExecutionOutcome::Succeeded,
|
||||
);
|
||||
```
|
||||
|
||||
`TransactionExecutionOutcome` distingue uniquement `Succeeded` et `Failed` et reste `#[non_exhaustive]`.
|
||||
|
||||
Le `Debug` de `TransactionSignature` et de `TransactionExecutionEvent` n'affiche pas les bytes de signature.
|
||||
|
||||
## Convertir depuis Transport
|
||||
|
||||
Ne pas ajouter `ksp-onchain-transport-lib` comme dépendance de `ksp-interface-lib` pour fournir des `From<TransportDto>`.
|
||||
|
||||
La conversion appartient au composant qui connaît les deux côtés :
|
||||
|
||||
```text
|
||||
Transport DTO riche
|
||||
|
|
||||
| conversion explicite dans composition/consumer
|
||||
v
|
||||
Interface event passif minimal
|
||||
```
|
||||
|
||||
Ne construire un événement Interface que si la source fournit suffisamment d'information pour le fait commun exact. Si l'état est ambigu, conserver le DTO dans son owner Transport ou déclencher une hydratation adaptée ; ne pas inventer de valeur par défaut.
|
||||
|
||||
## Ne pas utiliser les événements comme stockage durable
|
||||
|
||||
`SlotLifecycleEvent` et `TransactionExecutionEvent` sont des faits passifs, pas des modèles RAW replayables.
|
||||
|
||||
Ils ne remplacent pas :
|
||||
|
||||
```text
|
||||
RawTransaction
|
||||
RawTransactionObservation
|
||||
RawAccountState
|
||||
RawAccountObservation
|
||||
Store backlog / cursor / retention
|
||||
```
|
||||
|
||||
Les consumers qui ont besoin de reprise après crash ou de replay doivent s'appuyer sur `ksp-store-lib`/`ksp-store-api` selon leur responsabilité, pas sur un event Interface en mémoire.
|
||||
|
||||
## Dépendances à ne pas ajouter côté consumer
|
||||
|
||||
Un consumer de la façade Interface n'a pas besoin d'ajouter un SDK Program Solana uniquement pour reconstruire `ProgramInstruction`. La crate utilise le `Pubkey` canonique partagé avec Core et conserve son propre contrat passif.
|
||||
Un consumer de la façade Interface n'a pas besoin d'ajouter un SDK Program Solana uniquement pour reconstruire `ProgramInstruction`, ni un runtime Transport pour manipuler les événements passifs déjà normalisés.
|
||||
|
||||
La foundation ne fournit volontairement pas :
|
||||
La crate ne fournit volontairement pas :
|
||||
|
||||
```text
|
||||
serde générique
|
||||
Borsh / Wincode générique
|
||||
solana-instruction interop automatique
|
||||
transport réseau
|
||||
converters provider automatiques
|
||||
Program decoder/preparer
|
||||
signing/execution
|
||||
persistence/event bus
|
||||
```
|
||||
|
||||
Ces surfaces doivent être introduites dans leur owner respectif lorsqu'un cas réel le justifie, pas comme dépendances implicites d'un consumer Interface.
|
||||
Ces surfaces doivent être introduites dans leur owner respectif lorsqu'un cas réel le justifie.
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
// file: crates/ksp-interface-lib/src/lib.rs
|
||||
// version: 3
|
||||
// version: 5
|
||||
|
||||
#![warn(missing_docs)]
|
||||
#![deny(unreachable_pub)]
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
//! Passive wire contracts shared by KSP Program implementations.
|
||||
//! Passive contracts shared across KSP component boundaries.
|
||||
//!
|
||||
//! The foundation reuses the canonical Solana [`Pubkey`] owned by
|
||||
//! `ksp-core-lib` and exposes only bounded, passive Program-facing structures.
|
||||
//! Runtime, transport, persistence and Program behavior remain outside this
|
||||
//! crate.
|
||||
//! The crate reuses canonical Solana primitives owned by `ksp-core-lib` and
|
||||
//! exposes only bounded, passive Program-facing and provider-neutral
|
||||
//! acquisition structures. Runtime, transport, persistence and Program
|
||||
//! behavior remain outside this crate.
|
||||
|
||||
mod error;
|
||||
mod program_account_meta;
|
||||
mod program_instruction;
|
||||
mod slot_lifecycle;
|
||||
mod transaction_execution;
|
||||
|
||||
/// Error code used when an Interface-owned Program instruction admission limit is exceeded.
|
||||
pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;
|
||||
@@ -26,5 +28,15 @@ pub use self::program_account_meta::ProgramAccountMeta;
|
||||
pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;
|
||||
/// Passive, bounded Program instruction wire contract.
|
||||
pub use self::program_instruction::ProgramInstruction;
|
||||
/// Passive provider-neutral occurrence of one slot lifecycle stage.
|
||||
pub use self::slot_lifecycle::SlotLifecycleEvent;
|
||||
/// Provider-neutral stage in the lifecycle of an observed Solana slot.
|
||||
pub use self::slot_lifecycle::SlotLifecycleStage;
|
||||
/// Passive provider-neutral observation of one transaction execution result.
|
||||
pub use self::transaction_execution::TransactionExecutionEvent;
|
||||
/// Provider-neutral outcome of one observed transaction execution.
|
||||
pub use self::transaction_execution::TransactionExecutionOutcome;
|
||||
/// Canonical 64-byte Solana transaction signature used by passive Interface events.
|
||||
pub use self::transaction_execution::TransactionSignature;
|
||||
/// Canonical Solana account address primitive owned by `ksp-core-lib`.
|
||||
pub use ksp_core_lib::Pubkey;
|
||||
|
||||
53
crates/ksp-interface-lib/src/slot_lifecycle.rs
Normal file
53
crates/ksp-interface-lib/src/slot_lifecycle.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
// file: crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||
// version: 1
|
||||
|
||||
/// Provider-neutral stage in the lifecycle of an observed Solana slot.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum SlotLifecycleStage {
|
||||
/// The slot has been processed.
|
||||
Processed,
|
||||
/// The first shred for the slot has been received.
|
||||
FirstShredReceived,
|
||||
/// Slot ingestion has completed.
|
||||
Completed,
|
||||
/// A bank has been created for the slot.
|
||||
CreatedBank,
|
||||
/// The slot has been marked dead.
|
||||
Dead,
|
||||
/// The slot has reached optimistic confirmation.
|
||||
OptimisticallyConfirmed,
|
||||
/// The slot has become rooted.
|
||||
Rooted,
|
||||
}
|
||||
|
||||
/// Passive provider-neutral occurrence of one slot lifecycle stage.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct SlotLifecycleEvent {
|
||||
slot: u64,
|
||||
stage: SlotLifecycleStage,
|
||||
}
|
||||
|
||||
impl SlotLifecycleEvent {
|
||||
/// Creates a lifecycle event for `slot` and `stage`.
|
||||
#[must_use]
|
||||
pub const fn new(slot: u64, stage: SlotLifecycleStage) -> Self {
|
||||
return Self { slot, stage };
|
||||
}
|
||||
|
||||
/// Returns the observed slot exactly as supplied.
|
||||
#[must_use]
|
||||
pub const fn slot(&self) -> u64 {
|
||||
return self.slot;
|
||||
}
|
||||
|
||||
/// Returns the provider-neutral lifecycle stage.
|
||||
#[must_use]
|
||||
pub const fn stage(&self) -> SlotLifecycleStage {
|
||||
return self.stage;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/slot_lifecycle.rs"]
|
||||
mod tests;
|
||||
85
crates/ksp-interface-lib/src/transaction_execution.rs
Normal file
85
crates/ksp-interface-lib/src/transaction_execution.rs
Normal file
@@ -0,0 +1,85 @@
|
||||
// file: crates/ksp-interface-lib/src/transaction_execution.rs
|
||||
// version: 1
|
||||
|
||||
/// Canonical 64-byte Solana transaction signature used by passive Interface events.
|
||||
#[derive(Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct TransactionSignature([u8; 64]);
|
||||
|
||||
impl TransactionSignature {
|
||||
/// Creates one transaction signature from already-decoded canonical bytes.
|
||||
#[must_use]
|
||||
pub const fn new(bytes: [u8; 64]) -> Self {
|
||||
return Self(bytes);
|
||||
}
|
||||
|
||||
/// Returns the exact canonical signature bytes.
|
||||
#[must_use]
|
||||
pub const fn as_bytes(&self) -> &[u8; 64] {
|
||||
return &self.0;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TransactionSignature {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter.write_str("TransactionSignature(..)");
|
||||
}
|
||||
}
|
||||
|
||||
/// Provider-neutral outcome of one observed transaction execution.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[non_exhaustive]
|
||||
pub enum TransactionExecutionOutcome {
|
||||
/// The observed transaction execution completed without a transaction error.
|
||||
Succeeded,
|
||||
/// The observed transaction execution completed with a transaction error.
|
||||
Failed,
|
||||
}
|
||||
|
||||
/// Passive provider-neutral observation of one transaction execution result.
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct TransactionExecutionEvent {
|
||||
slot: u64,
|
||||
signature: TransactionSignature,
|
||||
outcome: TransactionExecutionOutcome,
|
||||
}
|
||||
|
||||
impl TransactionExecutionEvent {
|
||||
/// Creates one transaction execution event from its common provider-neutral fields.
|
||||
#[must_use]
|
||||
pub const fn new(slot: u64, signature: TransactionSignature, outcome: TransactionExecutionOutcome) -> Self {
|
||||
return Self { slot, signature, outcome };
|
||||
}
|
||||
|
||||
/// Returns the containing slot exactly as observed by the producer.
|
||||
#[must_use]
|
||||
pub const fn slot(&self) -> u64 {
|
||||
return self.slot;
|
||||
}
|
||||
|
||||
/// Returns the canonical transaction signature.
|
||||
#[must_use]
|
||||
pub const fn signature(&self) -> TransactionSignature {
|
||||
return self.signature;
|
||||
}
|
||||
|
||||
/// Returns the normalized execution outcome.
|
||||
#[must_use]
|
||||
pub const fn outcome(&self) -> TransactionExecutionOutcome {
|
||||
return self.outcome;
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for TransactionExecutionEvent {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
return formatter
|
||||
.debug_struct("TransactionExecutionEvent")
|
||||
.field("slot", &self.slot)
|
||||
.field("signature", &"<omitted>")
|
||||
.field("outcome", &self.outcome)
|
||||
.finish();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/transaction_execution.rs"]
|
||||
mod tests;
|
||||
@@ -1,5 +1,5 @@
|
||||
// file: crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
// version: 5
|
||||
// version: 8
|
||||
|
||||
//! Dependency and passive-surface canaries for the Interface foundation.
|
||||
|
||||
@@ -91,6 +91,8 @@ fn pre_005_all_production_sources_preserve_the_dependency_firewall() {
|
||||
include_str!("../src/lib.rs"),
|
||||
include_str!("../src/program_account_meta.rs"),
|
||||
include_str!("../src/program_instruction.rs"),
|
||||
include_str!("../src/slot_lifecycle.rs"),
|
||||
include_str!("../src/transaction_execution.rs"),
|
||||
];
|
||||
for source in production_sources {
|
||||
for forbidden in [
|
||||
@@ -129,3 +131,52 @@ fn pre_005_instruction_source_has_no_narrowing_cast_or_hidden_codec_entry_point(
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_004_acquisition_sources_remain_provider_neutral_and_runtime_free() {
|
||||
let acquisition_sources = [include_str!("../src/slot_lifecycle.rs"), include_str!("../src/transaction_execution.rs")];
|
||||
for source in acquisition_sources {
|
||||
for forbidden in [
|
||||
"borsh::",
|
||||
"bincode::",
|
||||
"ksp_config_lib::",
|
||||
"ksp_logging_lib::",
|
||||
"ksp_onchain_transport_lib::",
|
||||
"ksp_store_api::",
|
||||
"ksp_store_lib::",
|
||||
"reqwest::",
|
||||
"serde::",
|
||||
"serde_json::",
|
||||
"solana_instruction::",
|
||||
"tauri::",
|
||||
"tokio::",
|
||||
"tonic::",
|
||||
concat!("tracing", "::"),
|
||||
"wincode::",
|
||||
] {
|
||||
assert!(!source.contains(forbidden), "forbidden acquisition dependency path detected: {forbidden}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_005_manifest_keeps_exact_core_only_graph_without_features_or_hidden_dependency_sections() {
|
||||
let manifest = include_str!("../Cargo.toml");
|
||||
assert!(!manifest.contains("[features]"));
|
||||
assert!(!manifest.contains("[dev-dependencies]"));
|
||||
assert!(!manifest.contains("[build-dependencies]"));
|
||||
assert_eq!(manifest.matches("[dependencies]").count(), 1);
|
||||
let dependencies_tail = manifest.split("[dependencies]").nth(1);
|
||||
assert!(dependencies_tail.is_some(), "Interface dependencies section must exist");
|
||||
let dependencies_tail = match dependencies_tail {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
let dependencies = match dependencies_tail.split("[lints]").next() {
|
||||
std::option::Option::Some(value) => value,
|
||||
std::option::Option::None => return,
|
||||
};
|
||||
assert_eq!(manifest_dependency_names(dependencies), std::vec!["ksp-core-lib"]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
// file: crates/ksp-interface-lib/tests/external_consumer.rs
|
||||
// version: 1
|
||||
// version: 2
|
||||
|
||||
//! Downstream-style consumer canary for the public Interface facade.
|
||||
//! Downstream-style consumer canaries for the public Interface facade.
|
||||
|
||||
fn consume_instruction(instruction: ksp_interface_lib::ProgramInstruction) -> (ksp_interface_lib::Pubkey, usize, usize) {
|
||||
return (*instruction.program_id(), instruction.accounts().len(), instruction.data().len());
|
||||
}
|
||||
|
||||
fn consume_slot_lifecycle(event: ksp_interface_lib::SlotLifecycleEvent) -> (u64, ksp_interface_lib::SlotLifecycleStage) {
|
||||
return (event.slot(), event.stage());
|
||||
}
|
||||
|
||||
fn consume_transaction_execution(
|
||||
event: ksp_interface_lib::TransactionExecutionEvent,
|
||||
) -> (u64, ksp_interface_lib::TransactionSignature, ksp_interface_lib::TransactionExecutionOutcome) {
|
||||
return (event.slot(), event.signature(), event.outcome());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_external_consumer_uses_only_the_crate_root_facade() {
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xA1_u8; 32]);
|
||||
@@ -25,3 +35,13 @@ fn pre_005_external_consumer_uses_only_the_crate_root_facade() {
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_004_external_consumer_uses_only_crate_root_for_both_acquisition_families() {
|
||||
let lifecycle = ksp_interface_lib::SlotLifecycleEvent::new(u64::MAX, ksp_interface_lib::SlotLifecycleStage::OptimisticallyConfirmed);
|
||||
assert_eq!(consume_slot_lifecycle(lifecycle), (u64::MAX, ksp_interface_lib::SlotLifecycleStage::OptimisticallyConfirmed));
|
||||
let signature = ksp_interface_lib::TransactionSignature::new([0xA3_u8; 64]);
|
||||
let execution = ksp_interface_lib::TransactionExecutionEvent::new(u64::MAX - 1, signature, ksp_interface_lib::TransactionExecutionOutcome::Failed);
|
||||
assert_eq!(consume_transaction_execution(execution), (u64::MAX - 1, signature, ksp_interface_lib::TransactionExecutionOutcome::Failed));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,75 +1,75 @@
|
||||
// file: crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
// version: 1
|
||||
// version: 5
|
||||
|
||||
//! Release-level completeness canaries for the `0.2.13` Interface foundation.
|
||||
//! Release-completeness canaries for the public `ksp-interface-lib` surface.
|
||||
|
||||
#[test]
|
||||
fn pre_005_exact_crate_root_export_inventory_is_stable() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
let mut actual = std::vec::Vec::new();
|
||||
for line in crate_root.lines() {
|
||||
let trimmed = line.trim();
|
||||
if trimmed.starts_with("pub use ") {
|
||||
actual.push(trimmed);
|
||||
}
|
||||
}
|
||||
actual.sort_unstable();
|
||||
let mut expected = std::vec![
|
||||
"pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;",
|
||||
"pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;",
|
||||
"pub use self::program_account_meta::ProgramAccountMeta;",
|
||||
"pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;",
|
||||
"pub use self::program_instruction::ProgramInstruction;",
|
||||
"pub use ksp_core_lib::Pubkey;",
|
||||
];
|
||||
expected.sort_unstable();
|
||||
assert_eq!(actual, expected);
|
||||
assert!(!crate_root.contains("pub mod "));
|
||||
return;
|
||||
fn crate_root_source() -> std::result::Result<std::string::String, std::io::Error> {
|
||||
let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src/lib.rs");
|
||||
return std::fs::read_to_string(path);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_production_module_inventory_contains_no_second_wire_domain() -> std::io::Result<()> {
|
||||
let source_root = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("src");
|
||||
let entries = match std::fs::read_dir(source_root) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let mut names = std::vec::Vec::new();
|
||||
for entry in entries {
|
||||
let entry = match entry {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
let file_type = match entry.file_type() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(error) => return std::result::Result::Err(error),
|
||||
};
|
||||
if !file_type.is_file() {
|
||||
continue;
|
||||
}
|
||||
let name = match entry.file_name().into_string() {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => continue,
|
||||
};
|
||||
if name.ends_with(".rs") {
|
||||
names.push(name);
|
||||
}
|
||||
}
|
||||
names.sort_unstable();
|
||||
assert_eq!(names, std::vec!["error.rs", "lib.rs", "program_account_meta.rs", "program_instruction.rs"]);
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pre_005_foundation_has_one_error_code_and_two_bounded_passive_types() {
|
||||
fn v0_3_5_pre_004_foundation_keeps_exactly_two_passive_acquisition_families() {
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.domain(), "interface");
|
||||
assert_eq!(ksp_interface_lib::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED.code(), "program_instruction_limit_exceeded");
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xB1_u8; 32]);
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xB2_u8; 32]), false);
|
||||
let instruction = ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account], std::vec![0xB3_u8]);
|
||||
assert!(instruction.is_ok());
|
||||
let lifecycle = ksp_interface_lib::SlotLifecycleEvent::new(u64::MAX, ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||
assert_eq!(lifecycle.slot(), u64::MAX);
|
||||
assert_eq!(lifecycle.stage(), ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||
let signature = ksp_interface_lib::TransactionSignature::new([0xB4_u8; 64]);
|
||||
let execution = ksp_interface_lib::TransactionExecutionEvent::new(u64::MAX, signature, ksp_interface_lib::TransactionExecutionOutcome::Succeeded);
|
||||
assert_eq!(execution.slot(), u64::MAX);
|
||||
assert_eq!(execution.signature(), signature);
|
||||
assert_eq!(execution.outcome(), ksp_interface_lib::TransactionExecutionOutcome::Succeeded);
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_004_exact_crate_root_export_inventory_is_stable() -> std::result::Result<(), std::io::Error> {
|
||||
let source = match crate_root_source() {
|
||||
Ok(source) => source,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let public_use_count = source.lines().filter(|line| return line.starts_with("pub use ")).count();
|
||||
assert_eq!(public_use_count, 11);
|
||||
assert!(source.contains("pub use self::error::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED;"));
|
||||
assert!(source.contains("pub use self::program_account_meta::MAX_PROGRAM_INSTRUCTION_ACCOUNTS;"));
|
||||
assert!(source.contains("pub use self::program_account_meta::ProgramAccountMeta;"));
|
||||
assert!(source.contains("pub use self::program_instruction::MAX_PROGRAM_INSTRUCTION_DATA_LEN;"));
|
||||
assert!(source.contains("pub use self::program_instruction::ProgramInstruction;"));
|
||||
assert!(source.contains("pub use self::slot_lifecycle::SlotLifecycleEvent;"));
|
||||
assert!(source.contains("pub use self::slot_lifecycle::SlotLifecycleStage;"));
|
||||
assert!(source.contains("pub use self::transaction_execution::TransactionExecutionEvent;"));
|
||||
assert!(source.contains("pub use self::transaction_execution::TransactionExecutionOutcome;"));
|
||||
assert!(source.contains("pub use self::transaction_execution::TransactionSignature;"));
|
||||
assert!(source.contains("pub use ksp_core_lib::Pubkey;"));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_004_production_module_inventory_is_exact() -> std::result::Result<(), std::io::Error> {
|
||||
let source = match crate_root_source() {
|
||||
Ok(source) => source,
|
||||
Err(error) => return Err(error),
|
||||
};
|
||||
let modules = source
|
||||
.lines()
|
||||
.filter_map(|line| return line.strip_prefix("mod ").and_then(|module| return module.strip_suffix(';')))
|
||||
.collect::<std::vec::Vec<_>>();
|
||||
assert_eq!(modules, std::vec!["error", "program_account_meta", "program_instruction", "slot_lifecycle", "transaction_execution"]);
|
||||
assert!(!source.contains("serde"));
|
||||
assert!(!source.contains("tracing"));
|
||||
assert!(!source.contains("ksp_onchain_transport"));
|
||||
assert!(!source.contains("ksp_store"));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_004_evolutive_acquisition_enums_remain_non_exhaustive() {
|
||||
let lifecycle_source = include_str!("../src/slot_lifecycle.rs");
|
||||
let execution_source = include_str!("../src/transaction_execution.rs");
|
||||
assert!(lifecycle_source.contains("#[non_exhaustive]\npub enum SlotLifecycleStage"));
|
||||
assert!(execution_source.contains("#[non_exhaustive]\npub enum TransactionExecutionOutcome"));
|
||||
return;
|
||||
}
|
||||
|
||||
100
crates/ksp-interface-lib/tests/security_hardening.rs
Normal file
100
crates/ksp-interface-lib/tests/security_hardening.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
// file: crates/ksp-interface-lib/tests/security_hardening.rs
|
||||
// version: 1
|
||||
|
||||
//! Adversarial and ownership-hardening canaries for passive Interface acquisition events.
|
||||
|
||||
const HOSTILE_MARKER: &str = "INTERFACE-ACQUISITION-SECRET-CANARY";
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_005_signature_and_event_debug_never_render_signature_bytes() {
|
||||
let mut bytes = [0x41_u8; 64];
|
||||
bytes[..HOSTILE_MARKER.len()].copy_from_slice(HOSTILE_MARKER.as_bytes());
|
||||
let signature = ksp_interface_lib::TransactionSignature::new(bytes);
|
||||
assert_eq!(signature.as_bytes(), &bytes);
|
||||
let signature_debug = std::format!("{signature:?}");
|
||||
assert_eq!(signature_debug, "TransactionSignature(..)");
|
||||
assert!(!signature_debug.contains(HOSTILE_MARKER));
|
||||
let event = ksp_interface_lib::TransactionExecutionEvent::new(u64::MAX, signature, ksp_interface_lib::TransactionExecutionOutcome::Failed);
|
||||
let event_debug = std::format!("{event:?}");
|
||||
assert!(event_debug.contains("TransactionExecutionEvent"));
|
||||
assert!(event_debug.contains("18446744073709551615"));
|
||||
assert!(event_debug.contains("Failed"));
|
||||
assert!(!event_debug.contains(HOSTILE_MARKER));
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_005_acquisition_structs_keep_exact_minimal_fields_without_payload_or_source_metadata() {
|
||||
let lifecycle_source = include_str!("../src/slot_lifecycle.rs");
|
||||
let execution_source = include_str!("../src/transaction_execution.rs");
|
||||
assert!(lifecycle_source.contains("pub struct SlotLifecycleEvent {\n slot: u64,\n stage: SlotLifecycleStage,\n}"));
|
||||
assert!(execution_source.contains("pub struct TransactionSignature([u8; 64]);"));
|
||||
assert!(execution_source.contains(
|
||||
"pub struct TransactionExecutionEvent {\n slot: u64,\n signature: TransactionSignature,\n outcome: TransactionExecutionOutcome,\n}"
|
||||
));
|
||||
for source in [lifecycle_source, execution_source] {
|
||||
for forbidden in [
|
||||
"std::vec::Vec<",
|
||||
"std::string::String",
|
||||
"Box<",
|
||||
"serde_json::Value",
|
||||
"timestamp:",
|
||||
"provider_id:",
|
||||
"endpoint:",
|
||||
"filter:",
|
||||
"network:",
|
||||
"payload:",
|
||||
] {
|
||||
assert!(!source.contains(forbidden), "forbidden acquisition field/surface detected: {forbidden}");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_005_interface_exports_no_second_raw_or_deferred_event_family() {
|
||||
let crate_root = include_str!("../src/lib.rs");
|
||||
for forbidden in [
|
||||
"RawTransaction",
|
||||
"RawAccount",
|
||||
"RawPayload",
|
||||
"RawPageCursor",
|
||||
"RawRetention",
|
||||
"RawObservation",
|
||||
"TransactionLogEvent",
|
||||
"TransactionCommitmentEvent",
|
||||
"LedgerEntryEvent",
|
||||
"VoteEvent",
|
||||
"BlockEvent",
|
||||
] {
|
||||
assert!(!crate_root.contains(forbidden), "forbidden Interface export detected: {forbidden}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn v0_3_5_pre_005_program_instruction_foundation_remains_bounded_and_unchanged() {
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS, 255);
|
||||
assert_eq!(ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN, 10_240);
|
||||
let program_id = ksp_interface_lib::Pubkey::new_from_array([0xD1_u8; 32]);
|
||||
let account = ksp_interface_lib::ProgramAccountMeta::readonly(ksp_interface_lib::Pubkey::new_from_array([0xD2_u8; 32]), false);
|
||||
let admitted = ksp_interface_lib::ProgramInstruction::try_new(
|
||||
program_id,
|
||||
std::vec![account; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS],
|
||||
std::vec![0x5A_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN],
|
||||
);
|
||||
assert!(admitted.is_ok());
|
||||
let admitted = match admitted {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => return,
|
||||
};
|
||||
assert_eq!(admitted.accounts().len(), ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS);
|
||||
assert_eq!(admitted.data().len(), ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN);
|
||||
let too_many_accounts =
|
||||
ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![account; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_ACCOUNTS + 1], std::vec![]);
|
||||
assert!(too_many_accounts.is_err());
|
||||
let oversized_data =
|
||||
ksp_interface_lib::ProgramInstruction::try_new(program_id, std::vec![], std::vec![0x5A_u8; ksp_interface_lib::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1]);
|
||||
assert!(oversized_data.is_err());
|
||||
return;
|
||||
}
|
||||
29
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
Normal file
29
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
// file: crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||
// version: 2
|
||||
|
||||
//! Public API canaries for the shared slot lifecycle event contract.
|
||||
|
||||
#[test]
|
||||
fn public_v0_3_5_pre_002_slot_lifecycle_contract_is_available_from_crate_root() {
|
||||
let event = ksp_interface_lib::SlotLifecycleEvent::new(u64::MAX, ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||
assert_eq!(event.slot(), u64::MAX);
|
||||
assert_eq!(event.stage(), ksp_interface_lib::SlotLifecycleStage::Rooted);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_v0_3_5_pre_002_slot_lifecycle_stage_remains_downstream_evolvable() {
|
||||
fn stage_label(stage: ksp_interface_lib::SlotLifecycleStage) -> &'static str {
|
||||
return match stage {
|
||||
ksp_interface_lib::SlotLifecycleStage::Processed => "processed",
|
||||
ksp_interface_lib::SlotLifecycleStage::FirstShredReceived => "first_shred_received",
|
||||
ksp_interface_lib::SlotLifecycleStage::Completed => "completed",
|
||||
ksp_interface_lib::SlotLifecycleStage::CreatedBank => "created_bank",
|
||||
ksp_interface_lib::SlotLifecycleStage::Dead => "dead",
|
||||
ksp_interface_lib::SlotLifecycleStage::OptimisticallyConfirmed => "optimistically_confirmed",
|
||||
ksp_interface_lib::SlotLifecycleStage::Rooted => "rooted",
|
||||
_ => "future",
|
||||
};
|
||||
}
|
||||
assert_eq!(stage_label(ksp_interface_lib::SlotLifecycleStage::Processed), "processed");
|
||||
assert_eq!(stage_label(ksp_interface_lib::SlotLifecycleStage::Rooted), "rooted");
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// file: crates/ksp-interface-lib/tests/transaction_execution_public_api.rs
|
||||
// version: 1
|
||||
|
||||
//! Public API canaries for the provider-neutral transaction execution contract.
|
||||
|
||||
#[test]
|
||||
fn public_v0_3_5_pre_003_transaction_execution_contract_is_available_from_crate_root() {
|
||||
let signature = ksp_interface_lib::TransactionSignature::new([0xC7_u8; 64]);
|
||||
let event = ksp_interface_lib::TransactionExecutionEvent::new(u64::MAX, signature, ksp_interface_lib::TransactionExecutionOutcome::Succeeded);
|
||||
assert_eq!(signature.as_bytes(), &[0xC7_u8; 64]);
|
||||
assert_eq!(event.slot(), u64::MAX);
|
||||
assert_eq!(event.signature(), signature);
|
||||
assert_eq!(event.outcome(), ksp_interface_lib::TransactionExecutionOutcome::Succeeded);
|
||||
}
|
||||
|
||||
fn outcome_label(outcome: ksp_interface_lib::TransactionExecutionOutcome) -> &'static str {
|
||||
return match outcome {
|
||||
ksp_interface_lib::TransactionExecutionOutcome::Succeeded => "succeeded",
|
||||
ksp_interface_lib::TransactionExecutionOutcome::Failed => "failed",
|
||||
_ => "future",
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn public_v0_3_5_pre_003_transaction_execution_outcome_remains_downstream_evolvable() {
|
||||
assert_eq!(outcome_label(ksp_interface_lib::TransactionExecutionOutcome::Succeeded), "succeeded");
|
||||
assert_eq!(outcome_label(ksp_interface_lib::TransactionExecutionOutcome::Failed), "failed");
|
||||
}
|
||||
45
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
Normal file
45
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
// file: crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||
// version: 2
|
||||
|
||||
#[test]
|
||||
fn slot_lifecycle_stages_are_distinct_copy_and_complete_for_the_admitted_family() {
|
||||
fn assert_copy<T: Copy>() {}
|
||||
assert_copy::<crate::SlotLifecycleStage>();
|
||||
let stages = [
|
||||
crate::SlotLifecycleStage::Processed,
|
||||
crate::SlotLifecycleStage::FirstShredReceived,
|
||||
crate::SlotLifecycleStage::Completed,
|
||||
crate::SlotLifecycleStage::CreatedBank,
|
||||
crate::SlotLifecycleStage::Dead,
|
||||
crate::SlotLifecycleStage::OptimisticallyConfirmed,
|
||||
crate::SlotLifecycleStage::Rooted,
|
||||
];
|
||||
for (index, stage) in stages.iter().enumerate() {
|
||||
for other in stages.iter().skip(index + 1) {
|
||||
assert_ne!(stage, other);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slot_lifecycle_event_preserves_full_u64_slot_and_stage() {
|
||||
fn assert_copy<T: Copy>() {}
|
||||
assert_copy::<crate::SlotLifecycleEvent>();
|
||||
let event = crate::SlotLifecycleEvent::new(u64::MAX, crate::SlotLifecycleStage::Rooted);
|
||||
assert_eq!(event.slot(), u64::MAX);
|
||||
assert_eq!(event.stage(), crate::SlotLifecycleStage::Rooted);
|
||||
let copied = event;
|
||||
assert_eq!(event, copied);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slot_lifecycle_debug_is_bounded_and_contains_only_shared_fields() {
|
||||
let event = crate::SlotLifecycleEvent::new(42, crate::SlotLifecycleStage::OptimisticallyConfirmed);
|
||||
let debug = std::format!("{event:?}");
|
||||
assert!(debug.len() <= 128);
|
||||
assert!(debug.contains("slot: 42"));
|
||||
assert!(debug.contains("OptimisticallyConfirmed"));
|
||||
assert!(!debug.contains("provider"));
|
||||
assert!(!debug.contains("yellowstone"));
|
||||
assert!(!debug.contains("websocket"));
|
||||
}
|
||||
28
crates/ksp-interface-lib/unit_tests/transaction_execution.rs
Normal file
28
crates/ksp-interface-lib/unit_tests/transaction_execution.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
// file: crates/ksp-interface-lib/unit_tests/transaction_execution.rs
|
||||
// version: 1
|
||||
|
||||
#[test]
|
||||
fn transaction_signature_preserves_exact_bytes_and_redacts_debug() {
|
||||
let signature = crate::TransactionSignature::new([0xA5_u8; 64]);
|
||||
assert_eq!(signature.as_bytes(), &[0xA5_u8; 64]);
|
||||
assert_eq!(std::format!("{signature:?}"), "TransactionSignature(..)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_execution_outcomes_are_distinct_and_copy() {
|
||||
let succeeded = crate::TransactionExecutionOutcome::Succeeded;
|
||||
let failed = crate::TransactionExecutionOutcome::Failed;
|
||||
assert_ne!(succeeded, failed);
|
||||
let copied = succeeded;
|
||||
assert_eq!(copied, crate::TransactionExecutionOutcome::Succeeded);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transaction_execution_event_preserves_full_slot_signature_and_outcome() {
|
||||
let signature = crate::TransactionSignature::new([0xB6_u8; 64]);
|
||||
let event = crate::TransactionExecutionEvent::new(u64::MAX, signature, crate::TransactionExecutionOutcome::Failed);
|
||||
assert_eq!(event.slot(), u64::MAX);
|
||||
assert_eq!(event.signature(), signature);
|
||||
assert_eq!(event.outcome(), crate::TransactionExecutionOutcome::Failed);
|
||||
assert_eq!(std::format!("{event:?}"), "TransactionExecutionEvent { slot: 18446744073709551615, signature: \"<omitted>\", outcome: Failed }");
|
||||
}
|
||||
191
deltas/0.3.5/pre.001-fix.001.md
Normal file
191
deltas/0.3.5/pre.001-fix.001.md
Normal file
@@ -0,0 +1,191 @@
|
||||
<!-- file: deltas/0.3.5/pre.001-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.001-fix.001` — correction du gate Interface acquisition events
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.001
|
||||
workspace.package.version = 0.3.5-pre.1
|
||||
```
|
||||
|
||||
Ce fix est strictement documentaire. Conformément au workflow KSP, il ne modifie pas `workspace.package.version` et ne touche aucun fichier Cargo/Rust/runtime/config.
|
||||
|
||||
## Motif du fix
|
||||
|
||||
Le brainstorming post-gate a identifié deux décisions trop conservatrices dans `pre.001` :
|
||||
|
||||
1. `OptimisticConfirmation <-> Yellowstone Confirmed` et `Root <-> Yellowstone Finalized` représentent bien les mêmes faits de lifecycle lorsqu'ils sont normalisés avec des noms KSP qui conservent la sémantique source ;
|
||||
2. la catégorie générique « transaction status » mélangeait snapshot, commitment et exécution, masquant un candidat event-only transversal possible.
|
||||
|
||||
## Corrections de conception
|
||||
|
||||
### Slot lifecycle
|
||||
|
||||
L'intersection admise devient :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage
|
||||
+ Processed
|
||||
+ FirstShredReceived
|
||||
+ Completed
|
||||
+ CreatedBank
|
||||
+ Dead
|
||||
+ OptimisticallyConfirmed
|
||||
+ Rooted
|
||||
```
|
||||
|
||||
Mappings corrigés :
|
||||
|
||||
```text
|
||||
Solana slotsUpdates::OptimisticConfirmation
|
||||
-> SlotLifecycleStage::OptimisticallyConfirmed
|
||||
<- Yellowstone SlotStatus::Confirmed
|
||||
|
||||
Solana rootSubscribe / slotsUpdates::Root
|
||||
-> SlotLifecycleStage::Rooted
|
||||
<- Yellowstone SlotStatus::Finalized
|
||||
```
|
||||
|
||||
Les noms `OptimisticallyConfirmed` et `Rooted` évitent de promouvoir les labels Yellowstone `Confirmed`/`Finalized` en terminologie KSP universelle. `Frozen` reste hors intersection.
|
||||
|
||||
### Transaction execution
|
||||
|
||||
`TransactionExecutionEvent` est rouvert comme **candidat actif de `0.3.5`**, conceptuellement :
|
||||
|
||||
```text
|
||||
TransactionExecutionEvent {
|
||||
slot,
|
||||
signature,
|
||||
outcome = Succeeded | Failed,
|
||||
}
|
||||
```
|
||||
|
||||
Producers candidats :
|
||||
|
||||
```text
|
||||
Solana logsSubscribe
|
||||
Yellowstone TransactionStatus
|
||||
Helius transactionSubscribe
|
||||
```
|
||||
|
||||
Le type n'est pas encore admis. `pre.003` doit d'abord auditer la représentation KSP de signature, les mappings exacts, l'anti-duplication Store et le consumer concret. Aucun type partiel ne doit être créé si ce gate échoue.
|
||||
|
||||
### Logs et commitment
|
||||
|
||||
Les familles sont désormais explicitement séparées :
|
||||
|
||||
```text
|
||||
TransactionLogEvent
|
||||
-> idée différée ; bornes/consumer/multi-producer à démontrer
|
||||
|
||||
getSignatureStatuses
|
||||
-> snapshot Transport
|
||||
|
||||
signatureSubscribe
|
||||
-> transition one-shot de commitment Transport
|
||||
|
||||
TransactionCommitmentEvent
|
||||
-> non admis ; ne jamais fusionner avec TransactionExecutionEvent par Option soup
|
||||
```
|
||||
|
||||
### Extensions provider/protocol
|
||||
|
||||
La règle d'ownership est clarifiée :
|
||||
|
||||
```text
|
||||
DTO provider/protocol spécifique
|
||||
-> Transport
|
||||
|
||||
fait passif provider-neutral réellement commun
|
||||
-> Interface après gate sémantique
|
||||
```
|
||||
|
||||
Ainsi `Helius transactionSubscribe` et Yellowstone `Entry` restent Transport-owned comme DTOs. Leur caractère non standard n'interdit pas qu'un futur fait commun qu'ils permettent d'observer soit Interface-owned.
|
||||
|
||||
## Traçabilité TODO/IDEAS
|
||||
|
||||
Le fix ne crée pas artificiellement une entrée durable séparée pendant que le gate `0.3.5` est encore actif :
|
||||
|
||||
```text
|
||||
TransactionExecutionEvent -> suivi actif dans plan/validation 0.3.5
|
||||
TransactionLogEvent -> idée différée explicitement tracée dans plan/validation
|
||||
```
|
||||
|
||||
Si `TransactionLogEvent` reste hors scope à la réconciliation documentaire finale, il devra être transféré dans le TODO/IDEAS durable approprié.
|
||||
|
||||
## Plan de prereleases corrigé
|
||||
|
||||
```text
|
||||
pre.002 implémentation SlotLifecycleEvent/Stage à 7 stages
|
||||
pre.003 gate TransactionExecutionEvent + implémentation seulement si gate complet
|
||||
pre.004 canaris externes + complétude API
|
||||
pre.005 hardening final
|
||||
pre.006 gate technique final
|
||||
pre.007 réconciliation documentaire finale
|
||||
pre.008 préparation de publication
|
||||
rel.001 stable 0.3.5
|
||||
```
|
||||
|
||||
## Gate opérateur reçu pour `pre.001`
|
||||
|
||||
Avant ce fix, l'opérateur a rejoué :
|
||||
|
||||
```text
|
||||
cargo clean
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
```
|
||||
|
||||
Résultat fourni :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (251 table(s), 137 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
```
|
||||
|
||||
Les tests Interface détaillés fournis sont tous propres : 10 unitaires, 4 dependency-boundary, 1 external-consumer, 5 public-api, 3 release-completeness, aucun échec de doc-test.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
deltas/0.3.5/pre.001-fix.001.md
|
||||
```
|
||||
|
||||
## Fichiers explicitement inchangés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## Gate demandé après application du fix
|
||||
|
||||
Le fix ne change que Markdown. Rejouer :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
```
|
||||
|
||||
Aucun rerun Cargo n'est requis par le contenu du fix lui-même.
|
||||
119
deltas/0.3.5/pre.001.md
Normal file
119
deltas/0.3.5/pre.001.md
Normal file
@@ -0,0 +1,119 @@
|
||||
<!-- file: deltas/0.3.5/pre.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.001` — audit et planification Interface acquisition events
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
v0.3.4
|
||||
workspace.package.version = 0.3.4
|
||||
```
|
||||
|
||||
Le log opérateur fourni avec l'archive d'entrée montre le gate stable `v0.3.4` propre. Cette tranche part exclusivement de l'archive `khadhroony-solana-project-v0.3.4.zip` fournie par l'opérateur.
|
||||
|
||||
## Objectif
|
||||
|
||||
Exécuter le gate `pre.001` prescrit par `prompts/024-V0_3_5_START_PROMPT.md` : lecture, inventaire producer/consumer, audit sémantique multi-transport actuel, ownership Interface/Transport/Store, threat model, sizing et planification.
|
||||
|
||||
Aucun modèle Rust n'est implémenté dans cette tranche.
|
||||
|
||||
## Décisions prises
|
||||
|
||||
Une seule famille passe le gate d'admission Interface :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent
|
||||
+ Processed
|
||||
+ FirstShredReceived
|
||||
+ Completed
|
||||
+ CreatedBank
|
||||
+ Dead
|
||||
```
|
||||
|
||||
Cette intersection correspond uniquement aux faits communs démontrés entre Solana WebSocket et Yellowstone. Les metadata riches restent Transport.
|
||||
|
||||
Décisions négatives :
|
||||
|
||||
```text
|
||||
Root -X-> Finalized
|
||||
OptimisticConfirmation -X-> Confirmed
|
||||
logsSubscribe -> reporté
|
||||
TransactionStatusObservation -> reporté
|
||||
vote -> reporté
|
||||
account/program -> Store/Transport
|
||||
transaction/block -> Store/Transport
|
||||
Yellowstone Entry -> Transport
|
||||
Helius Enhanced transaction -> Transport
|
||||
notification after commit -> Store API selon KSP-NOTIFY-001..006
|
||||
```
|
||||
|
||||
La release est redimensionnée autour d'une seule famille et réserve explicitement les couloirs hardening, gate technique final, réconciliation documentaire puis publication.
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.001.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
```
|
||||
|
||||
Modifications Cargo :
|
||||
|
||||
```text
|
||||
header version: 382 -> 383
|
||||
workspace.package.version: 0.3.4 -> 0.3.5-pre.1
|
||||
```
|
||||
|
||||
## Fichiers supprimés
|
||||
|
||||
Aucun.
|
||||
|
||||
## Validations exécutées
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
-> General Rust rule audit: clean
|
||||
-> Rust export completeness audit: 0 candidate(s)
|
||||
-> KSP workspace Rust rule audit: clean
|
||||
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
-> Markdown table audit: clean (251 table(s), 137 file(s))
|
||||
```
|
||||
|
||||
## Validations non exécutées dans l'environnement d'assemblage
|
||||
|
||||
`cargo` n'est pas installé dans l'environnement d'assemblage. Les commandes suivantes ne sont donc pas déclarées réussies :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
```
|
||||
|
||||
Elles doivent être rejouées par l'opérateur après application de l'overlay.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question bloquante pour `pre.002`.
|
||||
|
||||
Les familles logs/status/vote/root restent volontairement reportées et ne doivent être rouvertes que si un nouveau producer/consumer concret apporte une convergence qui n'existe pas dans ce gate.
|
||||
|
||||
## Suite prévue
|
||||
|
||||
```text
|
||||
pre.002 implémentation SlotLifecycleEvent/Stage
|
||||
pre.003 canaris externes + complétude API
|
||||
pre.004 hardening final
|
||||
pre.005 gate technique final
|
||||
pre.006 réconciliation documentaire finale
|
||||
pre.007 préparation de publication
|
||||
rel.001 stable 0.3.5
|
||||
```
|
||||
67
deltas/0.3.5/pre.002-fix.001.md
Normal file
67
deltas/0.3.5/pre.002-fix.001.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Delta `0.3.5-pre.002-fix.001`
|
||||
|
||||
## Objet
|
||||
|
||||
Corriger les défauts de conformité Rust révélés par le gate opérateur de `0.3.5-pre.002`, sans modifier le contrat fonctionnel `SlotLifecycleEvent` / `SlotLifecycleStage`.
|
||||
|
||||
## Base
|
||||
|
||||
```text
|
||||
0.3.5-pre.002
|
||||
workspace.package.version = 0.3.5-pre.2
|
||||
```
|
||||
|
||||
## Diagnostic opérateur
|
||||
|
||||
Le code fonctionnel et les tests ciblés passent, mais le gate global n'est pas propre :
|
||||
|
||||
- 15 violations `RUST-FMT-101` pour des lignes vides à l'intérieur de fonctions de tests ;
|
||||
- 2 usages de l'opérateur `?` rejetés par `clippy::question_mark_used` ;
|
||||
- closures à retour implicite rejetées par `clippy::implicit_return` ;
|
||||
- documentation crate-level manquante dans les deux nouveaux tests d'intégration.
|
||||
|
||||
## Correction
|
||||
|
||||
- supprimer les lignes vides internes aux fonctions concernées ;
|
||||
- remplacer `?` par une propagation explicite via `match` ;
|
||||
- rendre explicites les `return` des closures concernées ;
|
||||
- ajouter la documentation crate-level aux tests d'intégration ;
|
||||
- conserver strictement les sept variantes de `SlotLifecycleStage` et la forme de `SlotLifecycleEvent` ;
|
||||
- ne pas ajouter de `allow`, de dépendance, de codec, de runtime ou de conversion Transport.
|
||||
|
||||
## Version
|
||||
|
||||
Le fix modifie des fichiers Rust ; la version workspace est donc incrémentée suivant la convention de fix prerelease :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.2.fix.1
|
||||
```
|
||||
|
||||
Le numéro documentaire reste :
|
||||
|
||||
```text
|
||||
0.3.5-pre.002-fix.001
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.002-fix.001.md
|
||||
```
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
180
deltas/0.3.5/pre.002.md
Normal file
180
deltas/0.3.5/pre.002.md
Normal file
@@ -0,0 +1,180 @@
|
||||
<!-- file: deltas/0.3.5/pre.002.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.002` — `SlotLifecycleEvent`
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.001-fix.001
|
||||
workspace.package.version = 0.3.5-pre.1
|
||||
```
|
||||
|
||||
Gate d'entrée opérateur reçu après le fix :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 138 file(s))
|
||||
```
|
||||
|
||||
## Objectif
|
||||
|
||||
Matérialiser uniquement la famille passive provider-neutral `SlotLifecycleEvent` admise par le gate corrigé de `pre.001`, sans ouvrir la famille candidate `TransactionExecutionEvent` et sans déplacer les DTOs protocol/provider hors de Transport.
|
||||
|
||||
## Version
|
||||
|
||||
Cette tranche est une nouvelle prerelease non-fix. La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.2
|
||||
```
|
||||
|
||||
Le manifest `crates/ksp-interface-lib/Cargo.toml` reste inchangé et continue d'hériter de la version workspace.
|
||||
|
||||
## Implémentation
|
||||
|
||||
Nouvelle surface crate-root :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage
|
||||
SlotLifecycleEvent
|
||||
```
|
||||
|
||||
`SlotLifecycleStage` est `#[non_exhaustive]` et contient exactement :
|
||||
|
||||
```text
|
||||
Processed
|
||||
FirstShredReceived
|
||||
Completed
|
||||
CreatedBank
|
||||
Dead
|
||||
OptimisticallyConfirmed
|
||||
Rooted
|
||||
```
|
||||
|
||||
`SlotLifecycleEvent` reste volontairement minimal :
|
||||
|
||||
```text
|
||||
slot: u64
|
||||
stage: SlotLifecycleStage
|
||||
```
|
||||
|
||||
avec uniquement :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent::new(slot, stage)
|
||||
SlotLifecycleEvent::slot()
|
||||
SlotLifecycleEvent::stage()
|
||||
```
|
||||
|
||||
Aucune validation faillible n'est ajoutée : tout `u64` est un slot admissible au niveau de ce contrat passif.
|
||||
|
||||
## Ownership et dépendances
|
||||
|
||||
Préservé :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -> ksp-core-lib
|
||||
```
|
||||
|
||||
Absent :
|
||||
|
||||
```text
|
||||
serde
|
||||
codec wire
|
||||
tracing/logging runtime
|
||||
tokio/channel/event bus
|
||||
ksp-onchain-transport-lib
|
||||
ksp-store-api
|
||||
ksp-store-lib
|
||||
ksp-store-postgres-lib
|
||||
```
|
||||
|
||||
Aucun converter depuis les DTOs Solana WS, Yellowstone ou Helius n'est ajouté dans Interface. Les conversions appartiennent à la future composition/consumer.
|
||||
|
||||
## Canaris
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||
```
|
||||
|
||||
Le premier verrouille les 7 stages, le domaine `u64`, les traits passifs retenus et un `Debug` borné/provider-neutral. Le second vérifie la consommation depuis crate root et la capacité d'évolution downstream de l'enum non-exhaustive.
|
||||
|
||||
Le canari historique `tests/release_completeness.rs` est ajusté afin que son inventaire exact accepte la seule extension prévue de cette tranche : `slot_lifecycle` et ses deux reexports publics.
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||
deltas/0.3.5/pre.002.md
|
||||
```
|
||||
|
||||
## Fichiers explicitement hors scope
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## Validations exécutées dans l'environnement d'assemblage
|
||||
|
||||
Validations statiques de l'overlay :
|
||||
|
||||
```text
|
||||
version workspace = 0.3.5-pre.2
|
||||
nouvelle source Interface sans serde/tracing/tokio/Transport/Store
|
||||
crate-root = 4 modules privés / 8 reexports publics attendus
|
||||
SlotLifecycleStage = 7 variantes prévues
|
||||
aucun TransactionExecutionEvent introduit
|
||||
archive = fichiers modifiés/ajoutés uniquement
|
||||
```
|
||||
|
||||
L'environnement d'assemblage ne fournit pas le workspace Cargo complet exécutable ; aucun `cargo check`, Clippy ou test Rust de cette tranche n'est donc déclaré réussi ici.
|
||||
|
||||
## Gate opérateur demandé
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
`ksp-program-api` est inclus car il est le consumer actuel direct de `ksp-interface-lib`, même si `pre.002` ne modifie aucun contrat Program existant.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question ne bloque `SlotLifecycleEvent`.
|
||||
|
||||
Le seul gate fonctionnel suivant reste `TransactionExecutionEvent` : représentation de signature, convergence exacte Solana/Yellowstone/Helius, anti-duplication Store et consumer concret doivent être prouvés en `pre.003` avant toute implémentation.
|
||||
|
||||
## Suite
|
||||
|
||||
```text
|
||||
0.3.5-pre.003 — gate TransactionExecutionEvent ; implémentation uniquement si le gate est complet
|
||||
```
|
||||
193
deltas/0.3.5/pre.003.md
Normal file
193
deltas/0.3.5/pre.003.md
Normal file
@@ -0,0 +1,193 @@
|
||||
<!-- file: deltas/0.3.5/pre.003.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.003` — `TransactionExecutionEvent`
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.2.fix.1
|
||||
```
|
||||
|
||||
Le gate opérateur de cette base confirme les audits Rust, `cargo check --workspace`, Clippy, `cargo test -p ksp-interface-lib` et `cargo test -p ksp-program-api`. Le seul défaut restant est une double ligne vide dans `docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md`; conformément à la décision opérateur, cette correction documentaire est absorbée par le présent delta au lieu de créer un fix dédié.
|
||||
|
||||
## Version
|
||||
|
||||
Le delta modifie la surface Rust Interface. La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.3
|
||||
```
|
||||
|
||||
## Mission
|
||||
|
||||
Fermer le gate dédié à `TransactionExecutionEvent` prévu par le plan corrigé de `0.3.5` : représentation de signature, convergence Solana/Yellowstone/Helius, anti-duplication Store et consumer concret doivent tous être démontrés avant création du type.
|
||||
|
||||
## Décision de gate
|
||||
|
||||
Le gate passe avec une projection strictement minimale :
|
||||
|
||||
```text
|
||||
TransactionSignature([u8; 64])
|
||||
|
||||
TransactionExecutionOutcome {
|
||||
Succeeded,
|
||||
Failed,
|
||||
}
|
||||
|
||||
TransactionExecutionEvent {
|
||||
slot,
|
||||
signature,
|
||||
outcome,
|
||||
}
|
||||
```
|
||||
|
||||
La convergence retenue est :
|
||||
|
||||
```text
|
||||
Solana logsSubscribe
|
||||
context.slot + signature + err
|
||||
|
||||
Yellowstone TransactionStatus
|
||||
slot + signature + err
|
||||
|
||||
Helius transactionSubscribe
|
||||
slot + signature + résultat d'exécution seulement lorsque la forme/detail mode le rend déterminable
|
||||
```
|
||||
|
||||
`err` n'est jamais copié dans Interface. Solana `err: null`, Yellowstone `err: None` et un Helius `err: null` explicitement disponible donnent `Succeeded`; une erreur explicite donne `Failed`.
|
||||
|
||||
Pour Helius, la projection est conservative : un `err` omis, une forme `none`, inconnue ou sans information d'erreur exploitable ne produit pas artificiellement un `TransactionExecutionEvent`.
|
||||
|
||||
## Signature
|
||||
|
||||
`TransactionSignature` possède exactement 64 octets déjà décodés.
|
||||
|
||||
Interface n'ajoute :
|
||||
|
||||
```text
|
||||
aucun base58
|
||||
aucun serde
|
||||
aucun codec
|
||||
aucune crate Solana/Anza supplémentaire
|
||||
aucune capability Wallet de signature
|
||||
```
|
||||
|
||||
Le `Debug` est redacted et ne rend jamais les bytes.
|
||||
|
||||
`ksp-store-api::RawTransactionSignature` reste Store-owned. Aucun alias/reexport/converter cross-domain n'est ajouté ; la future composition convertit explicitement les 64 octets si nécessaire.
|
||||
|
||||
## Ownership
|
||||
|
||||
Restent Transport-owned :
|
||||
|
||||
```text
|
||||
Solana logs notification DTO
|
||||
Yellowstone TransactionStatus DTO
|
||||
Helius transactionSubscribe DTOs
|
||||
commitment
|
||||
subscription/filter metadata
|
||||
transaction index
|
||||
logs
|
||||
memo
|
||||
block time
|
||||
confirmation status
|
||||
provider timestamps
|
||||
opaque transaction errors
|
||||
```
|
||||
|
||||
Interface possède uniquement le fait passif commun.
|
||||
|
||||
## Consumer
|
||||
|
||||
Le futur worker RAW live peut utiliser `TransactionExecutionEvent` comme signal provider-neutral d'exécution observée et décider ensuite d'hydrater/persister un `RawTransaction` par sa propre composition/policy.
|
||||
|
||||
Le premier backfill historique `0.3.6` reste indépendant de cette API.
|
||||
|
||||
## Surface Rust
|
||||
|
||||
Ajouts crate-root :
|
||||
|
||||
```text
|
||||
TransactionSignature
|
||||
TransactionExecutionOutcome
|
||||
TransactionExecutionEvent
|
||||
```
|
||||
|
||||
`TransactionExecutionOutcome` est `#[non_exhaustive]`.
|
||||
|
||||
Les champs des structs restent privés et la surface ne possède ni runtime ni comportement réseau.
|
||||
|
||||
## Tests/canaris
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
unit_tests/transaction_execution.rs
|
||||
tests/transaction_execution_public_api.rs
|
||||
```
|
||||
|
||||
Le canari `tests/release_completeness.rs` évolue pour figer :
|
||||
|
||||
```text
|
||||
5 modules privés de production
|
||||
11 reexports crate-root
|
||||
transaction_execution comme seule nouvelle famille pre.003
|
||||
absence de serde/tracing/Transport/Store dans la racine Interface
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
Le plan et la validation passent `TransactionExecutionEvent` de candidat actif à `ADMIS pre.003`.
|
||||
|
||||
`TransactionLogEvent` reste une idée différée distincte. `TransactionCommitmentEvent` reste non admis. Yellowstone `Entry` et les DTOs Helius restent Transport-owned même lorsqu'ils pourront contribuer à de futurs faits Interface réellement transversaux.
|
||||
|
||||
La double ligne vide signalée par le gate opérateur précédent est supprimée dans la validation.
|
||||
|
||||
## Fichiers
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/transaction_execution.rs
|
||||
crates/ksp-interface-lib/unit_tests/transaction_execution.rs
|
||||
crates/ksp-interface-lib/tests/transaction_execution_public_api.rs
|
||||
deltas/0.3.5/pre.003.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## Gate opérateur
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les gates Cargo ne sont pas déclarés réussis par l'environnement d'assemblage.
|
||||
153
deltas/0.3.5/pre.004.md
Normal file
153
deltas/0.3.5/pre.004.md
Normal file
@@ -0,0 +1,153 @@
|
||||
<!-- file: deltas/0.3.5/pre.004.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.004` — canaris externes et complétude API
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.3
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.003` est entièrement propre : audits Rust/Markdown, `cargo check --workspace`, Clippy, tests `ksp-interface-lib` et `ksp-program-api` passent.
|
||||
|
||||
## Version
|
||||
|
||||
La tranche modifie des sources Rust de test/canari. La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.4
|
||||
```
|
||||
|
||||
## Mission
|
||||
|
||||
Verrouiller la surface des deux familles passives admises sans ajouter de comportement ni de type de production :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent / SlotLifecycleStage
|
||||
TransactionExecutionEvent / TransactionExecutionOutcome / TransactionSignature
|
||||
```
|
||||
|
||||
## Consumer externe
|
||||
|
||||
`tests/external_consumer.rs` consomme maintenant les deux familles acquisition uniquement depuis le crate-root public.
|
||||
|
||||
Le canari prouve notamment qu'un consumer downstream peut récupérer :
|
||||
|
||||
```text
|
||||
slot + stage
|
||||
slot + signature + outcome
|
||||
```
|
||||
|
||||
sans accès aux modules privés, à Transport ou à Store.
|
||||
|
||||
Le canari Program historique reste conservé.
|
||||
|
||||
## Inventaire exact
|
||||
|
||||
`tests/release_completeness.rs` fige :
|
||||
|
||||
```text
|
||||
5 modules privés de production
|
||||
11 reexports crate-root
|
||||
2 familles passives d'acquisition exactement
|
||||
```
|
||||
|
||||
Aucun nouveau module ni export de production n'est ajouté par `pre.004`.
|
||||
|
||||
## Evolutivité
|
||||
|
||||
Les deux enums publics évolutifs restent explicitement `#[non_exhaustive]` :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage
|
||||
TransactionExecutionOutcome
|
||||
```
|
||||
|
||||
Les canaris publics downstream de `pre.002` et `pre.003` restent inchangés et continuent d'utiliser un fallback `_`.
|
||||
|
||||
## Firewalls négatifs
|
||||
|
||||
Le scan de production inclut désormais les deux modules acquisition.
|
||||
|
||||
Un canari spécifique interdit dans `slot_lifecycle.rs` et `transaction_execution.rs` les paths de :
|
||||
|
||||
```text
|
||||
Config
|
||||
Logging
|
||||
Transport
|
||||
Store
|
||||
reqwest
|
||||
serde
|
||||
Solana instruction
|
||||
Tauri
|
||||
Tokio
|
||||
Tonic
|
||||
tracing
|
||||
borsh/bincode/wincode
|
||||
```
|
||||
|
||||
Le manifeste `ksp-interface-lib` reste Core-only et inchangé.
|
||||
|
||||
## Hors scope
|
||||
|
||||
Toujours interdits/reportés :
|
||||
|
||||
```text
|
||||
converters Transport -> Interface
|
||||
provider DTOs
|
||||
Store RAW
|
||||
serde/codecs
|
||||
runtime/channels
|
||||
logging
|
||||
TransactionLogEvent
|
||||
TransactionCommitmentEvent
|
||||
```
|
||||
|
||||
## Fichiers
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-interface-lib/tests/external_consumer.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajouté :
|
||||
|
||||
```text
|
||||
deltas/0.3.5/pre.004.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
crates/ksp-program-api/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## Gate opérateur
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les gates Cargo restent à exécuter par l'opérateur.
|
||||
78
deltas/0.3.5/pre.005-fix.001.md
Normal file
78
deltas/0.3.5/pre.005-fix.001.md
Normal file
@@ -0,0 +1,78 @@
|
||||
# Delta `0.3.5-pre.005-fix.001`
|
||||
|
||||
## Objet
|
||||
|
||||
Corriger le faux négatif du canari de manifeste ajouté par `0.3.5-pre.005`, sans modifier le contrat fonctionnel ni le graphe de dépendances de `ksp-interface-lib`.
|
||||
|
||||
## Base
|
||||
|
||||
```text
|
||||
0.3.5-pre.005
|
||||
workspace.package.version = 0.3.5-pre.5
|
||||
```
|
||||
|
||||
## Diagnostic opérateur
|
||||
|
||||
Le gate du `2026-08-31` est propre pour les audits Rust/Markdown et `cargo check --workspace`, mais le nouveau test :
|
||||
|
||||
```text
|
||||
v0_3_5_pre_005_manifest_keeps_exact_core_only_graph_without_features_or_hidden_dependency_sections
|
||||
```
|
||||
|
||||
échoue avec :
|
||||
|
||||
```text
|
||||
left: 2
|
||||
right: 1
|
||||
```
|
||||
|
||||
La cause est le comptage textuel `manifest.matches("ksp-core-lib")` appliqué à la déclaration :
|
||||
|
||||
```text
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
```
|
||||
|
||||
Cette ligne contient légitimement deux occurrences de la chaîne tout en déclarant une seule dépendance. Le manifeste lui-même est correct.
|
||||
|
||||
## Correction
|
||||
|
||||
- conserver les interdictions de sections `[features]`, `[dev-dependencies]` et `[build-dependencies]` ;
|
||||
- conserver l'exigence d'une seule section `[dependencies]` ;
|
||||
- extraire cette section puis réutiliser `manifest_dependency_names(...)` ;
|
||||
- vérifier l'inventaire exact des clés de dépendance : `ksp-core-lib` uniquement ;
|
||||
- ne modifier aucun manifeste de crate, source de production, type public ou dependency graph.
|
||||
|
||||
## Version
|
||||
|
||||
Le fix modifie une source Rust de test ; la version workspace devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.5.fix.1
|
||||
```
|
||||
|
||||
Le numéro documentaire reste :
|
||||
|
||||
```text
|
||||
0.3.5-pre.005-fix.001
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.005-fix.001.md
|
||||
```
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
138
deltas/0.3.5/pre.005.md
Normal file
138
deltas/0.3.5/pre.005.md
Normal file
@@ -0,0 +1,138 @@
|
||||
<!-- file: deltas/0.3.5/pre.005.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.005` — hardening et complétude Interface
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.4
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.004` est entièrement propre : audits Rust/Markdown, `cargo check --workspace`, Clippy, tests `ksp-interface-lib` et `ksp-program-api` passent.
|
||||
|
||||
## Version
|
||||
|
||||
La tranche ajoute/modifie des sources Rust de test/canari. La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.5
|
||||
```
|
||||
|
||||
## Mission
|
||||
|
||||
Fermer le hardening fonctionnel de `0.3.5` sans ajouter de troisième famille Interface ni modifier les contrats de production admis :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent / SlotLifecycleStage
|
||||
TransactionExecutionEvent / TransactionExecutionOutcome / TransactionSignature
|
||||
```
|
||||
|
||||
## Hardening adversarial
|
||||
|
||||
Le nouveau `tests/security_hardening.rs` vérifie :
|
||||
|
||||
- conservation byte-exact d'une signature hostile de 64 octets ;
|
||||
- redaction de la signature dans son `Debug` et dans celui de `TransactionExecutionEvent` ;
|
||||
- conservation de `u64::MAX` sans narrowing ;
|
||||
- structure minimale exacte des deux events ;
|
||||
- absence de collection/payload/timestamp/provider/endpoint/filter/network dans les contrats acquisition ;
|
||||
- absence de second RAW ou de famille reportée exportée silencieusement ;
|
||||
- non-régression des bornes `ProgramInstruction` historiques.
|
||||
|
||||
## Graphe et dépendances
|
||||
|
||||
`tests/dependency_boundary.rs` ajoute un canari final imposant :
|
||||
|
||||
```text
|
||||
une seule section [dependencies]
|
||||
exactement une référence ksp-core-lib
|
||||
aucune [features]
|
||||
aucune [dev-dependencies]
|
||||
aucune [build-dependencies]
|
||||
```
|
||||
|
||||
Le manifeste `ksp-interface-lib` reste inchangé et Core-only.
|
||||
|
||||
## Candidats reportés
|
||||
|
||||
Aucun candidat reporté n'est promu par hardening :
|
||||
|
||||
```text
|
||||
TransactionLogEvent -> idée différée
|
||||
TransactionCommitmentEvent -> reporté
|
||||
VoteEvent -> reporté
|
||||
LedgerEntryEvent -> reporté
|
||||
Account/Program RAW event -> rejet Interface
|
||||
Transaction complète -> rejet Interface
|
||||
Block event -> rejet Interface
|
||||
Persisted-data available -> Store API owner
|
||||
```
|
||||
|
||||
`TransactionLogEvent` devra être transféré vers TODO/IDEAS durable pendant `pre.007` s'il reste hors scope.
|
||||
|
||||
## Fichiers
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/tests/security_hardening.rs
|
||||
deltas/0.3.5/pre.005.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
crates/ksp-program-api/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## Validations exécutées dans l'environnement d'assemblage
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
```
|
||||
|
||||
## Validations non exécutées dans l'environnement d'assemblage
|
||||
|
||||
`cargo` n'est pas installé dans le sandbox d'assemblage. Restent donc à exécuter côté opérateur :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
## Décisions
|
||||
|
||||
- deux familles acquisition exactement restent admises ;
|
||||
- aucun contrat production n'est modifié ;
|
||||
- aucun nouveau bound métier n'est inventé ;
|
||||
- la signature reste une primitive passive fixe de 64 octets sans codec ;
|
||||
- aucune metadata source/provider n'entre dans Interface ;
|
||||
- aucun second RAW n'est créé ;
|
||||
- Program instruction foundation reste inchangée.
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
Aucune question fonctionnelle bloquante pour `pre.006`. La seule idée différée explicitement à conserver durablement est `TransactionLogEvent`.
|
||||
80
deltas/0.3.5/pre.006.md
Normal file
80
deltas/0.3.5/pre.006.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Delta `0.3.5-pre.006`
|
||||
|
||||
## Objet
|
||||
|
||||
Matérialiser le gate technique final de `0.3.5` après le hardening Interface et son fix de canari, sans rouvrir la surface fonctionnelle.
|
||||
|
||||
## Base
|
||||
|
||||
```text
|
||||
0.3.5-pre.005-fix.001
|
||||
workspace.package.version = 0.3.5-pre.5.fix.1
|
||||
```
|
||||
|
||||
## Gate d'entrée opérateur
|
||||
|
||||
Le gate du `2026-08-31` est propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 144 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
cargo test --workspace: PASS
|
||||
```
|
||||
|
||||
Les tests réseau/live et probes diagnostiques restent `ignored` conformément à leur contrat. Aucun test non ignoré n'échoue.
|
||||
|
||||
## Scope
|
||||
|
||||
`pre.006` ne modifie aucun code Rust, aucun manifeste de crate et aucun contrat Interface. Elle prépare uniquement le gate technique final prévu par `prompts/024-V0_3_5_START_PROMPT.md`.
|
||||
|
||||
La clôture doit établir :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -> ksp-core-lib uniquement
|
||||
aucune feature Interface
|
||||
aucune dev/build dependency Interface
|
||||
2 familles acquisition exactement
|
||||
aucun runtime/serde/codec/logging/Transport/Store dans Interface
|
||||
aucun duplicate dependency nouveau imputable à 0.3.5
|
||||
```
|
||||
|
||||
## Version
|
||||
|
||||
La version workspace devient :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.6
|
||||
```
|
||||
|
||||
## Fichiers
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.006.md
|
||||
```
|
||||
|
||||
Aucun autre fichier n'est modifié.
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree -p ksp-interface-lib -e features
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Aucun smoke réseau n'est requis par défaut.
|
||||
154
deltas/0.3.5/pre.007.md
Normal file
154
deltas/0.3.5/pre.007.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Delta `0.3.5-pre.007`
|
||||
|
||||
## Objet
|
||||
|
||||
Réconcilier la documentation durable avec la surface Interface réellement acquise après le gate technique final propre de `pre.006`, sans rouvrir le code ni les contrats publics.
|
||||
|
||||
## Base
|
||||
|
||||
```text
|
||||
0.3.5-pre.006
|
||||
workspace.package.version = 0.3.5-pre.6
|
||||
```
|
||||
|
||||
La base opérateur inclut les corrections locales de numéros d'en-tête signalées après l'overlay `pre.006` :
|
||||
|
||||
```text
|
||||
Cargo.toml header 389
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md header 8
|
||||
```
|
||||
|
||||
Ces corrections d'en-tête ne changent pas le contenu fonctionnel du gate validé.
|
||||
|
||||
## Gate d'entrée
|
||||
|
||||
Le gate `pre.006` est intégralement propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 145 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test --workspace: PASS
|
||||
```
|
||||
|
||||
Les graphes confirment :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -> ksp-core-lib uniquement
|
||||
aucune feature Interface
|
||||
aucune dev/build dependency Interface
|
||||
aucun duplicate dependency nouveau imputable à 0.3.5
|
||||
```
|
||||
|
||||
Les tests live/réseau et probes diagnostiques restent `ignored` conformément à leur contrat.
|
||||
|
||||
## Réconciliation
|
||||
|
||||
La documentation durable était encore partiellement figée sur la foundation Program-only :
|
||||
|
||||
```text
|
||||
README Interface -> rôle Program-only et affirmation « aucun événement runtime »
|
||||
USAGE Interface -> page explicitement matérialisée par 0.2.13
|
||||
architecture -> rôle Interface décrit surtout comme façade wire Program
|
||||
TransactionLogEvent -> idée différée encore enfermée dans le plan/validation de release
|
||||
```
|
||||
|
||||
`pre.007` corrige ces incohérences sans transformer Interface en runtime :
|
||||
|
||||
```text
|
||||
Program wire contracts -> Interface
|
||||
provider-neutral passive acquisition -> Interface lorsque convergence exacte démontrée
|
||||
rich HTTP/WS/gRPC/provider DTOs -> Transport
|
||||
persistent/replayable RAW -> Store API
|
||||
post-commit durable-data wake-up -> Store API
|
||||
converters Transport -> Interface -> composition/consumer
|
||||
backlog/recovery -> Store
|
||||
```
|
||||
|
||||
La surface durable documentée contient exactement les deux familles acquisition acquises :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent
|
||||
TransactionExecutionEvent
|
||||
```
|
||||
|
||||
`TransactionLogEvent` est transféré dans `docs/IDEAS.md` et reste soumis à un futur gate consumer + bornes + convergence multi-source.
|
||||
|
||||
## Version
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.7
|
||||
```
|
||||
|
||||
## Fichiers
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/IDEAS.md
|
||||
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
|
||||
docs/architecture/003-COMPONENT_CONTRACTS.md
|
||||
docs/architecture/004-COMPONENT_INVENTORY.md
|
||||
docs/architecture/005-DEPENDENCY_GRAPH.md
|
||||
docs/architecture/006-WIRE_AND_PROGRAM.md
|
||||
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajouté :
|
||||
|
||||
```text
|
||||
deltas/0.3.5/pre.007.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/**
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/tests/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
crates/ksp-program-api/**
|
||||
```
|
||||
|
||||
## Gate d'assemblage
|
||||
|
||||
Les contrôles statiques disponibles dans l'environnement d'assemblage sont propres :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 146 file(s))
|
||||
```
|
||||
|
||||
Aucun code Rust n'est modifié par cette tranche. Les commandes Cargo restent à confirmer dans le repository opérateur après application de l'overlay.
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Aucun smoke réseau n'est requis. Après gate propre, la tranche suivante est la préparation de publication minimale `0.3.5-pre.008`.
|
||||
177
deltas/0.3.5/pre.008-fix.001.md
Normal file
177
deltas/0.3.5/pre.008-fix.001.md
Normal file
@@ -0,0 +1,177 @@
|
||||
<!-- file: deltas/0.3.5/pre.008-fix.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-pre.008-fix.001` — enrichissement du prompt `0.3.6` et trajectoire Job/Worker
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.008
|
||||
workspace.package.version = 0.3.5-pre.8
|
||||
```
|
||||
|
||||
Ce fix est **strictement documentaire**. Il ne modifie aucun fichier Rust/build/runtime/config et ne change donc pas `workspace.package.version`.
|
||||
|
||||
`Cargo.toml` reste exactement celui de `pre.008` :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.8
|
||||
```
|
||||
|
||||
## Motif du fix
|
||||
|
||||
Le prompt `025` de `pre.008` était insuffisamment détaillé par rapport :
|
||||
|
||||
- aux règles de construction des prompts KSP ;
|
||||
- à la portée réelle attendue de `0.3.6` ;
|
||||
- aux fonctionnalités de backfill déjà présentes historiquement dans kbot3 ;
|
||||
- au besoin d'observabilité par une couche supérieure ;
|
||||
- à la trajectoire Worker qui doit reprendre le même pattern de notifications.
|
||||
|
||||
Il laissait également le nom de la crate concrète à décider alors que la direction est désormais fixée :
|
||||
|
||||
```text
|
||||
ksp-job-backfill-lib
|
||||
```
|
||||
|
||||
## Corrections du prompt `0.3.6`
|
||||
|
||||
Le prompt version 2 ouvre désormais explicitement :
|
||||
|
||||
```text
|
||||
ksp-job-api
|
||||
+
|
||||
ksp-job-backfill-lib
|
||||
+
|
||||
backfill RawTransaction historique fonctionnel
|
||||
+
|
||||
lifecycle/progression/outcome
|
||||
+
|
||||
notifications/listeners sûrs pour UI/composition
|
||||
```
|
||||
|
||||
### Archive kbot3
|
||||
|
||||
L'archive :
|
||||
|
||||
```text
|
||||
khadhroony-bot3_v0.5.3-pre.005-fix010.zip
|
||||
```
|
||||
|
||||
redevient **obligatoire en `0.3.6-pre.001`**, mais uniquement comme inventaire fonctionnel historique.
|
||||
|
||||
Le plan doit construire une matrice :
|
||||
|
||||
```text
|
||||
REPRENDRE FONCTIONNELLEMENT
|
||||
REDESSINER POUR KSP
|
||||
REPORTER
|
||||
REJETER
|
||||
```
|
||||
|
||||
Le code, les anciennes crates, DTOs, SQL, retries et choix runtime kbot3 ne sont pas à copier.
|
||||
|
||||
### Parité fonctionnelle minimale à réauditer
|
||||
|
||||
Le prompt rend explicites les invariants historiquement démontrés :
|
||||
|
||||
- scans latest/before/after/explicit selon audit ;
|
||||
- anchors et directions ;
|
||||
- candidats/pages dédupliqués ;
|
||||
- nearest-newer/gap-fill si conservé ;
|
||||
- frontier de complétion contiguë ;
|
||||
- reprise après cancellation sans saut ;
|
||||
- cancellation coopérative pendant RPC long et wait/backoff ;
|
||||
- ownership séparé du retry Transport et du retry Job ;
|
||||
- compteurs de campagne distinguant sélection, complétion, insert/idempotence/existing, missing et observations.
|
||||
|
||||
### Notifications Job
|
||||
|
||||
Le prompt exige désormais un vrai contrat d'observabilité `ksp-job-api` :
|
||||
|
||||
```text
|
||||
identity
|
||||
state/phase
|
||||
progress/snapshot
|
||||
checkpoint/frontier
|
||||
sequence ou ordre observable
|
||||
terminal outcome
|
||||
safe error code
|
||||
listener isolation/backpressure
|
||||
resynchronisation après perte/coalescing
|
||||
```
|
||||
|
||||
Ces notifications sont explicitement distinctes :
|
||||
|
||||
```text
|
||||
Interface acquisition events
|
||||
Store KSP-NOTIFY-* post-commit wake-ups
|
||||
logging/tracing
|
||||
```
|
||||
|
||||
Aucune dépendance Tokio/channel précise n'est imposée dans `ksp-job-api` avant l'audit `pre.001`.
|
||||
|
||||
### Alignement Worker futur
|
||||
|
||||
Le même pattern conceptuel devra être repris par `ksp-worker-api`, sans créer dès `0.3.6` une crate générique spéculative supplémentaire.
|
||||
|
||||
## Corrections du ROADMAP
|
||||
|
||||
La trajectoire RAW opérationnelle devient explicitement :
|
||||
|
||||
```text
|
||||
0.3.6 ksp-job-api + ksp-job-backfill-lib + notifications
|
||||
0.3.7 application backfill/inspection RAW
|
||||
0.3.8 ksp-worker-api
|
||||
0.3.9 ksp-worker-live-transactions-retriever-lib
|
||||
0.3.10 application monitoring/visualisation Jobs + Workers
|
||||
```
|
||||
|
||||
L'ancien placeholder générique « worker/service live ensuite » est supprimé au profit de releases nommées et ordonnées.
|
||||
|
||||
## Correction du CHANGELOG
|
||||
|
||||
Le paragraphe ouvrant `0.3.6` est aligné sur la portée réelle du prompt version 2 et sur la nouvelle trajectoire ROADMAP.
|
||||
|
||||
Aucune information sur le contenu fonctionnel déjà stabilisé de `0.3.5` n'est changée.
|
||||
|
||||
## Versions d'en-tête
|
||||
|
||||
```text
|
||||
CHANGELOG.md 24 -> 25
|
||||
ROADMAP.md 99 -> 100
|
||||
prompts/025-V0_3_6_START_PROMPT.md 1 -> 2
|
||||
deltas/0.3.5/pre.008-fix.001.md nouveau -> 1
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
Exactement :
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
deltas/0.3.5/pre.008-fix.001.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/**
|
||||
docs/architecture/**
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
## Gate demandé
|
||||
|
||||
Le fix ne modifie aucun Rust. Le gate minimal est :
|
||||
|
||||
```bash
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
```
|
||||
|
||||
Aucun rerun Cargo n'est requis par ce fix documentaire lui-même.
|
||||
112
deltas/0.3.5/pre.008.md
Normal file
112
deltas/0.3.5/pre.008.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Delta `0.3.5-pre.008`
|
||||
|
||||
## Objet
|
||||
|
||||
Préparer la publication de `0.3.5` après le gate technique final et la réconciliation documentaire propres, sans rouvrir le code ni les documents de conception de la release.
|
||||
|
||||
## Base
|
||||
|
||||
```text
|
||||
0.3.5-pre.007
|
||||
workspace.package.version = 0.3.5-pre.7
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.007` est propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 146 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
```
|
||||
|
||||
Le gate technique final `pre.006` avait déjà confirmé `cargo test --workspace` et les graphes Cargo Interface Core-only.
|
||||
|
||||
## Modifications
|
||||
|
||||
### Version workspace
|
||||
|
||||
```text
|
||||
0.3.5-pre.8
|
||||
```
|
||||
|
||||
Le numéro d'en-tête de `Cargo.toml` est incrémenté avec cette modification réelle.
|
||||
|
||||
### `CHANGELOG.md`
|
||||
|
||||
Ajout de l'entrée de release `0.3.5` décrivant :
|
||||
|
||||
- `SlotLifecycleEvent` et ses sept stages admis ;
|
||||
- `TransactionSignature`, `TransactionExecutionOutcome` et `TransactionExecutionEvent` ;
|
||||
- les frontières Transport / Interface / Store ;
|
||||
- le graphe Interface Core-only ;
|
||||
- les gates finaux propres ;
|
||||
- l'ouverture de `0.3.6` sur Job API + premier backfill RAW.
|
||||
|
||||
### `ROADMAP.md`
|
||||
|
||||
- `0.3.5` passe à terminé ;
|
||||
- `0.3.6` est précisé comme premier backfill RAW avec ownership Job de la policy/progression/checkpoint ;
|
||||
- les TODO historiques sont réconciliés avec les deux familles Interface réellement acquises ;
|
||||
- `TransactionLogEvent` reste une idée différée et `vote` reste hors Interface.
|
||||
|
||||
### Prompt suivant
|
||||
|
||||
Ajout de :
|
||||
|
||||
```text
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
```
|
||||
|
||||
Le prompt ouvre `0.3.6` sur :
|
||||
|
||||
```text
|
||||
ksp-job-api
|
||||
+ premier backfill historique RAW concret
|
||||
+ audit prioritaire RawTransaction par adresse
|
||||
+ getSignaturesForAddress -> getTransaction comme candidat
|
||||
+ policy/batch/progression/checkpoint/cancellation Job-owned
|
||||
```
|
||||
|
||||
L'archive historique kbot3 n'est pas requise pour cette release.
|
||||
|
||||
## Fichiers de la tranche
|
||||
|
||||
Exactement :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
deltas/0.3.5/pre.008.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/**
|
||||
docs/architecture/**
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
```
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Si ce gate reste propre, la tranche suivante est `0.3.5-rel.001` et doit être strictement mécanique : version stable `0.3.5`, delta de release et aucune correction fonctionnelle/documentaire.
|
||||
123
deltas/0.3.5/rel.001.md
Normal file
123
deltas/0.3.5/rel.001.md
Normal file
@@ -0,0 +1,123 @@
|
||||
<!-- file: deltas/0.3.5/rel.001.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.5-rel.001` — publication stable
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.5-pre.008
|
||||
workspace.package.version = 0.3.5-pre.8
|
||||
```
|
||||
|
||||
La base inclut le fix documentaire :
|
||||
|
||||
```text
|
||||
0.3.5-pre.008-fix.001
|
||||
```
|
||||
|
||||
dont le gate minimal est propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 149 file(s))
|
||||
```
|
||||
|
||||
Les gates techniques et documentaires précédents ont déjà fermé la release :
|
||||
|
||||
- `pre.006` : gate technique final complet, tests workspace et graphes Cargo Interface ;
|
||||
- `pre.007` : réconciliation documentaire finale ;
|
||||
- `pre.008` : lane minimale de publication ;
|
||||
- `pre.008-fix.001` : enrichissement documentaire du prompt `0.3.6` et de la trajectoire Job/Worker.
|
||||
|
||||
## Objet
|
||||
|
||||
Publier mécaniquement la version stable :
|
||||
|
||||
```text
|
||||
0.3.5
|
||||
```
|
||||
|
||||
Aucune correction fonctionnelle, architecturale ou documentaire n'est autorisée dans cette tranche.
|
||||
|
||||
## Modification
|
||||
|
||||
### `Cargo.toml`
|
||||
|
||||
Le numéro d'en-tête est incrémenté avec la modification réelle :
|
||||
|
||||
```text
|
||||
391 -> 392
|
||||
```
|
||||
|
||||
La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.8 -> 0.3.5
|
||||
```
|
||||
|
||||
Aucune autre ligne de `Cargo.toml` n'est modifiée.
|
||||
|
||||
## Surface publiée
|
||||
|
||||
`0.3.5` stabilise dans `ksp-interface-lib` les deux familles passives d'acquisition retenues par les gates de la release :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent
|
||||
TransactionExecutionEvent
|
||||
```
|
||||
|
||||
La surface reste provider-neutral, Core-only, sans runtime/event bus/serde/codec, sans duplication de la couche RAW Store et sans élargissement de la fondation Program existante.
|
||||
|
||||
Le prompt suivant déjà préparé reste :
|
||||
|
||||
```text
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
```
|
||||
|
||||
et ouvre `0.3.6` sur le développement parallèle de `ksp-job-api` et `ksp-job-backfill-lib`, avec reprise fonctionnelle du backfill historique kbot3 et notifications/listeners observables.
|
||||
|
||||
## Fichiers de la tranche
|
||||
|
||||
Exactement :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
deltas/0.3.5/rel.001.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
crates/**
|
||||
docs/**
|
||||
```
|
||||
|
||||
## Gate demandé
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
```
|
||||
|
||||
Après ce gate, la release stable peut être taguée :
|
||||
|
||||
```text
|
||||
v0.3.5
|
||||
```
|
||||
|
||||
La session suivante démarre depuis cette base stable en exécutant :
|
||||
|
||||
```text
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/IDEAS.md -->
|
||||
<!-- version: 26 -->
|
||||
<!-- version: 27 -->
|
||||
|
||||
# Idées à explorer
|
||||
|
||||
@@ -96,6 +96,14 @@ Aucun `ksp-data-api` global n'est prévu actuellement. Les modèles appartiennen
|
||||
|
||||
Réévaluer seulement si les premières implémentations montrent une duplication réellement nuisible impossible à résoudre sans contrat commun supplémentaire.
|
||||
|
||||
### Événement passif de logs transaction
|
||||
|
||||
**Status :** À explorer après la première surface d'événements Interface
|
||||
|
||||
Conserver `TransactionLogEvent` comme idée différée, sans type public tant qu'un consumer concret et des bornes sûres ne sont pas démontrés. Le futur gate doit comparer au minimum `logsSubscribe` et les formes transaction/meta des transports réellement consommés, sans supposer que leur richesse, leur volumétrie ou leur disponibilité sont identiques.
|
||||
|
||||
Un éventuel contrat partagé doit rester un fait passif provider-neutral, distinct de `TransactionExecutionEvent` et des logs replayables contenus dans `RawTransaction`. Il ne doit créer ni `RawLog` Store par défaut, ni event bus Interface, ni wrapper d'un DTO Transport.
|
||||
|
||||
### Mesure du trafic et metering futur
|
||||
|
||||
**Status :** À explorer plus tard
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/002-LAYERS_AND_DEPENDENCIES.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Couches et dépendances KSP
|
||||
|
||||
@@ -150,7 +150,7 @@ Les exécutables et couches supérieures n'importent pas directement les crates
|
||||
|
||||
Exceptions bas niveau explicitement autorisées restent limitées aux primitives stables décidées par les règles KSP.
|
||||
|
||||
`ksp-interface-lib` concentre les interfaces/wires officielles ou compatibles afin d'éviter les doublons de générations et les dépendances protocolaires dans les couches supérieures.
|
||||
`ksp-interface-lib` concentre les contrats passifs KSP réellement partagés — wires officiels/compatibles et faits provider-neutral admis — afin d'éviter les doublons de générations, les dépendances protocolaires dans les couches supérieures et la promotion accidentelle d'un DTO Transport en contrat transversal. Les converters depuis Transport restent dans la composition.
|
||||
|
||||
## Principe contract-first
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/003-COMPONENT_CONTRACTS.md -->
|
||||
<!-- version: 11 -->
|
||||
<!-- version: 12 -->
|
||||
|
||||
# Contrats initiaux des composants KSP
|
||||
|
||||
@@ -94,13 +94,13 @@ Il ne possède pas `WalletPolicy` ni les règles d'autorisation d'exécution.
|
||||
|
||||
Le wallet temporaire JSON historique n'est pas migré.
|
||||
|
||||
## Interface / wire
|
||||
## Interface / contrats passifs
|
||||
|
||||
`ksp-interface-lib` est la façade wire officielle KSP et expose aussi une API publique wire réutilisable par `ksp-program-lib` et les extensions Program externes.
|
||||
`ksp-interface-lib` possède les contrats passifs KSP réellement partagés entre composants : façade wire officielle lorsqu'un protocole commun l'exige, et faits d'acquisition provider-neutral lorsqu'une sémantique commune exacte est démontrée. Sa surface publique est réutilisable notamment par `ksp-program-lib`, les extensions Program externes et les composants de composition/acquisition qui ne doivent pas dépendre d'un DTO Transport particulier.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue actuellement.
|
||||
|
||||
La crate sélectionne entre réexport contrôlé, wrapper ou implémentation wire compatible selon stabilité, ownership et graphe de dépendances des interfaces externes.
|
||||
La crate sélectionne entre réexport contrôlé, wrapper ou implémentation KSP-owned selon stabilité, ownership et graphe de dépendances. Elle ne possède ni Transport/runtime, ni Store/persistence, ni event bus ; les conversions depuis les DTOs Transport restent dans la composition.
|
||||
|
||||
## Program
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/004-COMPONENT_INVENTORY.md -->
|
||||
<!-- version: 26 -->
|
||||
<!-- version: 27 -->
|
||||
|
||||
# Inventaire initial des composants KSP
|
||||
|
||||
@@ -32,7 +32,7 @@ Ce document maintient l'inventaire synthétique des composants retenus ou presse
|
||||
| Yellowstone | `ksp-onchain-transport-lib` | lib | Stable | `0.2.9` | client gRPC standard/provider-neutral |
|
||||
| Off-chain price | `ksp-offchain-transport-lib` | lib | Stable | `0.2.11` | prix SOL/USD multi-provider, limits et availability |
|
||||
| SOL Prices Desk | `ksp-app-solprices-desk` | app | Stable | `0.2.12` | HID provider-agnostic pour visualisation/refresh prix |
|
||||
| Wire | `ksp-interface-lib` | lib | Stable | `0.2.13` | façade wire officielle + API publique wire |
|
||||
| Interface passive | `ksp-interface-lib` | lib | Stable | `0.2.13` | façade wire + contrats passifs partagés, dont événements acquisition provider-neutral |
|
||||
| Program API | `ksp-program-api` | API | Stable | `0.2.14` | contrats extensibles Program |
|
||||
| Program impl. | `ksp-program-lib` | lib | Retenu | vertical slices ultérieurs | implementations Program officielles |
|
||||
| Program extension | `ksp-program-<name>-lib` | lib externe | À la demande | dès besoin | implementation externe de `ksp-program-api` |
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/005-DEPENDENCY_GRAPH.md -->
|
||||
<!-- version: 17 -->
|
||||
<!-- version: 18 -->
|
||||
|
||||
# Graphe de dépendances KSP
|
||||
|
||||
@@ -169,16 +169,17 @@ Le Wallet stocke/ouvre/signe. Il ne décide pas si une dépense est autorisée.
|
||||
|
||||
`WalletPolicy` historique migre conceptuellement vers execution policy, pas vers `ksp-wallet-lib`.
|
||||
|
||||
## Interface / wire
|
||||
## Interface / contrats passifs
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
-> ksp-core-lib
|
||||
-> ksp-logging-lib lorsque runtime logging réel
|
||||
-> official/compatible wire dependencies retenues
|
||||
-> official/compatible wire dependencies uniquement lorsqu'un protocole réel les exige
|
||||
```
|
||||
|
||||
`ksp-interface-lib` contient **à la fois** la façade wire officielle et une API publique wire utilisable par les implémentations Program officielles/externes.
|
||||
`ksp-interface-lib` contient la façade wire officielle **et** les contrats passifs KSP-owned dont la sémantique est réellement partagée, y compris des faits d'acquisition provider-neutral. Les composants Program et les composants de composition peuvent consommer ces contrats sans importer un runtime Transport.
|
||||
|
||||
Un événement passif n'autorise aucune dépendance Interface vers Transport, Store, worker/job ou logging runtime. Les converters depuis des DTOs Transport restent dans la composition.
|
||||
|
||||
Aucune `ksp-interface-api` séparée n'est retenue actuellement.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/006-WIRE_AND_PROGRAM.md -->
|
||||
<!-- version: 2 -->
|
||||
<!-- version: 3 -->
|
||||
|
||||
# Wire, Program API et implémentations Program
|
||||
|
||||
@@ -22,7 +22,7 @@ Les types Rust exacts restent volontairement à définir lors de la première im
|
||||
|
||||
## `ksp-interface-lib`
|
||||
|
||||
`ksp-interface-lib` est la façade wire officielle KSP pour les programmes Solana supportés officiellement.
|
||||
`ksp-interface-lib` est la façade des contrats passifs KSP réellement partagés. Elle possède notamment les wires officiels nécessaires aux programmes Solana supportés et peut aussi posséder des faits d'acquisition provider-neutral lorsqu'ils ne sont ni des DTOs Transport ni des modèles persistants Store.
|
||||
|
||||
Elle possède ou réexporte de manière contrôlée les contrats nécessaires tels que :
|
||||
|
||||
@@ -38,29 +38,51 @@ Les Program IDs fondamentaux restent possédés par `ksp-core-lib`.
|
||||
|
||||
`ksp-interface-lib` ne possède pas :
|
||||
|
||||
- RPC/WS/provider ;
|
||||
- wallet/signature ;
|
||||
- persistence ;
|
||||
- RPC/WS/gRPC/provider DTOs ou sessions ;
|
||||
- event bus, worker, job ou scheduler ;
|
||||
- wallet/signature capability ;
|
||||
- persistence, Store, cursor ou retention ;
|
||||
- matérialisation ;
|
||||
- interprétation canonique/métier d'une instruction ;
|
||||
- policy/safety ;
|
||||
- lifecycle d'exécution réseau.
|
||||
|
||||
Les événements d'acquisition admis dans Interface sont de simples faits passifs supplémentaires. Ils ne remplacent pas le DTO Transport riche et leurs conversions appartiennent à la composition qui connaît les deux contrats.
|
||||
|
||||
## API publique de `ksp-interface-lib`
|
||||
|
||||
`ksp-interface-lib` reste une seule crate pour l'instant : aucune `ksp-interface-api` séparée n'est créée.
|
||||
|
||||
La façade doit néanmoins exposer une API publique wire stable et réutilisable par :
|
||||
La façade doit néanmoins exposer une API publique stable et réutilisable par :
|
||||
|
||||
```text
|
||||
ksp-program-lib
|
||||
external ksp-program-<name>-lib
|
||||
compositions/acquisition consumers utilisant un fait passif partagé
|
||||
```
|
||||
|
||||
Une implementation externe peut donc expérimenter contre les mêmes contrats wire publics avant intégration officielle dans KSP. Lorsqu'un wire externe devient officiel, son intégration dans `ksp-interface-lib` doit rester compatible avec l'API publique retenue, sauf évolution de contrat explicitement versionnée/documentée.
|
||||
|
||||
Si une future contrainte de dépendances démontre qu'un split `ksp-interface-api` apporte une valeur réelle, il pourra être étudié selon `KSP-API-007`; la symétrie avec Program ne suffit pas.
|
||||
|
||||
## Événements passifs d'acquisition
|
||||
|
||||
Interface peut posséder un événement d'acquisition seulement si plusieurs sources/consumers partagent exactement le même fait et que le type reste plus petit que les DTOs producteurs. Le contrat ne doit pas accumuler des champs `Option` pour simuler l'union de protocoles hétérogènes.
|
||||
|
||||
La frontière durable est :
|
||||
|
||||
```text
|
||||
DTO Transport riche et lossless
|
||||
|
|
||||
| conversion explicite par composition/consumer
|
||||
v
|
||||
événement Interface passif provider-neutral
|
||||
```
|
||||
|
||||
Un événement Interface ne devient ni un message de bus obligatoire ni une donnée durable. Les informations replayables appartiennent à `ksp-store-api`; les détails de transport, provider, commitment, session, timestamp source-specific et diagnostics qui ne font pas partie du fait commun restent Transport-owned.
|
||||
|
||||
Les familles actuellement démontrées sont le lifecycle de slot et le résultat d'exécution d'une transaction. Toute nouvelle famille exige un nouveau gate de convergence, consumer et bornes.
|
||||
|
||||
## Propriété des codecs wire
|
||||
|
||||
Pour le code KSP officiel, les dépendances directement utilisées pour encoder/décoder les formats wire, notamment `borsh`, `wincode` ou codecs équivalents, appartiennent normalement à `ksp-interface-lib`.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!-- file: docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md -->
|
||||
<!-- version: 7 -->
|
||||
<!-- version: 8 -->
|
||||
|
||||
# Acquisition, workers, jobs et pipelines spécialisés
|
||||
|
||||
@@ -353,11 +353,14 @@ ksp-job-backfill
|
||||
ksp-worker-raw-retriever
|
||||
-> ksp-worker-api
|
||||
-> ksp-onchain-transport-lib
|
||||
-> ksp-interface-lib # seulement si un fait passif partagé aide la composition live
|
||||
-> ksp-store-lib # façade Store ; backend sélectionné par feature + Config
|
||||
-> ksp-config-lib
|
||||
-> ksp-logging-lib
|
||||
```
|
||||
|
||||
Les événements Interface peuvent servir de signal provider-neutral à la composition live, mais ne constituent jamais le backlog durable. Après crash ou perte d'un événement, la reprise s'appuie sur Store et sur les primitives de replay/hydratation appropriées.
|
||||
|
||||
### CORE replay/worker
|
||||
|
||||
```text
|
||||
|
||||
757
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
Normal file
757
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
Normal file
@@ -0,0 +1,757 @@
|
||||
<!-- file: docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md -->
|
||||
<!-- version: 4 -->
|
||||
|
||||
# Plan `0.3.5` — Interface passive acquisition events
|
||||
|
||||
## 1. Statut de la release
|
||||
|
||||
Base canonique auditée :
|
||||
|
||||
```text
|
||||
v0.3.4
|
||||
workspace.package.version = 0.3.4
|
||||
```
|
||||
|
||||
Version de travail à la réconciliation documentaire finale :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.7
|
||||
label = 0.3.5-pre.007
|
||||
```
|
||||
|
||||
La release est fonctionnellement fermée. `pre.001` a ouvert l'audit ; son fix a établi l'intersection exacte de sept stages slot et rouvert le candidat transaction execution. `pre.002` a matérialisé `SlotLifecycleEvent`, `pre.003` a admis `TransactionExecutionEvent`, `pre.004`/`pre.005` ont fermé les canaris de complétude et le hardening, puis `pre.006` a validé le gate workspace et le graphe Cargo final.
|
||||
|
||||
`pre.007` ne modifie aucun contrat Rust. Elle réconcilie les documents durables avec la surface réellement acquise et transfère l'idée `TransactionLogEvent` vers `docs/IDEAS.md` au lieu de laisser un TODO caché dans le plan de release.
|
||||
|
||||
## 2. Mission
|
||||
|
||||
La release doit étendre `ksp-interface-lib` seulement lorsqu'un consumer de composition peut recevoir un fait passif KSP-owned sans dépendre du protocole producteur et sans créer un second modèle RAW.
|
||||
|
||||
Le contrat cible reste :
|
||||
|
||||
```text
|
||||
producer Transport
|
||||
-> DTO Transport riche et lossless
|
||||
-> conversion explicite à la composition
|
||||
-> fait Interface passif minimal, seulement si la sémantique commune est prouvée
|
||||
```
|
||||
|
||||
Le type Interface ne remplace jamais le DTO Transport. Les informations source-specific qui ne font pas partie du fait commun restent disponibles sur le DTO Transport et ne sont pas copiées dans Interface.
|
||||
|
||||
## 3. Sources relues
|
||||
|
||||
### 3.1 Sources internes
|
||||
|
||||
Le gate a relu les familles prescrites par le prompt :
|
||||
|
||||
```text
|
||||
RULES.md
|
||||
docs/000-README.md
|
||||
|
||||
docs/rules/RULES_GENERAL.md
|
||||
docs/rules/RULES_KSP.md
|
||||
docs/rules/RULES_RUST.md
|
||||
docs/rules/RULES_DEPENDENCIES.md
|
||||
docs/rules/RULES_DOCUMENTATION.md
|
||||
docs/rules/FILE_CONTRACTS.md
|
||||
docs/rules/VERSION_WORKFLOW.md
|
||||
docs/rules/PROMPT_STRUCTURE.md
|
||||
|
||||
docs/architecture/000-README.md
|
||||
docs/architecture/001-PROJECT_OBJECTIVES.md
|
||||
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
|
||||
docs/architecture/003-COMPONENT_CONTRACTS.md
|
||||
docs/architecture/004-COMPONENT_INVENTORY.md
|
||||
docs/architecture/005-DEPENDENCY_GRAPH.md
|
||||
docs/architecture/006-WIRE_AND_PROGRAM.md
|
||||
docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md
|
||||
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
|
||||
docs/architecture/010-APPS_SERVICES_SCENARIOS_AND_CONTROL.md
|
||||
|
||||
docs/plans/020-V0_2_13_INTERFACE_PLAN.md
|
||||
docs/validation/016-V0_2_13_INTERFACE.md
|
||||
docs/plans/022-V0_3_1_STORE_RAW_PLAN.md
|
||||
docs/validation/018-V0_3_1_STORE_RAW.md
|
||||
docs/plans/023-V0_3_2_STORE_POSTGRES_FOUNDATION_PLAN.md
|
||||
docs/plans/024-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION_PLAN.md
|
||||
docs/plans/025-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT_PLAN.md
|
||||
docs/validation/019-V0_3_2_STORE_POSTGRES_FOUNDATION.md
|
||||
docs/validation/020-V0_3_3_STORE_POSTGRES_RAW_TRANSACTION.md
|
||||
docs/validation/021-V0_3_4_STORE_POSTGRES_RAW_ACCOUNT.md
|
||||
```
|
||||
|
||||
Les sources Rust relues couvrent `ksp-interface-lib`, `ksp-store-api`, la façade/backend Store et les modules HTTP/WS/gRPC/Helius event-like de `ksp-onchain-transport-lib` demandés par le prompt.
|
||||
|
||||
### 3.2 Surface Interface/Store stable constatée
|
||||
|
||||
Inventaire crate-root actuel de `ksp-interface-lib` :
|
||||
|
||||
```text
|
||||
Pubkey
|
||||
ProgramAccountMeta
|
||||
ProgramInstruction
|
||||
MAX_PROGRAM_INSTRUCTION_ACCOUNTS
|
||||
MAX_PROGRAM_INSTRUCTION_DATA_LEN
|
||||
ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED
|
||||
```
|
||||
|
||||
Modules de production actuels :
|
||||
|
||||
```text
|
||||
error
|
||||
program_account_meta
|
||||
program_instruction
|
||||
```
|
||||
|
||||
Le manifeste Interface ne possède qu'une dependency normale :
|
||||
|
||||
```text
|
||||
ksp-core-lib
|
||||
```
|
||||
|
||||
Le consumer runtime/public actuel identifié est `ksp-program-api`, qui réutilise `ProgramAccountMeta` et `ProgramInstruction`. Aucun consumer actuel n'impose encore un event d'acquisition.
|
||||
|
||||
La surface Store stable expose exactement dix capabilities RAW :
|
||||
|
||||
```text
|
||||
RawTransactionRead
|
||||
RawTransactionWrite
|
||||
RawTransactionObservationRead
|
||||
RawTransactionObservationWrite
|
||||
RawTransactionRetentionRead
|
||||
RawTransactionRetentionWrite
|
||||
RawAccountStateRead
|
||||
RawAccountStateWrite
|
||||
RawAccountObservationRead
|
||||
RawAccountObservationWrite
|
||||
```
|
||||
|
||||
### 3.3 Sources externes courantes auditées le 2026-08-31
|
||||
|
||||
L'audit externe a porté sur les documents normatifs/courants suivants :
|
||||
|
||||
```text
|
||||
Solana RPC WebSocket:
|
||||
- slotSubscribe
|
||||
- slotsUpdatesSubscribe
|
||||
- rootSubscribe / index WebSocket
|
||||
- signatureSubscribe
|
||||
- logsSubscribe
|
||||
- voteSubscribe
|
||||
- accountSubscribe
|
||||
- programSubscribe
|
||||
|
||||
Solana RPC HTTP:
|
||||
- getSignatureStatuses
|
||||
- getTransaction
|
||||
- getBlock
|
||||
|
||||
Yellowstone gRPC upstream et version KSP :
|
||||
- KSP stable déclare `yellowstone-grpc-proto = ^12.6`
|
||||
- geyser.proto / SlotStatus / SubscribeUpdateSlot
|
||||
- transaction_status
|
||||
- account / transaction / block / block_meta / entry update families
|
||||
- upstream courant comparé pour vérifier que l'intersection SlotStatus retenue n'est pas une hypothèse obsolète
|
||||
|
||||
Helius:
|
||||
- LaserStream-powered standard WebSockets
|
||||
- Enhanced WebSocket transactionSubscribe
|
||||
```
|
||||
|
||||
Les conclusions externes qui structurent le plan sont :
|
||||
|
||||
- `slotSubscribe` signale le traitement d'un nouveau slot et transporte `slot`, `parent` et le root courant ;
|
||||
- `slotsUpdatesSubscribe` est instable et publie `firstShredReceived`, `completed`, `createdBank`, `frozen`, `dead`, `optimisticConfirmation` et `root`, avec metadata conditionnelle ;
|
||||
- Yellowstone expose `Processed`, `Confirmed`, `Finalized`, `FirstShredReceived`, `Completed`, `CreatedBank` et `Dead` ;
|
||||
- `signatureSubscribe` est un abonnement one-shot à une signature, éventuellement précédé de `receivedSignature`, et n'est pas un snapshot HTTP ;
|
||||
- `getSignatureStatuses` reste un snapshot queryable avec confirmations/status/confirmationStatus ;
|
||||
- `voteSubscribe` publie des votes gossip pré-consensus, sans garantie qu'ils entrent dans le ledger ;
|
||||
- Helius conserve les méthodes standard Solana et possède en plus des extensions Enhanced WebSocket, notamment `transactionSubscribe`, qui restent provider-specific.
|
||||
|
||||
## 4. Invariants d'ownership
|
||||
|
||||
Les règles directement structurantes restent :
|
||||
|
||||
```text
|
||||
KSP-TRANSPORT-002..004
|
||||
KSP-STORE-001..002
|
||||
KSP-NOTIFY-001..006
|
||||
KSP-PROC-007..008
|
||||
KSP-REL-005..016
|
||||
DEP-KSP-*
|
||||
DEP-LOG-*
|
||||
DEP-STORE-*
|
||||
DEP-WORKER-*
|
||||
DEP-JOB-*
|
||||
```
|
||||
|
||||
Le graphe cible reste :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Et les frontières restent :
|
||||
|
||||
```text
|
||||
Interface -X-> Transport
|
||||
Interface -X-> Store API / Store
|
||||
Interface -X-> Program API / Program Lib
|
||||
Interface -X-> Config / Wallet
|
||||
Transport -X-> Store API
|
||||
Store API -X-> Transport
|
||||
composition supérieure = owner des conversions
|
||||
```
|
||||
|
||||
`ksp-program-api` reste un consumer de la surface Program-facing existante de `ksp-interface-lib`. Il n'a aucune raison de re-exporter les futurs événements d'acquisition.
|
||||
|
||||
## 5. Critères d'admission d'une famille Interface
|
||||
|
||||
Une famille n'est admise que si toutes les conditions suivantes sont vraies :
|
||||
|
||||
1. le type est passif et ne possède aucun lifecycle/runtime ;
|
||||
2. le fait est provider-neutral ;
|
||||
3. il ne duplique pas un modèle persistant/replayable de `ksp-store-api` ;
|
||||
4. l'intersection sémantique entre producers est précise et documentable ;
|
||||
5. au moins deux producers/converters peuvent produire exactement ce fait, ou plusieurs consumers ont un besoin identique déjà démontré ;
|
||||
6. le type n'est pas une union d'options destinée à masquer des sémantiques différentes ;
|
||||
7. les détails non communs peuvent rester sur les DTOs Transport sans forcer Interface à devenir lossless pour le protocole source ;
|
||||
8. un usage de composition proche est identifiable.
|
||||
|
||||
Une égalité de noms ne suffit pas. Une proximité de commitment ne suffit pas. Une possibilité théorique de conversion ne suffit pas.
|
||||
|
||||
## 6. Inventaire producer -> nature de fait
|
||||
|
||||
| Producer / surface | Nature du fait | Champs structurants obligatoires | Optionalité utile | Ordre / lifecycle | Timestamp semantics | Error semantics | Metadata session/provider | Volume potentiel | Persistent/replayable ? |
|
||||
| -------------------------------------- | ----------------------------------- | ----------------------------------------------------- | --------------------------------- | ------------------------------------------------- | ----------------------------------------- | -------------------------------------- | -------------------------------------- | --------------------- | --------------------------------------- |
|
||||
| Solana WS `slotSubscribe` | progression de slot | slot, parent, root | aucune | event répété à chaque slot traité | aucun | aucune | subscription id hors DTO métier | minime | non |
|
||||
| Solana WS `rootSubscribe` | progression de root | root slot | aucune | event répété lors du changement de root | aucun | aucune | subscription id | minime | non |
|
||||
| Solana WS `slotsUpdatesSubscribe` | lifecycle interne slot | slot, type, timestamp | parent/stats/error selon variante | multi-event par slot ; méthode instable | Unix update timestamp en ms | texte seulement pour `dead` | subscription id | faible à modéré | non |
|
||||
| Solana WS `logsSubscribe` | logs transaction realtime | signature, err, logs + context slot | err nullable | flux continu selon filtre/commitment | aucun provider timestamp | opaque RPC transaction error | filtre + commitment + subscription id | logs non bornés wire | non par défaut |
|
||||
| Solana WS `signatureSubscribe` | réception/terminal signature | signature en request ; context slot + result en event | received précoce | one-shot terminal ; reçu optionnel avant terminal | aucun | transaction error au terminal | commitment/request/subscription | minime | non |
|
||||
| Solana HTTP `getSignatureStatuses` | snapshot de status | signatures request ; slot/status/confirmationStatus | nulls/confirmations | requête ponctuelle, pas une transition | aucun | transaction error dans snapshot | search history request policy | faible | queryable côté node, pas event KSP |
|
||||
| Solana WS `voteSubscribe` | vote gossip pré-consensus | votePubkey, slots, hash, signature | timestamp | flux gossip ; aucune garantie ledger | timestamp vote optionnel | aucune erreur transaction canonique | subscription id | faible | non |
|
||||
| Solana WS `accountSubscribe` | changement d'état account | context slot + account payload | selon encoding/dataSlice | flux d'état selon commitment | aucun | payload account, pas error event | commitment/encoding/subscription | potentiellement élevé | peut alimenter `RawAccountState` |
|
||||
| Solana WS `programSubscribe` | changement account d'un programme | context + pubkey + account payload | selon encoding/filters | flux d'état filtré | aucun | payload account | program/filter/commitment/subscription | potentiellement élevé | peut alimenter `RawAccountState` |
|
||||
| Solana WS `blockSubscribe` | bloc/transactions realtime | slot/context + block ou erreur | block nullable | flux de blocs selon config | blockTime dans payload si présent | RPC/block error | filter/config/subscription | très élevé | conteneur d'acquisition |
|
||||
| Yellowstone `Slot` | lifecycle/commitment slot | slot, status | parent/dead_error/created_at | plusieurs statuts possibles par slot | `created_at` = création serveur update | dead diagnostic optionnel | filter echo + server metadata | faible | non |
|
||||
| Yellowstone `TransactionStatus` | update execution/status transaction | slot, signature, is_vote, index | err/created_at | flux transaction status | server `created_at` | erreur transaction encodée | filter echo | faible | non par lui-même |
|
||||
| Yellowstone `Account` | état account + provenance Geyser | account bytes/info + slot + is_startup | txn signature/created_at | flux state/replay startup | server `created_at` | decode/transport error hors payload | filters + write/version metadata | potentiellement élevé | peut alimenter `RawAccountState` |
|
||||
| Yellowstone `Transaction` | transaction complète + meta | slot + transaction info/meta | created_at | flux transaction | server `created_at` | transaction meta error | filters + transaction index | très élevé | peut alimenter `RawTransaction` |
|
||||
| Yellowstone `Block` / `BlockMeta` | bloc / metadata de bloc | slot + block/meta fields | champs block spécifiques | flux block/meta | server `created_at` | payload/meta-specific | filters | très élevé | conteneur d'acquisition |
|
||||
| Yellowstone `Entry` | entry Geyser | slot/index/entry-specific fields | created_at | flux protocol-specific | server `created_at` | protocol-specific | filters | modéré | non retenu |
|
||||
| Helius standard WebSocket | mêmes faits standard Solana | mêmes champs standard | mêmes optionalités | même wire sémantique, runtime provider différent | mêmes semantics Solana | mêmes semantics Solana | Helius session/runtime | selon méthode | suit la famille standard |
|
||||
| Helius Enhanced `transactionSubscribe` | transaction provider-filtered | slot/signature ou transaction selon details | options/detail modes | extension provider continue | provider payload semantics | provider/RPC semantics | filtres Helius + options + session | faible à très élevé | acquisition possible, Transport-owned |
|
||||
| Store notification after commit | wake-up de donnée durable | future référence durable compacte | à définir avec publisher/consumer | après commit ; jamais source de vérité | non requis par le contrat normatif actuel | code safe éventuel, pas payload source | mécanisme de diffusion indépendant | minime | référence une persistence déjà commitée |
|
||||
|
||||
### 6.1 Consumers actuels et imminents
|
||||
|
||||
| Consumer | Besoin actuel / prévu | Dépendance à Interface event | Décision `pre.001` |
|
||||
| ----------------------------------------- | --------------------------------------------------------- | ---------------------------- | ------------------------------------------------------------------------- |
|
||||
| `ksp-program-api` | ProgramInstruction / ProgramAccountMeta | non | préserver la surface Program existante ; aucun re-export acquisition |
|
||||
| `0.3.6` premier backfill RAW | range historique -> Transport -> RAW ingestion -> Store | non | ne pas forcer SlotLifecycle dans le backfill |
|
||||
| futur worker RAW live | subscriptions/fetch live multi-transport -> RAW ingestion | oui, candidat concret | consumer proche justifiant une projection slot lifecycle provider-neutral |
|
||||
| futurs processors CORE/DECODE/SPECIALIZED | backlog Store + wake-up post-commit | non pour event réseau | consommer Store/backlog ; ne pas détourner les events réseau |
|
||||
| apps de contrôle/inspection futures | observabilité et commandes de composants | non démontré | aucun type Interface ajouté uniquement pour une UI future |
|
||||
|
||||
## 7. Matrice de convergence sémantique
|
||||
|
||||
| Nature candidate | Sources comparées | Intersection exacte retenue | Différences non représentables sans perte | Projection commune lossless pour le fait ciblé ? | Consumer concret | Owner | Décision |
|
||||
| ----------------------------- | --------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------ | ----------------------------- | ------------------------------ | ------------------- |
|
||||
| lifecycle slot | slotSubscribe + slotsUpdates + rootSubscribe + Yellowstone Slot | Processed, FirstShredReceived, Completed, CreatedBank, Dead, OptimisticallyConfirmed, Rooted | Frozen ; parent/timestamps/diagnostics ; noms wire Confirmed/Finalized côté Yellowstone | oui, pour l'occurrence `slot + stage` | futur worker RAW live | Interface | ADMIS |
|
||||
| transaction execution | logsSubscribe + Yellowstone TransactionStatus + Helius transactionSubscribe | `slot + TransactionSignature + Succeeded/Failed` | metadata/provider/detail modes ; commitment/delivery ; erreur source | oui pour le fait d'exécution observée | futur worker RAW live | Interface | ADMIS `pre.003` |
|
||||
| logs realtime | logsSubscribe + transaction/meta Yellowstone/Helius | logs associés à une transaction | volume/bornes, richesse de source, disponibilité selon détail | non admis dans cette release sans consumer/bornes | hydratation possible | Interface si futur gate | IDÉE DIFFÉRÉE |
|
||||
| signature commitment/snapshot | getSignatureStatuses + signatureSubscribe | identité de signature seulement | snapshot HTTP vs transition one-shot commitment | non comme event d'exécution | aucun contrat unique démontré | Transport | REPORTÉ |
|
||||
| vote | voteSubscribe + Yellowstone transaction `is_vote` | qualificatif « vote » seulement | gossip pré-consensus vs transaction exécutée | non | aucun besoin commun démontré | Transport | REPORTÉ |
|
||||
| account/program | WS account/program + Yellowstone Account | état account complet possible | persistance/replay déjà possédés par RawAccountState/Observation | non comme event distinct | RAW ingestion | Store/Transport | REJET Interface |
|
||||
| transaction complète | HTTP/WS/Helius/Yellowstone transaction | transaction complète selon source | format/commitment/provider metadata ; RawTransaction déjà canonique Store | non comme second type | RAW ingestion | Store/Transport | REJET Interface |
|
||||
| block | getBlock/blockSubscribe/Yellowstone Block | slot + block container | payloads/options/reconstruction ; pas de consumer passif minimal prouvé | non | extraction RAW transaction | Transport | REJET Interface |
|
||||
| Yellowstone Entry | Yellowstone aujourd'hui | aucune multi-source démontrée | mono-producer et protocole-specific aujourd'hui | non aujourd'hui ; futur fait transversal -> Interface | aucun actuel | Transport DTO | REPORTÉ |
|
||||
| persisted-data available | Store after commit | référence durable compacte conceptuelle | event réseau sans relation ; owner déjà normé par KSP-NOTIFY | oui mais hors owner Interface | processors futurs | Store API | REJET Interface |
|
||||
| Helius Enhanced transaction | Helius transactionSubscribe | peut produire `TransactionExecutionEvent` lorsque signature/slot/outcome sont déterminables | filtres/options/provider behavior et DTO riche | DTO non ; projection sémantique admise via converter | futur worker RAW live | Transport DTO / Interface fact | PRODUCTEUR ADMIS |
|
||||
|
||||
### 7.1 Lifecycle de slot — ADMIS sous intersection stricte
|
||||
|
||||
| Fait commun | Solana standard | Yellowstone | Stage KSP | Décision Interface | Metadata volontairement non commune |
|
||||
| ------------------------ | --------------------------------------- | -------------------- | ------------------------- | ------------------ | ------------------------------------------------------------------------------ |
|
||||
| slot traité | `slotSubscribe` | `Processed` | `Processed` | ADMIS | parent/root courant côté WS ; filters/created_at/parent côté Yellowstone |
|
||||
| premier shred reçu | `FirstShredReceived` | `FirstShredReceived` | `FirstShredReceived` | ADMIS | timestamp WS ; created_at/filters côté Yellowstone |
|
||||
| ingestion slot complétée | `Completed` | `Completed` | `Completed` | ADMIS | timestamp WS ; created_at/filters côté Yellowstone |
|
||||
| bank créé | `CreatedBank` | `CreatedBank` | `CreatedBank` | ADMIS | parent requis WS, optionnel Yellowstone ; il reste dans le DTO Transport riche |
|
||||
| slot mort | `Dead` | `Dead` | `Dead` | ADMIS | diagnostics source-specific et horodatages restent Transport |
|
||||
| confirmation optimiste | `OptimisticConfirmation` | `Confirmed` | `OptimisticallyConfirmed` | ADMIS | le nom KSP conserve la sémantique Solana ; delivery reste Transport |
|
||||
| root atteint | `rootSubscribe` / `slotsUpdates` `Root` | `Finalized` | `Rooted` | ADMIS | le nom KSP évite de généraliser `Finalized` au-delà du mapping audité |
|
||||
| frozen | `Frozen` | aucun statut exact | — | REJETÉ | pas d'intersection |
|
||||
|
||||
Le fait commun est volontairement plus petit que chaque DTO producteur. La conversion **n'efface pas** le DTO Transport : elle ajoute une projection passive `slot + stage` pour les consumers qui n'ont besoin que de l'occurrence de l'étape commune.
|
||||
|
||||
Le timestamp n'entre pas dans le contrat commun : `slotsUpdatesSubscribe.timestamp` décrit l'horodatage Unix de l'update côté validator alors que `YellowstoneUpdateTimestamp` est une metadata de création serveur. Les réunir sous un seul champ produirait une fausse équivalence.
|
||||
|
||||
Le `parent`, le root courant exposé comme metadata de certaines notifications, `dead_error` et les détails de delivery restent source-owned ; un consumer qui en a besoin doit conserver le DTO Transport ou définir un contrat supérieur spécifique. Les mappings `OptimisticConfirmation -> OptimisticallyConfirmed <- Yellowstone Confirmed` et `Root -> Rooted <- Yellowstone Finalized` sont des normalisations sémantiques documentées, pas des renommages universels des commitments Solana.
|
||||
|
||||
### 7.2 Transaction execution — ADMIS `pre.003`
|
||||
|
||||
`pre.003` confirme que l'**exécution observée d'une transaction** est distincte des snapshots/commitments de signature et possède une intersection multi-producer compacte :
|
||||
|
||||
```text
|
||||
Solana logsSubscribe
|
||||
-> context slot + signature base58 + err
|
||||
|
||||
Yellowstone TransactionStatus
|
||||
-> slot + signature [u8; 64] + err + metadata Yellowstone
|
||||
|
||||
Helius transactionSubscribe
|
||||
-> slot + signature + résultat d'exécution lorsque le detail mode expose l'erreur
|
||||
```
|
||||
|
||||
Le contrat admis est :
|
||||
|
||||
```text
|
||||
TransactionSignature([u8; 64])
|
||||
|
||||
TransactionExecutionOutcome {
|
||||
Succeeded,
|
||||
Failed,
|
||||
}
|
||||
|
||||
TransactionExecutionEvent {
|
||||
slot,
|
||||
signature,
|
||||
outcome,
|
||||
}
|
||||
```
|
||||
|
||||
Décisions du gate :
|
||||
|
||||
- `TransactionSignature` est une primitive passive Interface-owned de **64 octets déjà décodés** ; Interface n'ajoute ni base58, ni codec, ni dépendance Solana supplémentaire ;
|
||||
- cette primitive représente l'identité transactionnelle observée, pas une capability de signature Wallet ;
|
||||
- `logsSubscribe` fournit directement `slot`, `signature` et `err`; `err == null` produit `Succeeded`, une erreur produit `Failed` ;
|
||||
- Yellowstone `TransactionStatus` fournit exactement `slot`, signature et erreur optionnelle ; `is_vote`, `index`, filters et `created_at` restent Transport ;
|
||||
- Helius `transactionSubscribe` reste provider-specific : une projection n'est produite que lorsque le DTO/detail mode permet de déterminer `slot`, signature et outcome sans ambiguïté ; une forme `none`, inconnue ou sans information d'erreur ne fabrique aucun outcome ;
|
||||
- commitment, transaction index, logs, memo, block time, confirmation status, provider timestamps et erreurs opaques restent hors Interface ;
|
||||
- le futur worker RAW live peut utiliser ce fait comme signal d'acquisition/hydratation provider-neutral sans le confondre avec une donnée RAW persistée.
|
||||
|
||||
`TransactionSignature` ne remplace pas `ksp-store-api::RawTransactionSignature`. Les deux contrats ont des owners distincts : Interface possède l'identité compacte d'un **event-only fact**, Store possède l'identité d'une **référence RAW persistante**. La conversion explicite entre les deux appartient à la composition conformément à `DEP-KSP-003`; aucune dépendance Interface -> Store n'est introduite.
|
||||
|
||||
Les DTOs `logsSubscribe`, Yellowstone `TransactionStatus` et Helius `transactionSubscribe` restent intégralement Transport-owned. Interface ne contient aucun converter depuis ces types.
|
||||
|
||||
### 7.3 Logs realtime et signature commitment — DIFFÉRENCIÉS
|
||||
|
||||
Les logs ne sont plus utilisés comme argument pour rejeter l'exécution commune : `logsSubscribe` peut produire un `TransactionExecutionEvent` sans que les lignes de logs entrent dans le contrat partagé.
|
||||
|
||||
Une éventuelle famille distincte reste une **idée différée** :
|
||||
|
||||
```text
|
||||
TransactionLogEvent {
|
||||
slot,
|
||||
signature,
|
||||
logs,
|
||||
}
|
||||
```
|
||||
|
||||
Elle n'est pas admise en `0.3.5` tant que les bornes, la disponibilité multi-producer et un consumer concret ne sont pas démontrés. Aucun `RawLog` n'est créé.
|
||||
|
||||
Les surfaces de commitment/snapshot restent séparées de l'exécution :
|
||||
|
||||
```text
|
||||
HTTP getSignatureStatuses
|
||||
= snapshot interrogé, avec confirmations/status/confirmationStatus
|
||||
|
||||
WS signatureSubscribe
|
||||
= transition one-shot vers le commitment demandé, éventuellement précédée de ReceivedSignature
|
||||
```
|
||||
|
||||
Aucun `TransactionCommitmentEvent` n'est admis. Une future famille de commitment devra être auditée indépendamment et ne pourra pas être fusionnée avec `TransactionExecutionEvent` par une struct à nombreux `Option`.
|
||||
|
||||
### 7.4 Vote — REPORTÉ
|
||||
|
||||
`voteSubscribe` est explicitement pré-consensus et ne garantit pas l'entrée du vote dans le ledger. Le booléen `is_vote` de la famille transaction Yellowstone qualifie une transaction et n'est pas une notification gossip équivalente.
|
||||
|
||||
Aucun `VoteEvent` partagé n'est admis.
|
||||
|
||||
### 7.5 Account/program — REJET Interface
|
||||
|
||||
Les updates account/program peuvent contenir l'état complet nécessaire à l'acquisition RAW. `ksp-store-api` possède déjà :
|
||||
|
||||
```text
|
||||
RawAccountState
|
||||
RawAccountObservation
|
||||
```
|
||||
|
||||
Créer un second account event structurel dans Interface serait soit :
|
||||
|
||||
- un doublon persistant déguisé ;
|
||||
- un wrapper des DTOs Transport ;
|
||||
- un type incomplet qui perd les conditions d'admission RAW.
|
||||
|
||||
La conversion Transport -> Store API reste à la composition.
|
||||
|
||||
### 7.6 Transaction/block — REJET Interface
|
||||
|
||||
`RawTransaction` et `RawTransactionObservation` sont déjà Store-owned. Les blocs servent de conteneurs d'acquisition ou de payloads Transport riches. Aucun `RawBlock`, `TransactionEvent` ou `BlockEvent` transversal n'est ajouté.
|
||||
|
||||
### 7.7 Yellowstone Entry — Transport aujourd'hui, ownership sémantique réservé
|
||||
|
||||
`SubscribeUpdateEntry` reste un DTO Yellowstone strictement Transport-owned : un seul producer/protocole est démontré aujourd'hui et aucun consumer transversal proche ne justifie un type partagé. Cette décision ne réserve toutefois pas le **fait** à Transport : si une future seconde source permet de reconstruire un même `LedgerEntryEvent` provider-neutral, ce nouveau fait passif devra être audité pour ownership Interface, sans déplacer le DTO Yellowstone lui-même.
|
||||
|
||||
### 7.8 Notification after commit — REJET Interface
|
||||
|
||||
Les règles `KSP-NOTIFY-001..006` sont explicites : le format canonique du signal « persisted data available » appartient à `ksp-store-api`, est publié après commit et ne constitue jamais le backlog. `0.3.5` ne crée aucun équivalent Interface.
|
||||
|
||||
## 8. API sketch admise
|
||||
|
||||
La seule API planifiée pour `pre.002` est conceptuellement :
|
||||
|
||||
```rust
|
||||
#[non_exhaustive]
|
||||
pub enum SlotLifecycleStage {
|
||||
Processed,
|
||||
FirstShredReceived,
|
||||
Completed,
|
||||
CreatedBank,
|
||||
Dead,
|
||||
OptimisticallyConfirmed,
|
||||
Rooted,
|
||||
}
|
||||
|
||||
pub struct SlotLifecycleEvent {
|
||||
slot: u64,
|
||||
stage: SlotLifecycleStage,
|
||||
}
|
||||
```
|
||||
|
||||
Surface publique visée :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage
|
||||
SlotLifecycleEvent::new(slot, stage)
|
||||
SlotLifecycleEvent::slot()
|
||||
SlotLifecycleEvent::stage()
|
||||
```
|
||||
|
||||
Décisions de représentation :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage -> #[non_exhaustive] + Clone + Copy + Debug + Eq + PartialEq
|
||||
SlotLifecycleEvent -> champs privés + Clone + Copy + Debug + Eq + PartialEq
|
||||
Hash -> absent tant qu'un consumer réel ne l'exige pas
|
||||
validation -> aucune borne variable ; slot u64 conservé exactement
|
||||
error code -> aucun ; aucune admission faillible n'est nécessaire
|
||||
```
|
||||
|
||||
Contraintes :
|
||||
|
||||
- pas de serde imposé ;
|
||||
- pas de `String`, JSON, bytes, timestamp ou diagnostic ;
|
||||
- pas de network id dupliquant `RawNetworkId` ; la composition est déjà liée à son contexte réseau ;
|
||||
- `Debug` est sûr par construction ;
|
||||
- aucun error code n'est nécessaire si tout `u64` de slot et toute variante publique construite sont valides ;
|
||||
- aucune dépendance nouvelle n'est requise ;
|
||||
- aucun trait universel `Event`, `EventSource`, `Subscriber` ou `Handler` ;
|
||||
- aucune conversion `From<TransportType>` dans Interface, car cela créerait une dépendance interdite ;
|
||||
- les converters appartiennent au futur consumer/composition ou, si un usage concret le justifie plus tard, à une crate de composition dédiée.
|
||||
|
||||
Le nom final peut être ajusté pendant `pre.002` seulement si les canaris montrent une ambiguïté réelle. Le sens `slot + stage commun` ne doit pas être élargi. `OptimisticallyConfirmed` et `Rooted` sont volontairement préférés à `Confirmed` et `Finalized` afin de conserver la sémantique KSP du fait normalisé sans transformer les labels Yellowstone en terminologie universelle.
|
||||
|
||||
## 9. Consumer proche et usage concret
|
||||
|
||||
L'architecture prévoit un futur worker RAW live :
|
||||
|
||||
```text
|
||||
subscriptions/fetch live
|
||||
-> ksp-onchain-transport-lib
|
||||
-> RAW ingestion
|
||||
-> D1 RAW
|
||||
```
|
||||
|
||||
Ce worker est le consumer proche qui peut recevoir des événements de progression/lifecycle de slot venant soit des WebSockets standard, soit de Yellowstone sans connaître les DTOs des deux protocoles lorsqu'il n'a besoin que de déclencher/ordonner une réaction de composition propre au lifecycle.
|
||||
|
||||
Le même worker peut consommer `TransactionExecutionEvent` comme signal compact qu'une signature a été exécutée dans un slot avec succès ou échec, puis décider dans sa propre policy/composition s'il doit hydrater/persister un `RawTransaction`. Le fait Interface ne contient ni payload ni provenance et n'est jamais utilisé comme preuve durable de présence dans Store.
|
||||
|
||||
Ces APIs ne deviennent pas un prérequis de `0.3.6` : le premier backfill historique reste fondé sur Transport + Store et peut ne jamais consommer les events Interface.
|
||||
|
||||
## 10. Anti-duplication Store
|
||||
|
||||
| Contrat Store comparé | Chevauchement Interface admis | Pourquoi il n'y a pas de seconde vérité |
|
||||
| ------------------------------ | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
||||
| `RawTransaction` | slot + signature possibles via execution event | aucun payload/format/hash/block_time ; l'event ne peut reconstruire ni remplacer une transaction RAW |
|
||||
| `RawTransactionReference` | signature sémantiquement apparentée | la référence Store inclut `RawNetworkId` et possède l'identité durable ; Interface reste contextuel |
|
||||
| `RawTransactionSignature` | même primitive protocolaire 64 octets | wrapper Store et primitive Interface restent owner-specific ; conversion explicite à la composition |
|
||||
| `RawTransactionObservation` | référence transaction possible indirectement | aucune provenance acquisition, observation key ou timestamp durable |
|
||||
| `RawAccountState` | slot possible via lifecycle seulement | aucune pubkey/state hash/lamports/owner/data ; aucun état account |
|
||||
| `RawAccountObservation` | slot indirect possible | aucune référence account/provenance Geyser |
|
||||
| `RawAcquisitionProvenance` | aucun | pas d'origin/provider code/timestamps ; les metadata source restent Transport/composition |
|
||||
| `RawTimestamp` | aucun | aucun timestamp commun inventé |
|
||||
| `RawContentHash` | aucun | aucune identité de contenu durable |
|
||||
| `RawObservationKey` | aucun | aucune identité d'observation persistante |
|
||||
| notification after commit | aucun | event réseau observe l'acquisition ; wake-up Store référence une donnée déjà commitée |
|
||||
|
||||
Le gate conserve les canaris conceptuels suivants :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent -X-> RawTransaction
|
||||
TransactionExecutionEvent -X-> RawTransaction
|
||||
TransactionExecutionEvent -X-> RawTransactionObservation
|
||||
TransactionSignature -X-> RawTransactionSignature implicit conversion
|
||||
Interface -X-> ksp-store-api
|
||||
Interface -X-> ksp-store-lib
|
||||
Store API -X-> Interface
|
||||
```
|
||||
|
||||
Une couche de composition peut convertir explicitement `TransactionSignature::as_bytes()` vers `RawTransactionSignature::new(...)`, mais aucun `From` cross-domain n'est possédé par Interface ou Store API. Aucun champ d'un event admis ne constitue à lui seul une preuve RAW durable.
|
||||
|
||||
## 11. Graphe cible
|
||||
|
||||
Après implémentation de la release :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Aucune nouvelle dependency normale ou feature n'est planifiée.
|
||||
|
||||
Les consumers restent :
|
||||
|
||||
```text
|
||||
ksp-program-api
|
||||
-> ksp-interface-lib # ProgramInstruction / ProgramAccountMeta seulement
|
||||
|
||||
future acquisition composition / RAW live worker
|
||||
-> ksp-onchain-transport-lib
|
||||
-> ksp-interface-lib # SlotLifecycleEvent / TransactionExecutionEvent
|
||||
-> ksp-store-lib / ksp-store-api selon ownership
|
||||
```
|
||||
|
||||
## 12. Threat model
|
||||
|
||||
| Risque | Menace | Garde planifiée |
|
||||
| ------------------------------ | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||
| mega enum | Interface devient catalogue de tous les transports | familles admises séparées et étroites ; aucun `Event` générique |
|
||||
| Option soup | sémantiques différentes fusionnées par champs optionnels | familles séparées : SlotLifecycle / TransactionExecution ; logs/commitment restent distincts |
|
||||
| persistence creep | event-only devient second Store | aucun RAW/payload/cursor/retention ; `KSP-NOTIFY-*` reste Store API |
|
||||
| transport wrapper | copie des DTOs WS/gRPC/provider | aucune metadata protocol/provider dans le type Interface |
|
||||
| faux timestamp commun | horodatages WS et Yellowstone confondus | aucun timestamp partagé |
|
||||
| root/finality confusion | label Yellowstone `Finalized` promu comme vérité universelle | stage KSP `Rooted` ; mapping source explicite `Root <-> Yellowstone Finalized` sans renommer le fait KSP |
|
||||
| optimistic/confirmed confusion | label Yellowstone `Confirmed` promu comme commitment générique | stage KSP `OptimisticallyConfirmed` ; mapping source explicite avec l'optimistic confirmation Solana |
|
||||
| dead diagnostic leak | texte provider/validator traverse une API partagée durable | stage `Dead` sans diagnostic ; détail reste Transport |
|
||||
| cross-network confusion | event sans réseau mélangé entre sessions | conversion autorisée seulement dans une composition déjà liée à un contexte réseau ; pas de network id dupliqué |
|
||||
| signature/payload leak | signature ou payload brut fuit via Debug | signature fixe 64 octets, Debug redacted ; aucun payload variable |
|
||||
| public enum breakage | ajout futur casse les matches externes | `SlotLifecycleStage` et `TransactionExecutionOutcome` non-exhaustive |
|
||||
| logging/runtime creep | crate passive acquiert tracing/Tokio/channel | aucune dependency/runtime/logging ajoutée |
|
||||
| Helius semantic promotion | DTO/provider extension devient norme KSP | `transactionSubscribe` reste Transport ; seule une projection sémantique commune peut devenir Interface |
|
||||
| Yellowstone protocol promotion | DTO `Entry`/filters/created_at deviennent Interface | types Yellowstone restent Transport ; un futur fait transversal est réaudité séparément |
|
||||
|
||||
## 13. Stratégie de tests
|
||||
|
||||
### 13.1 `pre.002` — modèle admis
|
||||
|
||||
Tests unitaires Interface :
|
||||
|
||||
- chaque stage public est distinct ;
|
||||
- `slot` est conservé sans narrowing ;
|
||||
- le constructeur/getters sont passifs et déterministes ;
|
||||
- le type n'emporte aucune metadata de transport.
|
||||
|
||||
Tests d'intégration :
|
||||
|
||||
- crate-root public API ;
|
||||
- external consumer ;
|
||||
- dependency boundary Core-only ;
|
||||
- exact production module/export inventory.
|
||||
|
||||
### 13.2 `pre.003` — transaction execution admis
|
||||
|
||||
Tests unitaires Interface :
|
||||
|
||||
- `TransactionSignature` conserve exactement 64 octets et masque ses bytes en `Debug` ;
|
||||
- `Succeeded` et `Failed` sont distincts ;
|
||||
- `TransactionExecutionEvent` conserve `u64::MAX`, signature et outcome sans narrowing ;
|
||||
- `Debug` d'event ne rend pas la signature.
|
||||
|
||||
Tests d'intégration :
|
||||
|
||||
- les trois nouveaux symboles sont disponibles depuis le crate-root ;
|
||||
- `TransactionExecutionOutcome` impose un wildcard downstream via `#[non_exhaustive]` ;
|
||||
- l'inventaire crate-root passe de 8 à 11 reexports ;
|
||||
- l'inventaire de production ajoute uniquement `transaction_execution`.
|
||||
|
||||
### 13.3 Convergence sans dépendance Transport
|
||||
|
||||
`ksp-interface-lib` ne doit pas ajouter `ksp-onchain-transport-lib` même en dépendance normale pour « tester » les converters. Les preuves d'équivalence sémantique restent dans le plan/validation de release et les canaris de frontière Interface.
|
||||
|
||||
Si un converter concret est introduit plus tard dans une crate de composition, sa propre crate devra tester les mappings exacts :
|
||||
|
||||
```text
|
||||
SolanaSlotNotification -> Processed
|
||||
SolanaSlotUpdate::FirstShredReceived -> FirstShredReceived
|
||||
SolanaSlotUpdate::Completed -> Completed
|
||||
SolanaSlotUpdate::CreatedBank -> CreatedBank
|
||||
SolanaSlotUpdate::Dead -> Dead
|
||||
SolanaSlotUpdate::OptimisticConfirmation -> OptimisticallyConfirmed
|
||||
SolanaRoot / SolanaSlotUpdate::Root -> Rooted
|
||||
YellowstoneSlotStatus::Confirmed -> OptimisticallyConfirmed
|
||||
YellowstoneSlotStatus::Finalized -> Rooted
|
||||
YellowstoneSlotStatus autres équivalents -> mêmes stages
|
||||
```
|
||||
|
||||
Et devra explicitement refuser `Frozen` ou toute variante future sans mapping audité au lieu d'inventer un faux stage commun.
|
||||
|
||||
### 13.4 Traçabilité des candidats différés
|
||||
|
||||
`TransactionExecutionEvent` est admis par `pre.003` et n'est donc plus un TODO. `TransactionLogEvent` reste explicitement une idée différée. Si cette idée reste hors scope à la réconciliation documentaire finale, elle doit être reportée dans la surface TODO/IDEAS durable appropriée au lieu d'être perdue avec le plan de release.
|
||||
|
||||
## 14. Prévision souple des prereleases
|
||||
|
||||
La release reste dimensionnée pour une seule session. `SlotLifecycleEvent` est matérialisé en `pre.002` et `TransactionExecutionEvent` devient la seconde famille admise en `pre.003`; aucune troisième famille n'est ouverte sans nouveau gate.
|
||||
|
||||
### `0.3.5-pre.001` — audit + plan
|
||||
|
||||
- lecture des règles/architectures/surfaces ;
|
||||
- audit externe actuel ;
|
||||
- matrice producer/fact et convergence ;
|
||||
- ownership et anti-duplication Store ;
|
||||
- threat model ;
|
||||
- API sketch ;
|
||||
- sizing et plan de release.
|
||||
|
||||
### `0.3.5-pre.002` — `SlotLifecycleEvent`
|
||||
|
||||
- implémenter la famille minimale admise ;
|
||||
- crate-root exports ;
|
||||
- tests unitaires et public API ciblés ;
|
||||
- préserver le graphe Core-only.
|
||||
|
||||
### `0.3.5-pre.003` — `TransactionExecutionEvent`
|
||||
|
||||
- gate signature/dependency : PASS avec `TransactionSignature([u8; 64])` passive, sans codec ni dépendance supplémentaire ;
|
||||
- mappings Solana `logsSubscribe` / Yellowstone `TransactionStatus` / Helius `transactionSubscribe` : PASS sous projection conservative ;
|
||||
- anti-duplication Store : PASS, conversion explicite Interface <-> Store à la composition ;
|
||||
- consumer concret : PASS, futur worker RAW live ;
|
||||
- implémenter `TransactionSignature`, `TransactionExecutionOutcome` et `TransactionExecutionEvent` seulement ;
|
||||
- ne pas introduire logs, commitment, metadata provider ou converters Transport dans Interface.
|
||||
|
||||
### `0.3.5-pre.004` — canaris externes + complétude API
|
||||
|
||||
- external consumer pour toutes les familles effectivement admises ;
|
||||
- inventaire exact des modules/exports ;
|
||||
- canaris négatifs contre Transport/Store/runtime/serde/logging ;
|
||||
- non-exhaustive et stabilité de la surface.
|
||||
|
||||
### `0.3.5-pre.005` — hardening final
|
||||
|
||||
- adversarial/API hardening ;
|
||||
- absence de payload/source metadata ;
|
||||
- absence de second RAW ;
|
||||
- validation du graphe et des dépendances ;
|
||||
- aucun élargissement fonctionnel opportuniste.
|
||||
|
||||
### `0.3.5-pre.006` — gate technique final
|
||||
|
||||
- gates Rust/workspace complets ;
|
||||
- `cargo tree` Interface normal/features/duplicates ;
|
||||
- aucun smoke live requis : les contrats Interface restent passifs et ne possèdent aucun réseau.
|
||||
|
||||
### `0.3.5-pre.007` — réconciliation documentaire finale
|
||||
|
||||
- plan + validation réconciliés avec le gate `pre.006` propre ;
|
||||
- README/USAGE Interface durables et version-neutral ;
|
||||
- rôle Interface explicité dans les documents d'architecture réellement devenus incomplets ;
|
||||
- `TransactionLogEvent` transféré dans `docs/IDEAS.md` comme idée différée ;
|
||||
- aucun CHANGELOG/ROADMAP/prompt suivant dans cette tranche.
|
||||
|
||||
### `0.3.5-pre.008` — préparation de publication
|
||||
|
||||
Lane minimale :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
CHANGELOG.md
|
||||
ROADMAP.md
|
||||
prompts/025-V0_3_6_START_PROMPT.md
|
||||
deltas/0.3.5/pre.008.md
|
||||
```
|
||||
|
||||
Aucun code, README/USAGE, plan ou validation ne doit être rouvert ici.
|
||||
|
||||
### `0.3.5-rel.001` — stable
|
||||
|
||||
- mécanique de publication uniquement ;
|
||||
- version Cargo finale `0.3.5` ;
|
||||
- aucun rattrapage fonctionnel/documentaire.
|
||||
|
||||
## 15. Gates opérateur
|
||||
|
||||
### 15.1 Après chaque overlay fonctionnel
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
```
|
||||
|
||||
Ajouter `cargo test -p ksp-program-api` lorsqu'une modification publique Interface pourrait affecter son consumer actuel.
|
||||
|
||||
### 15.2 Gate technique final
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree -p ksp-interface-lib -e features
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Aucun live test n'est justifié par `0.3.5` : un type passif ne doit pas acquérir de dépendance réseau pour prouver son existence.
|
||||
|
||||
## 16. Hors périmètre
|
||||
|
||||
```text
|
||||
grand enum Event
|
||||
event bus / channel / broadcaster
|
||||
scheduler / worker / job
|
||||
backfill 0.3.6
|
||||
persistence ou migration Store
|
||||
nouvelle capability Store
|
||||
RawLog / RawBlock
|
||||
TransactionStatusObservation fusionné
|
||||
TransactionCommitmentEvent fusionné avec execution
|
||||
TransactionLogEvent sans nouveau gate de bornes/consumer
|
||||
VoteEvent partagé
|
||||
label KSP `Finalized` utilisé comme alias universel de root
|
||||
label KSP `Confirmed` utilisé comme alias universel d'optimistic confirmation
|
||||
Helius Enhanced DTO dans Interface
|
||||
Yellowstone Entry DTO dans Interface
|
||||
serde/wincode/borsh ajouté sans protocole réel
|
||||
logging/runtime dans Interface
|
||||
conversion Transport -> Interface possédée par Interface
|
||||
```
|
||||
|
||||
## 17. Critère de clôture de `0.3.5`
|
||||
|
||||
La release peut fermer si et seulement si :
|
||||
|
||||
```text
|
||||
une famille minimale SlotLifecycle est publique et bornée
|
||||
intersection = Processed + FirstShredReceived + Completed + CreatedBank + Dead + OptimisticallyConfirmed + Rooted
|
||||
Frozen et toute variante future sans mapping audité ne sont pas normalisées artificiellement
|
||||
TransactionExecutionEvent est admis en pre.003 sous la forme minimale slot + TransactionSignature + outcome
|
||||
aucun payload/diagnostic/timestamp/provider metadata n'entre dans Interface
|
||||
Interface reste Core-only
|
||||
Store RAW 10/10 reste inchangé
|
||||
KSP-NOTIFY ownership reste Store API
|
||||
aucun event bus/runtime/persistence n'est ajouté
|
||||
external consumer et crate-root canaries passent
|
||||
README/USAGE finaux restent durables et version-neutral
|
||||
```
|
||||
|
||||
Si l'implémentation montre qu'un de ces invariants ne peut pas être préservé, la famille SlotLifecycle est retirée plutôt qu'élargie artificiellement.
|
||||
936
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
Normal file
936
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
Normal file
@@ -0,0 +1,936 @@
|
||||
<!-- file: docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md -->
|
||||
<!-- version: 9 -->
|
||||
|
||||
# Validation `0.3.5` — Interface passive acquisition events
|
||||
|
||||
## 1. Portée
|
||||
|
||||
Ce document suit toute la fermeture de `0.3.5`. `pre.002` matérialise `SlotLifecycleEvent`; `pre.003` admet `TransactionExecutionEvent`; `pre.004` verrouille les canaris externes et la complétude ; `pre.005` ajoute le hardening adversarial ; son fix corrige uniquement un faux négatif du canari de manifeste ; `pre.006` ferme le gate technique final ; `pre.007` réconcilie la documentation durable sans modifier la surface Rust.
|
||||
|
||||
Base :
|
||||
|
||||
```text
|
||||
v0.3.4
|
||||
workspace.package.version = 0.3.4
|
||||
```
|
||||
|
||||
Version de travail :
|
||||
|
||||
```text
|
||||
0.3.5-pre.7
|
||||
```
|
||||
|
||||
## 2. Gate d'entrée `v0.3.4`
|
||||
|
||||
Le log opérateur fourni avec l'archive indique un gate stable `v0.3.4` propre : audits Rust/Markdown, `cargo check`, Clippy, tests ciblés des crates, `cargo test --workspace`, `ksp-store-lib --no-default-features` et graphes Store ont été exécutés sans échec visible ; les smokes réseau restent explicitement ignorés/opt-in.
|
||||
|
||||
Cette preuve est l'entrée de `0.3.5`. Elle n'est pas réétiquetée comme validation exécutée dans l'environnement d'assemblage de `pre.001`.
|
||||
|
||||
## 3. Gate de lecture `pre.001`
|
||||
|
||||
| Contrôle | Résultat | Preuve / décision |
|
||||
| ------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| règles globales relues | PASS | familles KSP-API/TRANSPORT/STORE/NOTIFY/PROC/REL et DEP applicables relues |
|
||||
| architecture durable relue | PASS | Interface passif, Transport protocol/runtime, Store persistant, composition owner des conversions |
|
||||
| fondation Interface stable relue | PASS | surface Program petite ; dépendance normale Core-only |
|
||||
| Store API RAW relu | PASS | `RawTransaction*` + `RawAccount*` restent Store-owned |
|
||||
| Store/PostgreSQL `0.3.2`–`0.3.4` relu | PASS | RAW physique 10/10 fermé ; aucune rétention account |
|
||||
| surfaces HTTP/WS/gRPC/Helius relues | PASS | status/log/slot/vote/account/transaction/block/Entry inventoriés |
|
||||
| documentation Solana courante auditée | PASS | `slotSubscribe`, `slotsUpdatesSubscribe`, status/log/vote/account/program, getTransaction/getBlock |
|
||||
| Yellowstone upstream courant audité | PASS | `SlotStatus` et familles SubscribeUpdate courantes |
|
||||
| Helius courant audité | PASS | standard WSS préserve wire Solana ; Enhanced `transactionSubscribe` reste extension provider |
|
||||
| producer/consumer inventory | PASS | lifecycle slot 7 stages admis ; TransactionExecutionEvent rouvert comme candidat actif |
|
||||
| threat model | PASS | mega enum, Option soup, Store duplication, mapping lifecycle explicite et provider promotion couverts |
|
||||
| sizing release | PASS | 8 prereleases prévues avant `rel.001` ; second candidat soumis à gate dédié |
|
||||
|
||||
## 4. Matrice de décision par famille
|
||||
|
||||
| Famille | Décision | Owner | Motif déterminant |
|
||||
| ------------------------------------- | ------------------- | ------------------------------ | ---------------------------------------------------------------------------------------- |
|
||||
| slot lifecycle intersection | ADMIS | Interface | 7 faits compacts normalisés ; détails protocol/provider restent Transport |
|
||||
| transaction execution | ADMIS `pre.003` | Interface | `slot + TransactionSignature + Succeeded/Failed` multi-producer |
|
||||
| logs realtime | IDÉE DIFFÉRÉE | Interface si futur gate | payload variable/bornes/consumer non démontrés ; ne pas mélanger avec execution |
|
||||
| signature commitment/snapshot | REPORTÉ | Transport | HTTP snapshot != WS one-shot commitment ; distinct de l'exécution |
|
||||
| vote | REPORTÉ | Transport | gossip pré-consensus != transaction qualifiée `is_vote` |
|
||||
| account/program | REJET Interface | Store/Transport | risque de doublon `RawAccountState`/observation ou wrapper Transport |
|
||||
| transaction | REJET Interface | Store/Transport | `RawTransaction`/observation déjà persistants |
|
||||
| block | REJET Interface | Transport | conteneur/payload d'acquisition ; aucun besoin passif transversal démontré |
|
||||
| Yellowstone Entry | REPORTÉ | Transport DTO | mono-producer aujourd'hui ; un futur fait transversal KSP serait réaudité pour Interface |
|
||||
| persisted-data available notification | REJET Interface | Store API | ownership normatif `KSP-NOTIFY-001..006` |
|
||||
| Helius Enhanced transaction | PRODUCTEUR ADMIS | Transport DTO / Interface fact | DTO provider-specific ; projection conservative vers le fait commun admis |
|
||||
|
||||
## 5. Intersection lifecycle retenue
|
||||
|
||||
| Stage Interface prévu | Producer Solana standard | Producer Yellowstone | Verdict | Détails exclus du contrat commun |
|
||||
| ------------------------- | -------------------------------------- | -------------------- | ------- | -------------------------------------------------------------------------------- |
|
||||
| `Processed` | `slotSubscribe` | `Processed` | PASS | WS parent/root ; Yellowstone filters/created_at/parent |
|
||||
| `FirstShredReceived` | `slotsUpdates::FirstShredReceived` | `FirstShredReceived` | PASS | timestamps/metadata source |
|
||||
| `Completed` | `slotsUpdates::Completed` | `Completed` | PASS | timestamps/metadata source |
|
||||
| `CreatedBank` | `slotsUpdates::CreatedBank` | `CreatedBank` | PASS | parent reste dans le DTO Transport riche |
|
||||
| `Dead` | `slotsUpdates::Dead` | `Dead` | PASS | diagnostic `err`/`dead_error` et timestamp restent Transport |
|
||||
| `OptimisticallyConfirmed` | `slotsUpdates::OptimisticConfirmation` | `Confirmed` | PASS | nom KSP conserve l'optimistic confirmation ; delivery/metadata restent Transport |
|
||||
| `Rooted` | `rootSubscribe` / `slotsUpdates::Root` | `Finalized` | PASS | nom KSP conserve le fait root ; `Finalized` reste un label Yellowstone source |
|
||||
| — | `slotsUpdates::Frozen` | — | FAIL | pas d'intersection |
|
||||
|
||||
## 6. Validation anti-Option-soup
|
||||
|
||||
Les modèles suivants sont explicitement **non admis** par le gate :
|
||||
|
||||
```text
|
||||
TransactionStatusObservation {
|
||||
confirmations?: ...,
|
||||
confirmation_status?: ...,
|
||||
received?: ...,
|
||||
is_vote?: ...,
|
||||
transaction_index?: ...,
|
||||
logs?: ...,
|
||||
...
|
||||
}
|
||||
|
||||
SlotLifecycleEvent {
|
||||
parent?: ...,
|
||||
root?: ...,
|
||||
timestamp?: ...,
|
||||
dead_error?: ...,
|
||||
provider?: ...,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
La surface admise reste conceptuellement :
|
||||
|
||||
```text
|
||||
SlotLifecycleEvent { slot, stage }
|
||||
```
|
||||
|
||||
Le candidat séparé, non encore admis, reste :
|
||||
|
||||
```text
|
||||
TransactionExecutionEvent { slot, signature, outcome }
|
||||
```
|
||||
|
||||
## 7. Validation anti-duplication Store
|
||||
|
||||
| Modèle Store stable | Action `0.3.5` | Justification |
|
||||
| ------------------------------- | ------------------- | ---------------------------------------------- |
|
||||
| `RawTransaction` | inchangé | payload durable/replayable |
|
||||
| `RawTransactionObservation` | inchangé | provenance persistante |
|
||||
| `RawAccountState` | inchangé | état account durable |
|
||||
| `RawAccountObservation` | inchangé | observation persistante |
|
||||
| pagination/cursors RAW | inchangés | contrats de navigation Store |
|
||||
| retention/tombstone transaction | inchangés | lifecycle de persistence Store |
|
||||
| notification after commit | non implémentée ici | ownership Store API réservé par `KSP-NOTIFY-*` |
|
||||
|
||||
Canari conceptuel : aucun futur fichier source Interface de `0.3.5` ne doit importer `ksp_store_api`, `ksp_store_lib` ou copier leurs modèles.
|
||||
|
||||
## 8. Validation dependency/ownership
|
||||
|
||||
État de l'archive stable inspecté :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
runtime dependency = ksp-core-lib seulement
|
||||
```
|
||||
|
||||
Cible `0.3.5` :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -> ksp-core-lib
|
||||
ksp-interface-lib -X-> ksp-onchain-transport-lib
|
||||
ksp-interface-lib -X-> ksp-store-api
|
||||
ksp-interface-lib -X-> ksp-store-lib
|
||||
ksp-interface-lib -X-> ksp-program-api
|
||||
ksp-interface-lib -X-> serde/tracing/tokio/channel runtime additions
|
||||
```
|
||||
|
||||
Le gate opérateur de `pre.001` confirme `cargo check --workspace`, Clippy et les tests `ksp-interface-lib`. Les graphes `cargo tree` restent réservés au gate technique final de la release.
|
||||
|
||||
## 9. Consumer concret retenu
|
||||
|
||||
Consumer proche documenté par l'architecture : futur worker RAW live / composition d'acquisition.
|
||||
|
||||
Usage possible sans dépendance protocol-specific :
|
||||
|
||||
```text
|
||||
Solana standard WS -----------+
|
||||
+-> converter composition -> SlotLifecycleEvent -> réaction lifecycle du consumer
|
||||
Yellowstone gRPC -------------+
|
||||
```
|
||||
|
||||
`0.3.6` backfill n'est pas forcé d'utiliser ce type ; il reste une composition historique Transport + Store.
|
||||
|
||||
## 10. Threat gates
|
||||
|
||||
| Gate | Attendu `0.3.5` | Statut courant |
|
||||
| ------------------------------------ | ------------------------------------------------- | ------------------ |
|
||||
| mega enum | absent | PLAN PASS |
|
||||
| protocol/provider enum leakage | absent | PLAN PASS |
|
||||
| timestamp semantics conflated | absent | PLAN PASS |
|
||||
| root/finalized label confusion | évitée par le stage KSP `Rooted` | PLAN PASS |
|
||||
| optimistic/confirmed label confusion | évitée par le stage KSP `OptimisticallyConfirmed` | PLAN PASS |
|
||||
| dead diagnostic in shared API | absent | PLAN PASS |
|
||||
| RAW Store duplication | absent | PLAN PASS |
|
||||
| event persistence | absent | PLAN PASS |
|
||||
| event bus/runtime | absent | PLAN PASS |
|
||||
| network id duplicated from Store | absent | PLAN PASS |
|
||||
| cross-network use | composition doit conserver son scope réseau | À CANARIER |
|
||||
| public enum evolution | `SlotLifecycleStage` doit être non-exhaustive | IMPLÉMENTÉ pre.002 |
|
||||
| Core-only graph | aucune dependency nouvelle | PASS opérateur |
|
||||
| external consumer | type consommable depuis crate externe | CANARI pre.002 |
|
||||
|
||||
## 11. Fichiers de `pre.001`
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.001.md
|
||||
```
|
||||
|
||||
Modifié :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
```
|
||||
|
||||
Aucun autre fichier ne doit changer dans cet overlay.
|
||||
|
||||
## 12. Validations statiques de l'overlay initial
|
||||
|
||||
L'overlay `pre.001` avait exécuté les audits disponibles dans l'environnement d'assemblage :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
-> General Rust rule audit: clean
|
||||
-> Rust export completeness audit: 0 candidate(s)
|
||||
-> KSP workspace Rust rule audit: clean
|
||||
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
-> Markdown table audit: clean (251 table(s), 137 file(s))
|
||||
```
|
||||
|
||||
## 13. Gate opérateur `pre.001` reçu avant `fix.001`
|
||||
|
||||
L'opérateur a rejoué depuis un `cargo clean` :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
```
|
||||
|
||||
Résultat : **PASS intégral**.
|
||||
|
||||
Preuves synthétiques :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (251 table(s), 137 file(s))
|
||||
cargo check --workspace -> PASS
|
||||
cargo clippy --workspace --all-targets -> PASS
|
||||
ksp-interface-lib unit tests -> 10 passed
|
||||
ksp-interface-lib dependency_boundary -> 4 passed
|
||||
ksp-interface-lib external_consumer -> 1 passed
|
||||
ksp-interface-lib public_api -> 5 passed
|
||||
ksp-interface-lib release_completeness -> 3 passed
|
||||
doc-tests -> 0 failed
|
||||
```
|
||||
|
||||
`pre.001-fix.001` est documentation-only ; il ne modifie ni Cargo ni Rust. L'opérateur doit néanmoins rejouer les deux audits Markdown/Rust après application du fix pour confirmer l'overlay final.
|
||||
|
||||
## 14. Exit gate `pre.001-fix.001`
|
||||
|
||||
Le gate corrigé impose désormais :
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.5-pre.1 inchangée
|
||||
SlotLifecycle admis avec 7 stages
|
||||
stages = Processed / FirstShredReceived / Completed / CreatedBank / Dead / OptimisticallyConfirmed / Rooted
|
||||
Frozen reste hors intersection
|
||||
TransactionExecutionEvent = candidat actif mais non encore admis
|
||||
TransactionLogEvent = idée différée, distincte de l'exécution
|
||||
getSignatureStatuses/signatureSubscribe = snapshot/commitment Transport, non fusionnés avec execution
|
||||
Helius transactionSubscribe et Yellowstone Entry restent des DTOs Transport
|
||||
un futur fait provider-neutral produit par une extension provider peut appartenir à Interface après gate
|
||||
aucun fichier Rust/Transport/Store/Cargo n'est modifié par le fix
|
||||
```
|
||||
|
||||
## 15. Gate opérateur post-`pre.001-fix.001`
|
||||
|
||||
Avant l'ouverture de `pre.002`, l'opérateur a rejoué les audits demandés sur l'état corrigé :
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
```
|
||||
|
||||
Résultat fourni : **PASS**.
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 138 file(s))
|
||||
```
|
||||
|
||||
Ce résultat constitue le gate d'entrée immédiat de `0.3.5-pre.002`.
|
||||
|
||||
## 16. Implémentation `0.3.5-pre.002`
|
||||
|
||||
`pre.002` ajoute exactement une famille passive provider-neutral à `ksp-interface-lib` :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage
|
||||
Processed
|
||||
FirstShredReceived
|
||||
Completed
|
||||
CreatedBank
|
||||
Dead
|
||||
OptimisticallyConfirmed
|
||||
Rooted
|
||||
|
||||
SlotLifecycleEvent
|
||||
new(slot, stage)
|
||||
slot()
|
||||
stage()
|
||||
```
|
||||
|
||||
Propriétés de représentation matérialisées :
|
||||
|
||||
```text
|
||||
SlotLifecycleStage -> #[non_exhaustive] + Clone + Copy + Debug + Eq + PartialEq
|
||||
SlotLifecycleEvent -> champs privés + Clone + Copy + Debug + Eq + PartialEq
|
||||
slot -> u64 conservé exactement, y compris u64::MAX
|
||||
validation -> aucune admission faillible
|
||||
error code -> aucun nouvel error code
|
||||
serde/codec -> absent
|
||||
runtime/logging -> absent
|
||||
Transport/Store -> aucune dépendance ni conversion
|
||||
```
|
||||
|
||||
Le graphe Cargo reste inchangé pour `ksp-interface-lib` : son manifest n'est pas modifié et sa seule dépendance normale demeure `ksp-core-lib`.
|
||||
|
||||
Canaris ajoutés/ajustés :
|
||||
|
||||
```text
|
||||
unit_tests/slot_lifecycle.rs
|
||||
-> 7 stages distincts
|
||||
-> traits Copy/Eq attendus
|
||||
-> domaine u64 complet
|
||||
-> Debug borné et provider-neutral
|
||||
|
||||
tests/slot_lifecycle_public_api.rs
|
||||
-> construction et getters depuis crate root
|
||||
-> match downstream avec wildcard imposé par #[non_exhaustive]
|
||||
|
||||
tests/release_completeness.rs
|
||||
-> inventaire crate-root mis à jour à 8 reexports
|
||||
-> inventaire de modules mis à jour avec slot_lifecycle uniquement
|
||||
-> absence de serde/tracing/Transport/Store dans la racine Interface
|
||||
```
|
||||
|
||||
`TransactionExecutionEvent` reste **non implémenté** et réservé au gate `pre.003`.
|
||||
|
||||
## 17. Fichiers de `pre.002`
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/slot_lifecycle.rs
|
||||
crates/ksp-interface-lib/unit_tests/slot_lifecycle.rs
|
||||
crates/ksp-interface-lib/tests/slot_lifecycle_public_api.rs
|
||||
deltas/0.3.5/pre.002.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## 18. Gate opérateur demandé pour `pre.002`
|
||||
|
||||
Après application de l'overlay :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les validations Cargo de `pre.002` restent **à exécuter par l'opérateur** ; elles ne sont pas déclarées réussies par l'environnement d'assemblage.
|
||||
|
||||
## 19. Gate opérateur `pre.002` et correction `pre.002-fix.001`
|
||||
|
||||
Le gate opérateur de `pre.002` confirme que le contrat fonctionnel `SlotLifecycleEvent` compile et que ses tests ciblés passent, mais la tranche n'est pas admissible en l'état : l'audit Rust détecte quinze violations `RUST-FMT-101` dans les nouveaux tests et Clippy rejette deux usages de `?` ainsi que des closures à retour implicite. Les deux nouveaux tests d'intégration exposent également un warning `missing_docs` au niveau crate.
|
||||
|
||||
`pre.002-fix.001` corrige uniquement ces défauts de conformité : suppression des lignes vides à l'intérieur des fonctions, propagation d'erreur explicite par `match`, `return` explicite dans les closures concernées et documentation crate-level des tests d'intégration. Aucun contrat public `SlotLifecycleEvent` / `SlotLifecycleStage` n'est modifié.
|
||||
|
||||
Comme le fix modifie des sources Rust, la version workspace évolue conformément à la politique KSP :
|
||||
|
||||
```text
|
||||
0.3.5-pre.2.fix.1
|
||||
```
|
||||
|
||||
Le nom documentaire de la correction reste `0.3.5-pre.002-fix.001`.
|
||||
|
||||
## 20. Gate opérateur `pre.002-fix.001`
|
||||
|
||||
Le gate opérateur du `2026-08-31` confirme :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
```
|
||||
|
||||
Le seul défaut restant est documentaire : deux lignes vides consécutives dans ce fichier de validation. L'opérateur demande explicitement de ne pas créer un fix dédié pour ce seul défaut ; `pre.003` le corrige avec ses propres modifications.
|
||||
|
||||
## 21. Gate `TransactionExecutionEvent` — `pre.003`
|
||||
|
||||
### 21.1 Représentation de signature
|
||||
|
||||
Verdict : `PASS`.
|
||||
|
||||
La primitive admise est :
|
||||
|
||||
```text
|
||||
TransactionSignature([u8; 64])
|
||||
```
|
||||
|
||||
Contraintes :
|
||||
|
||||
- construction depuis 64 octets déjà décodés uniquement ;
|
||||
- aucun base58/serde/codec dans Interface ;
|
||||
- `Debug` masque systématiquement les bytes ;
|
||||
- aucune dependency Solana supplémentaire ;
|
||||
- aucune capability de signature Wallet ; il s'agit uniquement d'une identité transactionnelle passive observée.
|
||||
|
||||
`ksp-store-api::RawTransactionSignature` reste Store-owned. Aucun alias, reexport ou conversion implicite cross-domain n'est introduit. Une future composition peut effectuer explicitement la conversion via les 64 octets lorsque nécessaire.
|
||||
|
||||
### 21.2 Convergence producer
|
||||
|
||||
| Producer | Slot | Signature | Outcome | Metadata volontairement exclue | Verdict |
|
||||
| -------------------------------------- | ----------------------- | ----------------------------------- | ----------------------------------- | -------------------------------------------------------------- | ------- |
|
||||
| Solana WS `logsSubscribe` | `context.slot` | base58, décodée par la composition | `err == null` / `err != null` | logs, commitment, subscription | PASS |
|
||||
| Yellowstone `TransactionStatus` | `slot` | 64 bytes | `err None` / `err Some` | filters, created_at, is_vote, index, opaque error bytes | PASS |
|
||||
| Helius `transactionSubscribe` | `slot` si forme typée | signature si forme typée | seulement si erreur déterminable | detail mode, transactionIndex, memo, blockTime, confirmation | PASS* |
|
||||
|
||||
`PASS*` Helius signifie **projection conservative** : aucune `TransactionExecutionEvent` n'est fabriquée pour une forme `none`, inconnue ou dont l'erreur d'exécution est absente/indéterminable. Le DTO provider reste Transport-owned.
|
||||
|
||||
### 21.3 Outcome commun
|
||||
|
||||
Le contrat n'encode pas les erreurs provider :
|
||||
|
||||
```text
|
||||
Solana `err: null` / Yellowstone `err: None` / Helius `err: null` explicite -> Succeeded
|
||||
Solana/Yellowstone/Helius erreur explicite -> Failed
|
||||
Helius `err` omis ou forme inconnue -> aucune projection
|
||||
```
|
||||
|
||||
Cette normalisation décrit uniquement le résultat d'exécution observé. Elle ne prétend pas encoder un commitment, une finalité, une cause d'erreur, un index de transaction ou une garantie de replay.
|
||||
|
||||
### 21.4 Consumer concret
|
||||
|
||||
Verdict : `PASS`.
|
||||
|
||||
Le futur worker RAW live décrit dans `docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md` peut consommer le fait compact pour déclencher une hydratation/acquisition par signature sans dépendre du DTO source. Le premier backfill historique `0.3.6` ne dépend pas de cet event.
|
||||
|
||||
### 21.5 Anti-duplication Store
|
||||
|
||||
Verdict : `PASS`.
|
||||
|
||||
`TransactionExecutionEvent` ne contient ni payload RAW, format, content hash, block time, provenance, observation key, retention state ni network id durable. Il ne peut donc pas remplacer `RawTransaction`, `RawTransactionReference` ou `RawTransactionObservation`.
|
||||
|
||||
### 21.6 Décision finale
|
||||
|
||||
```text
|
||||
TransactionSignature
|
||||
TransactionExecutionOutcome
|
||||
TransactionExecutionEvent
|
||||
-> ADMIS Interface
|
||||
|
||||
TransactionLogEvent
|
||||
-> idée différée
|
||||
|
||||
TransactionCommitmentEvent
|
||||
-> non admis
|
||||
|
||||
DTOs logsSubscribe / Yellowstone TransactionStatus / Helius transactionSubscribe
|
||||
-> Transport-owned
|
||||
```
|
||||
|
||||
## 22. Implémentation `0.3.5-pre.003`
|
||||
|
||||
Surface ajoutée au crate-root :
|
||||
|
||||
```text
|
||||
TransactionSignature
|
||||
TransactionExecutionOutcome
|
||||
TransactionExecutionEvent
|
||||
```
|
||||
|
||||
API :
|
||||
|
||||
```text
|
||||
TransactionSignature::new([u8; 64])
|
||||
TransactionSignature::as_bytes()
|
||||
|
||||
TransactionExecutionOutcome::{Succeeded, Failed}
|
||||
|
||||
TransactionExecutionEvent::new(slot, signature, outcome)
|
||||
TransactionExecutionEvent::slot()
|
||||
TransactionExecutionEvent::signature()
|
||||
TransactionExecutionEvent::outcome()
|
||||
```
|
||||
|
||||
`TransactionExecutionOutcome` est `#[non_exhaustive]`. Les deux `Debug` contenant une signature sont bornés et n'affichent aucun byte de signature.
|
||||
|
||||
Le graphe normal visé reste :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Aucun converter Transport, aucune dependency Store, aucun `serde`, logging, runtime, channel ou codec n'est ajouté.
|
||||
|
||||
## 23. Fichiers de `pre.003`
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/src/lib.rs
|
||||
crates/ksp-interface-lib/tests/release_completeness.rs
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/src/transaction_execution.rs
|
||||
crates/ksp-interface-lib/unit_tests/transaction_execution.rs
|
||||
crates/ksp-interface-lib/tests/transaction_execution_public_api.rs
|
||||
deltas/0.3.5/pre.003.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## 24. Gate opérateur demandé pour `pre.003`
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les gates Cargo de `pre.003` restent à exécuter par l'opérateur dans le repository réel.
|
||||
|
||||
## 25. Gate opérateur `pre.003`
|
||||
|
||||
Le gate opérateur du `2026-08-31` est intégralement propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 141 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
```
|
||||
|
||||
`ksp-interface-lib` exécute alors seize tests unitaires, dont les trois canaris `transaction_execution`, et les deux tests publics `transaction_execution_public_api` passent. `ksp-program-api` reste vert avec ses frontières historiques inchangées.
|
||||
|
||||
## 26. Complétude API et canaris externes — `pre.004`
|
||||
|
||||
`pre.004` n'ajoute aucun contrat de production. La version workspace évolue vers `0.3.5-pre.4` parce que la tranche modifie des sources Rust de test/canari.
|
||||
|
||||
Les canaris figent désormais explicitement :
|
||||
|
||||
```text
|
||||
2 familles passives d'acquisition exactement
|
||||
5 modules privés de production exactement
|
||||
11 reexports crate-root exactement
|
||||
SlotLifecycleStage #[non_exhaustive]
|
||||
TransactionExecutionOutcome #[non_exhaustive]
|
||||
consumer externe crate-root pour SlotLifecycleEvent
|
||||
consumer externe crate-root pour TransactionExecutionEvent
|
||||
aucune dependency/path Transport, Store, runtime, serde ou logging dans les sources acquisition
|
||||
```
|
||||
|
||||
Le consumer externe ne dépend d'aucun module privé et consomme les deux contrats uniquement via `ksp_interface_lib::*`. Le firewall de dépendances balaie maintenant également `slot_lifecycle.rs` et `transaction_execution.rs`.
|
||||
|
||||
Restent hors de la surface :
|
||||
|
||||
```text
|
||||
converters Transport -> Interface
|
||||
DTOs provider
|
||||
Store RAW
|
||||
serde/codecs
|
||||
logging/tracing
|
||||
runtime/channels
|
||||
TransactionLogEvent
|
||||
TransactionCommitmentEvent
|
||||
```
|
||||
|
||||
Aucun changement n'est apporté à `crates/ksp-interface-lib/Cargo.toml`, aux sources de production Interface, à Transport, Store, Program API, README, ROADMAP ou CHANGELOG.
|
||||
|
||||
## 27. Gate opérateur demandé pour `pre.004`
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les gates Cargo de `pre.004` restent à exécuter par l'opérateur dans le repository réel.
|
||||
|
||||
## 28. Gate opérateur `pre.004`
|
||||
|
||||
Le gate opérateur du `2026-08-31` est intégralement propre :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 142 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
```
|
||||
|
||||
`ksp-interface-lib` exécute alors seize tests unitaires, cinq canaris de dependency boundary, deux canaris external consumer, quatre canaris de release completeness et les quatre tests publics des deux familles acquisition. `ksp-program-api` reste vert sans changement de contrat.
|
||||
|
||||
## 29. Hardening final Interface — `pre.005`
|
||||
|
||||
`pre.005` n'ajoute aucun type ni champ de production. La version workspace évolue vers `0.3.5-pre.5` parce que la tranche ajoute/modifie des sources Rust de test/canari.
|
||||
|
||||
Le hardening verrouille explicitement :
|
||||
|
||||
```text
|
||||
TransactionSignature = exactement 64 octets déjà décodés
|
||||
Debug TransactionSignature = redacted
|
||||
Debug TransactionExecutionEvent = aucune signature brute
|
||||
SlotLifecycleEvent = exactement slot + stage
|
||||
TransactionExecutionEvent = exactement slot + signature + outcome
|
||||
aucun Vec/String/Box/payload/timestamp/provider/endpoint/filter/network dans les events acquisition
|
||||
aucun second RAW exporté depuis Interface
|
||||
aucune famille deferred promue silencieusement
|
||||
manifest Interface = Core-only, sans features/dev/build dependencies
|
||||
ProgramInstruction foundation = bornes historiques inchangées
|
||||
```
|
||||
|
||||
Le canari adversarial injecte une signature contenant un marqueur hostile lisible et vérifie que les octets exacts restent accessibles par `as_bytes()` tout en restant absents des surfaces `Debug`. L'event d'exécution conserve `u64::MAX` sans narrowing.
|
||||
|
||||
Le contrôle anti-persistence interdit explicitement dans la façade Interface les familles `RawTransaction`, `RawAccount`, payload/cursor/retention/observation RAW. Interface conserve uniquement des faits event-only compacts.
|
||||
|
||||
Le graphe reste :
|
||||
|
||||
```text
|
||||
ksp-interface-lib
|
||||
└── ksp-core-lib
|
||||
```
|
||||
|
||||
Le manifeste ne possède toujours ni `[features]`, ni `[dev-dependencies]`, ni `[build-dependencies]`. Aucun `serde`, codec, logging, runtime, Transport ou Store n'est ajouté.
|
||||
|
||||
## 30. Inventaire des candidats reportés après hardening
|
||||
|
||||
La clôture fonctionnelle de `pre.005` conserve exactement deux familles acquisition admises. Les autres candidats restent :
|
||||
|
||||
```text
|
||||
TransactionLogEvent -> idée différée ; aucun type 0.3.5
|
||||
TransactionCommitmentEvent -> reporté ; signatureSubscribe/getSignatureStatuses ne sont pas fusionnés
|
||||
VoteEvent -> reporté ; vote gossip != transaction is_vote
|
||||
LedgerEntryEvent -> reporté ; Yellowstone Entry reste mono-producer/protocol-specific
|
||||
Account/Program event RAW -> rejet Interface ; Store/Transport owner
|
||||
Transaction complète -> rejet Interface ; RawTransaction/Transport owner
|
||||
Block event -> rejet Interface ; Transport/acquisition container
|
||||
Persisted-data available -> rejet Interface ; Store API notification owner
|
||||
```
|
||||
|
||||
`TransactionExecutionEvent` n'est plus un candidat reporté : il est admis depuis `pre.003`. `TransactionLogEvent` reste l'idée différée à transférer vers la surface TODO/IDEAS durable pendant la réconciliation documentaire `pre.007` si elle demeure hors scope.
|
||||
|
||||
## 31. Fichiers de `pre.005`
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/tests/dependency_boundary.rs
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajoutés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/tests/security_hardening.rs
|
||||
deltas/0.3.5/pre.005.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/Cargo.toml
|
||||
crates/ksp-interface-lib/src/**
|
||||
crates/ksp-interface-lib/unit_tests/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
crates/ksp-program-api/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
|
||||
## 32. Gate opérateur demandé pour `pre.005`
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test -p ksp-program-api
|
||||
```
|
||||
|
||||
Les gates Cargo de `pre.005` restent à exécuter par l'opérateur dans le repository réel.
|
||||
|
||||
## 33. Gate opérateur `pre.005` et correction `pre.005-fix.001`
|
||||
|
||||
Le gate opérateur du `2026-08-31` confirme que les audits Rust/Markdown et `cargo check --workspace` sont propres, mais révèle un défaut dans le nouveau canari de manifeste :
|
||||
|
||||
```text
|
||||
v0_3_5_pre_005_manifest_keeps_exact_core_only_graph_without_features_or_hidden_dependency_sections: FAILED
|
||||
left: 2
|
||||
right: 1
|
||||
```
|
||||
|
||||
Le manifeste Interface reste pourtant strictement Core-only. Le canari comptait naïvement les occurrences textuelles de `ksp-core-lib` dans :
|
||||
|
||||
```text
|
||||
ksp-core-lib = { path = "../ksp-core-lib" }
|
||||
```
|
||||
|
||||
Le nom apparaît donc deux fois sur une seule déclaration de dépendance : une fois comme clé et une fois dans le chemin. `pre.005-fix.001` corrige uniquement ce faux négatif en réutilisant le parseur de clés de dépendances déjà présent dans `dependency_boundary.rs`. Le canari vérifie désormais que la section `[dependencies]` existe exactement une fois et que son inventaire de clés vaut exactement `ksp-core-lib`, tout en conservant les interdictions `[features]`, `[dev-dependencies]` et `[build-dependencies]`.
|
||||
|
||||
Le fix modifie une source Rust de test ; la version workspace évolue donc vers :
|
||||
|
||||
```text
|
||||
0.3.5-pre.5.fix.1
|
||||
```
|
||||
|
||||
Aucun manifeste de crate, source de production, contrat public ou dependency graph n'est modifié.
|
||||
|
||||
## 34. Gate opérateur `pre.005-fix.001`
|
||||
|
||||
Le gate opérateur du `2026-08-31` est intégralement propre après correction du faux négatif du canari de manifeste :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 144 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test -p ksp-program-api: PASS
|
||||
cargo test --workspace: PASS
|
||||
```
|
||||
|
||||
Les tests live/diagnostiques restent uniquement `ignored` et n'introduisent aucun échec. Le canari corrigé `v0_3_5_pre_005_manifest_keeps_exact_core_only_graph_without_features_or_hidden_dependency_sections` passe. La surface Interface reste limitée aux deux familles acquisition admises et au graphe Core-only.
|
||||
|
||||
## 35. Gate technique final — `pre.006`
|
||||
|
||||
`pre.006` n'ajoute ni type, ni test, ni dépendance, ni source de production. La tranche matérialise uniquement le gate technique final prévu par le prompt de démarrage et fait évoluer la version workspace vers `0.3.5-pre.6`.
|
||||
|
||||
Le gate final doit confirmer l'état suivant :
|
||||
|
||||
```text
|
||||
ksp-interface-lib -> ksp-core-lib uniquement
|
||||
aucune feature Interface
|
||||
aucune dev/build dependency Interface
|
||||
aucun duplicate dependency introduit par 0.3.5
|
||||
2 familles acquisition exactement
|
||||
SlotLifecycleEvent
|
||||
TransactionExecutionEvent
|
||||
aucun serde/codec/logging/runtime/Transport/Store dans Interface
|
||||
```
|
||||
|
||||
Les commandes opérateur de clôture technique sont :
|
||||
|
||||
```text
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.5
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-interface-lib
|
||||
cargo test --workspace
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
cargo tree -p ksp-interface-lib -e features
|
||||
cargo tree --duplicates
|
||||
```
|
||||
|
||||
Aucun smoke réseau n'est requis : `0.3.5` ne modifie aucun moteur Transport et les contrats Interface sont passifs. Les résultats `cargo tree` sont capturés dans le résultat opérateur de clôture ci-dessous.
|
||||
|
||||
## 36. Fichiers de `pre.006`
|
||||
|
||||
Modifiés :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
```
|
||||
|
||||
Ajouté :
|
||||
|
||||
```text
|
||||
deltas/0.3.5/pre.006.md
|
||||
```
|
||||
|
||||
Explicitement inchangés :
|
||||
|
||||
```text
|
||||
crates/ksp-interface-lib/**
|
||||
crates/ksp-program-api/**
|
||||
crates/ksp-onchain-transport-lib/**
|
||||
crates/ksp-store-api/**
|
||||
crates/ksp-store-lib/**
|
||||
crates/ksp-store-postgres-lib/**
|
||||
README.md
|
||||
ROADMAP.md
|
||||
CHANGELOG.md
|
||||
```
|
||||
## 37. Résultat du gate technique final `pre.006`
|
||||
|
||||
Le gate opérateur du `2026-08-31` est propre après correction locale des numéros d'en-tête réellement modifiés dans `Cargo.toml` et ce document de validation :
|
||||
|
||||
```text
|
||||
General Rust rule audit: clean
|
||||
Rust export completeness audit: 0 candidate(s)
|
||||
KSP workspace Rust rule audit: clean
|
||||
Markdown table audit: clean (240 table(s), 145 file(s))
|
||||
cargo check --workspace: PASS
|
||||
cargo clippy --workspace --all-targets: PASS
|
||||
cargo test -p ksp-interface-lib: PASS
|
||||
cargo test --workspace: PASS
|
||||
```
|
||||
|
||||
Les tests live/réseau et probes diagnostiques restent explicitement `ignored` conformément à leur contrat ; aucun test non ignoré n'échoue.
|
||||
|
||||
Les trois preuves Cargo finales confirment :
|
||||
|
||||
```text
|
||||
cargo tree -p ksp-interface-lib --edges normal
|
||||
ksp-interface-lib -> ksp-core-lib -> solana-pubkey -> solana-address
|
||||
|
||||
cargo tree -p ksp-interface-lib -e features
|
||||
aucune feature propre Interface ; seule la feature default de ksp-core-lib est activée
|
||||
|
||||
cargo tree --duplicates
|
||||
doublons du workspace global présents, aucun nouveau doublon imputable à ksp-interface-lib/0.3.5
|
||||
```
|
||||
|
||||
Le manifeste Interface reste sans `[features]`, `[dev-dependencies]` ni `[build-dependencies]`. La surface fonctionnelle finale demeure exactement :
|
||||
|
||||
```text
|
||||
ProgramAccountMeta / ProgramInstruction
|
||||
SlotLifecycleEvent / SlotLifecycleStage
|
||||
TransactionSignature / TransactionExecutionEvent / TransactionExecutionOutcome
|
||||
```
|
||||
|
||||
Aucun serde, codec, logging, runtime, Transport ou Store n'est entré dans le graphe Interface.
|
||||
|
||||
## 38. Réconciliation documentaire finale — `pre.007`
|
||||
|
||||
`pre.007` ne modifie aucun code Rust ni manifeste de crate. La version workspace devient :
|
||||
|
||||
```text
|
||||
0.3.5-pre.7
|
||||
```
|
||||
|
||||
La réconciliation ferme les incohérences documentaires restantes :
|
||||
|
||||
- `crates/ksp-interface-lib/README.md` décrit désormais les contrats Program et les deux familles d'événements passifs sans présenter Interface comme un runtime ;
|
||||
- `crates/ksp-interface-lib/USAGE.md` devient version-neutral et documente la construction/consommation des événements via le crate-root ;
|
||||
- les documents d'architecture concernés distinguent explicitement contrat passif Interface, DTO riche Transport et modèle replayable Store ;
|
||||
- le futur RAW worker peut dépendre d'Interface pour un fait passif partagé, mais son backlog/recovery reste Store-owned ;
|
||||
- `TransactionLogEvent` reste hors scope et est transféré vers `docs/IDEAS.md` avec un nouveau gate consumer/bornes obligatoire ;
|
||||
- `CHANGELOG.md`, `ROADMAP.md` et le prompt `0.3.6` restent réservés à la tranche de publication suivante.
|
||||
|
||||
Fichiers modifiés par la tranche :
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-interface-lib/README.md
|
||||
crates/ksp-interface-lib/USAGE.md
|
||||
docs/IDEAS.md
|
||||
docs/architecture/002-LAYERS_AND_DEPENDENCIES.md
|
||||
docs/architecture/003-COMPONENT_CONTRACTS.md
|
||||
docs/architecture/004-COMPONENT_INVENTORY.md
|
||||
docs/architecture/005-DEPENDENCY_GRAPH.md
|
||||
docs/architecture/006-WIRE_AND_PROGRAM.md
|
||||
docs/architecture/009-ACQUISITION_WORKERS_AND_JOBS.md
|
||||
docs/plans/026-V0_3_5_INTERFACE_ACQUISITION_EVENTS_PLAN.md
|
||||
docs/validation/022-V0_3_5_INTERFACE_ACQUISITION_EVENTS.md
|
||||
deltas/0.3.5/pre.007.md
|
||||
```
|
||||
|
||||
Aucun autre fichier ne doit être modifié.
|
||||
|
||||
1473
prompts/025-V0_3_6_START_PROMPT.md
Normal file
1473
prompts/025-V0_3_6_START_PROMPT.md
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user