v0.3.6-pre.005-fix.001

This commit is contained in:
2026-09-01 13:42:34 +02:00
parent 4fdeab4d67
commit ea5f756d17
9 changed files with 164 additions and 48 deletions

View File

@@ -1,12 +1,12 @@
# file: Cargo.toml
# version: 400
# version: 401
[workspace]
resolver = "3"
members = ["crates/ksp-app-config-desk", "crates/ksp-app-solprices-desk", "crates/ksp-app-wallet-desk", "crates/ksp-config-lib", "crates/ksp-core-lib", "crates/ksp-interface-lib", "crates/ksp-job-api", "crates/ksp-job-backfill-lib", "crates/ksp-logging-lib", "crates/ksp-offchain-transport-lib", "crates/ksp-onchain-transport-lib", "crates/ksp-program-api", "crates/ksp-store-api", "crates/ksp-store-lib", "crates/ksp-store-postgres-lib", "crates/ksp-wallet-lib"]
[workspace.package]
version = "0.3.6-pre.5"
version = "0.3.6-pre.5.fix.1"
edition = "2024"
license = "MIT"
repository = "https://git.sasedev.com/Sasedev/khadhroony-solana-project"

View File

@@ -1,5 +1,5 @@
// file: crates/ksp-job-backfill-lib/src/discovery.rs
// version: 1
// version: 2
/// Network-scoped identity of one discovered transaction candidate before canonical signature decoding.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
@@ -262,7 +262,7 @@ where
std::option::Option::None => return std::result::Result::Err(discovery_invalid("scope.address")),
};
let mut before = match request.scope().kind() {
crate::BackfillScopeKind::BeforeAddress => request.scope().anchor().map(|value| value.as_str().to_owned()),
crate::BackfillScopeKind::BeforeAddress => request.scope().anchor().map(|value| return value.as_str().to_owned()),
crate::BackfillScopeKind::LatestAddress => std::option::Option::None,
crate::BackfillScopeKind::AfterAddress | crate::BackfillScopeKind::ExplicitSignatures => {
return std::result::Result::Err(discovery_invalid("scope.kind"));
@@ -434,8 +434,7 @@ fn discovery_invalid(field: &'static str) -> ksp_core_lib::Error {
}
fn discovery_stalled() -> ksp_core_lib::Error {
return ksp_core_lib::Error::new(crate::ERROR_CODE_BACKFILL_DISCOVERY_STALLED, "Backfill discovery cursor did not advance")
.with_context("field", "before");
return ksp_core_lib::Error::new(crate::ERROR_CODE_BACKFILL_DISCOVERY_STALLED, "Backfill discovery cursor did not advance").with_context("field", "before");
}
#[cfg(test)]

View File

@@ -51,10 +51,10 @@ pub use self::request::BackfillSignature;
pub use self::request::MAX_BACKFILL_CANDIDATES;
/// Maximum number of concurrent transaction hydrations admitted by one Backfill request.
pub use self::request::MAX_BACKFILL_HYDRATION_CONCURRENCY;
/// Maximum number of `getSignaturesForAddress` pages admitted by one address Backfill request.
pub use self::request::MAX_BACKFILL_PAGES;
/// Maximum page size admitted for one `getSignaturesForAddress` request.
pub use self::request::MAX_BACKFILL_PAGE_SIZE;
/// Maximum number of `getSignaturesForAddress` pages admitted by one address Backfill request.
pub use self::request::MAX_BACKFILL_PAGES;
/// Maximum Base58 text length possible for one canonical 64-byte Solana signature.
pub use self::request::MAX_BACKFILL_SIGNATURE_TEXT_BYTES;
/// Minimum Base58 text length possible for one canonical 64-byte Solana signature.

View File

@@ -43,16 +43,9 @@ fn pre_005_production_sources_keep_transport_and_store_in_their_owned_layers() {
include_str!("../src/request.rs"),
];
for source in sources {
for forbidden in [
"ksp_config_lib::",
"ksp_interface_lib::",
"ksp_store_api::",
"ksp_store_postgres_lib::",
"reqwest::",
"serde_json::",
"std::env",
"tonic::",
] {
for forbidden in
["ksp_config_lib::", "ksp_interface_lib::", "ksp_store_api::", "ksp_store_postgres_lib::", "reqwest::", "serde_json::", "std::env", "tonic::"]
{
assert!(!source.contains(forbidden), "forbidden concrete Backfill path detected: {forbidden}");
}
}

View File

@@ -63,14 +63,13 @@ impl super::SignaturePageSource for FakeSource {
},
std::result::Result::Err(_) => {
return std::boxed::Box::pin(async {
return std::result::Result::Err(ksp_core_lib::Error::new(
crate::ERROR_CODE_BACKFILL_DISCOVERY_INVALID,
"test page queue lock poisoned",
));
return std::result::Result::Err(ksp_core_lib::Error::new(crate::ERROR_CODE_BACKFILL_DISCOVERY_INVALID, "test page queue lock poisoned"));
});
},
};
return std::boxed::Box::pin(async move { return std::result::Result::Ok(page); });
return std::boxed::Box::pin(async move {
return std::result::Result::Ok(page);
});
}
}
@@ -223,10 +222,7 @@ async fn pre_005_after_page_bound_is_partial_and_does_not_claim_anchor_completio
std::option::Option::Some(value) => value,
std::option::Option::None => return,
};
let source = FakeSource::new(std::vec![
std::vec![page_entry('7', 70), page_entry('6', 60)],
std::vec![page_entry('5', 50), page_entry('4', 40)],
]);
let source = FakeSource::new(std::vec![std::vec![page_entry('7', 70), page_entry('6', 60)], std::vec![page_entry('5', 50), page_entry('4', 40)],]);
let result = super::discover_with_source(&source, &request).await;
let discovery = match result {
std::result::Result::Ok(value) => value,

View File

@@ -127,18 +127,8 @@ fn pre_005_request_bounds_are_exact_and_explicit_context_is_rejected() {
std::result::Result::Ok(value) => value,
std::result::Result::Err(_) => return,
};
let explicit_with_context = crate::BackfillRequest::new(
job_id,
network,
role,
crate::BackfillCommitment::Confirmed,
explicit_scope,
1,
1,
1,
1,
std::option::Option::Some(10),
);
let explicit_with_context =
crate::BackfillRequest::new(job_id, network, role, crate::BackfillCommitment::Confirmed, explicit_scope, 1, 1, 1, 1, std::option::Option::Some(10));
assert!(explicit_with_context.is_err());
return;
}

