Files
IdeA/.ideai/memory/checkpoint-b8-command-runner-loop-closed.md
Blomios ebd992e41a docs(memory): notes projet tâches de fond, tickets V1 et checkpoints ticket #1
Capitalise la mémoire projet accumulée pendant les chantiers B7/B8
(tâches de fond first-class), le système de tickets V1 et le ticket #1 :
design, cadrages d'archi, checkpoints d'avancement et verdicts QA/frontend.
Mise à jour de l'index MEMORY.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 00:21:43 +02:00

3.3 KiB

name, description, metadata
name description metadata
checkpoint-b8-command-runner-loop-closed memory note checkpoint-b8-command-runner-loop-closed
type
project

B8 — Runner de commandes + boucle sink fermée (DevBackend, 2026-07-03)

Base feature/background-tasks-first-class. Suite de b8-command-runner-pty-framing. Build workspace vert ; sink tests (6) + tail units (5) + reconcile B7 verts. Non committé (Git tranche). QA à suivre.

Livré (sous-tâches 1-5)

  • Domaine : nouveau port BackgroundCommandArchive { spec_for(TaskId)->Option<SpawnSpec> } (ports.rs, exporté lib). Ajouté car le retry a besoin de la commande d'origine, qui n'est PAS un champ persisté du BackgroundTask. À faire bénir par Architect (ajout hors port figé).
  • Infra : background_task.rs → module dir (sink.rs déplacé verbatim, tail.rs, runner.rs).
    • tail.rs : BoundedTail ring UTF-8-safe + bounded_tail() + tail_cap_bytes() (env IDEA_BG_TAIL_BYTES, défaut 8 KiB, clamp [1 KiB, domaine 16 KiB]).
    • runner.rs : CommandBackgroundRunner compose Arc<dyn PtyPort> + Arc<dyn Clock>. spawn → pty.spawn(24x80) + worker détaché ; détection de fin = EOF du stream single-consumer ; tail lu du scrollback (pas du stream, robuste à la course subscribe) ; exit code via kill() (wait après EOF naturel) ; cancel = flag+Notify (la branche cancel gagne la course EOF) ; deadline→Expired via select. Implémente BackgroundTaskRunner + BackgroundCommandArchive. Émet 1 complétion/tâche, n'écrit ni store ni inbox.
  • Application : module background : SpawnBackgroundCommand (alloue TaskId, create Queued→save Running, runner.spawn ; si spawn KO → task Failed best-effort), CancelBackgroundTask, RetryBackgroundTask (nouveau TaskId, deadline droppée pour éviter l'expiry instantané ; réutilise create_and_run).
  • Composition root (state.rs ~1545) : runner + BackgroundCompletionSink::new(store, ready_tx.clone()) + sink.start_from_runner(runner) DANS tauri::async_runtime::spawn (Handle::current requis) ; JoinHandle du drain gardé vivant via .await. 4 champs AppState + use cases câblés. Boucle B2 fermée (avant : sink/runner uniquement en tests).
  • app-tauri : BackgroundTaskDto camelCase (aplati result→exitCode/summary/tails), parse_task_id, commandes spawn_background_command (AJOUTÉE hors liste framing pour rendre la boucle atteignable/testable), cancel_background_task, retry_background_task, list_background_tasks — enregistrées dans invoke_handler.

Écarts au cadrage (à arbitrer)

  1. Tee PTY live (sous-tâche 6) NON câblé : le Broadcast de PortablePtyAdapter est single-consumer (chaque subscribe_output supersede le précédent). Un tee UI re-souscrirait et casserait la détection EOF du runner. Un vrai tee live exige un broadcast multi-consommateur OU un port wait/try_wait sur PtyPort → décision Architect (PtyPort figé). Documenté dans runner.rs.
  2. stderr_tail toujours None : le PTY fusionne stdout/stderr → sortie fusionnée dans stdout_tail.
  3. Port BackgroundCommandArchive ajouté (voir ci-dessus).
  4. list_background_tasks sans agentId ne renvoie que les complétions non livrées du projet (le store ne sait pas énumérer les tâches ouvertes par projet).