# Delta `0.3.6-pre.002` — identité, lifecycle et annulation Job API ## Base requise ```text 0.3.6-pre.001-fix.001 workspace.package.version = 0.3.6-pre.1.fix.1 ``` Le gate opérateur communiqué pour la base passe les cinq tests Python du validateur Markdown, l'audit de 264 tables dans 141 fichiers, l'audit Rust workspace et `cargo check --workspace` sur les 14 crates existantes. ## Objectif Créer la fondation runtime-neutral de `ksp-job-api` avec identité bornée, lifecycle explicite et annulation coopérative, sans ouvrir les notifications de `pre.003` ni aucun contrat Backfill ou Worker. ## Surface ajoutée - `JobId` : code opaque de 1 à 128 octets, alphabet ASCII alphanumérique plus `_`, `-`, `.` et `:` ; - `JobKindCode` : code stable soumis aux mêmes bornes ; - `JobCompletion` : `Complete` ou `Partial` ; - `JobState` : `Created`, `Running`, `Cancelling`, `Completed`, `Cancelled` ou `Failed` ; - `JobLifecycle` : propriétaire non cloneable des transitions ; - `JobCancellationToken` : demande atomique cloneable, idempotente, `Send + Sync` et indépendante de Tokio ; - trois `ErrorCode` stables sous le domaine `job_api` ; - constantes publiques de bornes d'identité. ## Invariants de lifecycle ```text Created -> Running Created -> Cancelled Running -> Cancelling Running -> Completed Running -> Failed Cancelling -> Completed Cancelling -> Cancelled Cancelling -> Failed ``` Toute autre transition échoue avec les codes source/cible en contexte sûr et laisse l'état inchangé. Un état terminal n'accepte plus aucune mutation. Le lifecycle n'est pas cloneable afin qu'une copie divergente ne puisse pas créer un second état de vérité. Le token d'annulation est volontairement distinct du lifecycle : un consumer demande l'annulation de façon idempotente ; le producteur observe le token puis applique la transition appropriée. Aucun thread, task, callback ou primitive runtime n'est créé par l'API. ## Firewalls La crate dépend exactement de `ksp-core-lib`. Elle n'a aucune feature, dev-dependency ou build-dependency et n'expose aucun type Config, Interface, Logging, Transport, Store, Tokio, serde, Worker ou Backfill. Les notifications, séquences, snapshots et listeners restent réservés à `pre.003`. ## Tests ajoutés Dix unitaires : - admission exacte et rejets des deux identités ; - alphabet sûr ; - partage, idempotence et état initial du token ; - chemins terminaux, transitions depuis `Cancelling`, erreur sûre, immuabilité terminale et matrice exacte 6 par 6. Onze canaries d'intégration : - 2 dépendances et runtime-neutralité ; - 3 API publique externe ; - 3 complétude et non-ouverture des tranches futures ; - 3 sécurité, redaction et visibilité cross-thread. ## Fichiers ajoutés ```text crates/ksp-job-api/Cargo.toml crates/ksp-job-api/src/cancellation.rs crates/ksp-job-api/src/error.rs crates/ksp-job-api/src/identity.rs crates/ksp-job-api/src/lib.rs crates/ksp-job-api/src/lifecycle.rs crates/ksp-job-api/unit_tests/cancellation.rs crates/ksp-job-api/unit_tests/identity.rs crates/ksp-job-api/unit_tests/lifecycle.rs crates/ksp-job-api/tests/dependency_boundary.rs crates/ksp-job-api/tests/public_api.rs crates/ksp-job-api/tests/release_completeness.rs crates/ksp-job-api/tests/security_hardening.rs deltas/0.3.6/pre.002.md ``` ## Fichiers modifiés ```text Cargo.toml docs/plans/027-V0_3_6_JOB_API_BACKFILL_PLAN.md docs/validation/023-V0_3_6_JOB_API_BACKFILL.md ``` Mécanique Cargo : ```text header version: 394 -> 395 workspace.package.version: 0.3.6-pre.1.fix.1 -> 0.3.6-pre.2 workspace members: ajout de crates/ksp-job-api ``` ## Fichiers supprimés Aucun. ## Décisions prises - l'hôte fournit le `JobId` pour pouvoir le conserver lors d'une reprise contrôlée ; - aucune génération UUID ou dépendance aléatoire n'entre dans Job API ; - les identités ne sont pas sérialisables par défaut et leurs champs restent privés ; - `JobId` est masqué en `Debug`, alors que le kind stable reste visible ; - le lifecycle est possédé, passif et non cloneable ; - l'annulation partage uniquement un `AtomicBool` standard ; - `Failed` n'embarque pas encore de cause optionnelle ; les snapshots structurés de `pre.003` porteront l'observabilité sans Option-soup ; - aucune README/USAGE intermédiaire n'est créée avant la surface consommable réconciliée prévue par le couloir documentaire. ## Validations exécutées ```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 / 142 fichiers) python3 -m unittest scripts/tests/test_audit_markdown_tables.py -> 5 tests / OK ``` La reconstruction indépendante de la base par extraction successive de v0.3.5, `pre.001` puis `pre.001-fix.001` confirme que le delta ne touche que les 17 fichiers ajoutés ou modifiés listés ci-dessus. Les inventaires statiques confirment dix tests unitaires, onze canaries d'intégration et la dépendance normale unique vers Core. ## Validations non exécutées L'environnement d'assemblage ne fournit ni `cargo` ni `rustfmt`. Les commandes suivantes ne sont pas annoncées comme réussies : ```text cargo fmt --all cargo check --workspace cargo clippy --workspace --all-targets cargo test -p ksp-job-api cargo tree -p ksp-job-api --edges normal cargo tree -p ksp-job-api -e features ``` ## 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-api cargo tree -p ksp-job-api --edges normal cargo tree -p ksp-job-api -e features ``` ## Questions ouvertes Aucune question ne bloque `pre.003` après un gate opérateur vert.