v0.3.7-pre.010

This commit is contained in:
2026-09-02 18:56:09 +02:00
parent 97f84e5c58
commit 313d2a1ea6
20 changed files with 533 additions and 40 deletions

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/028-V0_3_7_BACKFILL_DESK_PLAN.md -->
<!-- version: 9 -->
<!-- version: 10 -->
# Plan v0.3.7 — Backfill Desk
@@ -123,7 +123,7 @@ Commandes prévues :
backfill_options() -> BackfillDeskOptionsDto
backfill_status() -> BackfillRunStatusDto
backfill_start(request) -> BackfillRunStatusDto
backfill_cancel() -> BackfillCancelResponseDto
backfill_cancel(job_id) -> BackfillCancelResponseDto
backfill_resume() -> BackfillResumeResponseDto
backfill_reset() -> BackfillRunStatusDto
```
@@ -182,8 +182,9 @@ Règles :
- start atomique : refus si un run est `starting/running/cancelling` ;
- le handle est installé avant spawn afin que Cancel ne perde pas la course au démarrage ;
- Cancel cible le `job_id` backend affiché par le monitoring afin qu'une requête IPC retardée ne puisse jamais annuler un run ultérieur ;
- Cancel répété est idempotent au niveau UX, mais le retour expose si la demande a été acceptée ;
- un terminal publié gagne sur un Cancel tardif ;
- un terminal publié gagne sur un Cancel tardif ; un Cancel visant l'ancien JobId après admission d'un nouveau run est rejeté comme mismatch ;
- la source latest-value est conservée jusqu'à projection du terminal ;
- reset/new campaign n'est autorisé qu'en absence de run actif ;
- fermeture de l'application déclenche une demande d'annulation coopérative best-effort puis laisse la destruction du process terminer les ressources ; aucune promesse de drain crash-safe n'est faite ;
@@ -275,7 +276,9 @@ Le backend émet `ksp-backfill-status` à partir de `JobSnapshotSource::wait_for
### pre.010 — Cancel et races terminales
Cancel, état cancelling, idempotence UX, concurrence Start/Cancel/terminal, sémantique de drain Store et fermeture app.
Ajouter `backfill_cancel(job_id)` avec `BackfillCancelResponseDto { accepted, job_id, state }`. Le JobId est celui généré par le backend et projeté par le monitoring ; il cible le slot actif pour empêcher un Cancel IPC retardé d'atteindre un run suivant. Le premier Cancel pré-terminal est accepté, les répétitions sont idempotentes et renvoient `accepted=false`, un terminal gagne sur un Cancel tardif et un JobId périmé est rejeté sans toucher au run courant.
Le frontend expose **Annuler** uniquement pour un status actif, trace seulement JobId/état/acceptation et se resynchronise par `backfill_status`. L'état `cancelling` reste l'intention coopérative : le runtime arrête les nouvelles admissions mais draine le travail déjà soumis au Store. À la fermeture de la fenêtre principale, le one-shot shutdown bloque d'abord les nouveaux Starts, demande ensuite best-effort l'annulation du run actif, puis poursuit le shutdown Store/process sans promettre un drain crash-safe. Resume reste hors tranche.
### pre.011 — checkpoint/frontier et Resume

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/024-V0_3_7_BACKFILL_DESK.md -->
<!-- version: 17 -->
<!-- version: 18 -->
# Validation v0.3.7 — Backfill Desk
@@ -480,3 +480,24 @@ Le correctif conserve le même niveau de sécurité mais cible désormais les d
- [X] version Cargo synchronisée en `0.3.7-pre.9.fix.2` ;
- [X] audits statiques Rust/Markdown rejoués dans l'environnement d'assemblage ;
- [ ] replay opérateur `cargo fmt/check/clippy/test` du fix à exécuter ; aucun `cargo tree` requis car dépendances/features inchangées.
## 24. `pre.010` — Cancel ciblé, idempotence et races terminales
Le replay opérateur de `pre.009-fix.002` ferme le monitoring latest-value : audits Rust/Markdown, `cargo check --workspace`, Clippy, les 49 tests unitaires `ksp-job-backfill-lib` et toutes les suites Backfill Desk passent. La surface `pre.010` peut donc ouvrir le contrôle coopératif sans rattrapage antérieur.
`backfill_cancel(job_id)` cible explicitement le JobId backend actuellement observé. Cette cible empêche une requête Cancel IPC retardée, émise pour un run terminé, d'annuler un run ultérieur. Le slot single-run sérialise Start/Cancel/finish : le premier Cancel pré-terminal appelle `BackfillJobHandle::cancel()` et renvoie `accepted=true`; les répétitions renvoient `accepted=false`; un terminal déjà gagné reste terminal; un JobId qui ne correspond ni au run actif ni au terminal retenu est rejeté par un code `backfill_desk` stable.
Le frontend ajoute un bouton **Annuler** au monitoring, transmet uniquement le JobId sûr, n'envoie aucun payload de campagne et se resynchronise immédiatement via `backfill_status`. La fermeture de la fenêtre principale gagne d'abord `begin_shutdown()`, ce qui interdit tout nouveau Start, puis demande best-effort l'annulation du run actif avant le shutdown Store et l'exit. Cette fermeture ne promet pas le drain crash-safe du travail déjà soumis ; le runtime Job conserve seul la sémantique de drain coopératif.
### Gate statique local `pre.010`
- [X] Cancel ciblé par JobId backend, sans identité fournie au Start ;
- [X] premier Cancel accepté et répétitions idempotentes ;
- [X] stale JobId rejeté avant action sur un nouveau run ;
- [X] terminal tardif prioritaire sur un Cancel non accepté ;
- [X] shutdown bloque Start puis tente l'annulation active avant exit ;
- [X] DTO Cancel limité à `accepted`, `job_id`, `state` ;
- [X] frontend Cancel sans adresse/signature/provider/endpoint/checkpoint/payload ;
- [X] aucune dépendance/feature Cargo ajoutée ;
- [X] Resume non ouvert ;
- [ ] `cargo fmt/check/clippy/test` de `pre.010` à rejouer par l'opérateur.