v0.3.13-pre.001

This commit is contained in:
2026-09-10 09:01:00 +02:00
parent 1dc57a85c2
commit ee0359efd5
5 changed files with 1632 additions and 4 deletions

View File

@@ -0,0 +1,860 @@
<!-- file: docs/plans/034-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE_PLAN.md -->
<!-- version: 1 -->
# Plan v0.3.13 — WS standard / Helius / HTTP live + convergence multi-source RawTransaction
## 1. But de la version
`0.3.13` étend la verticale live stable de `0.3.12` sans remplacer Yellowstone, sans recréer Transport et sans transformer le Worker en Job historique.
Pipeline durable :
```text
source live caller-composed
-> signal ou matériau Worker privé
-> convergence/coalescence bornée Worker
-> hydration HTTP observed si le matériau n'est pas complet
-> Common RAW ksp-raw-transaction-lib
-> admission Worker centrale existante
-> persistence ksp-store-lib
```
Sources P0 retenues :
```text
Yellowstone existant
WS standard logsSubscribe + getTransaction observed
WS standard blockSubscribe full/base64
Helius transactionSubscribe full/base64 + getTransaction observed
HTTP live getSlot + getBlocksWithLimit + getBlock observed
```
`0.3.13` ferme la convergence live et les observations multiples. Le gap repair multi-source, les campagnes historiques et les sources EARLY restent `0.3.14+` / `0.3.16+` selon la roadmap.
## 2. Base autoritaire auditée en pre.001
```text
archive : khadhroony-solana-project-v0.3.12.zip
SHA-256 : 85c41eb9f8575ee58edd9863445cbc37b79ef59c4a7cf882679ff24dc8991bf5
ZIP bytes : 8260528
ZIP entries : 1981
ZIP files : 1788
workspace members : 21
workspace.package.version : 0.3.12
stable delta : deltas/0.3.12/rel.001.md
prompt : prompts/032-V0_3_13_START_PROMPT.md
```
Contrôles archive :
```text
unzip -t : PASS
entrée absolue : 0
path traversal : 0
doublon d'entrée ZIP : 0
symlink ZIP : 0
Cargo.lock : 0
rust-toolchain.toml : 0
package-lock/pnpm-lock/yarn.lock : 0
.env : 0
crate manifests : 21
workspace members sans crate : 0
crates hors workspace : 0
```
La stable contient bien la verticale productive `Worker -> Transport -> Common RAW -> Store` de `0.3.12`, sans edge Worker vers Config, Job Backfill ou backend Store physique.
## 3. Audit des règles actives
Les documents normatifs ont été relus depuis `RULES.md` et `docs/rules/`.
Contraintes bloquantes :
```text
Rust 2024
unsafe interdit
unwrap / expect / panic interdits en production
? interdit en production
retours explicites
pas de pub mod
pub/pub(crate) partagés réexportés au crate-root
accès intra-crate partagé via crate::Item
unit_tests/ pour les tests privés, tests/ pour l'API publique
Config possède fichiers/profils/endpoints/secrets
Transport ne dépend ni de Config ni de Store
Worker ne dépend ni de Job Backfill ni d'un backend Store physique
Worker persiste via ksp-store-lib seulement
aucun acteur/socket/client Transport réimplémenté dans Worker
une prerelease non-fix synchronise workspace.package.version
archive d'échange = delta minimal
commande non exécutée != PASS
```
### 3.1 Collision normative trouvée
L'audit supplémentaire d'unicité des identifiants de règles a trouvé deux règles distinctes nommées `KSP-CONFIG-018` dans `docs/rules/RULES_KSP.md`.
Le delta historique `0.1.3-pre.014` prouve que la règle d'inventaire `.env.example` est l'identité `KSP-CONFIG-018` d'origine. La règle desktop ajoutée ultérieurement doit donc devenir `KSP-CONFIG-019` sans changement de contenu normatif.
Cette correction documentaire est intégrée à `pre.001` parce qu'elle ferme une ambiguïté normative découverte pendant le gate de règles demandé par le prompt.
## 4. État stable à préserver
`0.3.12` possède déjà :
```text
start/stop/supervisor Worker
mpsc d'admission centrale bornée
persistence Store atomique/idempotente
Common RAW Legacy/V0/V1
une source Yellowstone caller-composed
Transaction/TransactionStatus/Block -> hydration HTTP observed
BlockMeta/Slot -> continuité seulement
coalescence hydration (network, signature, commitment)
processing frontier run-local
reconnect/replay/gap source-neutral
fault sur retention gap prouvé
shutdown borné avec abort/join
snapshot latest-value redacted
canaris dependency/security cross-layer
```
La migration multi-source doit réutiliser ces contrats plutôt que créer un second pipeline.
## 5. Audit Transport interne actuel
### 5.1 WebSocket standard
`ksp-onchain-transport-lib` possède déjà `SolanaStandardWsSession`, façade typée au-dessus du même `WsSession` physique.
Elle expose notamment :
```text
logs_subscribe
block_subscribe
signature_subscribe
slot/root/cluster wrappers existants
snapshot/state/close
```
Le reconnect, le resubscribe, les IDs distants, les queues de notifications et le backpressure WebSocket sont Transport-owned.
### 5.2 Helius WebSocket
`HeliusLaserStreamWsSession` réutilise le même acteur physique Transport et expose `transaction_subscribe` sans escape hatch vers le `WsSession` générique.
Le type `HeliusFullTransactionNotification` fournit le matériau transactionnel riche, la signature, le slot et l'index, mais l'enveloppe full qualifiée ne contient pas directement tous les champs Common RAW déjà garantis par `getTransaction observed`.
### 5.3 HTTP
Le pool HTTP expose déjà les primitives nécessaires :
```text
get_transaction_observed
get_block_observed
get_slot
get_blocks
get_blocks_with_limit
```
Le winner provider/endpoint est projeté sous forme sûre ; URL, credential et erreur distante arbitraire restent cachés.
Retry, rate limit, timeout et sélection d'endpoint restent Transport-owned.
## 6. Audit externe courant du 10 septembre 2026
### 6.1 Solana logsSubscribe
La documentation Solana courante confirme :
```text
all
allWithVotes
mentions avec exactement un pubkey par abonnement
notification = context.slot + signature + err + logs
```
Cette source ne transporte pas un RAW complet ; `getTransaction observed` reste requis.
### 6.2 Solana blockSubscribe
La documentation courante maintient `blockSubscribe` comme méthode instable, disponible seulement sur les validators qui activent explicitement la subscription de blocs. Commitment admis : `confirmed` ou `finalized`.
Pour KSP P0 :
```text
encoding = base64
transactionDetails = full
showRewards = false
maxSupportedTransactionVersion = 1
```
Le guide Solana Transaction V1 courant précise qu'un client version-aware doit utiliser `maxSupportedTransactionVersion = 1` pour `getTransaction`, `getBlock` et la consommation de blocs ; sinon une transaction V1 peut faire échouer HTTP ou produire `block: null` côté `blockSubscribe`.
Le format V1 n'est pas encore actif sur les clusters publics au 10 septembre 2026, mais KSP doit être prêt avant activation.
### 6.3 Helius transactionSubscribe
La documentation/pricing Helius courant confirme :
```text
transactionSubscribe disponible à partir du tier Developer
standard WSS disponible sur Free+
blockSubscribe classé unstable et non supporté sur LaserStream WSS
maxSupportedTransactionVersion doit être préparé à 1 pour Legacy/V0/V1
```
Conclusion :
```text
Helius transactionSubscribe reste une source dédiée Helius
blockSubscribe reste une source WS standard, jamais HeliusLaserStreamWsSession
aucun tier/prix n'entre dans une constante métier KSP
smoke Helius live conditionnel au credential/tier opérateur
```
### 6.4 Sources externes normatives
```text
https://solana.com/docs/rpc/websocket/logssubscribe
https://solana.com/docs/rpc/websocket/blocksubscribe
https://solana.com/docs/rpc/http/getslot
https://solana.com/docs/rpc/http/getblocks
https://solana.com/docs/rpc/http/getblockswithlimit
https://solana.com/docs/rpc/http/getblock
https://solana.com/docs/rpc/http/gettransaction
https://solana.com/docs/core/transactions/versioned-transactions
https://www.helius.dev/docs/api-reference/rpc/websocket-methods
https://www.helius.dev/pricing
https://www.helius.dev/blog/laserstream-websockets
```
## 7. Décision de maintien de la release
Décision : **maintenir `0.3.13` telle que prévue**, sans rescission fonctionnelle avant codage.
Motifs :
```text
les quatre nouvelles familles de Transport existent déjà
aucune nouvelle dépendance externe n'est nécessaire
Common RAW et Store n'ont pas besoin d'être redessinés
le Worker a déjà une admission centrale bornée et des observations déterministes
le principal refactor est local au Worker : source inventory + convergence globale
la prévision pre.002..pre.012 sépare correctement les risques
pre.013/pre.014/pre.015 réservent gate, documentation et publication
```
Le scope serait rescindé uniquement si `pre.002` démontre qu'une collection multi-source sûre exige une rupture de Common RAW/Store/Transport, ce que l'audit `pre.001` ne montre pas.
## 8. Modèle de source multi-source retenu
### 8.1 Source logique
Le Worker introduira une source live interne discriminée par **capability**, pas par provider :
```text
Yellowstone
StandardLogs
StandardBlock
HeliusTransaction
HttpBlockPolling
```
Le provider/endpoint reste une donnée de route/provenance Transport, pas un enum Worker.
### 8.2 Identité de source
Chaque source reçoit une `source_key` stable de 32 octets dérivée par SHA-256 d'un domaine KSP et des seules données sûres nécessaires :
```text
network
source family
safe provider/endpoint identity ou profile-safe identity
commitment
filter fingerprint / request fingerprint
```
Aucune URL, API key, header, transaction, log ou erreur distante ne participe en clair à la clé ou à Debug.
Deux sources configurées avec exactement la même identité logique sont rejetées à la construction des runtime resources afin d'éviter une duplication accidentelle invisible.
### 8.3 Collection bornée
Décision P0 :
```text
MAX_RAW_TRANSACTION_INGEST_LIVE_SOURCES = 32
minimum = 1 source pour start_with_runtime_resources
maximum = 32 sources logiques par Worker
```
Cette borne concerne les **sources runtime**, pas la cardinalité des filtres provider, laquelle reste possédée et bornée par Transport.
La collection est validée entièrement avant tout spawn réseau.
### 8.4 Simultanéité
Toutes les sources retenues dans `RawTransactionIngestRuntimeResources` sont démarrées simultanément.
Il n'existe pas en `0.3.13` de politique implicite :
```text
first-provider-wins
priority/fallback caché
source primaire + standby
arrêt des autres sources après première observation
```
Les priorités Config éventuelles restent hors Worker tant qu'une sémantique de coverage/failover n'est pas définie en `0.3.14`.
## 9. Convergence globale retenue
### 9.1 Deux classes d'entrée
Une source Worker produit l'une des formes privées suivantes :
```text
ReferenceSignal
network + signature + slot + commitment + source observation seed
CompleteMaterial
RawTransactionMaterial + source observation seed
```
`ReferenceSignal` doit être hydraté. `CompleteMaterial` peut entrer directement dans Common RAW si sa qualification de version est prouvée.
### 9.2 Coordinator Worker global
Le coordinator d'hydration actuellement privé à la source Yellowstone devient une ressource Worker **globale aux sources**.
Clé de coalescence :
```text
(network, signature, hydration commitment)
```
Un seul `getTransaction observed` est ouvert pour plusieurs signaux simultanés portant la même clé. Les observation seeds restent distincts et sont conservés dans un vecteur borné par le nombre total de signaux admis.
### 9.3 Bornes globales
Décision P0 :
```text
source signal queue capacity = settings.admission_queue_capacity()
global pending signal count <= settings.admission_queue_capacity()
hydration tasks in flight <= settings.persistence_concurrency()
source count <= 32
pas de queue provider privée dans Worker
pas de Vec/Map pending non bornée
```
Les limites existantes restent :
```text
admission queue : 1 .. 65536
persistence concurrency : 1 .. 64
shutdown timeout : bornes 0.3.12 conservées
```
Le coordinator doit utiliser la capacité effective configurée plutôt que la constante maximale comme borne opérationnelle de pending.
### 9.4 Fairness minimale
Aucune source ne reçoit une queue Worker non bornée. Tous les producteurs attendent sur le même canal borné et subissent le même backpressure.
`pre.009` doit prouver qu'un duplicate storm d'une source ne peut ni faire croître la mémoire sans borne, ni créer un fanout d'hydration, ni empêcher définitivement une autre source déjà prête d'être consommée.
Aucune promesse de scheduler pondéré complexe n'est introduite en `0.3.13`.
## 10. Observations multiples sans identité RawTransaction dupliquée
Identité canonique durable :
```text
(RawNetworkId, TransactionSignature)
```
Elle ne contient jamais la source.
Pour une même transaction observée par plusieurs sources :
```text
canonicalisation Common RAW une fois par matériau convergé
première observation -> persist_raw_transaction_acquisition atomique
observations supplémentaires du même lot -> record_raw_transaction_observation
```
Cette stratégie réutilise la capability Store existante conçue pour enregistrer une observation supplémentaire sans resoumettre le payload RAW potentiellement volumineux.
Les clés d'observation restent producteur-owned et déterministes. Deux sources distinctes doivent produire deux observation keys distinctes ; une rediffusion idempotente de la même source doit retrouver la même key.
Si la persistence atomique initiale échoue, aucune observation additionnelle n'est écrite. Si une observation additionnelle échoue, le Worker conserve la politique de faute Store sûre de `0.3.12` ; aucun succès silencieux n'est déclaré.
## 11. Content conflict et disagreement cross-source
Politique conservatrice :
```text
même identité + même canonical payload/hash = idempotence
même identité + payload/hash divergent = content conflict explicite
```
Aucune majorité de providers, préférence de tier ou overwrite n'est autorisé.
Le Store reste l'autorité durable finale du conflit. Le coordinator peut détecter plus tôt une divergence lorsque plusieurs matériaux complets de même identité coexistent dans le même lot, mais cette optimisation ne remplace jamais le guard Store.
Un content conflict reste terminal pour le Worker en `0.3.13`.
## 12. Contrat source Yellowstone existant
Entrée :
```text
YellowstoneGrpcChannel
YellowstoneSubscribeRequest
HttpTransportPool
HttpRoleName hydration
network dérivé et validé
```
Sortie : `ReferenceSignal` pour les familles Transaction/TransactionStatus/Block qualifiées, continuité seule pour BlockMeta/Slot.
Bornes : Transport + queue globale Worker ; aucune nouvelle queue par source.
Retry/reconnect : Transport Yellowstone et HTTP.
Preuve : suites `0.3.12` non régressées + canaris multi-source avec Yellowstone en parallèle d'une seconde source factice/déterministe.
## 13. Contrat source WS standard logsSubscribe
Entrée caller-composed :
```text
WsEndpointSettings kind solana_standard
SolanaLogsSubscribeFilter
commitment Confirmed ou Finalized
HttpTransportPool
HttpRoleName hydration
```
Le Worker ouvre `SolanaStandardWsSession::connect` via Transport puis `logs_subscribe`.
Sortie :
```text
context.slot
signature
source observation seed
```
Les logs et l'erreur distante ne sont jamais recopiés dans snapshot/tracing ; ils ne sont pas nécessaires à Common RAW.
Hydration : `get_transaction_observed` avec Base64 et `maxSupportedTransactionVersion = 1`.
Retry/reconnect/resubscribe : Transport WS.
Hydration retry/rate limit : Transport HTTP.
Preuve : fixture logs notification -> une seule hydration -> exact Common RAW golden ; mentions/all/allWithVotes ; stop/reconnect/backpressure ; redaction des logs.
## 14. Contrat source WS standard blockSubscribe
Entrée caller-composed :
```text
WsEndpointSettings kind solana_standard
SolanaBlockSubscribeFilter
commitment Confirmed ou Finalized
encoding Base64
transactionDetails Full
maxSupportedTransactionVersion = 1
showRewards = false
```
Sortie : transactions du bloc sous forme `CompleteMaterial` lorsque la version est qualifiée ; fallback/fault explicite ailleurs.
Qualification P0 :
```text
Legacy : RAW-direct déjà prouvé par 0.3.10, à rejouer
V0 : RAW-direct déjà prouvé par 0.3.10, à rejouer
V1 : doit être prouvé en pre.004 sur fixture locale v1 avant RAW-direct
```
Tant que le golden V1 n'est pas vert, une transaction V1 n'est pas déclarée direct-qualified. Le chemin autorisé est hydration `getTransaction observed` si l'identité peut être obtenue, sinon faute explicite sûre.
`block: null` avec erreur de version/support n'est jamais interprété comme bloc vide ni comme progression de frontier.
Retry/reconnect/resubscribe : Transport WS.
Preuve : parité bytes/hash entre notification blockSubscribe et `getBlock`/fixture Common RAW pour Legacy/V0 puis V1 ; canari `block:null` ; unsupported validator explicite.
## 15. Contrat source Helius transactionSubscribe
Entrée caller-composed :
```text
WsEndpointSettings kind helius_laserstream
HeliusTransactionSubscribeRequest
commitment Confirmed ou Finalized
encoding Base64
transactionDetails Full
maxSupportedTransactionVersion = 1
HttpTransportPool
HttpRoleName hydration
```
Sortie : `ReferenceSignal` riche mais hydraté avant Common RAW P0.
Motif : conserver une seule source de vérité de complétude `getTransaction observed` pour `blockTime`, version et wire exact, même si Helius enrichit son enveloppe à l'avenir.
Retry/reconnect/resubscribe : Transport WS.
Hydration retry/rate limit : Transport HTTP.
Config : réutiliser uniquement `KSP_SECRET_HELIUS_API_KEY`. Aucun secret Helius supplémentaire et aucun SDK provider.
Live smoke : conditionnel à un credential/tier Developer+ disponible. L'absence de ressource reste `NON EXÉCUTÉ`.
## 16. Contrat source HTTP live block polling
### 16.1 Borne de run
Au démarrage de la source :
```text
start_slot = getSlot(commitment)
next_scan_slot = start_slot
```
Aucun slot inférieur à `start_slot` n'est recherché par cette source. Elle reste donc live/run-local et ne devient pas un Backfill.
### 16.2 Discovery
À chaque cycle :
```text
current_tip = getSlot(commitment)
getBlocksWithLimit(next_scan_slot, bounded_limit, commitment)
getBlock observed pour les slots réellement listés
```
Les skipped slots sont exclus naturellement par `getBlocksWithLimit`; aucun faux gap n'est créé simplement parce qu'un slot n'a pas de bloc confirmé.
### 16.3 Bornes P0
Le contrat Worker de polling introduira :
```text
poll interval default = 1 s
poll interval min = 100 ms
poll interval max = 30 s
max discovered blocks per cycle default = 128
max discovered blocks per cycle min = 1
max discovered blocks per cycle max = 1024
```
Le rate limit physique reste Transport-owned et peut ralentir l'exécution réelle.
Une réponse `getBlock = null` pour un slot précédemment listé ne fait pas avancer silencieusement `next_scan_slot`; le slot reste la tête de travail du cycle suivant ou devient une faute sûre selon le résultat déterministe défini en `pre.006`.
Timer/cadence : Worker source task.
Retry HTTP : Transport.
Preuve : faux pool/fixtures déterministes avec skipped slots, tip qui avance, null transitoire, stop pendant timer/getBlock, rate-limit lent et absence de scan antérieur au start slot.
## 17. Source lifecycle et health
Le lifecycle physique détaillé reste privé/source-neutral.
États existants à préserver :
```text
Active
Reconnecting
Closing
Closed
Failed
```
Sous multi-source, le Worker maintient un inventaire privé `source_key -> latest state` borné à 32 entrées.
Projection publique P0 :
```text
source_total
source_active
source_reconnecting
source_failed
source_state agrégé compatible
source_failure_total agrégé existant
backpressure_total agrégé existant
```
Aucun provider, endpoint, filtre, URL ou credential n'est exposé.
Politique conservatrice de terminalité : une source configurée qui atteint `Failed` reste terminale pour le Worker en `0.3.13`. KSP ne peut pas supposer que les autres sources couvrent le même univers de filtres. La relaxation vers degraded/failover exige une preuve de coverage et appartient à `0.3.14`.
Un reconnect transitoire peut projeter `Degraded` sans terminalité. Un retention gap prouvé reste terminal comme en `0.3.12`.
## 18. Processing frontier et continuité
La processing frontier reste run-local et ne devient ni checkpoint durable ni preuve de blockchain completeness.
Sous multi-source :
```text
chaque signal/material observe son slot
un pending coalescé reste pending tant que sa persistence/observation requise n'est pas réglée
la frontier globale n'avance jamais à travers un pending de n'importe quelle source
reconnect != replay != repair
source redondante != preuve automatique de couverture
```
Le gap repair reste explicitement `0.3.14`.
## 19. Threat model 0.3.13
### 19.1 Duplicate storm
Risque : une même signature arrive par plusieurs subscriptions/providers.
Réponse : coalescence globale, signal count borné, observation keys idempotentes, aucune hydration fanout.
### 19.2 Source skew
Risque : une source fournit un slot/index différent d'une autre.
Réponse : identity/material guards et conflit explicite ; aucune préférence silencieuse.
### 19.3 Provider disagreement
Risque : contenu divergent pour la même signature.
Réponse : hash canonique + Store content conflict terminal.
### 19.4 Reconnect storms
Risque : resubscribe simultané et duplicates.
Réponse : reconnect Transport-owned, logical subscription stable, coordinator idempotent/borné.
### 19.5 Hydration fanout
Risque : N sources déclenchent N getTransaction identiques.
Réponse : une hydration globale par `(network, signature, commitment)`.
### 19.6 Polling drift
Risque : timer plus rapide que capacité HTTP/Store.
Réponse : pas de spawn par tick, cycle séquentiel/borné, backpressure et rate limit Transport.
### 19.7 Slow Store
Risque : accumulation signal/hydration.
Réponse : admission et convergence bornées ; producteurs attendent ; aucun drop silencieux.
### 19.8 Stop/fault concurrent
Risque : connect/resubscribe/timer/hydration/persistence actifs au terminal.
Réponse : ownership supervisor, stop préemptif là où sûr, drain Store borné, abort/join de toutes tasks owned.
### 19.9 Secrets/remote material
Interdit dans Debug/error/snapshot/tracing :
```text
URL
API key/token/header
transaction bytes
raw signature text dans logs
provider logs
Helius filter values
remote error text arbitraire
```
## 20. Graphe Cargo cible
Aucune nouvelle dépendance externe n'est nécessaire.
```text
ksp-worker-raw-transaction-ingest-lib
-> ksp-core-lib
-> ksp-logging-lib
-> ksp-onchain-transport-lib
-> ksp-raw-transaction-lib
-> ksp-store-lib default-features=false
-> ksp-worker-api
-> sha2
-> tokio macros,rt,sync,time
```
Toujours interdit :
```text
Worker -> ksp-config-lib
Worker -> ksp-job-backfill-lib
Worker -> ksp-store-postgres-lib
Worker -> reqwest direct
Worker -> tonic direct
Worker -> yellowstone-grpc-proto direct
Worker -> provider SDK
Transport -> Common RAW
Transport -> Store
```
## 21. Config et secrets
L'archive stable contient des profils standard Solana committed et des exemples Helius LaserStream. `KSP_SECRET_HELIUS_API_KEY` est déjà l'identité de secret documentée.
Décision : `pre.001` n'ajoute aucun profil Config. `pre.005` ne modifiera Config que si un profil runtime committed est réellement nécessaire à un consumer/smoke de cette release. Le Worker reste incapable de lire Config.
Aucune nouvelle clé `.env` n'est anticipée.
## 22. Preuves déterministes obligatoires
Avant clôture technique :
```text
resource collection 1..32 + duplicate source identity reject
Yellowstone non-régression
logs -> one hydration -> RAW exact
blockSubscribe Legacy/V0 direct exact
blockSubscribe V1 qualification ou fallback/fault exact
block:null non assimilé à vide
Helius full -> hydration -> RAW exact
HTTP polling never scans before run start
skipped slots handled without false transaction/gap
cross-source same identity/same content -> one entity + N observations
cross-source same identity/divergent content -> content conflict
one hydration for duplicate cross-source references
pending queues bounded under storm
fair progress for a second ready source
source failure/reconnect aggregate projection redacted
stop/fault joins WS/poll/hydration/persistence tasks
no Config/Job/backend/provider dependency leak
Legacy/V0/V1 canaries cross-layer
```
## 23. Smokes live et qualification
Disponibles sans secret selon l'environnement opérateur :
```text
Solana HTTP Devnet
Solana WS Devnet logsSubscribe
Solana WS Devnet blockSubscribe seulement si endpoint/validator l'expose
HTTP polling Devnet
```
Conditionnels :
```text
Helius transactionSubscribe : credential/tier Developer+
Yellowstone : credential/provider selon stable 0.3.12
```
Chaque smoke indisponible est `NON EXÉCUTÉ`, jamais PASS.
## 24. Sizing recalibré
### pre.001 — audit / règles / sizing / plan
Archive, règles, collision `KSP-CONFIG-018`, audit interne/externe, contrats sources, convergence, threat model, graphes, validation.
### pre.002 — runtime resources multi-source
Collection bornée 1..32, source key, discriminants capability-owned, validation globale, sans branchement productif des nouvelles sources.
### pre.003 — WS standard logsSubscribe + hydration
Source logs, signal privé, intégration coordinator global et hydration observed.
### pre.004 — WS standard blockSubscribe
Source block, projection full/base64, qualification Legacy/V0/V1, `block:null` et fallback/fault.
### pre.005 — Helius transactionSubscribe
Source Helius, max version 1, hydration, Config uniquement si réellement requis, tests redaction/tier non codé.
### pre.006 — HTTP live block polling
Borne de run, timer, getSlot/getBlocksWithLimit/getBlock observed, skipped slots/null/stop.
### pre.007 — supervisor/source inventory
Démarrage simultané, source lifecycle privé, stop/fault/joins et processing frontier multi-source.
### pre.008 — convergence + observations multiples
Coalescence cross-source, canonicalisation de lot, persistence entity + observations supplémentaires, idempotence.
### pre.009 — conflits/backpressure/fairness
Disagreement, content conflict, duplicate storms, global bounds, starvation canaries.
### pre.010 — snapshots/health multi-source
Counts source-neutral, agrégation health/activity, redaction publique.
### pre.011 — races/shutdown hardening
Stop/fault pendant connect/reconnect/hydration/polling/Store, no orphan et counter exhaustion.
### pre.012 — completeness/security cross-layer
Canaris API/dependencies/Legacy-V0-V1/Transport-Worker-CommonRAW-Store et non-régression Yellowstone.
### pre.013 — gate technique/live
Workspace complet, Clippy strict, tests, graphes/duplicates et smokes accessibles. Aucun nouveau scope.
### pre.014 — réconciliation documentaire
README/USAGE, plan, validation et architectures réellement affectées. Pas de CHANGELOG/ROADMAP/prompt suivant.
### pre.015 — préparation publication
Prompt `0.3.14`, CHANGELOG, ROADMAP et mécanique autorisée par les règles.
### rel.001
Publication stable mécanique après dernier gate validé.
## 25. Critère de sortie pre.001
Fermé avant `pre.002` :
```text
release maintenue
sources P0 identifiées
entrée/sortie de chaque source définie
retry/reconnect owner défini
bornes multi-source définies
coalescence cross-source définie
stratégie observations multiples définie
content conflict défini
HTTP run bound/cadence définis
health publique conservative définie
smokes qualifiés
aucune dépendance externe nouvelle
collision normative corrigée
```
Questions volontairement reportées :
```text
preuve de coverage entre sources
failover non-terminal d'une source
repair multi-source
historical replay/backfill
EARLY feeds
consumer Desk 0.3.15
```

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_KSP.md -->
<!-- version: 41 -->
<!-- version: 42 -->
# Règles spécifiques à KSP
@@ -45,8 +45,8 @@
- **KSP-CONFIG-015** — L'environnement du processus reste read-only. La surface management peut créer/modifier/supprimer uniquement des entrées KSP/KSPB du `.env`; chaque mutation rapporte séparément changement de source persistée, changement effectif courant, shadowing par le process et besoin de reload.
- **KSP-CONFIG-016** — Les rapports management ordinaires n'exposent que des valeurs sûres/redacted. L'accès en clair à une valeur d'environnement passe par un appel `reveal_*` explicite; l'authentification/autorisation de l'utilisateur final appartient à l'application et cette révélation n'autorise jamais le secret dans les logs/`Debug`/diagnostics génériques.
- **KSP-CONFIG-017** — Les frontières d'ownership Config sont vérifiées par des audits exécutables du workspace : Core/Logging ne dépendent pas de Config, les crates hors `ksp-config-lib` ne lisent pas directement les variables KSP/KSPB via `std::env::var*`/énumération de l'environnement et ne codent pas en dur les noms physiques des fichiers gérés lorsqu'un contrat Config existe.
- **KSP-CONFIG-018** — Dans un runtime desktop packagé, `ksp-config-lib` possède la préparation de la racine KSP writable à partir des resources applicatives : les documents Config packagés ne sont seedés que lorsqu'ils sont absents, les JSON Schemas possédés par le package courant sont resynchronisés à chaque lancement, et `.env` n'est jamais embarqué ni seedé. La localisation physique writable est résolue par une primitive plateforme dédiée et n'est pas codée en dur dans les applications.
- **KSP-CONFIG-018** — L'inventaire `.env.example` est vérifié automatiquement contre les variables KSP/KSPB concrètes utilisées par les JSON sous `config/` et le code Rust production. Toute clé runtime détectée doit posséder une entrée d'inventaire précédée d'un commentaire explicatif.
- **KSP-CONFIG-019** — Dans un runtime desktop packagé, `ksp-config-lib` possède la préparation de la racine KSP writable à partir des resources applicatives : les documents Config packagés ne sont seedés que lorsqu'ils sont absents, les JSON Schemas possédés par le package courant sont resynchronisés à chaque lancement, et `.env` n'est jamais embarqué ni seedé. La localisation physique writable est résolue par une primitive plateforme dédiée et n'est pas codée en dur dans les applications.
## Programmes et exécution

