v0.3.6-pre.009
This commit is contained in:
272
deltas/0.3.6/pre.009.md
Normal file
272
deltas/0.3.6/pre.009.md
Normal file
@@ -0,0 +1,272 @@
|
||||
<!-- file: deltas/0.3.6/pre.009.md -->
|
||||
<!-- version: 1 -->
|
||||
|
||||
# Delta `0.3.6-pre.009` — runtime Backfill, annulation coopérative et snapshots latest-value
|
||||
|
||||
## Base requise
|
||||
|
||||
```text
|
||||
0.3.6-pre.008-fix.001 appliquée
|
||||
workspace.package.version = 0.3.6-pre.8.fix.1
|
||||
```
|
||||
|
||||
Le gate opérateur fourni pour cette base confirme :
|
||||
|
||||
```text
|
||||
cargo fmt --all PASS
|
||||
python3 scripts/audit_rust_workspace_rules.py PASS / clean
|
||||
python3 scripts/audit_markdown_tables.py ... PASS / clean (264 tables / 154 fichiers)
|
||||
cargo check --workspace PASS
|
||||
cargo clippy --workspace --all-targets PASS / aucun warning
|
||||
cargo test -p ksp-job-backfill-lib PASS
|
||||
unitaires 39 PASS
|
||||
dependency_boundary 2 PASS
|
||||
public_api 5 PASS
|
||||
release_completeness 2 PASS
|
||||
```
|
||||
|
||||
Les arbres Cargo ne sont pas rejoués pour le fix `pre.008-fix.001`, qui ne modifie ni dépendance ni feature. La présente tranche modifie en revanche le manifeste de `ksp-job-backfill-lib` en promouvant Tokio en dépendance normale privée ; les arbres Cargo redeviennent donc pertinents pour son gate.
|
||||
|
||||
## Objectif
|
||||
|
||||
Matérialiser exclusivement `pre.009` du plan 027 : fournir le runtime concret du premier Backfill RAW avec annulation coopérative, arbitrage terminal déterministe et diffusion latest-value de snapshots sûrs via le contrat runtime-neutral de `ksp-job-api`.
|
||||
|
||||
La tranche ne crée pas de scheduler global, ne persiste pas les checkpoints, ne modifie pas Store/Transport/Job API et ne prépare pas encore le hardening externe final de `pre.010`.
|
||||
|
||||
## Runtime concret
|
||||
|
||||
La crate expose désormais :
|
||||
|
||||
```text
|
||||
BACKFILL_JOB_KIND_CODE
|
||||
BackfillJobPhase
|
||||
BackfillJobSnapshot
|
||||
BackfillSnapshotSource
|
||||
BackfillJobHandle
|
||||
BackfillJobRuntime
|
||||
ERROR_CODE_BACKFILL_RUNTIME_INVALID
|
||||
```
|
||||
|
||||
`BackfillJobRuntime::new` construit un état initial `Created`, un canal latest-value privé et un canal de réveil d'annulation privé. `handle()` est obtenu avant de déplacer le runtime dans `run`, afin que l'hôte conserve une surface cloneable de contrôle et d'observation pendant l'exécution.
|
||||
|
||||
Le kind stable est :
|
||||
|
||||
```text
|
||||
solana.raw_transaction.backfill
|
||||
```
|
||||
|
||||
Aucun type Tokio n'est réexporté à la crate root.
|
||||
|
||||
## Snapshot latest-value
|
||||
|
||||
`BackfillJobSnapshot` expose uniquement des faits sûrs et bornés :
|
||||
|
||||
```text
|
||||
phase
|
||||
scope_kind
|
||||
discovery_boundary
|
||||
candidates_selected
|
||||
candidates_admitted
|
||||
candidates_finished
|
||||
entities_inserted
|
||||
entities_existing
|
||||
entities_purged
|
||||
missing
|
||||
conflicts
|
||||
observations_inserted
|
||||
observations_existing
|
||||
cancelled_candidates
|
||||
holes
|
||||
maximum_in_flight
|
||||
contiguous_completed
|
||||
checkpoint
|
||||
failure_code
|
||||
```
|
||||
|
||||
Il n'expose ni URL, provider, endpoint, payload RAW, transaction encodée, credential ou message humain libre.
|
||||
|
||||
`BackfillSnapshotSource` implémente le trait `ksp_job_api::JobSnapshotSource` avec un `tokio::sync::watch` entièrement privé. La source est latest-value : un listener lent peut coalescer les transitions intermédiaires et récupère toujours la valeur la plus récente. Les listeners clonés sont indépendants et la valeur terminale reste retenue après fermeture logique du Job.
|
||||
|
||||
Chaque publication incrémente `JobNotificationSequence`. Une source observant déjà la séquence terminale retourne immédiatement le snapshot terminal retenu.
|
||||
|
||||
## Annulation coopérative
|
||||
|
||||
`BackfillJobHandle::cancel` accepte atomiquement la première annulation tant que la décision terminale n'a pas été prise. L'annulation runtime-neutral reste portée par `JobCancellationToken`; un `watch<bool>` privé sert uniquement à réveiller immédiatement les futures Tokio en attente.
|
||||
|
||||
Les opérations abandonnables pré-Store utilisent une sélection coopérative :
|
||||
|
||||
```text
|
||||
pagination getSignaturesForAddress
|
||||
hydratation getTransaction
|
||||
future pré-Store encore non soumise
|
||||
```
|
||||
|
||||
Une annulation déjà demandée retourne immédiatement le code interne stable :
|
||||
|
||||
```text
|
||||
job_backfill.cancelled
|
||||
```
|
||||
|
||||
Ce code reste crate-internal et sert à distinguer l'annulation d'une erreur fatale avant projection vers `JobState::Cancelled`.
|
||||
|
||||
## Drainage après soumission Store
|
||||
|
||||
La frontière critique reste celle figée par le plan : une opération peut être abandonnée avant soumission durable, mais une persistance Store déjà soumise n'est jamais annulée aveuglément.
|
||||
|
||||
L'exécuteur :
|
||||
|
||||
1. arrête les nouvelles admissions lorsqu'une annulation est observée ;
|
||||
2. peut annuler les candidats encore dans une phase pré-Store abandonnable ;
|
||||
3. laisse les persistances déjà soumises produire un résultat connu ;
|
||||
4. draine toutes les futures déjà admises ;
|
||||
5. réconcilie la frontier et le checkpoint avant publication terminale.
|
||||
|
||||
`BackfillExecutionBatch` expose maintenant les compteurs détaillés nécessaires au snapshot concret : inserted, already-present, purged, missing, conflicts, observations, cancelled, holes et état `was_cancelled`.
|
||||
|
||||
## Arbitrage terminal
|
||||
|
||||
Un état atomique privé sérialise la course entre complétion normale, annulation et échec fatal.
|
||||
|
||||
Règles :
|
||||
|
||||
```text
|
||||
annulation acceptée avant claim terminal normal -> Cancelled
|
||||
claim Completed avant annulation -> annulation tardive rejetée
|
||||
échec fatal avant publication terminale -> Failed, même si annulation était pending
|
||||
```
|
||||
|
||||
La publication latest-value suit uniquement des transitions autorisées entre `Created`, `Running`, `Cancelling`, `Completed`, `Cancelled` et `Failed`. Une publication après état terminal est rejetée par `ERROR_CODE_BACKFILL_RUNTIME_INVALID`.
|
||||
|
||||
## Projection des résultats
|
||||
|
||||
En absence d'échec fatal :
|
||||
|
||||
- batch complet sans trou -> `Completed(Complete)` ;
|
||||
- batch partiel, notamment `Missing` -> `Completed(Partial)` ;
|
||||
- annulation gagnante après drainage -> `Cancelled` ;
|
||||
- conflit ou erreur Transport/conversion/Store terminale -> `Failed` avec code stable conservé dans le snapshot.
|
||||
|
||||
Le checkpoint terminal est celui du dernier préfixe contigu durable produit par `pre.008`; l'annulation ne peut pas faire avancer la frontier au-delà d'un trou ou d'un candidat annulé.
|
||||
|
||||
## Dépendances
|
||||
|
||||
La tranche promeut Tokio de dev-only à dépendance normale privée dans `ksp-job-backfill-lib` :
|
||||
|
||||
```text
|
||||
tokio = { workspace = true, features = ["macros", "sync"] }
|
||||
```
|
||||
|
||||
L'entrée versionnée existe déjà dans `[workspace.dependencies]`; aucune nouvelle version externe n'est introduite. Les tests conservent `rt-multi-thread` uniquement dans `[dev-dependencies]`.
|
||||
|
||||
`futures-util` reste la dépendance normale privée introduite par `pre.008`. Aucun type Tokio/Futures n'entre dans l'API publique.
|
||||
|
||||
## Tests matérialisés
|
||||
|
||||
La tranche ajoute **8 tests unitaires**, portant le total à **47 unitaires**. Ils couvrent notamment :
|
||||
|
||||
- latest-value coalescé pour listener lent et indépendance des listeners clonés ;
|
||||
- rétention du snapshot terminal et rejet d'une annulation tardive ;
|
||||
- arbitrage déterministe annulation contre complétion ;
|
||||
- échec fatal gagnant sur annulation pending avant publication terminale ;
|
||||
- future pré-Store longue abandonnée coopérativement ;
|
||||
- annulation pendant une page de découverte RPC pendante ;
|
||||
- arrêt des admissions et drainage du travail déjà admis ;
|
||||
- forme sûre du snapshot sans provenance Transport ni payload RAW.
|
||||
|
||||
Une canarie publique supplémentaire porte les canaries d'intégration à **10** :
|
||||
|
||||
```text
|
||||
dependency_boundary 2
|
||||
public_api 6
|
||||
release_completeness 2
|
||||
```
|
||||
|
||||
Total matérialisé attendu au gate :
|
||||
|
||||
```text
|
||||
47 unitaires
|
||||
10 canaries d'intégration
|
||||
```
|
||||
|
||||
## Fichiers ajoutés
|
||||
|
||||
```text
|
||||
crates/ksp-job-backfill-lib/src/runtime.rs
|
||||
crates/ksp-job-backfill-lib/unit_tests/runtime.rs
|
||||
deltas/0.3.6/pre.009.md
|
||||
```
|
||||
|
||||
## Fichiers modifiés
|
||||
|
||||
```text
|
||||
Cargo.toml
|
||||
crates/ksp-job-backfill-lib/Cargo.toml
|
||||
crates/ksp-job-backfill-lib/src/discovery.rs
|
||||
crates/ksp-job-backfill-lib/src/error.rs
|
||||
crates/ksp-job-backfill-lib/src/execution.rs
|
||||
crates/ksp-job-backfill-lib/src/lib.rs
|
||||
crates/ksp-job-backfill-lib/tests/dependency_boundary.rs
|
||||
crates/ksp-job-backfill-lib/tests/public_api.rs
|
||||
crates/ksp-job-backfill-lib/tests/release_completeness.rs
|
||||
crates/ksp-job-backfill-lib/unit_tests/discovery.rs
|
||||
crates/ksp-job-backfill-lib/unit_tests/execution.rs
|
||||
docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md
|
||||
docs/validation/023-V0_3_6_JOB_API_BACKFILL.md
|
||||
```
|
||||
|
||||
Aucune suppression.
|
||||
|
||||
## Versions d'en-tête
|
||||
|
||||
Les versions finales reflètent chaque modification réellement enregistrée pendant la matérialisation. Certains fichiers de tests ont donc avancé de plusieurs unités plutôt que d'être artificiellement ramenés à `N + 1` :
|
||||
|
||||
```text
|
||||
Cargo.toml 407 -> 408
|
||||
crates/ksp-job-backfill-lib/Cargo.toml 3 -> 4
|
||||
crates/ksp-job-backfill-lib/src/discovery.rs 3 -> 4
|
||||
crates/ksp-job-backfill-lib/src/error.rs 4 -> 5
|
||||
crates/ksp-job-backfill-lib/src/execution.rs 1 -> 2
|
||||
crates/ksp-job-backfill-lib/src/lib.rs 4 -> 5
|
||||
crates/ksp-job-backfill-lib/tests/dependency_boundary.rs 4 -> 6
|
||||
crates/ksp-job-backfill-lib/tests/public_api.rs 4 -> 6
|
||||
crates/ksp-job-backfill-lib/tests/release_completeness.rs 4 -> 7
|
||||
crates/ksp-job-backfill-lib/unit_tests/discovery.rs 2 -> 5
|
||||
crates/ksp-job-backfill-lib/unit_tests/execution.rs 1 -> 2
|
||||
docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md 15 -> 16
|
||||
docs/validation/023-V0_3_6_JOB_API_BACKFILL.md 15 -> 16
|
||||
```
|
||||
|
||||
Les deux nouveaux fichiers Rust ont été créés puis révisés pendant la tranche et sont livrés à `version: 2`. Le présent delta commence à `version: 1`.
|
||||
|
||||
## Version workspace
|
||||
|
||||
```text
|
||||
workspace.package.version = 0.3.6-pre.9
|
||||
delivery = 0.3.6-pre.009
|
||||
```
|
||||
|
||||
## Validations exécutées dans l'environnement d'assemblage
|
||||
|
||||
```text
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.6
|
||||
```
|
||||
|
||||
Les audits statiques sont exécutés avant et après création du présent delta. L'environnement d'assemblage ne fournit ni Cargo, ni Rustc, ni Rustfmt ; la compilation, Clippy et les tests Rust `pre.009` restent donc à exécuter par l'opérateur.
|
||||
|
||||
## Gate opérateur demandé
|
||||
|
||||
Le manifeste normal de `ksp-job-backfill-lib` change dans cette tranche, donc les arbres Cargo sont à rejouer :
|
||||
|
||||
```bash
|
||||
cargo fmt --all
|
||||
python3 scripts/audit_rust_workspace_rules.py
|
||||
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.6
|
||||
cargo check --workspace
|
||||
cargo clippy --workspace --all-targets
|
||||
cargo test -p ksp-job-backfill-lib
|
||||
cargo tree -p ksp-job-backfill-lib --edges normal
|
||||
cargo tree -p ksp-job-backfill-lib -e features
|
||||
```
|
||||
|
||||
Attendu : 47 unitaires et 10 canaries d'intégration, sans warning Clippy. Un `cargo clean` n'est pas requis par `cargo tree`; il constitue séparément une raison valable de rejouer les arbres lorsqu'une reconstruction propre est volontairement effectuée.
|
||||
Reference in New Issue
Block a user