Files
IdeA/.ideai/memory/background-tasks-first-class-design.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

6.9 KiB

name, description, metadata
name description metadata
background-tasks-first-class-design memory note background-tasks-first-class-design
type
project

Tâches de fond de 1re classe — CADRAGE FIGÉ (Architect, 2026-07-02)

Base : feature/background-tasks-first-class (@ fccc1e2, empilée sur v2 62915ee+fccc1e2, au-dessus de develop a9653bc, ligne CLI/PTY « toujours headless »).

Objectif (2 défauts à corriger)

  1. Complétion post-tour perdue : une tâche de fond (ex. build run_in_background) finit après la fin du tour de l'agent → IdeA ne ré-invoque pas le propriétaire avec le résultat.
  2. Pas de mailbox : message concurrent pendant working/waiting rejeté « still busy » au lieu d'être mis en file et drainé au tour suivant.

Modèle

BackgroundTask { task_id, owner_agent_id, project_id, kind, state, started/updated_at_ms, deadline_ms?, correlation, result, wake_policy }.

  • kind : Command | HeadlessRendezvous | SessionResume | Maintenance
  • state : Queued | Running | Waiting | Completed | Failed | Cancelled | Expired
  • result : None | Success(payload) | Failure(error) | Cancelled(reason)
  • wake_policy : WakeOwner | RecordOnly Règle centrale : la complétion n'est JAMAIS seulement un retour de future local ; elle est persistée/observée comme événement de tâche, puis transformée en message mailbox pour le propriétaire.

Réutilisé vs nouveau

Réutilisé : InputMediator/AgentMailbox (FIFO par agent), TicketId, AgentBusyState, run_ask_with_watchdog+plafond+liveness, live-state.json (projection maigre), ReplyEvent::Final/Announcement, session-limit scheduler (réveil différé annulable). Nouveau : BackgroundTask persistant, store/registry, completion sink durable, AgentWakePort, mailbox entrante bornée par agent (couvre user/agents/complétions système), reconcile au boot.

Ports

  • BackgroundTaskStore : create/get/save/list_open_for_agent/list_undelivered_completions/ mark_completion_delivered. B1 figé (async_trait, BackgroundTaskPortError).
  • BackgroundTaskRunner : spawn(spec)->handle / cancel / subscribe_completions()->stream. B1 figé.
  • AgentInbox (façade au-dessus d'InputMediator) : enqueue_message / dequeue_next / snapshot. Lot B4.
  • AgentWakePort : wake_agent(project, agent, reason) — ne connaît PAS Tauri ; adapter lance/rattache session structured/headless. Lot B5.

Contrats/DTO

InboxItem { id, agent_id, source: Human|Agent{id}|BackgroundTask{task_id}|System, kind: UserMessage|AgentDelegation|BackgroundCompletion|ResumeNotice, body, created_at_ms, correlation_id?, priority (FIFO défaut, pas de priorité cachée V1) }. BackgroundCompletionDto camelCase { taskId, ownerAgentId, projectId, kind, status, exitCode, stdoutTail, stderrTail, finishedAtMs }. Events DomainEvent : BackgroundTaskStarted/Progress(borné)/Completed/Failed/Cancelled, AgentInboxQueued/Drained, AgentWakeScheduled/Started/Failed. (Events = observabilité/UI ; store+mailbox = autorité.)

Flux nominal run_in_background

1 agent lance commande → 2 crée BackgroundTask{owner,Running} → 3 adapter démarre → 4 tour peut finir → 5 commande finit plus tard → 6 completion sink reçoit exit/stdout/stderr → 7 écrit Completed/Failed dans store → 8 enqueue InboxItem::BackgroundCompletion → 9 si owner Idle: AgentWakePort.wake_agent démarre nouveau tour headless avec résultat → 10 si Busy/Waiting: FIFO, drainé au prochain tour libre. Idempotence : 1 seule completion livrée par task_id ; crash entre store et wake réparé par reconcile.

Mailbox bornée

1 par agent, FIFO stricte, capacité configurable (IDEA_AGENT_INBOX_CAPACITY, défaut 100). Enqueue pendant Working/Waiting → queued (plus jamais busy). Overflow : messages humains/agents → InboxFull typée ; complétions de tâches → persistées delivery_pending, JAMAIS perdues. « Busy » = tour en cours, pas entrée refusée.

Lots backend

  • B1 domaine : types, ports Store/Runner, events, invariants purs. FAIT (12 tests). (AgentInbox/AgentWakePort reportés à B4/B5.)
  • B2 store+registry : adapter FS/sqlite-like simple, écriture atomique, reconcile boot (Running sans handle vivant → Unknown/Failed ou delivery_pending).
  • B3 completion sink : runner publie complétions sur canal interne ; sink persiste AVANT tout wake ; tests idempotence double completion.
  • B4 mailbox unifiée : étendre InputMediator/AgentMailbox (pas de 2e FIFO concurrente) ; enqueue_message, snapshots workstate ; remplacer refus « still busy » par queued.
  • B5 wake owner : adapter AgentWakePort au-dessus de StructuredSessions/ AgentSession::send ; wake seulement si idle ; sinon launch/rattach headless ; résultat injecté comme message système explicite.
  • B6 rendezvous-as-task : idea_ask_agent reste synchrone pour l'appelant mais son exécution interne = BackgroundTask{HeadlessRendezvous} ; timeouts/backstops → résultats de tâche, plus des états invisibles.
  • B7 reconcile boot : lire store, ré-enqueue complétions non livrées, recalculer live-state.

Lots frontend

  • F1 workstate : queue depth par agent, « Queued » au lieu de « busy rejected ».
  • F2 panel tâches de fond : liste par agent running/completed/failed ; cancel/open output/retry.
  • F3 agent cell : badge « messages en attente » + « tâche de fond terminée » ; pas de transcript brut auto-injecté.
  • F4 notifications : toast sobre à la fin d'une tâche longue ; clic ouvre owner/détail.

Invariants

completion persistée avant wake ; livrée au plus une fois ; aucun message vers agent connu rejeté pour Busy ; mailbox ne dépasse jamais capacité ; overflow ne perd jamais une completion système ; 1 item traité à la fois ; live-state = projection jamais autorité ; Final reste le seul terminal normal headless ; un redémarrage n'oublie pas les complétions persistées non drainées.

Critères QA (backend)

commande background finissant après le tour → owner réveillé avec exit code + résumé ; idem avec IdeA redémarré entre fin et wake → completion retrouvée ; message user à agent busy → queued ; deux agents vers même agent busy → FIFO ; mailbox pleine → InboxFull sur message normal, completion système en pending ; double event même task_id → 1 livraison ; annulation → Cancelled, pas de wake succès ; rendezvous silencieux → backstop = tâche Failed/NoReply, libère la queue ; session-limit resume continue et ne contourne pas la mailbox.

Liens : checkpoint-b2-bootstrap-applied-await-codex-reset-1430, rendezvous-no-reply-backstop-design, session-limit-handling-design, headless-interagent-conversation-objective, inter-agent-live-context-shared-per-agent.