v0.3.11-pre.001

This commit is contained in:
2026-09-08 08:57:07 +02:00
parent b5c84f3df8
commit e2689d1b04
6 changed files with 1613 additions and 11 deletions

View File

@@ -0,0 +1,765 @@
<!-- file: docs/plans/032-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION_PLAN.md -->
<!-- version: 1 -->
# Plan v0.3.11 — fondation runtime du Worker RawTransaction ingest
## 1. But de la version
`0.3.11` introduit `ksp-worker-raw-transaction-ingest-lib` comme premier Worker concret KSP, mais ferme uniquement sa fondation runtime source-neutral et déterministe.
La release doit prouver :
```text
crate + dependency firewall
settings techniques bornés
identité Worker concrète
start/stop et terminal
supervisor et tâches privés
admission bornée
canonicalisation via ksp-raw-transaction-lib
persistence via ksp-store-lib
idempotence/conflit déterministes
snapshots latest-value concrets
projection vers ksp-worker-api
shutdown/fault/backpressure bornés
```
Aucune source Yellowstone, WS, Helius ou HTTP live n'est nécessaire pour fermer `0.3.11`. Les sources réelles commencent en `0.3.12`.
## 2. Base autoritaire auditée en `pre.001`
Base opérateur :
```text
archive : khadhroony-solana-project-v0.3.10.zip
SHA-256 : befafea61304aaea15c94db7c8b3525c58b7c1622bf880a9110373bcc0ae6ac0
ZIP bytes : 7993096
ZIP entries : 1901
unzip -t : PASS
workspace.package.version : 0.3.10
workspace members : 20
deltas/0.3.10/rel.001.md : présent
ksp-raw-transaction-lib : présent
ksp-worker-api : présent
ksp-job-backfill-lib : présent et consommateur de ksp-raw-transaction-lib
ksp-worker-raw-transaction-ingest-lib : absent
```
Sécurité/forme du ZIP :
```text
une seule racine : khadhroony-solana-project
entrée absolue : 0
path traversal : 0
symlink : 0
.git/ : 0
target/ : 0
node_modules/ : 0
Cargo.lock : 0
.env : 0
```
La base satisfait donc les préconditions du prompt `030`.
## 3. Réconciliation normative obligatoire ouverte par l'audit
Deux divergences existent dans les règles actives de la stable `0.3.10`.
### 3.1 Vocabulaire D1D4
`RULES_KSP.md` et `RULES_DEPENDENCIES.md` contenaient encore une ancienne formulation où D2 était nommé `Core canonique`, alors que les règles plus récentes et l'architecture `008` imposent :
```text
D1 RAW
D2 STRUCTURAL
D3 DECODED
D4 DOMAIN
```
`pre.001` corrige uniquement les règles actives concernées. Les deltas/plans historiques restent des traces historiques et ne sont pas réécrits.
### 3.2 Nom du Worker RAW
Les règles `KSP-WORKER-005`, `006`, `007` et `010` utilisaient encore `ksp-worker-raw-retriever`. Le nom durable retenu par l'architecture, le ROADMAP, le CHANGELOG, le handoff `0.3.10` et le prompt `030` est :
```text
ksp-worker-raw-transaction-ingest-lib
```
`pre.001` normalise ces quatre règles sans modifier leur responsabilité fonctionnelle.
## 4. Frontières existantes à préserver
### 4.1 `ksp-worker-api`
Surface générique conservée sans modification :
```text
WorkerId
WorkerKindCode
WorkerState
WorkerHealth
WorkerActivity
WorkerLifecycle
WorkerStopToken
WorkerSnapshotSequence
WorkerSnapshot
WorkerSnapshotFuture
WorkerSnapshotSource
```
La crate reste runtime-neutral et dépend uniquement de `ksp-core-lib`. Aucun `start()`/`stop()` universel ni type Solana-specific n'y est ajouté pour `0.3.11`.
### 4.2 `ksp-raw-transaction-lib`
La common RAW reste propriétaire de :
```text
RawTransactionMaterial
canonicalize_raw_transaction
parse/extract signature
RAW v1 wire/canonical bytes/hash
RawTransactionAcquisition
assemble_raw_transaction_acquisition
```
Elle ne reçoit aucun edge runtime/Worker/Job/Transport/Config/backend.
### 4.3 `ksp-store-lib`
Le Worker concret persiste via la façade `Store` et le contrat atomique :
```text
RawTransactionWrite::persist_raw_transaction_acquisition
```
Le Store reste l'autorité de convergence pour `(network, signature)` et retourne les outcomes entity/observation. Le Worker ne dépend pas de `ksp-store-postgres-lib` et n'ouvre/ferme pas le Store qui lui est fourni.
### 4.4 Backfill
Les patterns réutilisables conceptuellement sont :
```text
port privé de persistence pour tests déterministes
persistence atomique entity + observation
mapping explicite du content conflict
latest-value coalescent
cancellation coopérative
redaction des surfaces publiques
```
Ne sont pas réutilisés :
```text
BackfillRequest
scope historique
before/after
checkpoint
JobId
campagne/limit historique
```
## 5. Dépendances externes et graphe cible
Fraîcheur vérifiée le 8 septembre 2026 :
```text
tokio latest stable : 1.53.1
workspace KSP : ^1.53
futures-util latest stable : 0.3.34
workspace KSP : ^0.3
sha2 latest stable : 0.11.0
workspace KSP : ^0.11
```
Aucun bump de contrainte workspace n'est requis.
Graphe de production prévu pour la fondation :
```text
ksp-worker-raw-transaction-ingest-lib
-> ksp-core-lib
-> ksp-worker-api
-> ksp-raw-transaction-lib
-> ksp-store-lib default-features=false
-> ksp-logging-lib
-> sha2
-> tokio
```
Tokio est direct parce que la crate concrète possède ses tâches runtime. Features de production retenues lorsque le runtime est matérialisé :
```text
macros
rt
sync
time
```
Raisons :
```text
rt -> spawn / JoinHandle / JoinSet privés
sync -> mpsc borné + watch latest-value
macros -> select! avec ordre biaisé explicite pour stop/fault
time -> deadline de drain bornée
```
`rt-multi-thread` reste test-only si les tests en ont besoin ; le Worker ne crée aucun runtime.
`futures-util` n'est pas ajouté en fondation : `JoinSet`, `mpsc`, `watch`, les futures boxed standard et `select!` couvrent le modèle retenu. `ksp-onchain-transport-lib` n'est pas ajouté à `0.3.11` : aucune source live n'existe encore et un edge inutilisé violerait le principe de dépendance minimale. Il sera réaudité avec Yellowstone en `0.3.12`.
Edges interdits :
```text
Worker -> ksp-config-lib
Worker -> ksp-job-backfill-lib
Worker -> ksp-job-api
Worker -> ksp-store-api direct sans nécessité démontrée
Worker -> ksp-store-postgres-lib
Worker -> SDK provider
common RAW -> Worker/runtime/Transport/Config
```
## 6. Surface publique minimale retenue
### 6.1 Constante d'identité
```text
RAW_TRANSACTION_INGEST_WORKER_KIND_CODE = "raw_transaction_ingest"
```
La construction de `WorkerKindCode` reste validée par `ksp-worker-api`.
### 6.2 `RawTransactionIngestSettings`
La fondation expose seulement les réglages runtime techniques dont le Worker est propriétaire :
```text
network: RawNetworkId
worker_id: WorkerId
admission_queue_capacity: usize
persistence_concurrency: usize
shutdown_drain_timeout: Duration
```
Bornes V1 :
```text
admission queue default : 256
admission queue min : 1
admission queue max : 65_536
persistence concurrency default : 8
persistence concurrency min : 1
persistence concurrency max : 64
shutdown drain default : 5 s
shutdown drain min : 100 ms
shutdown drain max : 30 s
```
Ces bornes reprennent des enveloppes déjà utilisées dans KSP : queue live conservatrice à 256, plafond de channel Transport à 65 536, concurrence Store usuelle 8 et plafond 64, timeout de shutdown Store 5 s avec enveloppe 100 ms30 s.
Aucun champ métier historique ni provider-specific n'entre dans cette structure.
### 6.3 Types différés
Ne sont pas figés publiquement en `0.3.11` :
```text
RawTransactionSourceId
RawTransactionSourceSettings
RawTransactionSourceCapability
RawTransactionSourceRole
RawTransactionContinuityState
source frontier/run frontier
provider enum
Yellowstone/WS/Helius fields
retry/replay/gap-repair settings
```
Le harness déterministe utilise des types privés. Les types source publics seront ouverts lorsque `0.3.12` disposera d'une première source réelle permettant de prouver leur contrat.
## 7. Forme du start, ownership et handle
### 7.1 Start
Forme cible :
```text
RawTransactionIngestWorker::start(
settings: RawTransactionIngestSettings,
store: Arc<ksp_store_lib::Store>,
) -> Result<RawTransactionIngestHandle>
```
`start` est synchrone et exige un runtime Tokio actif fourni par le caller. Il vérifie avant spawn :
```text
settings valides
runtime Tokio courant disponible
network settings == network Store
état initial cohérent
```
Le Worker ne ferme jamais le Store ; le caller conserve son lifecycle. `Arc<Store>` permet aux tâches privées de partager la même façade sans exposer un backend.
### 7.2 Handle
Surface minimale :
```text
request_stop() -> bool
snapshot_source()
worker_snapshot_source()
wait_terminal()
```
`request_stop()` est idempotent et retourne `true` seulement pour le premier appel effectif.
`wait_terminal()` retourne une future runtime-neutral boxed appartenant à la crate concrète ; aucun `tokio::task::JoinHandle` n'apparaît dans l'API publique.
## 8. Supervisor, tâches et channels
### 8.1 Ownership privé
Le modèle retenu est :
```text
start
-> crée stop token + signal stop privé
-> crée watch snapshot
-> crée mpsc admission borné
-> spawn supervisor privé
-> garde l'ownership des source tasks présentes/futures
-> garde l'ownership des persistence tasks
-> ferme et joint toutes les tâches avant terminal
```
Les `JoinHandle`/`JoinSet` restent strictement privés. Dropper le handle public ne détache pas le supervisor ; l'ownership interne du run reste suffisant pour atteindre un terminal ou répondre à stop par les clones encore présents.
### 8.2 Admission
Un seul channel central :
```text
tokio::sync::mpsc::channel<PrivateRawTransactionIngress>(admission_queue_capacity)
```
Le channel est borné. `send().await` applique le backpressure ; aucun `unbounded_channel`, aucun drop silencieux et aucune event queue publique ne sont admis.
Les futures sources posséderont des clones du sender. En `0.3.11`, seuls les tests/harness privés injectent des entrées.
### 8.3 Stop signal
`WorkerStopToken` porte l'intention commune. Un `watch<bool>` privé réveille immédiatement le supervisor/source harness sans polling. Le stop branch est placé en premier dans les `select!` biaisés afin qu'aucune nouvelle admission ne soit acceptée après observation du stop.
### 8.4 Snapshot
Un `watch<RawTransactionIngestSnapshot>` privé conserve uniquement la dernière valeur. La projection commune `WorkerSnapshotSource` et la source concrète lisent ce même état ; aucune seconde event queue n'est nécessaire.
## 9. Seam/harness déterministe sans réseau
Le runtime de fondation est prouvé par un harness privé qui produit des `PrivateRawTransactionIngress` contrôlés.
Une entrée de harness contient conceptuellement :
```text
RawTransactionMaterial
RawObservationKey déterministe Worker-owned
RawAcquisitionProvenance sûre
```
Le harness permet :
```text
N acquisitions séquentielles
acquisitions concurrentes
même transaction/même observation
même transaction/nouvelle observation
contenu canonique divergent
source qui fault
source qui reste bloquée
stop pendant admission
stop pendant persistence
saturation d'admission
lecteur snapshot lent ou absent
```
Le seam n'est pas public et ne constitue pas une API d'injection de données pour les applications. `0.3.12` branchera une source productive sur le même sender privé.
## 10. Canonicalisation, observation key et persistence
### 10.1 Pipeline central
```text
private ingress
-> vérifier network
-> canonicalize_raw_transaction(material)
-> assemble_raw_transaction_acquisition(...)
-> persist_raw_transaction_acquisition(..., Normal)
-> classifier outcome
-> publier counters/snapshot
```
Aucune canonicalisation RAW v1 n'est recodée dans le Worker.
### 10.2 Observation key Worker
La Worker observation key est un SHA-256 KSP-owned versionné et domain-separated. La fondation réserve le domaine :
```text
ksp.raw_transaction_ingest.observation.v1
```
Les bytes exacts/golden seront figés avec le premier code de persistence, à partir d'éléments stables fournis par la source technique et de l'identité `(network, signature)`. Aucun timestamp local aléatoire ni run id ne peut rendre une rediffusion identique non idempotente.
Les éléments source exacts ne sont pas figés publiquement avant `0.3.12`; le harness utilise une source key privée déterministe afin de prouver l'idempotence du domaine Worker.
### 10.3 Outcomes
Le Worker distingue au minimum :
```text
entity Inserted
entity AlreadyPresent
entity SkippedPurged
observation Inserted
observation AlreadyPresent
observation NotRecorded
content conflict
Store error
```
`Rehydrated` n'est pas produit en mode `Normal`; s'il apparaît malgré le contrat, le Worker le traite comme invariant runtime invalide plutôt que comme succès silencieux.
Le Store reste la source de vérité ; aucun cache de déduplication mémoire n'est requis en `0.3.11`.
## 11. Snapshots et projection Worker API
### 11.1 Snapshot concret
`RawTransactionIngestSnapshot` contient uniquement des données sûres :
```text
WorkerSnapshot commun ou champs de projection équivalents
admission_queue_capacity
admission_queue_depth
persistence_concurrency
in_flight_persistence
admitted_total
canonicalized_total
persisted_total
entity_inserted_total
entity_already_present_total
entity_skipped_purged_total
observation_inserted_total
observation_already_present_total
content_conflict_total
store_failure_total
source_failure_total
backpressure_wait_total
```
Compteurs : `u64` monotones avec incrément checked. L'épuisement est un fault statique, jamais un wrap silencieux.
Aucun timestamp/frontier public n'est nécessaire en fondation. `received_at` appartient à la provenance de l'entrée source ; le run frontier et la continuité sont différés jusqu'à la première source réelle.
### 11.2 Projection commune
La même séquence `WorkerSnapshotSequence` pilote le snapshot concret et la projection commune. Mapping :
```text
Created/Starting -> health Unknown
Running -> health Healthy tant qu'aucun fault n'est décidé
Stopping -> conserve le dernier health non terminal
Faulted -> health Unhealthy
queue ou persistence > 0 -> activity Active
sinon Running/Stopping -> activity Idle
```
La state machine reste celle de `WorkerLifecycle`.
## 12. Fault, shutdown et backpressure
### 12.1 Error codes publics prévus
```text
ERROR_CODE_RAW_TRANSACTION_INGEST_SETTINGS_INVALID
ERROR_CODE_RAW_TRANSACTION_INGEST_RUNTIME_INVALID
ERROR_CODE_RAW_TRANSACTION_INGEST_SOURCE_FAILED
ERROR_CODE_RAW_TRANSACTION_INGEST_STORE_FAILED
ERROR_CODE_RAW_TRANSACTION_INGEST_CONTENT_CONFLICT
ERROR_CODE_RAW_TRANSACTION_INGEST_DRAIN_TIMEOUT
ERROR_CODE_RAW_TRANSACTION_INGEST_COUNTER_EXHAUSTED
```
Domain ErrorCode :
```text
worker_raw_transaction_ingest
```
Les messages/contextes restent statiques et sûrs ; aucune signature, hash de conflit, payload, URL, token ou erreur distante arbitraire n'est copiée.
### 12.2 Content conflict
Policy :
```text
fermer l'admission
request stop interne
ne pas overwrite
ne pas choisir de source gagnante
continuer seulement le drain déjà admis tant que sûr
publier Faulted(content_conflict)
```
Le premier terminal décidé reste terminal ; une demande de stop tardive ne remplace pas le fault.
### 12.3 Store error
Une erreur Store non-conflict pendant une acquisition admise devient `Faulted(store_failed)`. Le code Store original peut être tracé uniquement s'il est déjà un `ErrorCode` sûr ; le texte d'erreur arbitraire n'est jamais propagé dans snapshot/Debug.
### 12.4 Source harness failure
Une panne de source privée devient `Faulted(source_failed)` en `0.3.11`. Les futures politiques required/optional/degraded sont reportées à la release qui possède de vraies sources.
### 12.5 Drain
Après stop/fault :
```text
fermer nouvelles admissions
signaler les tâches source
fermer les senders Worker-owned
continuer les acquisitions déjà reçues/admisses
attendre les persistence tasks jusqu'à shutdown_drain_timeout
si deadline dépassée -> abort privé des tâches restantes, join, Faulted(drain_timeout)
publier terminal seulement après absence de tâche privée survivante
```
Le timeout Tokio nécessite un runtime caller avec time driver actif ; cette précondition est documentée et testée dans les harness runtime de la crate.
## 13. Menaces et gardes de fondation
```text
payload hostile/oversized
-> common RAW/Store bounds ; aucun payload dans snapshot/log
duplicate storm
-> bounded mpsc + bounded persistence concurrency + Store idempotence
queue saturation
-> send await/backpressure observable ; aucun drop silencieux
Store lent
-> queue/concurrency bornées ; stop drain deadline
content conflict
-> fault terminal ; aucune overwrite/first-provider-wins
Store failure
-> fault statique ; aucune retry queue infinie en fondation
source task failure
-> détectée/joined ; fault sûr
task orphan
-> ownership supervisor/JoinSet ; terminal après join/abort complet
stop/fault race
-> première décision terminale cohérente ; fault d'intégrité prioritaire
slow/no snapshot reader
-> watch latest-value ; aucun impact lifecycle
secret/URL/signature leak
-> aucun champ public correspondant ; Debug redacted ; tests statiques
Job semantics leak
-> dependency/public-surface tests interdisant request/scope/checkpoint/JobId
Config leak
-> manifest/source scans ; aucun std::env/.env/ksp-config-lib
```
## 14. Preuves et suites de tests prévues
Tests unitaires :
```text
settings defaults/bounds/invalid
kind/identity
checked counters
snapshot mapping
observation-key golden privé
outcome mapping
fault precedence
```
Tests runtime déterministes :
```text
start sur runtime valide
start sans runtime -> erreur sûre
network Store mismatch -> erreur avant spawn
stop idempotent
terminal normal
no orphan task after terminal
bounded admission saturation/backpressure
bounded persistence concurrency
same entity/same observation idempotent
same entity/new observation conservée
content conflict terminal
Store failure terminal
source harness failure terminal
stop pendant queue/persistence
drain timeout -> abort/join -> terminal fault
slow/no listeners
common/concrete snapshot latest-value
```
Tests externes :
```text
dependency boundary
public API crate-root
release completeness
security hardening/redaction
source visibility crate::Item
forbidden historical request surface
manifest exactness
```
Aucun test provider live n'est requis en `0.3.11`.
## 15. Gates techniques cibles
À partir de la création de la crate :
```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 test -p ksp-worker-api
cargo test -p ksp-raw-transaction-lib
cargo test -p ksp-store-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
```
Gate technique final :
```bash
cargo test --workspace --all-targets --all-features
```
Une commande non exécutée n'est jamais déclarée PASS.
## 16. Hors périmètre et questions reportées
Reportés explicitement :
```text
Yellowstone live
WS standard live
Helius live
HTTP block polling live
Transport dependency productive
source capability/role publics
source required/optional policy
retry/reconnect policy provider
run frontier
continuity/gap repair
hydration productive
multi-source convergence live
hot reconfiguration desired/effective
Desk d'ingestion
Backfill multi-source
D2 STRUCTURAL
migration Store
```
Ces éléments ne bloquent pas le gate de fondation.
## 17. Prévision souple recalibrée
### `pre.001` — audit, règles, brainstorming, sizing, plan
Budget cible : **1015 min**. Vérifier la stable, corriger les deux divergences normatives actives, fermer le modèle runtime/dependencies/public-private/harness et créer plan + validation. Aucun Rust Worker.
### `pre.002` — crate skeleton + dependency firewall
Budget cible : **1015 min**. Créer la crate minimale, l'ajouter au workspace, installer uniquement les edges décidés et les tests de manifest/dependency boundary. Pas de runtime comportemental.
### `pre.003` — identity + settings foundation
Budget cible : **1015 min**. Kind code, settings, defaults/bounds, validation network/worker identity et erreurs correspondantes. Aucun spawn.
### `pre.004` — start/handle/lifecycle/terminal
Budget cible : **1520 min**. Start sur runtime caller-owned, handle public, stop idempotent, lifecycle générique, terminal future sans JoinHandle public. Harness runtime minimal.
### `pre.005` — supervisor privé + ownership des tâches
Budget cible : **1520 min**. Supervisor, JoinSet/joins privés, stop wake-up, test source seam et preuve qu'aucune tâche ne survit au terminal. Pas encore de persistence réelle.
### `pre.006` — admission bornée + canonicalisation common
Budget cible : **1520 min**. `mpsc` borné, backpressure, ingress privé, common `RawTransactionMaterial -> RawTransaction`, observation-key domain/golden et assembly. Pas de source réseau.
### `pre.007` — persistence Store + idempotence/conflict
Budget cible : **1520 min**. Port privé Store, mode Normal, concurrency bornée, outcomes new/idempotent/purged, observation distincte, Store error et content conflict terminal.
### `pre.008` — snapshots concrets + projection Worker API
Budget cible : **1520 min**. `watch` latest-value, compteurs checked, common projection, slow/no listener et terminal retained.
### `pre.009` — hardening shutdown/backpressure/fault races
Budget cible : **1520 min**. Drain deadline, stop/fault ordering, saturation, source failure, Store slow/failure, abort+join au timeout, no orphan tasks. Scinder immédiatement si le gate réel dépasse le budget.
### `pre.010` — hardening public/release/security
Budget cible : **1015 min**. Tests externes exacts : API root, dependencies, historical-surface absence, redaction, error codes, module inventory et scans Config/secret/backend.
### `pre.011` — gate technique final
Budget cible : **1015 min**. Workspace tests/all-features, Clippy strict, suites ciblées, arbres normal/features, duplicate tree. Aucun nouveau scope fonctionnel.
### `pre.012` — réconciliation documentaire
Budget cible : **1015 min**. README/USAGE Worker, plan, validation et architecture/références réellement affectées. Aucun CHANGELOG/ROADMAP/prompt suivant.
### `pre.013` — préparation publication
Budget cible : **510 min**. Prompt `0.3.12`, CHANGELOG, ROADMAP, Cargo/delta mécaniques uniquement.
### `rel.001` — stable
Publication mécanique sans rattrapage.
## 18. Décision de sizing `pre.001`
Décision : **maintenir `0.3.11`**.
Le périmètre reste clôturable dans une seule session à condition de préserver strictement :
```text
aucune source live
aucun edge Transport productif
aucune modification Config
aucune migration Store
aucun gap repair/continuity live
aucune API source provider prématurée
```
Le découpage initial `pre.002``pre.007` du prompt a été volontairement affiné afin que chaque tranche ne mélange pas plusieurs responsabilités runtime. Si `pre.007` ou `pre.009` révèle un volume supérieur au budget, la tranche est scindée avant exécution ; si cette scission révèle qu'un sous-système live est nécessaire, la release est rescindée avant d'introduire ce nouveau scope.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_DEPENDENCIES.md -->
<!-- version: 18 -->
<!-- version: 19 -->
# Règles des dépendances KSP
@@ -81,7 +81,7 @@ Elles complètent les règles Rust générales et le graphe de `docs/architectur
- **DEP-STORE-001** — `ksp-store-api` ne dépend pas de Program, Materializer ou Transport.
- **DEP-STORE-002** — `ksp-store-lib` dépend de `ksp-store-api`, porte la façade/runtime Store commune et peut dépendre optionnellement de crates backend compilées par feature ; il ne dépend pas des implémentations Program/Materializer/Transport.
- **DEP-STORE-003** — Les workers/jobs spécialisés sont propriétaires des conversions entre modèles runtime et DTO persistants.
- **DEP-STORE-004** — Les niveaux durables sont D1 Raw, D2 Core canonique, D3 journal de matérialisation générique et D4 projections spécialisées.
- **DEP-STORE-004** — Les niveaux durables canoniques sont D1 `RAW`, D2 `STRUCTURAL`, D3 `DECODED` et D4 `DOMAIN` ; le journal générique de matérialisation décodée appartient à D3 et les projections/faits de domaine queryables à D4.
- **DEP-STORE-005** — Les replays D1 -> D2, D2 -> D3 et D3 -> D4 doivent pouvoir être exécutés indépendamment.
- **DEP-STORE-006** — Une notification de donnée persistée ne constitue jamais la source de vérité du backlog ; les queries Store et marqueurs durables d'idempotence/version de processor font autorité.
- **DEP-STORE-007** — Une notification de donnée est publiée seulement après persistence/commit réussis.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/rules/RULES_KSP.md -->
<!-- version: 40 -->
<!-- version: 41 -->
# Règles spécifiques à KSP
@@ -97,11 +97,11 @@
## Niveaux durables et Store
- **KSP-DURABLE-001** — Les niveaux persistants utilisent la nomenclature D1 à D4, distincte des couches architecturales N1 à N4.
- **KSP-DURABLE-002** — D1 est Raw, D2 Core canonique, D3 le journal générique de matérialisation et D4 les projections spécialisées/queryables.
- **KSP-DURABLE-002** — Les niveaux durables canoniques sont D1 `RAW`, D2 `STRUCTURAL`, D3 `DECODED` et D4 `DOMAIN`. D3 conserve la matérialisation générique décodée/journal durable requis ; D4 porte les faits et projections de domaine queryables lorsque leur normalisation est pertinente.
- **KSP-DURABLE-003** — D1/D2/D3 sont destinés à devenir fortement stables après stabilisation de la première série Store ; D4 reste plus évolutif.
- **KSP-DURABLE-004** — Le journal D3 est durable et obligatoire ; il ne peut pas être supprimé au profit de projections D4 directes.
- **KSP-DURABLE-005** — Les replays D1 -> D2, D2 -> D3 et D3 -> D4 sont indépendants.
- **KSP-DURABLE-006** — Les instructions top-level et CPI restent des faits Core distincts lorsque leurs invariants/requêtes diffèrent.
- **KSP-DURABLE-006** — Les instructions top-level et CPI restent des faits STRUCTURAL distincts lorsque leurs invariants/requêtes diffèrent.
- **KSP-DURABLE-007** — D4 modélise des faits canoniques plutôt que des familles de tables par protocole lorsque les invariants sont normalisables.
- **KSP-DURABLE-008** — Les temporalités blockchain et locales restent distinctes ; un `block_time` absent n'est jamais remplacé par une date locale inventée.
@@ -138,12 +138,12 @@
- **KSP-WORKER-002** — Les contrats communs des workers appartiennent à `ksp-worker-api` et ne contiennent aucun contrat propre aux jobs.
- **KSP-WORKER-003** — `ksp-worker-api` est principalement une lifecycle API de services continus : identité, état, health, démarrage/arrêt et événements communs ; les capacités optionnelles ne deviennent universelles que si plusieurs workers les partagent réellement.
- **KSP-WORKER-004** — `ksp-worker-control-lib` est une implémentation commune de gouvernance/contrôle réutilisable d'abord par les apps manager spécialisées, puis éventuellement par un futur orchestrateur/application globale ; les apps ne réimplémentent pas cette gouvernance.
- **KSP-WORKER-005** — `ksp-worker-raw-retriever` est le worker d'acquisition raw live/quasi-live. Il ne décode pas, ne matérialise pas et ne réalise pas de replay/backfill historique.
- **KSP-WORKER-006** — `ksp-worker-raw-retriever` persiste les données raw puis notifie leur disponibilité selon les contrats de données normalisés.
- **KSP-WORKER-007** — `ksp-worker-raw-retriever` doit pouvoir faire évoluer à chaud les listeners et la sélection des données qu'il rapatrie/stocke.
- **KSP-WORKER-005** — `ksp-worker-raw-transaction-ingest-lib` est le worker d'acquisition raw live/quasi-live. Il ne décode pas, ne matérialise pas et ne réalise pas de replay/backfill historique.
- **KSP-WORKER-006** — `ksp-worker-raw-transaction-ingest-lib` persiste les données raw puis notifie leur disponibilité selon les contrats de données normalisés.
- **KSP-WORKER-007** — `ksp-worker-raw-transaction-ingest-lib` doit pouvoir faire évoluer à chaud les listeners et la sélection des données qu'il rapatrie/stocke.
- **KSP-WORKER-008** — Les workers de processing ne sont pas figés à l'avance sous une chaîne globale `structural -> generic materializer -> domain projector`. RAW et STRUCTURAL peuvent disposer de workers horizontaux propres à leur couche ; à partir de DECODED, les workers/processors sont introduits au besoin avec chaque groupe fonctionnel vertical afin que décodage, matérialisation, projection spécialisée et validation d'exécution évoluent ensemble.
- **KSP-WORKER-009** — Les workers de processing utilisent notification comme wake-up mais reconstruisent leur backlog depuis le Store.
- **KSP-WORKER-010** — `ksp-worker-raw-retriever` distingue une configuration desired et une configuration effective lors des reconfigurations à chaud.
- **KSP-WORKER-010** — `ksp-worker-raw-transaction-ingest-lib` distingue une configuration desired et une configuration effective lors des reconfigurations à chaud.
- **KSP-WORKER-011** — Un cursor de scan est une optimisation ; les processing outcomes durables constituent la preuve qu'un input a été traité pour un processor/version/capability.
- **KSP-WORKER-012** — La concurrence de processing utilise une sémantique de claim/lease récupérable après expiration/crash.
- **KSP-WORKER-013** — Chaque worker doit pouvoir fonctionner comme service/processus indépendant afin d'être arrêté/redémarré/mis à jour sans imposer l'arrêt volontaire des autres workers.

View File

@@ -0,0 +1,444 @@
<!-- file: docs/validation/028-V0_3_11_RAW_TRANSACTION_INGEST_WORKER_FOUNDATION.md -->
<!-- version: 3 -->
# Validation v0.3.11 — fondation runtime du Worker RawTransaction ingest
## 1. Rôle du document
Ce document suit les preuves de `0.3.11` pour `ksp-worker-raw-transaction-ingest-lib`.
Il distingue explicitement :
```text
preuve exécutée dans l'environnement d'assemblage
preuve opérateur fournie sur la stable de base
preuve planifiée pour une tranche future
preuve non applicable au scope 0.3.11
```
Aucune commande Cargo non exécutée localement n'est déclarée PASS.
## 2. Gate `pre.001` — audit/sizing/plan
État : **fermé pour la planification**. Le gate statique/Markdown final du delta complet est PASS dans lenvironnement dassemblage ; les gates Cargo restent non exécutables localement.
### 2.1 Archive stable contrôlée
```text
archive : khadhroony-solana-project-v0.3.10.zip
SHA-256 : befafea61304aaea15c94db7c8b3525c58b7c1622bf880a9110373bcc0ae6ac0
bytes : 7993096
entries : 1901
unzip -t : PASS
racine unique : khadhroony-solana-project
workspace.package.version : 0.3.10
workspace members : 20
stable delta : deltas/0.3.10/rel.001.md
```
Sécurité/forme :
```text
absolute entries : 0
path traversal entries : 0
symlinks : 0
.git/ : 0
target/ : 0
node_modules/ : 0
Cargo.lock : 0
.env : 0
workspace member manifest missing : 0
```
Préconditions fonctionnelles :
```text
ksp-raw-transaction-lib : présent + README/USAGE/src/tests/unit_tests
ksp-worker-api : présent
ksp-job-backfill-lib : présent
Backfill -> ksp-raw-transaction-lib : présent
ksp-worker-raw-transaction-ingest-lib : absent
```
### 2.2 Baseline statique exécutée avant modification
```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
Markdown table audit: clean (340 table(s), 772 file(s))
```
Les audits automatiques sont verts mais ne détectent pas toutes les contradictions sémantiques entre règles ; la lecture humaine reste obligatoire.
### 2.3 Cargo local
```text
cargo : indisponible dans l'environnement d'assemblage
```
Donc, pour `pre.001` local :
```text
cargo fmt : NON EXÉCUTÉ
cargo check : NON EXÉCUTÉ
cargo clippy: NON EXÉCUTÉ
cargo test : NON EXÉCUTÉ
cargo tree : NON EXÉCUTÉ
```
### 2.4 Preuve opérateur de la stable `0.3.10`
Le journal opérateur fourni le 8 septembre 2026 montre sur la base stable `0.3.10` :
```text
cargo fmt --all -- --check : terminé sans erreur
Rust rule audit : clean
Markdown audit : clean dans l'environnement opérateur
cargo check --workspace : terminé sans erreur
cargo clippy --workspace --all-targets --all-features -- -D warnings : terminé sans erreur
```
Suites ciblées communiquées :
```text
ksp-raw-transaction-lib : 26 tests verts au total
ksp-job-backfill-lib : 77 tests verts au total
```
Les arbres normaux des deux crates ont également été fournis. Cette preuve confirme la qualité de la stable opérateur ; elle ne remplace pas les futurs gates Cargo de `0.3.11-pre.*`.
## 3. Audit humain des règles
### 3.1 Divergence D2
Défaut trouvé dans la stable :
```text
RULES_KSP / KSP-DURABLE-002 : D2 encore nommé Core canonique
RULES_KSP / KSP-DURABLE-006 : instructions encore appelées faits Core
RULES_DEPENDENCIES / DEP-STORE-004 : D2 encore nommé Core canonique
```
Ces formulations contredisent les règles actives plus récentes et `docs/architecture/008-DATA_MATERIALIZATION_AND_STORE.md` :
```text
RAW -> STRUCTURAL -> DECODED -> DOMAIN
```
Correction `pre.001` : règles actives normalisées vers D1 `RAW`, D2 `STRUCTURAL`, D3 `DECODED`, D4 `DOMAIN`. Les traces historiques ne sont pas réécrites.
### 3.2 Ancien nom Worker
Défaut trouvé dans :
```text
KSP-WORKER-005
KSP-WORKER-006
KSP-WORKER-007
KSP-WORKER-010
```
Ancien nom :
```text
ksp-worker-raw-retriever
```
Nom durable confirmé par architecture/ROADMAP/CHANGELOG/handoff/prompt :
```text
ksp-worker-raw-transaction-ingest-lib
```
Correction `pre.001` : normalisation du nom uniquement, sans changement de responsabilité des règles.
### 3.3 Tension Store API/façade Worker auditée
`DEP-WORKER-003` privilégie l'injection d'APIs pour la logique réutilisable ; `DEP-STORE-010`, l'architecture `011` et le prompt `030` autorisent/ordonnent la façade `ksp-store-lib` pour le producer runtime concret.
Décision : pas de nouvelle règle nécessaire. La crate concrète dépend de `ksp-store-lib default-features=false`, tandis que la logique de persistence reste derrière un port privé testable. Aucun backend physique n'entre dans la crate.
## 4. Inventaire des surfaces de référence
### 4.1 Worker API
Surface crate-root constatée :
```text
WorkerId
WorkerKindCode
WorkerState
WorkerHealth
WorkerActivity
WorkerLifecycle
WorkerStopToken
WorkerSnapshotSequence
WorkerSnapshot
WorkerSnapshotFuture
WorkerSnapshotSource
```
Aucun runtime Tokio, Store, Transport, Config ou type Solana n'est présent.
### 4.2 Common RAW
Surface pertinente constatée :
```text
RawTransactionMaterial
RawTransactionWireField
RawTransactionVersion
canonicalize_raw_transaction
RawTransactionAcquisition
assemble_raw_transaction_acquisition
signature/wire helpers
```
La crate dépend de `ksp-store-api` pour les modèles persistables mais reste sans runtime/Transport/Worker/Job/backend.
### 4.3 Store
Contrat atomique pertinent :
```text
RawTransactionWrite::persist_raw_transaction_acquisition
RawTransactionAcquisitionMode::Normal
RawAcquisitionWriteOutcome
RawEntityWriteOutcome
RawObservationWriteOutcome
ERROR_CODE_RAW_CONFLICT
```
`Store` est non-Clone et possède son propre close ; le Worker recevra donc `Arc<Store>` et ne prendra pas la responsabilité de le fermer.
### 4.4 Backfill
Patterns vérifiés :
```text
RawTransactionPersistencePort privé
Store network check avant write
mapping explicite conflict vs idempotence
watch/latest-value runtime
cancellation et terminal
security hardening tests
```
Aucun scope/checkpoint Job n'est transféré au Worker.
## 5. Fraîcheur des dépendances
Vérifié le 8 septembre 2026 sur les documentations courantes :
```text
tokio 1.53.1
futures-util 0.3.34
sha2 0.11.0
```
Constats :
```text
Tokio spawn/JoinHandle -> feature rt
Tokio mpsc/watch -> feature sync
Tokio select! -> feature macros
Tokio timeout/time -> feature time
bounded mpsc applique du backpressure
watch ne retient que la dernière valeur
JoinHandle droppé détache la tâche -> handles privés doivent rester possédés/joints
```
Décision : aucun bump workspace. Le futur manifest Worker prévoit Tokio direct avec `macros,rt,sync,time`, `sha2` pour la key domain-separated, et aucun `futures-util` ni Transport tant qu'un usage réel n'est pas matérialisé.
## 6. Questions `pre.001` fermées
### 6.1 Settings
Surface minimale retenue :
```text
network
worker_id
admission_queue_capacity
persistence_concurrency
shutdown_drain_timeout
```
Bornes retenues :
```text
queue : 1..=65_536, default 256
persistence concurrency : 1..=64, default 8
drain : 100 ms..=30 s, default 5 s
```
### 6.2 Source types
Décision : `SourceId`, capability, role, continuity et settings provider restent privés/absents en `0.3.11`. Ils ne seront publics qu'avec une première source productive en `0.3.12+`.
### 6.3 Start/handle
Décision :
```text
RawTransactionIngestWorker::start(settings, Arc<Store>) -> Result<Handle>
request_stop idempotent
snapshot_source concret
projection WorkerSnapshot commune
wait_terminal async boxed sans JoinHandle public
```
### 6.4 Supervisor/tasks
Décision : supervisor unique privé, `JoinSet`/JoinHandle privés, ownership intégral jusqu'au terminal.
### 6.5 Channels
Décision :
```text
1 mpsc borné pour admission
1 watch latest-value pour snapshot concret
1 watch privé pour réveil stop
aucun unbounded channel
```
### 6.6 Timestamps/frontiers
Décision : aucun frontier/timestamp runtime public dans la fondation. `received_at` reste propriété de l'entrée/provenance source ; run frontier/continuity attendent une source réelle.
### 6.7 Persistence/conflict
Décision : Store mode `Normal`, vérité de correction dans Store, aucune cache-based correctness, conflict terminal sans overwrite ni source gagnante.
### 6.8 Fault
Décision : erreurs statiques Worker pour settings/runtime/source/store/conflict/drain/counter. Le texte d'erreur distant ou le matériau de transaction n'entre jamais dans snapshot/Debug public.
## 7. Harness déterministe prévu
Le harness privé doit pouvoir injecter des matériaux RAW complets et metadata sûre sans réseau et contrôler les ordres de terminaison.
Preuves minimales :
```text
start/stop normal
stop idempotent
queue pleine/backpressure
concurrency Store bornée
new/idempotent/new observation
content conflict
Store error
source failure
stop pendant admission/persistence
drain timeout
no orphan task
slow/no snapshot listener
latest-value concrete/common
redaction
```
Le harness ne devient pas une API publique d'injection.
## 8. Questions reportées sans blocage
```text
source IDs/capabilities/roles publics
required/optional source policy
retry/reconnect policy
Yellowstone/WS/Helius/HTTP productive adapters
run frontier
continuity/gap repair
hydration live
multi-source coalescence optimization
hot reconfiguration desired/effective
provider smokes
```
Ces sujets appartiennent aux releases `0.3.12+` ou à une tranche ultérieure explicitement ouverte si la base réelle l'impose.
## 9. Sizing et décision release
Le forecast initial du prompt est scindé afin de ne pas concentrer crate/settings/runtime/supervision/persistence/snapshots dans les mêmes tranches.
Prévision retenue :
```text
pre.001 audit/rules/plan
pre.002 crate + dependency firewall
pre.003 identity/settings
pre.004 lifecycle/start/handle/terminal
pre.005 supervisor/task ownership + harness
pre.006 bounded admission + common RAW
pre.007 Store persistence/idempotence/conflict
pre.008 snapshots + Worker API projection
pre.009 shutdown/backpressure/fault hardening
pre.010 public/release/security hardening
pre.011 technical final gate
pre.012 documentation reconciliation
pre.013 publication preparation
rel.001
```
Décision `pre.001` : **0.3.11 reste clôturable dans une seule session** si aucune source live, modification Transport/Config, migration Store ou continuity/gap-repair n'entre dans le scope.
## 10. Gates futurs
À partir de `pre.002`, chaque tranche Rust rejoue au minimum :
```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
```
Les suites et graphes s'ajoutent selon la responsabilité de la tranche. `pre.011` exécute le gate workspace final, y compris :
```bash
cargo test --workspace --all-targets --all-features
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
```
## 11. Non-claims `0.3.11`
Même après fermeture de cette release, ne pas revendiquer :
```text
Yellowstone support
WS standard support
Helius support
HTTP live ingestion
lossless provider continuity
replay/gap repair
multi-provider live convergence
hot source reconfiguration
Desk ingestion
```
`0.3.11` prouve uniquement que le host runtime Worker est sûr, borné, déterministe et prêt à recevoir ces sources dans les releases suivantes.
## 12. Gate final `pre.001` dans lenvironnement dassemblage
Après matérialisation du delta complet :
```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
Markdown table audit: clean (340 table(s), 775 file(s))
scan sémantique des règles actives : 0 formulation obsolète ciblée restante
comparaison byte-à-byte avec la stable : 3 fichiers ajoutés, 3 modifiés, 0 supprimé
```