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>
3.3 KiB
3.3 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| checkpoint-b8-command-runner-loop-closed | memory note checkpoint-b8-command-runner-loop-closed |
|
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é duBackgroundTask. À faire bénir par Architect (ajout hors port figé). - Infra :
background_task.rs→ module dir (sink.rsdéplacé verbatim,tail.rs,runner.rs).tail.rs:BoundedTailring UTF-8-safe +bounded_tail()+tail_cap_bytes()(envIDEA_BG_TAIL_BYTES, défaut 8 KiB, clamp [1 KiB, domaine 16 KiB]).runner.rs:CommandBackgroundRunnercomposeArc<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 viakill()(wait après EOF naturel) ;cancel= flag+Notify (la branche cancel gagne la course EOF) ; deadline→Expired via select. ImplémenteBackgroundTaskRunner+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éutilisecreate_and_run). - Composition root (state.rs ~1545) : runner +
BackgroundCompletionSink::new(store, ready_tx.clone())+sink.start_from_runner(runner)DANStauri::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 :
BackgroundTaskDtocamelCase (aplati result→exitCode/summary/tails),parse_task_id, commandesspawn_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)
- Tee PTY live (sous-tâche 6) NON câblé : le
BroadcastdePortablePtyAdapterest single-consumer (chaquesubscribe_outputsupersede 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 portwait/try_waitsur PtyPort → décision Architect (PtyPort figé). Documenté dansrunner.rs. - stderr_tail toujours None : le PTY fusionne stdout/stderr → sortie fusionnée dans
stdout_tail. - Port
BackgroundCommandArchiveajouté (voir ci-dessus). list_background_taskssansagentIdne renvoie que les complétions non livrées du projet (le store ne sait pas énumérer les tâches ouvertes par projet).