# Delta `0.3.6-pre.010` — hardening et canaries externes ## Base requise ```text 0.3.6-pre.009-fix.002 appliquée workspace.package.version = 0.3.6-pre.9.fix.2 ``` Le gate opérateur fourni pour cette base est intégralement vert : ```text cargo fmt --all PASS python3 scripts/audit_rust_workspace_rules.py PASS / clean python3 scripts/audit_markdown_tables.py ... PASS / clean (264 tables / 157 fichiers) cargo check --workspace PASS cargo clippy --workspace --all-targets PASS / aucun warning cargo test -p ksp-job-backfill-lib PASS unitaires 47 PASS dependency_boundary 2 PASS public_api 6 PASS release_completeness 2 PASS ``` `pre.009-fix.002` ne modifiait aucune dépendance ni feature, donc aucun arbre Cargo supplémentaire n'était requis pour ce fix. ## Objectif Matérialiser exclusivement le hardening `pre.010` du plan 027 : fermer les scénarios adversariaux, les firewalls de dépendances, la sécurité des surfaces `Debug`, la visibilité/import crate-root et l'API externe du premier vertical Backfill RAW. La tranche ne modifie aucun code de production, n'élargit aucune API, n'ajoute aucune dépendance et ne change aucune feature. Le smoke live PostgreSQL/Devnet reste conditionnel à un environnement explicitement configuré et n'est pas inventé dans l'environnement d'assemblage. ## Canaries adversariales et erreurs stables La nouvelle suite `tests/hardening.rs` vérifie depuis l'extérieur de la crate : - les neuf codes d'erreur publics Backfill, leur domaine `job_backfill`, leur code exact et leur unicité ; - une signature Base58 hostile contenant `0`, rejetée avec `ERROR_CODE_BACKFILL_SIGNATURE_INVALID` ; - une borne `page_size = 0`, rejetée avec `ERROR_CODE_BACKFILL_REQUEST_INVALID` et contexte `field=page_size` ; - un fingerprint identique pour deux JobId/rôles Transport différents mais un même réseau/scope ; - un fingerprint différent lorsque le réseau logique change. La canarie confirme donc que l'identité sémantique du scope reste indépendante du JobId et du rôle Transport, tout en restant sensible au réseau. ## Sécurité des surfaces publiques Les canaries externes vérifient : - `BackfillSignature` et `BackfillScopeFingerprint` restent redacted en `Debug` ; - `BackfillRequest` ne rend pas la signature brute d'un scope explicite ; - `BackfillJobHandle` s'appuie sur le `Debug` redacted de `JobNotification` et ne rend pas le payload snapshot ; - la façade `src/lib.rs` n'expose aucun `pub mod`, type Tokio/Futures, détail Serde/SHA, backend Store, Reqwest ou Tonic. Aucune URL, credential, provider, endpoint ni payload RAW n'est ajouté à l'API publique. ## Runtime externe Le handle public est exercé sans seam privée : ```text BackfillJobRuntime::new BackfillJobRuntime::handle BackfillJobHandle::snapshots JobSnapshotSource::current BackfillJobHandle::cancel ``` La canarie impose : - état initial `JobState::Created` ; - snapshot initial `BackfillJobPhase::Created` ; - première annulation acceptée ; - token observable comme demandé ; - seconde annulation rejetée idempotemment. Les races, waits RPC et drainage Store restent couverts par les unit tests `pre.009-fix.002`; `pre.010` ajoute ici la preuve par la surface publique externe. ## Firewalls de dépendances La surface normale de `ksp-job-backfill-lib` est vérifiée exactement : ```text futures-util ksp-core-lib ksp-job-api ksp-logging-lib ksp-onchain-transport-lib ksp-store-lib (default-features = false) serde_json.workspace sha2.workspace tokio (macros + sync) ``` La seule dev-dependency reste Tokio avec le runtime de test. La suite refuse explicitement `ksp-store-api` et `ksp-store-postgres-lib`. Elle vérifie en outre qu'aucune des couches basses suivantes ne dépend de `ksp-job-api` ni de `ksp-job-backfill-lib` : ```text ksp-core-lib ksp-logging-lib ksp-onchain-transport-lib ksp-store-api ksp-store-lib ksp-store-postgres-lib ``` Cela ferme la canarie de retour de dépendance vers Job sans modifier le graphe. ## Visibilité et chemins crate-root Une canarie source dédiée protège la correction `pre.009-fix.001/fix.002` : - `BackfillRuntimeControl` et `TerminalClaim` restent privés et absents du crate-root ; - les items partagés contrôlés ont leurs `impl` via `crate::Item` ; - aucun `crate::module::Item` n'est admis dans les modules Backfill contrôlés ; - la construction du fingerprint passe par `crate::BackfillScopeFingerprint::from_bytes(bytes)` ; - le constructeur tuple inaccessible `crate::BackfillScopeFingerprint(bytes)` reste interdit. Cette canarie est volontairement limitée à `ksp-job-backfill-lib` afin de verrouiller la crate active sans introduire un nouvel audit global qui signalerait rétroactivement des surfaces historiques hors mission v0.3.6. ## Tests matérialisés Aucun unit test n'est ajouté : le total reste **47 unitaires**. La tranche ajoute **9 canaries** dans `tests/hardening.rs` et **1 canarie** de complétude, portant l'intégration de 10 à **20 canaries** : ```text dependency_boundary 2 public_api 6 release_completeness 3 hardening 9 ``` Total attendu au gate : ```text 47 unitaires 20 canaries d'intégration ``` ## Fichiers ajoutés ```text crates/ksp-job-backfill-lib/tests/hardening.rs deltas/0.3.6/pre.010.md ``` ## Fichiers modifiés ```text Cargo.toml crates/ksp-job-backfill-lib/tests/release_completeness.rs docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md docs/validation/023-V0_3_6_JOB_API_BACKFILL.md ``` Aucune suppression. Aucun manifeste de dépendances de crate n'est modifié. ## Versions d'en-tête ```text Cargo.toml 410 -> 411 crates/ksp-job-backfill-lib/tests/release_completeness.rs 7 -> 9 docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md 20 -> 23 docs/validation/023-V0_3_6_JOB_API_BACKFILL.md 20 -> 23 ``` La nouvelle canarie `tests/hardening.rs` a été révisée pendant le hardening et est livrée à `version: 4`. Le présent delta commence à `version: 1`. ## Version workspace ```text workspace.package.version = 0.3.6-pre.10 delivery = 0.3.6-pre.010 ``` ## Validations 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 python3 -m unittest scripts.tests.test_audit_markdown_tables ``` L'environnement d'assemblage ne fournit ni Cargo, ni Rustc, ni Rustfmt. La compilation, Clippy et les 47 + 20 tests Rust restent donc à exécuter par l'opérateur. ## Gate opérateur demandé Aucune dépendance ni feature ne change dans `pre.010`; aucun `cargo tree` n'est demandé pour cette tranche. ```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 ``` Résultat attendu : **47 unitaires + 20 canaries d'intégration**, sans warning Clippy.