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>
This commit is contained in:
118
.ideai/memory/background-tasks-first-class-design.md
Normal file
118
.ideai/memory/background-tasks-first-class-design.md
Normal file
@ -0,0 +1,118 @@
|
||||
---
|
||||
name: background-tasks-first-class-design
|
||||
description: memory note background-tasks-first-class-design
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: background-tasks-first-class-design
|
||||
description: Cadrage hexagonal du modèle BackgroundTask + mailbox bornée par agent + wake owner après complétion post-tour. Fait autorité pour les lots B1-B7 / F1-F4.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# 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]].
|
||||
Reference in New Issue
Block a user