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
```