View File

@@ -0,0 +1,494 @@
<!-- file: docs/validation/030-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE.md -->
<!-- version: 1 -->
# Validation v0.3.13 — WS standard / Helius / HTTP live + convergence multi-source
## 1. Rôle
Ce document enregistre les preuves réellement exécutées et les non-claims de `0.3.13`. `pre.001` est exclusivement un gate d'archive, règles, audit, brainstorming, sizing et planification ; aucune nouvelle source live productive n'est codée dans cette tranche.
## 2. Archive stable contrôlée
```text
archive : khadhroony-solana-project-v0.3.12.zip
SHA-256 : 85c41eb9f8575ee58edd9863445cbc37b79ef59c4a7cf882679ff24dc8991bf5
bytes : 8260528
entries : 1981
files : 1788
directories : 193
absolute entries : 0
parent traversal entries : 0
duplicate entries : 0
symlink entries : 0
workspace members : 21
crate manifests : 21
workspace.package.version : 0.3.12
edition : 2024
stable delta : deltas/0.3.12/rel.001.md
```
Résultat structurel : PASS.
Artefacts interdits recherchés :
```text
Cargo.lock : absent
rust-toolchain.toml : absent
rust-toolchain : absent
package-lock.json : absent
pnpm-lock.yaml : absent
yarn.lock : absent
.env : absent
```
Résultat : PASS.
## 3. Baseline statique locale avant modification
Exécuté dans l'archive extraite :
```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
```
Résultat : PASS.
Exécuté :
```text
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.12
Markdown table audit: clean (306 table(s), 199 file(s))
```
Résultat : PASS.
## 4. Preuve opérateur stable fournie
Le journal opérateur fourni avec l'ouverture `0.3.13` montre sur `0.3.12` :
```text
cargo fmt --all -- --check : terminé sans erreur visible
audit Rust : clean, export completeness 0
audit Markdown ciblé stable : clean (306 tables, 199 fichiers)
cargo check --workspace : terminé avec succès
cargo clippy --workspace --all-targets --all-features -- -D warnings : terminé avec succès
cargo test -p ksp-worker-raw-transaction-ingest-lib : vert
cargo tree Worker --edges normal : produit
cargo tree Worker -e features : produit
```
Suites Worker affichées :
```text
unit : 66 pass
cross_layer_completeness : 4 pass
dependency_boundary : 9 pass
hardening : 16 pass
public_api : 9 pass
release_completeness : 4 pass
doc-tests : 0
```
Cette preuve concerne la stable d'entrée. Elle n'est pas présentée comme une exécution locale post-modification de `pre.001`.
## 5. Cargo local dans l'environnement d'assemblage
`cargo` et `rustfmt` ne sont pas installés dans l'environnement d'assemblage courant.
Non exécuté localement avant ou après modification :
```text
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p ksp-worker-raw-transaction-ingest-lib
cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal
cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
cargo tree --duplicates
```
Aucune de ces commandes n'est déclarée PASS localement.
## 6. Audit des règles
Documents normatifs audités :
```text
RULES.md
docs/rules/RULES_GENERAL.md
docs/rules/RULES_RUST.md
docs/rules/RULES_KSP.md
docs/rules/RULES_DEPENDENCIES.md
docs/rules/RULES_DOCUMENTATION.md
docs/rules/PROMPT_STRUCTURE.md
docs/rules/FILE_CONTRACTS.md
docs/rules/VERSION_WORKFLOW.md
docs/rules/SCENARIO_CONVENTION.md
```
Scan supplémentaire des identifiants normatifs :
```text
fichiers de règles : 10
rule ids détectés : 489
rule ids uniques : 488
collision : KSP-CONFIG-018 x2
```
Le dépôt stable ne contenait pas de contradiction de contenu entre ces deux règles, mais l'identifiant normatif n'était pas unique.
Preuve historique : `deltas/0.1.3/pre.014.md` définit explicitement l'inventaire `.env.example` comme `KSP-CONFIG-018`. La règle desktop est donc renumérotée `KSP-CONFIG-019` dans `pre.001` ; aucun texte de règle n'est affaibli ni supprimé.
## 7. Audit dépendances et frontières
Contrôlé statiquement :
```text
21 crates = 21 workspace members
aucune version package explicite hors workspace inheritance
aucune edition crate divergente
ksp-worker-raw-transaction-ingest-lib dépend de ksp-onchain-transport-lib
Worker ne dépend pas de ksp-config-lib
Worker ne dépend pas de ksp-job-backfill-lib
Worker ne dépend pas de ksp-store-postgres-lib
Worker ne dépend pas directement de reqwest/tonic/yellowstone-grpc-proto
Store physique absent du Worker
```
La primitive `solana-keypair` présente dans `ksp-wallet-lib` est autorisée explicitement par `DEP-SOL-004` et n'est pas une violation.
Résultat : aucune violation de dépendance stable identifiée par cet audit.
## 8. Handoff 0.3.12 vérifié
Sources lues :
```text
docs/plans/033-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY_PLAN.md
docs/validation/029-V0_3_12_YELLOWSTONE_HYDRATION_CONTINUITY.md
crates/ksp-worker-raw-transaction-ingest-lib/Cargo.toml
crates/ksp-worker-raw-transaction-ingest-lib/README.md
crates/ksp-worker-raw-transaction-ingest-lib/USAGE.md
crates/ksp-worker-raw-transaction-ingest-lib/src/
crates/ksp-worker-raw-transaction-ingest-lib/tests/
crates/ksp-worker-raw-transaction-ingest-lib/unit_tests/
```
Contrats stables confirmés :
```text
une source Yellowstone caller-composed
hydratation getTransaction observed
coalescence network/signature/commitment
source_key opaque 32 bytes
observation key = domain + network + signature + source_key
admission centrale bounded mpsc
canonicalisation Common RAW avant Store
persistence atomique transaction + observation
processing frontier run-local
reconnect/replay/gap sans repair
```
## 9. Common RAW et Store vérifiés
`ksp-raw-transaction-lib` expose :
```text
RawTransactionMaterial
canonicalize_raw_transaction
assemble_raw_transaction_acquisition
wire Legacy/V0/V1
```
`ksp-store-api` / `ksp-store-lib` exposent déjà deux capabilities distinctes utiles à la convergence :
```text
persist_raw_transaction_acquisition(transaction, observation, Normal)
record_raw_transaction_observation(observation)
```
La seconde est explicitement conçue pour une observation supplémentaire d'une transaction déjà persistée sans resoumettre le payload canonique.
Conclusion : aucun changement Store API n'est requis par le design `pre.001`.
## 10. Transport WS/HTTP vérifié
Surface standard :
```text
SolanaStandardWsSession::connect
logs_subscribe
block_subscribe
shared WsSession actor
reconnect/resubscribe Transport-owned
```
Surface Helius :
```text
HeliusLaserStreamWsSession::connect
transaction_subscribe
shared WsSession actor
pas d'escape hatch générique
blockSubscribe volontairement non exposé sur Helius facade
```
Surface HTTP :
```text
get_transaction_observed
get_block_observed
get_slot
get_blocks
get_blocks_with_limit
```
Conclusion : aucun nouveau client HTTP/WS ni nouvelle dépendance réseau n'est requis dans Worker.
## 11. Config/secrets vérifiés
`config/std.transport.json` contient les profils committed standard/public actuels. `config/examples/std.transport.example.json` démontre déjà les formes Helius LaserStream Mainnet/Devnet.
`KSP_SECRET_HELIUS_API_KEY` existe déjà dans l'inventaire `.env.example` et dans les contrats Config/tests concernés.
Conclusion pre.001 :
```text
aucune nouvelle variable secret
aucun profil Config ajouté dans cette tranche
Config reste hors Worker
pre.005 décidera un profil committed seulement si un consumer/smoke concret le justifie
```
## 12. Audit externe courant
Consulté le 10 septembre 2026.
### 12.1 logsSubscribe
Solana confirme `all`, `allWithVotes` et `mentions` avec un seul pubkey par appel. La notification contient contexte/slot, signature, erreur et logs mais pas le RAW complet.
Décision : hydration obligatoire.
### 12.2 blockSubscribe
Solana maintient la méthode comme instable et conditionnée à l'activation validator. Commitment `confirmed`/`finalized` seulement.
Le guide Transaction V1 courant impose la préparation `maxSupportedTransactionVersion = 1`; sinon V1 peut provoquer `-32015` en HTTP et `block:null`/stagnation côté blockSubscribe.
Décision : toutes les nouvelles requêtes transaction/block de `0.3.13` utilisent `1` lorsque la surface le permet. La qualification RAW-direct V1 reste test-gated en `pre.004`.
### 12.3 Helius
La référence Helius courante liste `transactionSubscribe` comme extension supportée et `blockSubscribe` parmi les méthodes instables non supportées sur LaserStream WSS.
Le pricing courant place `transactionSubscribe` à partir de Developer, pas sur Free.
Décision : aucun tier n'est codé ; smoke live conditionnel.
Sources :
```text
https://solana.com/docs/rpc/websocket/logssubscribe
https://solana.com/docs/rpc/websocket/blocksubscribe
https://solana.com/docs/core/transactions/versioned-transactions
https://www.helius.dev/docs/api-reference/rpc/websocket-methods
https://www.helius.dev/pricing
```
## 13. Contrats de source fermés par pre.001
### 13.1 Yellowstone
```text
input : channel/request + HTTP pool/role
output : reference signal + continuity
bound : Transport + global Worker queue
retry/reconnect : Transport
proof : non-regression 0.3.12
```
### 13.2 Standard logs
```text
input : standard WS endpoint/filter/confirmed-or-finalized + HTTP pool/role
output : signature/slot reference signal
bound : WS notification queue + global Worker queue
retry/reconnect : Transport WS
hydration retry : Transport HTTP
proof : deterministic notification -> one observed getTransaction -> RAW golden
```
### 13.3 Standard block
```text
input : standard WS + full/base64 + confirmed/finalized + maxVersion=1
output : complete material for qualified versions
bound : WS queue + global Worker queue
retry/reconnect : Transport WS
proof : RAW parity Legacy/V0, V1 dedicated fixture, block:null canary
```
### 13.4 Helius transaction
```text
input : Helius WS + full/base64 + maxVersion=1 + HTTP pool/role
output : reference signal then hydration
bound : Transport Helius filters/queue + global Worker queue
retry/reconnect : Transport WS
hydration retry : Transport HTTP
proof : deterministic Helius notification -> RAW golden; live conditional
```
### 13.5 HTTP live polling
```text
input : HTTP pool/roles + confirmed/finalized + polling settings
run bound : getSlot at source start; never scan lower slot
output : getBlock observed transactions
source timer owner : Worker
HTTP retry/rate-limit : Transport
proof : deterministic tip/skipped/null/stop tests
```
## 14. Bornes fermées
```text
live sources : 1..32
source signal queue : settings.admission_queue_capacity()
pending signals global : <= settings.admission_queue_capacity()
hydration in-flight : <= settings.persistence_concurrency()
no provider-private unbounded Worker queue
HTTP poll interval : 100 ms .. 30 s, default 1 s
HTTP poll max blocks/cycle : 1 .. 1024, default 128
```
Ces bornes sont des décisions de plan à matérialiser/tester dans les prereleases techniques correspondantes ; elles ne sont pas encore une API de `pre.001`.
## 15. Convergence et observations
Décision : coalescence avant hydration par `(network, signature, commitment)` pour toutes les sources reference-only.
Une hydration peut servir plusieurs observation seeds. Après canonicalisation :
```text
première observation : persistence atomique entity + observation
suivantes : record_raw_transaction_observation
```
Même identité/content identique : idempotent.
Même identité/content divergent : content conflict explicite et terminal.
## 16. Health/terminalité
L'inventaire de sources reste interne et borné. La projection publique future est source-neutral et agrège des counts d'états sans provider material.
Décision conservative : un `Failed` terminal d'une source configurée reste terminal pour le Worker en `0.3.13`, car aucune preuve de coverage équivalent n'existe encore. Failover/degraded non-terminal appartient au gap-repair/coverage `0.3.14`.
## 17. Sizing
Release maintenue avec :
```text
pre.002 resources multi-source
pre.003 logs + hydration
pre.004 blockSubscribe
pre.005 Helius
pre.006 HTTP polling
pre.007 supervisor/inventory
pre.008 convergence/observations
pre.009 conflict/backpressure/fairness
pre.010 snapshot/health
pre.011 races/shutdown
pre.012 completeness/security
pre.013 gate technique/live
pre.014 documentation
pre.015 publication prep
rel.001 stable
```
Aucune responsabilité de fermeture n'est fusionnée.
## 18. Non-claims pre.001
`pre.001` ne prétend pas :
```text
avoir ajouté une source productive
avoir modifié le runtime Worker multi-source
avoir exécuté un smoke Helius
avoir prouvé blockSubscribe V1 en live
avoir exécuté cargo dans l'environnement d'assemblage
avoir implémenté gap repair/failover
avoir ajouté un profil Config Helius committed
```
## 19. Validation post-modification pre.001
Exécuté :
```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
```
Résultat : PASS.
Exécuté :
```text
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas
Markdown table audit: clean (340 table(s), 828 file(s))
```
Résultat : PASS.
Exécuté :
```text
supplemental normative rule-id scan
489 ids, 489 uniques, 0 duplicate
```
Résultat : PASS.
Comparaison exhaustive du working tree avec l'archive stable après suppression du cache Python généré par l'audit :
```text
added : 3
deltas/0.3.13/pre.001.md
docs/plans/034-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE_PLAN.md
docs/validation/030-V0_3_13_MULTI_SOURCE_LIVE_CONVERGENCE.md
modified : 2
Cargo.toml
docs/rules/RULES_KSP.md
deleted : 0
extra/unexpected : 0
```
Résultat : PASS.
Cargo post-modification reste `NON EXÉCUTÉ LOCAL` parce que le toolchain n'est pas disponible.
## 20. Gate opérateur requis avant pre.002
Après application du delta :
```bash
cargo fmt --all -- --check
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
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p ksp-worker-raw-transaction-ingest-lib
cargo tree -p ksp-worker-raw-transaction-ingest-lib --edges normal
cargo tree -p ksp-worker-raw-transaction-ingest-lib -e features
```
`pre.002` ne doit pas commencer si cette livraison révèle une anomalie de règles/version/archive non corrigée.