View File

@@ -0,0 +1,129 @@
<!-- file: deltas/0.3.6/pre.005-fix.001.md -->
<!-- version: 1 -->
# Delta `0.3.6-pre.005-fix.001` — return explicite du curseur Before
## Base requise
```text
0.3.6-pre.005 appliquée
workspace.package.version = 0.3.6-pre.5
```
Le gate opérateur fourni pour `pre.005` 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 / 147 fichiers)
cargo check --workspace PASS
cargo clippy --workspace --all-targets FAIL / clippy::implicit_return
cargo test -p ksp-job-backfill-lib PASS
unitaires 11 PASS
dependency_boundary 2 PASS
public_api 2 PASS
release_completeness 2 PASS
cargo tree -p ksp-job-backfill-lib --edges normal exécuté
cargo tree -p ksp-job-backfill-lib -e features exécuté
```
## Objectif
Corriger exclusivement l'écart Clippy `implicit_return` dans la closure privée qui construit le curseur initial `before` du scope `BeforeAddress`, sans modifier la sémantique de découverte de `pre.005`.
## Cause exacte
Dans `crates/ksp-job-backfill-lib/src/discovery.rs`, `discover_older` initialise le curseur optionnel à partir de l'ancre du scope :
```rust
crate::BackfillScopeKind::BeforeAddress => request.scope().anchor().map(|value| value.as_str().to_owned()),
```
Le workspace interdit les retours implicites via `-D clippy::implicit-return`. La closure de `Option::map` doit donc rendre son résultat avec un `return` explicite.
Le correctif est strictement syntaxique :
```rust
crate::BackfillScopeKind::BeforeAddress => request.scope().anchor().map(|value| return value.as_str().to_owned()),
```
La valeur obtenue, l'exclusivité de l'ancre, l'ordre de pagination, la déduplication, les bornes et tous les contrats publics restent identiques.
## Version
Le fix modifie un fichier Rust. Conformément au workflow de version :
```text
workspace.package.version = 0.3.6-pre.5.fix.1
delivery = 0.3.6-pre.005-fix.001
commit = v0.3.6-pre.005-fix.001
```
Aucun tag prerelease.
## Fichiers ajoutés
```text
deltas/0.3.6/pre.005-fix.001.md
```
## Fichiers modifiés
```text
Cargo.toml
crates/ksp-job-backfill-lib/src/discovery.rs
docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md
docs/validation/023-V0_3_6_JOB_API_BACKFILL.md
```
## Fichiers supprimés
Aucun.
## Invariants préservés
- identité transactionnelle/candidate toujours `(RawNetworkId, signature)` ;
- provider, endpoint, protocole et rôle Transport restent hors identité ;
- aucune modification des quatre scopes, de leurs bornes ou du fingerprint ;
- aucune modification du chemin `HttpTransportPool::get_signatures_for_address` ;
- aucune nouvelle dépendance, feature, crate, API publique ou test ;
- aucune ouverture de RAW, persistance, checkpoint, runtime, README, USAGE, CHANGELOG, ROADMAP ou prompt.
## Validations exécutées pour l'assemblage du fix
```text
python3 scripts/audit_rust_workspace_rules.py
-> General Rust rule audit: clean
-> Rust export completeness audit: 0 candidate(s)
-> KSP workspace Rust rule audit: clean
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.6
-> Markdown table audit: clean (264 tables / 148 fichiers)
```
Le diff par rapport à `pre.005` est limité aux quatre fichiers modifiés ci-dessus et au présent delta.
## Validations non exécutées
L'environnement d'assemblage ne fournit ni `cargo` ni `rustfmt`. Le gate Rust du fix n'est donc pas annoncé comme vert localement.
Aucun smoke réseau ou PostgreSQL n'est pertinent pour ce correctif Clippy.
## Gate opérateur demandé
```bash
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
python3 scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts crates deltas/0.3.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
```
Résultat attendu : les onze tests unitaires et six canaries d'intégration restent verts, Clippy devient vert et le graphe de dépendances reste inchangé.
## Questions ouvertes
Aucune. `pre.006` reste interdit tant que ce gate de fix n'est pas intégralement vert.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# Plan v0.3.6 — Job API et premier backfill RAW
@@ -434,13 +434,19 @@ Les tests couvrent le succès direct `null`, la surface publique et surtout un r
### `pre.005` — Fondation Backfill et découverte
**Statut : matérialisé ; gate opérateur à rejouer.**
**Statut : alisé ; corrigé par `pre.005-fix.001`, gate opérateur du fix à rejouer.**
Budget cible : **15-20 min**. Entrée : Transport observé stable et gate `pre.004` vert. La tranche crée `ksp-job-backfill-lib` avec dépendances directes Job API, Core, Logging, Onchain Transport, Store façade sans feature backend imposée et SHA-256 déjà centralisé au workspace ; Tokio reste uniquement une dev-dependency pour les tests async de cette tranche.
La requête impose explicitement `JobId`, `RawNetworkId`, rôle HTTP, engagement `Confirmed|Finalized`, scope, page size `1..=1000`, pages `1..=10000`, candidats `1..=10000`, future concurrence d'hydratation `1..=64` et `min_context_slot` seulement pour les scopes adresse. Les quatre scopes sont matérialisés. Les signatures explicites sont bornées, Base58-shaped et dédupliquées à première occurrence ; le décodage exact vers 64 octets reste volontairement `pre.006`.
`BackfillCandidateIdentity` est explicitement `(RawNetworkId, BackfillSignature)` ; rôle/provider/endpoint/protocole sont exclus du fingerprint de scope et ne peuvent donc pas devenir une identité transactionnelle. La découverte réelle appelle uniquement `HttpTransportPool::get_signatures_for_address`, sans client, retry, pacing ou endpoint policy dans Job. Latest/Before paginent par `before`, After conserve la fenêtre plus récente la plus proche de l'ancre via `until`, et les limites de pages produisent un résultat partiel observable plutôt qu'une fausse complétion. Les doubles déterministes restent privés aux tests. La tranche matérialise 11 tests unitaires et 6 canaries dintégration ; leur exécution Cargo reste une preuve opérateur. Sortie attendue après gate : latest, before, after et explicite, déduplication stable, frontières partielles et firewall de dépendances verts.
`BackfillCandidateIdentity` est explicitement `(RawNetworkId, BackfillSignature)` ; rôle/provider/endpoint/protocole sont exclus du fingerprint de scope et ne peuvent donc pas devenir une identité transactionnelle. La découverte réelle appelle uniquement `HttpTransportPool::get_signatures_for_address`, sans client, retry, pacing ou endpoint policy dans Job. Latest/Before paginent par `before`, After conserve la fenêtre plus récente la plus proche de l'ancre via `until`, et les limites de pages produisent un résultat partiel observable plutôt qu'une fausse complétion. Les doubles déterministes restent privés aux tests. Le gate opérateur exécute avec succès les 11 tests unitaires et les 6 canaries dintégration, ainsi que `cargo check`; Clippy `--all-targets` révèle toutefois un unique écart de style `implicit_return` dans une closure privée de `discover_older`, corrigé par `pre.005-fix.001`.
#### `pre.005-fix.001` — Return explicite dans la closure du curseur Before
**Statut : matérialisé ; gate opérateur à rejouer.**
Le gate opérateur de `pre.005` confirme `cargo fmt`, les audits Rust/Markdown, `cargo check --workspace`, les 11 tests unitaires, les 6 canaries dintégration et les arbres Cargo. `cargo clippy --workspace --all-targets` échoue uniquement sur `clippy::implicit_return` à la construction optionnelle du curseur `before` dans `discover_older`. Le fix remplace l'expression implicite de la closure par `return value.as_str().to_owned()` sans modifier la valeur produite, les branches de scope, la pagination ou le contrat public. Comme un fichier Rust est corrigé, la version workspace devient `0.3.6-pre.5.fix.1`.
### `pre.006` — Conversion RAW v1 et provenance

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/023-V0_3_6_JOB_API_BACKFILL.md -->
<!-- version: 8 -->
<!-- version: 9 -->
# Validation v0.3.6 — Job API et premier backfill RAW
@@ -57,6 +57,9 @@ Aucune entrée absolue, traversée, avec séparateur inversé ou lien symbolique
- [X] Gate opérateur de `pre.003-fix.001` : `cargo fmt`, audits Rust/Markdown, `cargo check`, Clippy, treize unitaires + quatorze canaries `ksp-job-api` et arbres Cargo normal/features verts.
- [X] `pre.004` matérialise une voie observée additive de `getTransaction` sans modifier le client, les settings, le routage ni la politique de retry Transport ; gate opérateur vert.
- [X] Le workspace comptait 14 crates avant `pre.005`; `ksp-job-backfill-lib` devient la 15e crate membre sans créer d'exécutable ni de Worker.
- [X] Gate opérateur de `pre.005` : `cargo fmt`, audits Rust/Markdown et `cargo check --workspace` verts ; les 11 tests unitaires et 6 canaries `ksp-job-backfill-lib` sont verts.
- [X] Le même gate révèle un unique échec Clippy `clippy::implicit_return` dans la closure privée qui dérive le curseur `before`; les arbres Cargo normal/features sont néanmoins exécutés et cohérents avec le graphe prévu.
- [X] `pre.005-fix.001` ajoute uniquement le `return` explicite exigé dans cette closure et ne modifie ni valeur, ni pagination, ni identité réseau, ni dépendance, ni API publique.
## 4. Autorités et cohérence documentaire
@@ -97,7 +100,7 @@ Aucune entrée absolue, traversée, avec séparateur inversé ou lien symbolique
## 7. Admission et portées
`pre.005` matérialise les contrats et leurs tests, mais les critères comportementaux ci-dessous restent ouverts jusqu'au gate Cargo opérateur. L'identité candidate est auditée statiquement comme `(RawNetworkId, signature)` ; rôle HTTP, provider, endpoint et protocole ne participent ni à cette identité ni au fingerprint sémantique du scope.
`pre.005` matérialise les contrats et leurs tests. Le gate opérateur confirme les 11 unitaires et 6 canaries, tandis que Clippy impose un fix syntaxique sans effet comportemental avant clôture complète. L'identité candidate est `(RawNetworkId, signature)` ; rôle HTTP, provider, endpoint et protocole ne participent ni à cette identité ni au fingerprint sémantique du scope.
- [ ] `LatestAddress`, `BeforeAddress`, `AfterAddress` et `ExplicitSignatures` couverts.
- [ ] Adresse validée par le type Core existant.
@@ -190,12 +193,12 @@ Aucune entrée absolue, traversée, avec séparateur inversé ou lien symbolique
- [X] `ksp-job-backfill-lib` ne dépend pas de Config, App, Wallet, Program, Interface ou backend Store ; `ksp-store-lib` est consommée avec `default-features = false`.
- [ ] Aucun retour de dépendance vers Job depuis les couches basses.
- [X] Versions/features auditées : aucune nouvelle version externe ; `sha2` et `tokio` réutilisent les entrées workspace existantes, Tokio étant dev-only en `pre.005`.
- [X] `pre.005` matérialise 11 tests unitaires et 6 canaries dintégration ; leur exécution Cargo reste ouverte jusquau gate opérateur.
- [X] `pre.005` matérialise 11 tests unitaires et 6 canaries dintégration ; le gate opérateur les exécute tous avec succès.
- [ ] `cargo fmt --all -- --check` vert.
- [X] `scripts/audit_rust_workspace_rules.py` vert sur `pre.005` dans l'environnement d'assemblage.
- [X] `scripts/audit_markdown_tables.py` vert sur `pre.005` dans l'environnement d'assemblage (264 tables / 147 fichiers, delta inclus).
- [X] `scripts/audit_rust_workspace_rules.py` vert sur `pre.005` dans l'environnement d'assemblage et dans le gate opérateur.
- [X] `scripts/audit_markdown_tables.py` vert sur `pre.005` dans le gate opérateur (264 tables / 147 fichiers, delta inclus).
- [X] Contrats de fichiers de `FILE_CONTRACTS.md` vérifiés sur chaque ajout de `pre.001`.
- [ ] `cargo check --workspace` vert.
- [X] `cargo check --workspace` vert sur `pre.005`; le fix ne change qu'une closure privée refusée par Clippy.
- [ ] `cargo clippy --workspace --all-targets --all-features -- -D warnings` vert.
- [ ] `cargo test --workspace --all-targets --all-features` vert.
- [ ] `cargo tree -d` examiné et doublons justifiés.