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:
@ -43,3 +43,19 @@
|
||||
- [mcp-t10a-harness-interrupt-does-not-cancel-rendezvous](mcp-t10a-harness-interrupt-does-not-cancel-rendezvous.md) — memory note mcp-t10a-harness-interrupt-does-not-cancel-rendezvous
|
||||
- [mcp-t10b-pending-reboot-verification](mcp-t10b-pending-reboot-verification.md) — memory note mcp-t10b-pending-reboot-verification
|
||||
- [headless-interagent-conversation-objective](headless-interagent-conversation-objective.md) — memory note headless-interagent-conversation-objective
|
||||
- [checkpoint-b2-bootstrap-applied-await-codex-reset-1430](checkpoint-b2-bootstrap-applied-await-codex-reset-1430.md) — memory note checkpoint-b2-bootstrap-applied-await-codex-reset-1430
|
||||
- [background-tasks-first-class-design](background-tasks-first-class-design.md) — memory note background-tasks-first-class-design
|
||||
- [b7-wiring-anchor-state-rs](b7-wiring-anchor-state-rs.md) — memory note b7-wiring-anchor-state-rs
|
||||
- [appimage-build-no-strip-relr-dyn-fix](appimage-build-no-strip-relr-dyn-fix.md) — memory note appimage-build-no-strip-relr-dyn-fix
|
||||
- [checkpoint-b7-blocked-codex-session-limit](checkpoint-b7-blocked-codex-session-limit.md) — memory note checkpoint-b7-blocked-codex-session-limit
|
||||
- [issue-ticket-system-design](issue-ticket-system-design.md) — memory note issue-ticket-system-design
|
||||
- [checkpoint-issue-ticket-backend-v1-done](checkpoint-issue-ticket-backend-v1-done.md) — memory note checkpoint-issue-ticket-backend-v1-done
|
||||
- [tickets-frontend-v1-done](tickets-frontend-v1-done.md) — État du frontend du système de tickets — livré, vert, décisions de contrat clés.
|
||||
- [tickets-v1-e2e-validated-qa](tickets-v1-e2e-validated-qa.md) — Verdict QA du système de tickets V1 sans attachments sur feature/issue-ticket-system — vert de bout en bout, avec la seule réserve du typage de conflit côté UI.
|
||||
- [b8-command-runner-pty-framing](b8-command-runner-pty-framing.md) — Cadrage hexagonal figé du lot B8 : runner concret sur le port BackgroundTaskRunner, fermeture de la boucle sink en composition root, contrat de complétion, commandes cancel/retry.
|
||||
- [checkpoint-b8-command-runner-loop-closed](checkpoint-b8-command-runner-loop-closed.md) — memory note checkpoint-b8-command-runner-loop-closed
|
||||
- [b8-arbitration-outcomes](b8-arbitration-outcomes.md) — Décisions d'arbitrage Architecture sur les 5 écarts B8 remontés par DevBackend : ce qui reste dans B8 vs part en dette/ticket.
|
||||
- [b8-in-app-trigger-run-in-background](b8-in-app-trigger-run-in-background.md) — Arbitrage de l'écart de périmètre #1 — la surface agent MCP idea_run_in_background ferme la boucle B8, contrat et lots figés.
|
||||
- [checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending](checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending.md) — memory note checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending
|
||||
- [workstate-background-tasks-projection-fix](workstate-background-tasks-projection-fix.md) — Décision d'archi pour rendre visibles Cancel/Retry dans le panneau Work — extension du read-model GetProjectWorkState, contrat DTO et borne de livraison.
|
||||
- [tickets-t3-frontend-validation-verdict](tickets-t3-frontend-validation-verdict.md) — Verdict de validation frontend du fix T3 (projection backgroundTasks par agent) sur feature/background-tasks-first-class — vert, avec 3 désalignements de contrat mineurs.
|
||||
|
||||
52
.ideai/memory/appimage-build-no-strip-relr-dyn-fix.md
Normal file
52
.ideai/memory/appimage-build-no-strip-relr-dyn-fix.md
Normal file
@ -0,0 +1,52 @@
|
||||
---
|
||||
name: appimage-build-no-strip-relr-dyn-fix
|
||||
description: memory note appimage-build-no-strip-relr-dyn-fix
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: appimage-build-no-strip-relr-dyn-fix
|
||||
description: Le build AppImage échoue sur cette machine (CachyOS/Arch) à l'étape linuxdeploy/strip (.relr.dyn) ; correctif = NO_STRIP=true. Explique probablement les "builds qui ne produisent rien".
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# Build AppImage — échec linuxdeploy `.relr.dyn`, correctif NO_STRIP=true
|
||||
|
||||
## Symptôme
|
||||
`tauri build --bundles appimage` : la **compilation release réussit** (binaire à
|
||||
`target/release/app-tauri`), puis le **bundling échoue** :
|
||||
```
|
||||
[gtk/stdout] ERROR: Strip call failed: .../usr/bin/strip: .../libgobject-2.0.so...:
|
||||
unknown type [0x13] section `.relr.dyn'
|
||||
ERROR: Failed to run plugin: gtk (exit code: 1)
|
||||
failed to bundle project `failed to run .../.cache/tauri/linuxdeploy-x86_64.AppImage`
|
||||
```
|
||||
→ **aucune AppImage produite**, exit code 1. Le `tail` du log ne montrait au début que
|
||||
« failed to run linuxdeploy » sans détail ⇒ facile à prendre pour un blocage/bash de fond.
|
||||
|
||||
## Cause racine (environnement, PAS le code IdeA)
|
||||
Le `strip` (binutils) embarqué dans le vieux `linuxdeploy-x86_64.AppImage` ne comprend pas la
|
||||
section ELF moderne `.relr.dyn` (relocations `DT_RELR`, `unknown type [0x13]`) présente dans les
|
||||
libs système GTK/glibc de CachyOS/Arch (rolling). Le plugin `gtk` de linuxdeploy strip ces libs
|
||||
→ échec → tout le bundling casse.
|
||||
|
||||
## Correctif VALIDÉ (2026-07-02)
|
||||
Lancer le build avec `NO_STRIP=true` (le binaire release est déjà strippé par cargo) :
|
||||
```
|
||||
cd crates/app-tauri
|
||||
NO_STRIP=true ../../frontend/node_modules/.bin/tauri build --bundles appimage
|
||||
```
|
||||
Résultat : `Finished 1 bundle at target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage`.
|
||||
|
||||
## Séquence de build complète (rappel, pas de beforeBuildCommand dans tauri.conf.json)
|
||||
1. `npm --prefix frontend run build` (produit `frontend/dist`).
|
||||
2. depuis `crates/app-tauri` : `NO_STRIP=true <cli tauri> build --bundles appimage`.
|
||||
CLI tauri = `frontend/node_modules/.bin/tauri` (@tauri-apps/cli). Config = crates/app-tauri/tauri.conf.json.
|
||||
|
||||
## Implication produit
|
||||
C'est très probablement la vraie cause des « builds AppImage qui ne produisent rien / attente
|
||||
sans résultat » signalés par l'utilisateur. À intégrer idéalement dans le flux de build d'IdeA
|
||||
(passer NO_STRIP quand on cible AppImage sur Arch, ou vendoriser un linuxdeploy récent).
|
||||
|
||||
Lien : [[mcp-bridge-and-delegation-runtime-notes]],
|
||||
[[checkpoint-b2-bootstrap-applied-await-codex-reset-1430]].
|
||||
44
.ideai/memory/b7-wiring-anchor-state-rs.md
Normal file
44
.ideai/memory/b7-wiring-anchor-state-rs.md
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
name: b7-wiring-anchor-state-rs
|
||||
description: memory note b7-wiring-anchor-state-rs
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: b7-wiring-anchor-state-rs
|
||||
description: Ancre runtime précise pour câbler B7 (tâches de fond) dans app-tauri/state.rs — repérée par Main pour dé-risquer la délégation DevBackend.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# B7 — Ancre de câblage runtime (crates/app-tauri/src/state.rs)
|
||||
|
||||
Composition root = builder `AppState` dans `crates/app-tauri/src/state.rs`. Repères exacts
|
||||
(lecture Main 2026-07-02, base `feature/background-tasks-first-class`) :
|
||||
|
||||
- **Mailbox / inbox** construits l.1207-1242 : `InMemoryMailbox::new()` (1207) → `mailbox`
|
||||
(1208, `dyn AgentMailbox`) → `MediatedInbox::with_pty(...)` (1213) → `input_mediator`
|
||||
(1242, `dyn InputMediator`). C'est LA file existante ; B4 (`AgentInbox`) s'y branche.
|
||||
- **clock** dispo : `Arc<dyn Clock>` (cloné partout, ex. 1255, 1384).
|
||||
- **Pattern de boucle de fond OBLIGATOIRE** : `tauri::async_runtime::spawn` (PAS `tokio::spawn`
|
||||
— `build` tourne dans le hook `setup` sans runtime tokio ambiant). Exemples : sweep_stalled
|
||||
l.1234, drain scheduler session-limit l.1317. Le sink B3 + bridge B4 + wake B5 doivent être
|
||||
spawnés sur ce même pattern.
|
||||
- **Builder OrchestratorService** l.1356-1454 : chaîne `.with_input_mediator` (1369),
|
||||
`.with_events`, `.with_record_turn`, `.with_live_state`/`.with_live_state_read` (providers
|
||||
PAR ROOT, root fixée par appel), `.with_ask_liveness_probe`, `.with_ask_ceiling`,
|
||||
`.with_structured` (1453).
|
||||
**⚠ POINT CLÉ : `.with_background_tasks(store, clock)` de B6 N'EST PAS présent ici** → le
|
||||
rendez-vous-as-task est DORMANT au runtime. B7 doit l'ajouter.
|
||||
- **Nuance per-root** : `FsBackgroundTaskStore` écrit `<root>/.ideai/background-tasks/<projectId>.json`
|
||||
(per-projet), mais `OrchestratorService` est GLOBAL multi-projets. Suivre le précédent
|
||||
`AppLiveStateProvider` / `AppReconcileLiveState` (provider keyé par root, câblé dans
|
||||
`open_project`, cf. commentaire l.1247-1252) plutôt qu'une instance de store globale unique.
|
||||
- **Reconcile au boot** : précédent = `reconcile_live_state` (l.1252) appelé dans `open_project`
|
||||
(commands.rs l.134). Le reconcile des tâches de fond + ré-enqueue des complétions non livrées
|
||||
peut se greffer au même endroit (per project root à l'ouverture).
|
||||
|
||||
Point d'accroche B8 (déféré, couplage PTY) : création commande longue côté `pty.rs` /
|
||||
`LocalProcessSpawner` → créer `BackgroundTask{kind:Command}` au spawn + pousser exit/stdout
|
||||
dans le sink.
|
||||
|
||||
Lien : [[background-tasks-first-class-design]], [[checkpoint-b2-bootstrap-applied-await-codex-reset-1430]].
|
||||
21
.ideai/memory/b8-arbitration-outcomes.md
Normal file
21
.ideai/memory/b8-arbitration-outcomes.md
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
name: b8-arbitration-outcomes
|
||||
description: Décisions d'arbitrage Architecture sur les 5 écarts B8 remontés par DevBackend : ce qui reste dans B8 vs part en dette/ticket.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# B8 — Arbitrage des écarts (Architecture, 2026-07-03)
|
||||
|
||||
Suite de [[b8-command-runner-pty-framing]]. Build vert (sink 6/6, tail 5/5, b7 1/1).
|
||||
|
||||
1. **Tee PTY live** : ACCEPTER B8 sans rendu live (bloqueur levé). Le cœur complétion→wake fonctionne ; tee = orthogonal. NE PAS toucher PtyPort ni broadcast multi-conso dans B8. Dette = ticket A : ajouter `PtyPort::wait`/`try_wait` pour découpler détection d'exit de la consommation d'output (l'EOF-comme-proxy-de-fin est fragile), puis tee UI. Pas de broadcast multi-consommateur.
|
||||
2. **BackgroundCommandArchive** : REFACTORER — retirer le trait DOMAINE. Retry = registre runtime in-memory (app/runner), NON persisté (SpawnSpec porte des secrets, ne pas écrire dans .ideai/background-tasks/*.json qui voyage avec le projet). Conséquence : retry SESSION-SCOPED en V1, pas après reboot. Reboot-retry = dette ticket B (persistance sûre = redaction/store machine-local hors projet).
|
||||
3. **spawn_background_command** : ACCEPTER, nécessaire (point d'entrée manquant du cadrage). B8 a donc 4 commandes : spawn/cancel/retry/list.
|
||||
4. **stderr_tail = None** : ACCEPTER V1. Sémantique pty correcte (TTY fusionne stdout/stderr). Champ réservé à une future variante ProcessSpawner-backed. stdout_tail = sortie tty fusionnée.
|
||||
5. **list sans agentId dégradé** : ACCEPTER V1 (F2 centré agent). Limite : store n'énumère pas les tâches terminales/ouvertes par projet ; historique completed/failed partiel. Enrichir BackgroundTaskStore = dette ticket B.
|
||||
|
||||
## Tickets de suivi à ouvrir
|
||||
- A : PtyPort::wait + tee live + robustesse détection de fin.
|
||||
- B : persistance sûre de l'invocation (retry-after-reboot, secrets) + énumération terminale/projet du store.
|
||||
|
||||
B8 clôturable une fois le point 2 refactoré + points 1/5 tracés en dette.
|
||||
28
.ideai/memory/b8-command-runner-pty-framing.md
Normal file
28
.ideai/memory/b8-command-runner-pty-framing.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
name: b8-command-runner-pty-framing
|
||||
description: Cadrage hexagonal figé du lot B8 : runner concret sur le port BackgroundTaskRunner, fermeture de la boucle sink en composition root, contrat de complétion, commandes cancel/retry.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# B8 — Runner de commandes couplé PTY (FIGÉ Architecture, 2026-07-03)
|
||||
|
||||
Base `feature/background-tasks-first-class`. Fait suite à [[background-tasks-first-class-design]] et [[b7-wiring-anchor-state-rs]].
|
||||
|
||||
## Trou constaté
|
||||
`BackgroundCompletionSink::new`/`start_from_runner` n'existent QUE dans les tests. En prod `state.rs`, `background_ready_tx` n'est alimenté que par le reconcile boot ; aucun `impl BackgroundTaskRunner` concret. `LocalProcessSpawner.run` = one-shot Output, non couplé.
|
||||
|
||||
## Décisions
|
||||
- **Le spawner ne crée pas la task.** Concepts owner/project/wake_policy = application. On implémente le port FIGÉ `BackgroundTaskRunner` (domain/ports.rs:1349) via nouvel adapter infra `CommandBackgroundRunner` composant `Arc<dyn PtyPort>` (résolu via RemoteHost → Liskov SSH/WSL), PAS un PortablePtyAdapter en dur.
|
||||
- Application = use case `SpawnBackgroundCommand` : alloue TaskId, store.create(Queued)→Running, runner.spawn(BackgroundTaskSpec). Le spec (ports.rs:207) porte déjà task_id/project_id/owner_agent_id/kind/wake_policy/command:Option<SpawnSpec>/deadline.
|
||||
- Le runner n'écrit NI store NI inbox : il émet 1 `BackgroundTaskCompletion` sur subscribe_completions(). Le sink (single-writer) fait store.save PUIS ready_tx.send (persist-avant-signal).
|
||||
- Composition root ferme la boucle : construire runner + `BackgroundCompletionSink::new(store_port, background_ready_tx)` + `sink.start_from_runner(runner)` sur `tauri::async_runtime::spawn` (pas de tokio ambiant). Ancre state.rs ~1540-1660.
|
||||
- Frontière : seuls SpawnSpec/BackgroundTaskSpec/BackgroundTaskCompletion (domaine) franchissent ; portable-pty reste en infra. Rendu xterm = tee du même spawn vers PtyBridge, orthogonal au tracking.
|
||||
|
||||
## Contrat complétion
|
||||
BackgroundTaskResult Success/Failure { finished_at_ms, exit_code:Some, summary, stdout_tail, stderr_tail bornés (ring UTF-8-safe, cap IDEA_BG_TAIL_BYTES ~8-16KiB) }. Cancel→runner kill→Cancelled{reason}, pas de wake succès. Invariants tenus par le sink (dédup task_id, IgnoredAlreadyTerminal, mark_completion_delivered) + pont enqueue_message (jamais busy) + wake si idle. Final reste terminal-de-tour, la complétion est un InboxItem::BackgroundCompletion.
|
||||
|
||||
## Commandes Tauri (dépend B8)
|
||||
cancel_background_task({taskId}); retry_background_task({taskId})→BackgroundTaskDto (NOUVEAU task_id, jamais réutilisé); list_background_tasks({projectId,agentId?}). DTO camelCase {taskId,ownerAgentId,projectId,kind,state,exitCode?,summary?,stdoutTail?,stderrTail?,createdAtMs,updatedAtMs}.
|
||||
|
||||
## Sous-tâches DevBackend (ordre)
|
||||
1 util tail borné (infra). 2 CommandBackgroundRunner (infra/background_task.rs + lib.rs). 3 use cases SpawnBackgroundCommand/Cancel/Retry (application). 4 fermer boucle sink en composition root (app-tauri/state.rs). 5 handlers+DTO (commands.rs, events.rs). 6 tee PTY live (pty.rs). 7 tests (réutiliser tests/background_completion_sink.rs).
|
||||
30
.ideai/memory/b8-in-app-trigger-run-in-background.md
Normal file
30
.ideai/memory/b8-in-app-trigger-run-in-background.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
name: b8-in-app-trigger-run-in-background
|
||||
description: Arbitrage de l'écart de périmètre #1 — la surface agent MCP idea_run_in_background ferme la boucle B8, contrat et lots figés.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# B8 — Déclencheur in-app (FIGÉ Architecture, 2026-07-03)
|
||||
|
||||
Suite de [[b8-command-runner-pty-framing]] et [[b8-arbitration-outcomes]]. Constat : le consommateur B8 (runner PTY → sink → inbox → wake) est livré (8cac147) mais SANS producteur — `spawn_background_command` (commands.rs:2586) n'est appelé par personne. #1 n'a donc aucun déclencheur réel.
|
||||
|
||||
## Décision
|
||||
- **Retenu : outil MCP agent `idea_run_in_background`** (surface principale, fermante). Chemin humain UI (bouton panel F2) = secondaire optionnel, `wake_policy=RecordOnly`. **Promotion auto d'une commande PTY longue : REJETÉE** (pas d'owner/intention, heuristique fragile, change la sémantique de write_terminal).
|
||||
- Pourquoi (a) : toute la machinerie (WakeOwner, inbox, AgentWakePort) est agent-centrée ; seul un agent déclarant explicitement une tâche de fond exerce la boucle bout-en-bout.
|
||||
|
||||
## Contrat `idea_run_in_background`
|
||||
Params : label(req), command(req), args[], cwd?(déf=project root), deadline_ms?. **owner = identité handshake du demandeur (non paramètre, non usurpable, rejet si absente)** ; project = contexte du demandeur ; record_only NON exposé côté agent → **WakeOwner forcé**. Retour SYNCHRONE {taskId,state} ; le résultat arrive plus tard en InboxItem::BackgroundCompletion (fire-and-forget-avec-tracking, distinct d'idea_ask_agent synchrone).
|
||||
|
||||
## Frontière — ZÉRO nouveau port/adapter
|
||||
- Domaine : variante `OrchestratorCommand::RunInBackground` (domain/orchestrator.rs).
|
||||
- Adapter MCP : décl outil + map_tool_call (mcp/tools.rs), comme idea_ask_agent.
|
||||
- Exécution : handler route vers use case EXISTANT application::SpawnBackgroundCommand (déjà en composition root state.rs), owner=requester, WakeOwner. Suivre le MÊME dispatch qu'AskAgent pour atteindre la couche app ; ne pas ré-router par commande Tauri front.
|
||||
|
||||
## Lots
|
||||
- BE-1 : variante enum + outil + mapping + tests mapping.
|
||||
- BE-2 : handler RunInBackground → SpawnBackgroundCommand (rejet si demandeur absent).
|
||||
- FE-1 (secondaire) : formulaire création dans panel F2 → spawn_background_command record_only.
|
||||
- QA T1 : agent appelle idea_run_in_background(`sh -c 'sleep 8; echo done'`), finit son tour → owner ré-invoqué avec exit+résumé. T3 cancel/retry sur ce taskId (retry session-scoped, pas reboot — dette ticket B).
|
||||
|
||||
## Branche
|
||||
Tient sur feature/background-tasks-first-class (additif, réutilise la boucle figée). Rien à préparer côté Git.
|
||||
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]].
|
||||
@ -0,0 +1,45 @@
|
||||
---
|
||||
name: checkpoint-b2-bootstrap-applied-await-codex-reset-1430
|
||||
description: memory note checkpoint-b2-bootstrap-applied-await-codex-reset-1430
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-b2-bootstrap-applied-await-codex-reset-1430
|
||||
description: Reprise 2026-07-02 15h58 — B1-B6 tâches de fond commités+verts, AppImage fraîche buildée (NO_STRIP), prochaine étape = relance puis B7.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint — chantier tâches de fond de 1re classe (2026-07-02 ~15h58)
|
||||
|
||||
## Fait & COMMITÉ sur `feature/background-tasks-first-class`
|
||||
- `62915ee` fix(codex) Final canal ; `fccc1e2` chore(gitignore) target/ sous-crates.
|
||||
- **B1-B6 tâches de fond** (4 commits) : `f4a55e9` domaine (12 tests) · `c537da5` infra
|
||||
store+sink+mailbox (B2-B4, 7+6+7 tests) · `f94b542` application wake+rendezvous-as-task
|
||||
(B5-B6, agent_wake 5, orchestrator_watcher 11 passed) · `54c8ecf` app-tauri events.
|
||||
- `cargo check --workspace` + `fmt` verts. Validés QA jusqu'à B5.
|
||||
- Cadrage complet : [[background-tasks-first-class-design]]. Ancre de câblage B7 :
|
||||
[[b7-wiring-anchor-state-rs]].
|
||||
|
||||
## AppImage FRAÎCHE prête (à relancer par l'utilisateur)
|
||||
`target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage` (2026-07-02 15:57, 111 Mo),
|
||||
contient B1-B6. Buildée avec `NO_STRIP=true` (sinon linuxdeploy casse sur `.relr.dyn` —
|
||||
cf. [[appimage-build-no-strip-relr-dyn-fix]], correctif à retenir).
|
||||
|
||||
## PROCHAINES ÉTAPES (dès relance sur la nouvelle AppImage)
|
||||
1. **B7** = câbler la chaîne au runtime dans `crates/app-tauri/src/state.rs` (ancre précise
|
||||
dans [[b7-wiring-anchor-state-rs]] : `.with_background_tasks(...)` ABSENT du builder
|
||||
OrchestratorService l.1356-1453 → rendezvous-as-task dormant ; sink/bridge/wake à spawner
|
||||
via `tauri::async_runtime::spawn` ; store per-root façon `AppLiveStateProvider` ; reconcile
|
||||
greffé dans `open_project`). Déléguer à DevBackend (session fraîche recommandée).
|
||||
2. **F1-F4** front (queue depth/queued, panel tâches, badges agent cell, toasts).
|
||||
3. **QA e2e** complet (critères du cadrage) puis rebuild AppImage final (NO_STRIP=true).
|
||||
4. **B8 déféré** : coupler PTY/commandes longues (run_in_background) → BackgroundTask{Command}.
|
||||
|
||||
## Historique du blocage (résolu autrement)
|
||||
B7 a wedgé 4× en délégation DevBackend sur l'ANCIEN binaire (13:30, pré-B4/B6). D'où le
|
||||
rebuild pour déployer les fixes de canal avant de finir. Ne PAS re-tenter B7 sur l'ancien
|
||||
binaire : relancer d'abord.
|
||||
|
||||
Liens : [[background-tasks-first-class-design]], [[b7-wiring-anchor-state-rs]],
|
||||
[[appimage-build-no-strip-relr-dyn-fix]], [[mcp-e2e-findings-reply-wedge-phantom-busy]].
|
||||
47
.ideai/memory/checkpoint-b7-blocked-codex-session-limit.md
Normal file
47
.ideai/memory/checkpoint-b7-blocked-codex-session-limit.md
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
name: checkpoint-b7-blocked-codex-session-limit
|
||||
description: memory note checkpoint-b7-blocked-codex-session-limit
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-b7-blocked-codex-session-limit
|
||||
description: RÉSOLU 2026-07-02 — B7 (câblage runtime tâches de fond) + F1-F4 livrés, QA vert, commités ; rebuild AppImage lancé. Historique du blocage Codex conservé.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# Checkpoint — B7 + F1-F4 LIVRÉS (2026-07-02) — anciennement bloqué Codex
|
||||
|
||||
## RÉSOLUTION (à jour)
|
||||
Codex est revenu, le cycle complet a tourné via le canal inter-agent (fiable cette fois) :
|
||||
- **B7** câblé par DevBackend dans `crates/app-tauri/src/state.rs` (store per-root routé par
|
||||
project_id façon AppLiveStateProvider, `AppReconcileBackgroundTasks` reconcile boot,
|
||||
`AppWakeSessionProvider`, boucle ready→MediatedInbox→AgentWakeService via
|
||||
`tauri::async_runtime::spawn`, `.with_background_tasks(store,clock)` au builder
|
||||
OrchestratorService ~l.1858) + `commands.rs` (`reconcile_background_tasks` dans open_project).
|
||||
- **F1-F4** front par DevFrontend (workStateNormalization, ProjectWorkStatePanel, LayoutGrid
|
||||
badges Queued/Task done, ProjectsView toast, useProjectWorkState abonné aux events
|
||||
backgroundTaskChanged/agentInboxChanged/agentWakeChanged).
|
||||
- **QA vert** : app-tauri 52/52 (dont test reconcile boot dédié + 4 tests MCP périmés alignés
|
||||
au nouveau protocole : idea_reply retiré→JSON-RPC -32601, idea_ask_agent exposé=13 tools,
|
||||
rendez-vous capture Final inline), domain 224+12, application 5, infrastructure 30+,
|
||||
frontend 449. Zéro régression (les 4 tests MCP échouaient déjà à l'identique sur base @54c8ecf).
|
||||
- **Commité** (pas de push/merge sans validation user) : `e05edc6` backend (B7 + tests),
|
||||
`5d88c95` frontend. `.ideai/memory` + `.ideai/proposals` volontairement non commités.
|
||||
- **Rebuild AppImage** lancé : `NO_STRIP=true` (cf. [[appimage-build-no-strip-relr-dyn-fix]]).
|
||||
|
||||
## Réserves connues (assumées V1, = lot B8 déféré)
|
||||
- Pas de `BackgroundTaskRunner` concret dans infrastructure → le sink de complétion ne s'abonne
|
||||
pas à un runner réel ; complétion d'une commande `run_in_background` post-tour PAS testable
|
||||
e2e (le rendez-vous inter-agent B6/HeadlessRendezvous, lui, EST vivant — c'était la douleur
|
||||
principale). Boutons UI cancel/retry désactivés (pas de commande Tauri) — tooltip explicite.
|
||||
- Prochain lot naturel B8 : runner de commandes couplé PTY (crée BackgroundTask{Command} au
|
||||
spawn, pousse exit/stdout dans le sink) → active le flux run_in_background complet + cancel/retry.
|
||||
|
||||
## Historique du blocage (résolu)
|
||||
Codex était en limite de session ; les 4 workers (Architect/DevBackend/DevFrontend/QA, profil
|
||||
`664cc20c-…-dce4c09c3da4`) tous murés en même temps ; Main+Git sur `…dce3c09c0de4` libres.
|
||||
Décision user = attendre le reset (pas d'entorse Main/Git ne code). Reset survenu → cycle repris.
|
||||
|
||||
Lien : [[b7-wiring-anchor-state-rs]], [[background-tasks-first-class-design]],
|
||||
[[appimage-build-no-strip-relr-dyn-fix]], [[session-limit-handling-design]].
|
||||
24
.ideai/memory/checkpoint-b8-command-runner-loop-closed.md
Normal file
24
.ideai/memory/checkpoint-b8-command-runner-loop-closed.md
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
name: checkpoint-b8-command-runner-loop-closed
|
||||
description: memory note checkpoint-b8-command-runner-loop-closed
|
||||
metadata:
|
||||
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).
|
||||
54
.ideai/memory/checkpoint-issue-ticket-backend-v1-done.md
Normal file
54
.ideai/memory/checkpoint-issue-ticket-backend-v1-done.md
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
name: checkpoint-issue-ticket-backend-v1-done
|
||||
description: memory note checkpoint-issue-ticket-backend-v1-done
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-issue-ticket-backend-v1-done
|
||||
description: Checkpoint 2026-07-02 — backend V1 du système de tickets (T1-T5) terminé et vérifié vert sur feature/issue-ticket-system ; frontend F1-F5/F7 + QA formelle en attente du reset Codex.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# Checkpoint — système de tickets, backend V1 (T1-T5) fait & vérifié (2026-07-02)
|
||||
|
||||
Cadrage/design = [[issue-ticket-system-design]]. Branche `feature/issue-ticket-system` (base develop a9653bc).
|
||||
|
||||
## FAIT & vérifié (build + tests verts, harvesté sur disque)
|
||||
- **T1** domaine `Issue` : `crates/domain/src/issue.rs` (+ tests `domain/tests/issue.rs`),
|
||||
câblé dans `domain/src/{events.rs,ids.rs,lib.rs,ports.rs}`.
|
||||
- **T2** store FS Markdown + allocator : `crates/infrastructure/src/issues.rs`
|
||||
(`FsIssueStore`, `FsIssueNumberAllocator`, index.json, check version), tests `issue_store.rs`.
|
||||
- **T3** use cases : `crates/application/src/issues/` (Create/Read/List/Update/UpdateCarnet/
|
||||
Link/Unlink/AssignAgent, optimistic concurrency), tests `application/tests/issue_usecases.rs`.
|
||||
- **T4** surface MCP : 10 outils `idea_ticket_{create,read,list,update,update_status,
|
||||
update_priority,read_carnet,update_carnet,link,unlink}` enregistrés dans
|
||||
`infrastructure/src/orchestrator/mcp/{mod,server,tools}.rs`.
|
||||
- **T5** Tauri : `crates/app-tauri/src/tickets.rs` (commands + assign) + câblage composition-root
|
||||
`crates/app-tauri/src/state.rs` (~l.824 : FsIssueStore/FsIssueNumberAllocator/use cases/
|
||||
ticket_tool_provider). `cargo build` workspace OK ; app-tauri 47/51 tests verts.
|
||||
|
||||
## Dette pré-existante à NE PAS confondre avec régression
|
||||
4 tests app-tauri rouges (`mcp_e2e_loopback_tests::{orphan_reply_is_typed_error,
|
||||
ask_then_reply_round_trips_inline (+_codex)}`, `mcp_serve_peer_tests::handshake_then_tools_list`)
|
||||
+ `infrastructure::orchestrator_watcher::ask_request_surfaces_reply_alongside_detail` :
|
||||
tests de l'ANCIEN protocole ask/reply, échouent DÉJÀ sur `develop` vierge (prouvé par stash).
|
||||
Le fix existe sur `feature/background-tasks-first-class` (alignement QA). Résorbés quand
|
||||
background-tasks merge dans develop, ou à cherry-pick. NE PAS les compter contre les tickets.
|
||||
|
||||
## RESTE (bloqué reset Codex — les workers Architect/DevBackend/DevFrontend/QA partagent le
|
||||
profil Codex ; Main+Git libres)
|
||||
- **Frontend V1** : F1 gateway `IssueGateway` · F2 liste filtrable · F3 détail/édition
|
||||
(conflits expectedVersion) · F4 éditeur Carnet Markdown · F5 liens & assignations · F7 `#42`
|
||||
cliquable + pré-remplissage délégation. (F6 attachments = fast-follow hors V1.)
|
||||
- **QA formelle** backend+frontend (create→lire via MCP, #N séquentiel, carnet édité par agent,
|
||||
liens, assignation agent connu, optimistic concurrency conflit).
|
||||
- Puis Git commit final + rebuild AppImage (NO_STRIP=true, cf. [[appimage-build-no-strip-relr-dyn-fix]]).
|
||||
|
||||
## Note process
|
||||
Rendez-vous inter-agent timeout sur tâches LOURDES (binaire courant pré-B7) : l'agent produit
|
||||
quand même le code, harvesté sur disque par Main (build+tests réels) puis commité via Git libre.
|
||||
Confirme l'intérêt de B7/B8 (le rebuild B7 de 21:35 n'est pas encore le binaire lancé).
|
||||
|
||||
Lien : [[issue-ticket-system-design]], [[checkpoint-b7-blocked-codex-session-limit]],
|
||||
[[background-tasks-first-class-design]].
|
||||
@ -0,0 +1,34 @@
|
||||
---
|
||||
name: checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending
|
||||
description: memory note checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending
|
||||
description: Ticket #1 — T1 VERT live. T3 root cause = tâches de fond jamais projetées dans work-state ; fix BE+FE livré unit-green ; rebuild AppImage en cours ; reste re-QA live T3 + T2 reboot, puis merge.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Checkpoint ticket #1 — état au 2026-07-03
|
||||
|
||||
## T1 — VERT (validé live QA)
|
||||
Wake auto du propriétaire à la complétion + `completionDelivered: true` prouvés dans le store (`.ideai/background-tasks/<owner>.json`, task `02aa2493`). Fixes portant T1 (unit-green, NON commités) : wake.rs:119 (mark_completion_delivered dès session.send accepté), structured.rs:121 (drain_reply_stream_with_readiness), agent_wake.rs:504 (régression), + itér.1 MediatedInbox enqueue FIFO sans busy.
|
||||
Note : `idea_workstate_read` n'expose PAS les BackgroundTasks — lire le store JSON.
|
||||
|
||||
## T3 — root cause trouvée + fix livré (unit-green, NON commité)
|
||||
Défaut live : aucun bouton Cancel/Retry dans le panneau Work. Cause = le DTO `AgentWorkState` ne portait pas les tâches de fond et `GetProjectWorkState` n'avait pas de dépendance BackgroundTaskStore → `agent.backgroundTasks` toujours vide en live → section masquée (ProjectWorkStatePanel.tsx:638). Front déjà câblé, seule la projection backend manquait. Vitest verts en trompe-l'œil (payload mocké).
|
||||
Cadrage Architect : mémoire `workstate-background-tasks-projection-fix` (Option A — étendre le read-model unique, best-effort, aucun nouveau port).
|
||||
Livré :
|
||||
- BE (DevBackend) : VO `AgentBackgroundTaskState` + champ `background_tasks` sur AgentWorkState + builder `with_background_tasks` + projection union open/undelivered best-effort (workstate/mod.rs) ; DTO Tauri backgroundTasks (dto.rs) ; wiring state.rs. Tests : `cargo test -p application` 24 passed (workstate.rs), `-p app-tauri` vert, build workspace OK.
|
||||
- FE (DevFrontend) : mapping queued/waiting→pending explicité, test sur vrai shape backend, + correctif tri (finishedAtMs jamais émis → bascule sur updatedAtMs). vitest 460/460, build OK. Verdict : `tickets-t3-frontend-validation-verdict`.
|
||||
- Dette de contrat tracée en ticket #5 (summary non affiché, owner/project inutiles). Low.
|
||||
|
||||
## RESTE À FAIRE (ordre)
|
||||
1. Rebuild AppImage `NO_STRIP=true` — EN COURS (background bixa34tht). Voir [[appimage-build-no-strip-relr-dyn-fix]].
|
||||
2. Utilisateur relance l'AppImage.
|
||||
3. QA re-passe T3 LIVE : T3-a apparition running + Cancel actif ; T3-b Cancel agit → cancelled + Retry actif ; T3-c Retry → nouvelle tâche running ; T3-d borne livraison (tâche livrée disparaît = conforme V1, PAS un bug) ; T3-e isolation par agent ; T3-f non-régression live/busy/tickets. Détail dans cadrage Architect.
|
||||
4. T2 — reconcile après reboot (fin AVANT wake), protocole MANUEL, coordination reboot utilisateur.
|
||||
5. Si T1+T2+T3 verts → Git commit de TOUS les fix (T1 + T3 BE/FE) + merge feature/background-tasks-first-class → develop (résorbe aussi 4 tests protocole MCP périmés rouges sur develop).
|
||||
|
||||
Liens : [[workstate-background-tasks-projection-fix]], [[tickets-t3-frontend-validation-verdict]], [[b8-in-app-trigger-run-in-background]], [[background-tasks-first-class-design]].
|
||||
@ -0,0 +1,52 @@
|
||||
---
|
||||
name: develop-realigned-to-cli-ui-baseline-2026-07-02
|
||||
description: memory note develop-realigned-to-cli-ui-baseline-2026-07-02
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# develop réaligné sur la ligne UI CLI (pre-chat-ui-baseline) — 2026-07-02
|
||||
|
||||
**Type :** décision de topologie, validée utilisateur.
|
||||
|
||||
## Contexte / erreur corrigée
|
||||
|
||||
La feature « annonces inter-agent + fix Final Codex » avait été branchée par erreur sur
|
||||
`develop` @ `0072aff`, qui portait le chantier **canonical-conversation / chat** (LC1→LC5).
|
||||
Or l'UI de référence de l'utilisateur est la **ligne CLI** portée par
|
||||
`feature/pre-chat-ui-baseline` @ `a9653bc` (UI CLI + commit « délégation toujours headless,
|
||||
jamais d'injection PTY »). Le rebuild sur develop avait régressé l'UI (plus de terminaux CLI).
|
||||
De plus, `a9653bc` — prémisse runtime de l'overlay — n'était QUE sur pre-chat-ui-baseline.
|
||||
|
||||
## Opération effectuée (Git, réversible, locale, aucune sortante)
|
||||
|
||||
1. Secours du chantier chat : branche `snapshot/develop-canonical-conversation-0072aff` +
|
||||
tag homonyme → `0072aff` (récupérable à 100%).
|
||||
2. `git branch -f develop feature/pre-chat-ui-baseline` → **develop == `a9653bc`** (arbre
|
||||
exactement celui de la ligne CLI). Le chantier chat est SUPERSÉDÉ sur la mainline develop
|
||||
mais non détruit.
|
||||
3. Nouvelle branche de fix : **`feature/inter-agent-announcements-v2`** depuis le nouveau
|
||||
develop (@ a9653bc).
|
||||
|
||||
Retour arrière : `git branch -f develop snapshot/develop-canonical-conversation-0072aff`.
|
||||
|
||||
## État des refs
|
||||
|
||||
- `develop` = `a9653bc` (base de travail canonique désormais = ligne CLI).
|
||||
- `feature/inter-agent-announcements-v2` = base de travail pour reporter les fix.
|
||||
- `feature/inter-agent-announcements` = `71d307d` : ancien commit B0-B3 (basé sur l'ancien
|
||||
develop chat), conservé pour cherry-pick.
|
||||
- `snapshot/develop-canonical-conversation-0072aff` = chantier chat préservé.
|
||||
|
||||
## Conséquences pour la suite
|
||||
|
||||
- Reporter **B1/B2/B3** sur `feature/inter-agent-announcements-v2` (cherry-pick depuis
|
||||
71d307d). **B0 devient probablement REDONDANT** : `a9653bc` (headless alongside/toujours
|
||||
headless) est déjà la base — à vérifier avant de le rejouer.
|
||||
- **Re-planifier F1/F2/F3** : le design frontend (preview cellule demandeur + overlay cellule
|
||||
cible) avait été cadré contre le modèle de cellules canonical-conversation de develop ; sur
|
||||
la base CLI (`a9653bc`), il faut re-cibler le modèle de cellules CLI/PTY réel. À faire
|
||||
cadrer par Architect avant dev frontend.
|
||||
- Rebuild AppImage à faire depuis cette base → restaure l'UI CLI + embarque les fix.
|
||||
|
||||
Liens : [[inter-agent-announcements-feature-and-codex-final-bug]],
|
||||
[[inter-agent-live-context-shared-per-agent]].
|
||||
@ -0,0 +1,67 @@
|
||||
---
|
||||
name: inter-agent-announcements-feature-and-codex-final-bug
|
||||
description: memory note inter-agent-announcements-feature-and-codex-final-bug
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Annonces inter-agent (UI live) + fix du Final Codex — DESIGN FIGÉ
|
||||
|
||||
**Type :** design de feature + bug racine. Validé utilisateur le 2026-07-02, cadré par Architect.
|
||||
|
||||
## Bug racine (Codex)
|
||||
|
||||
`crates/infrastructure/src/session/codex.rs` : `parse_event` (~l.86) mappe CHAQUE
|
||||
`item.completed{item.type=="agent_message"}` vers `ReplyEvent::Final`, et `send` (~l.234)
|
||||
casse au PREMIER Final (`break 'lines`). Or `codex exec --json` émet plusieurs
|
||||
`agent_message` par tour (préambule → outils → conclusion → `turn.completed`). IdeA
|
||||
renvoyait donc le **préambule** au demandeur au lieu de la **conclusion**. Preuve live :
|
||||
Architect répondait « je vais interroger QA… » au lieu du résultat. **Défaut d'implémentation,
|
||||
pas du headless Codex** (un `codex exec` brut déroule tout le tour).
|
||||
|
||||
## Feature validée (le bug devient fonctionnalité)
|
||||
|
||||
- **Final** = DERNIER `agent_message` avant `turn.completed` → seule chose renvoyée au
|
||||
demandeur (résout le ticket). Bords : 1 seul message (préambule=conclusion) ; 0 message
|
||||
→ `TargetReturnedNoReply` (inchangé).
|
||||
- **Annonces** = `agent_message` intermédiaires → nouvel événement NON terminal
|
||||
`ReplyEvent::Announcement{text}`, poussé sur le bus vers l'UI, JAMAIS renvoyé au
|
||||
demandeur, JAMAIS persisté au transcript (éphémère).
|
||||
- **UI** : (a) cellule DEMANDEUR = petit cadre preview près de la drop-list d'agents,
|
||||
filtré par `ticket_id` ; (b) cellule CIBLE si visible = overlay d'indisponibilité (texte
|
||||
haut « un agent est en train de lui parler » + annonces défilantes au centre), monté sur
|
||||
live-state Working, retiré au Final/idle (reste tant qu'≥1 ticket actif sur la cible).
|
||||
|
||||
## Contrat (Architect)
|
||||
|
||||
- `ReplyEvent::Announcement{text}` (non terminal) vs `Final{text}` (terminal, résout).
|
||||
- `drain_with_readiness` : Announcement → publie event, ne résout pas, ne passe pas idle ;
|
||||
Final → résout ticket + idle + fin du drain.
|
||||
- Nouveau `DomainEvent::AgentAnnouncement{project_id, requester, target, ticket_id, text,
|
||||
at_ms}` (attribution obligatoire pour router vers la bonne cellule + isoler projet/onglet).
|
||||
- Overlay cible = état UI piloté par live-state (pas un blocage du PTY : le contact passe par
|
||||
session headless séparée, `allow_structured_alongside_pty:true`).
|
||||
- Généralisation Claude : `session/claude.rs` garde son terminal explicite (`result`) comme
|
||||
Final ; messages complets non terminaux → Announcement ; NE PAS promouvoir les `TextDelta`
|
||||
tokenisés (bruit) ; tool events restent `ToolActivity`.
|
||||
|
||||
## Découpage dev (Architect)
|
||||
|
||||
- **B1** domaine/appli : `ReplyEvent::Announcement`, `DomainEvent::AgentAnnouncement`,
|
||||
`structured.rs`, `service.rs` (`ask_structured` ne termine que sur Final).
|
||||
- **B2** Codex `codex.rs` : bufferiser le dernier `agent_message`, émettre les précédents en
|
||||
Announcement, le dernier en Final à `turn.completed`.
|
||||
- **B3** Tauri `app-tauri/{events,dto,state}.rs` : relay + DTO camelCase.
|
||||
- **F1** front store/gateway annonces (index par ticket/target, borné ~20-50).
|
||||
- **F2** front preview cellule demandeur.
|
||||
- **F3** front overlay cellule cible.
|
||||
- **Q** QA e2e : Main→Architect→QA, préambule+outil+conclusion ; Main ne reçoit que la
|
||||
conclusion ; preview demandeur + overlay cible pendant le travail ; fermeture au Final.
|
||||
Critère : reproduire le bug initial et constater la correction.
|
||||
|
||||
## État
|
||||
|
||||
Design figé, cadrage Architect complet. Reste : Git branche → B1/B2/B3 + F1/F2/F3 → QA.
|
||||
Non démarré côté dev au 2026-07-02.
|
||||
|
||||
Liens : [[inter-agent-live-context-shared-per-agent]], [[rendezvous-no-reply-backstop-design]],
|
||||
[[headless-interagent-conversation-objective]], [[conversation-viewer-ls7-frontend]].
|
||||
79
.ideai/memory/inter-agent-live-context-shared-per-agent.md
Normal file
79
.ideai/memory/inter-agent-live-context-shared-per-agent.md
Normal file
@ -0,0 +1,79 @@
|
||||
---
|
||||
name: inter-agent-live-context-shared-per-agent
|
||||
description: memory note inter-agent-live-context-shared-per-agent
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
# Contexte live inter-agent : PAR AGENT (partagé), pas par paire — DÉCISION FIGÉE
|
||||
|
||||
**Type :** decision d'architecture / produit — validée utilisateur le 2026-07-02.
|
||||
|
||||
## Décision
|
||||
|
||||
Le contexte live d'un agent IdeA est porté **par l'agent cible**, partagé entre TOUS les
|
||||
demandeurs. Pour un `AgentId` donné, IdeA maintient **au plus une** session
|
||||
headless/structurée vivante ; tous les `idea_ask_agent(requester, target)` vers le même
|
||||
`target` réutilisent cette session, quel que soit le demandeur.
|
||||
|
||||
Ce partage est **intentionnel et souhaité**, pas un bug ni une fuite : tous les agents du
|
||||
projet sont dans le même domaine de confiance (même utilisateur, même projet). Le contexte
|
||||
live d'un agent = mémoire de travail d'équipe / tableau blanc partagé. On NE veut PAS
|
||||
d'isolation par paire.
|
||||
|
||||
La paire `(requester, target)` n'est **pas** une frontière d'isolation du contexte moteur :
|
||||
elle sert uniquement à l'attribution, la corrélation requête/réponse, les vues UI et les
|
||||
filtres de transcript.
|
||||
|
||||
## Preuve empirique (2026-07-02)
|
||||
|
||||
Main a confié à QA le token `IDEA-TOKEN-7F3A-BLEEDCHECK` ; Architect a ensuite pu le
|
||||
récupérer auprès de QA **sans que Main le lui transmette**. Cause : `ensure_structured_session`
|
||||
(`crates/application/src/orchestrator/service.rs:1948`) fait un early-return sur
|
||||
`session_for_agent(&agent_id)` → une seule session vivante par agent, réutilisée.
|
||||
|
||||
## Modèle de transcript cible (cadré par Architect)
|
||||
|
||||
**Log canonique PAR AGENT + vues par paire dérivées.** Abandon du transcript canonique
|
||||
par paire comme source de vérité (il promet une isolation qui n'existe pas en live).
|
||||
|
||||
- Arbo cible : `.ideai/conversations/agents/<targetAgentId>/{log.jsonl, handoff.md, providers.json, log.N.jsonl}`
|
||||
- Chaque tour porte l'attribution : `thread_id=Agent(target)`, `requester`, `target`,
|
||||
`correlation_id`, `role`, `source`.
|
||||
- Vues = projections filtrées (`ForAgent`, `ForPair`, `ForCorrelation`), pas des logs séparés.
|
||||
|
||||
Impacts à traiter :
|
||||
- `resolve_conversation` → `resolve_agent_thread(target)` + `resolve_conversation_view(requester,target)`.
|
||||
- `bind_conversation_session` → bind sur `targetAgentId` ; réutiliser la session existante.
|
||||
- `ConversationRegistry` → index primaire `targetAgentId`, secondaires `requester`/`correlation_id` ;
|
||||
interdire 2 fils live pour le même target.
|
||||
- `ProviderSessionStore` clé `(agent_thread_id, provider_id)` au lieu de `(pair_id, provider_id)`.
|
||||
- `LeafCell.conversation_id` = désormais **id de fil agent**, plus « id de paire ».
|
||||
- Viewer LS7 : défaut = fil agent complet ; vue par paire = vue filtrée/partielle libellée comme telle.
|
||||
|
||||
## Garde-fou efficience (rotation multi-demandeurs)
|
||||
|
||||
Le design LS5/LS6 tient, mais un fil agent partagé **croît plus vite** (agrège les demandes
|
||||
de plusieurs requesters). Ajustements : la rotation s'applique au fil agent canonique (pas
|
||||
aux vues) ; le résumé/handoff doit conserver l'attribution minimale (`Objectif courant`,
|
||||
`Demandes actives par requester`, `Décisions récentes`, `Blocages`, `Dernière réponse
|
||||
corrélée`) ; transcript brut jamais réinjecté (humain-only) ; handoff borné à
|
||||
`HANDOFF_SUMMARY_MAX_CHARS=4096`. Risque principal : dilution si demandeurs poussent des
|
||||
objectifs contradictoires → mitigé par les rubriques stables du handoff.
|
||||
|
||||
## Découpage dev recommandé (Architect)
|
||||
|
||||
1. `ARCHITECTURE.md` §19.7 : remplacer « id de paire » par « fil agent partagé » (+ §16/§17/§21).
|
||||
2. Introduire `ConversationThreadId` / `ConversationViewId`.
|
||||
3. Adapter `resolve_conversation`, `bind_conversation_session`, `ConversationRegistry`.
|
||||
4. Compatibiliser les anciens chemins `for_pair(requester,target)` comme vues historiques.
|
||||
5. LS7 viewer : fil agent complet + filtres.
|
||||
6. Test QA : un fait confié à QA par Main est visible quand Architect interroge QA.
|
||||
|
||||
## État
|
||||
|
||||
Décision figée. Cadrage architectural livré par Architect. Reste à : intégrer la proposition
|
||||
dans `ARCHITECTURE.md`, puis planifier le dev (cycle normal Architect→Git→Dev→QA).
|
||||
|
||||
Liens : [[conversation-rotation-safety-design]], [[handoff-ls5-summary-bound-and-llm-seam]],
|
||||
[[conversation-log-ls6-rotation-and-paginated-read]], [[conversation-viewer-ls7-frontend]],
|
||||
[[headless-interagent-conversation-objective]].
|
||||
78
.ideai/memory/issue-ticket-system-design.md
Normal file
78
.ideai/memory/issue-ticket-system-design.md
Normal file
@ -0,0 +1,78 @@
|
||||
---
|
||||
name: issue-ticket-system-design
|
||||
description: memory note issue-ticket-system-design
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
---
|
||||
name: issue-ticket-system-design
|
||||
description: Cadrage figé (Architect+Main, 2026-07-02) du système de tickets IdeA façon Jira — domaine `Issue` par projet, exposé « ticket » côté UI/MCP, Carnet éditable, #N séquentiel. Fait autorité pour les lots T1-T6/F1-F7.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
# Système de tickets IdeA (domaine `Issue`) — CADRAGE FIGÉ 2026-07-02
|
||||
|
||||
## Décisions produit verrouillées (utilisateur)
|
||||
- **Portée PAR PROJET** : stockage dans `.ideai/tickets/` du projet (pas de backlog global).
|
||||
- **Identifiant court `#42`** : compteur séquentiel par projet, parlable à l'oral (poignée
|
||||
partagée humain↔agent, y compris dans une délégation `idea_ask_agent`).
|
||||
- **Champ de connaissances éditable = « Carnet »** (PAS « mémoire » — évite collision avec la
|
||||
mémoire projet). Markdown éditable/réorganisable, scoped ticket, pas append-only.
|
||||
- **Stockage Markdown + frontmatter**, un DOSSIER par ticket.
|
||||
- **V1 SANS attachments** : livrer T1-T5 + F1-F5 + F7 ; attachments (T6/F6) en fast-follow.
|
||||
|
||||
## Nommage (collision évitée avec le TicketId de délégation)
|
||||
Domaine/code = **`Issue`** (`IssueId`, `IssueNumber`, `IssueRef("#42")`, `IssueStore`,
|
||||
modules `domain::issue`/`application::issues`/`infrastructure::issues`). UI + MCP public =
|
||||
« ticket » (`idea_ticket_*`, DTO camelCase). Ne JAMAIS nommer `Ticket` en code (réservé à la
|
||||
délégation inter-agent).
|
||||
|
||||
## Frontière Carnet vs mémoire projet
|
||||
Carnet = savoir DU ticket (décisions locales, hypothèses, investigation, contraintes). Mémoire
|
||||
projet = savoir transverse durable. Règle : si l'info doit survivre à la fermeture du ticket et
|
||||
guider d'autres travaux → mémoire projet ; sinon → carnet.
|
||||
|
||||
## Modèle domaine
|
||||
`Issue { id(uuid), number(u64), title, description(md), status, priority, carnet, links,
|
||||
agent_refs, attachments, created_by/updated_by(IssueActor: User|Agent|System),
|
||||
created_at/updated_at, version(optimistic) }`.
|
||||
- `IssueStatus`: Open | InProgress | Qa | Closed (DTO: open|inProgress|QA|closed).
|
||||
- `IssuePriority`: Low | Medium | High | Critical.
|
||||
- `IssueLinkKind`: RelatesTo | Blocks | BlockedBy | Duplicates | DependsOn.
|
||||
- `AgentIssueRef { agent_id, role: Assigned|Mentioned|Reviewer|Owner }`.
|
||||
Invariants : number>0 unique/projet ; IssueRef = `#<u64>` ; titre non vide ; pas de self-link ;
|
||||
assignation → AgentId connu du manifeste ; toute écriture incrémente version ; attachments sous
|
||||
le dossier du ticket, pas de `..`/symlink/chemin absolu.
|
||||
|
||||
## Ports
|
||||
`IssueStore` (create/get_by_ref/list(filter)/update(expected_version)/read_carnet/
|
||||
write_carnet(expected_version)) ; `IssueNumberAllocator` (allocate_next, atomique via
|
||||
counter.json + counter.lock + rename, jamais de réutilisation de numéro) ; `IssueAttachmentStore`
|
||||
(add/remove/list — lot attachments). Adapters : `FsIssueStore`, `FsIssueNumberAllocator`,
|
||||
`FsIssueAttachmentStore`, `McpIssueTools`, `TauriIssueCommands`, `TauriIssueEventRelay`.
|
||||
|
||||
## Surface MCP (agents)
|
||||
`idea_ticket_create/read/list/update/update_status/update_priority/read_carnet/update_carnet/
|
||||
link/unlink` (+ `idea_ticket_attachment_*` au lot attachments). DTO camelCase ; `TicketRef` =
|
||||
`#${number}` ; concurrence via `expectedVersion` sur chaque écriture.
|
||||
|
||||
## Events domaine (→ projection UI, même modèle events→front B-series)
|
||||
IssueCreated/Updated/StatusChanged/PriorityChanged/CarnetUpdated/Linked/Unlinked/
|
||||
AgentAssigned/AgentUnassigned/AttachmentAdded/Removed/StorageConflictDetected.
|
||||
|
||||
## Layout stockage
|
||||
`.ideai/tickets/{counter.json, index.json(projection reconstructible), <N>/{issue.md(frontmatter
|
||||
+description), carnet.md, attachments/}}`. Attachments versionnés git par défaut (warning >5MiB,
|
||||
refus configurable >25MiB, pointeur URI pour les gros).
|
||||
|
||||
## Lots
|
||||
Backend : T1 domaine Issue · T2 store FS Markdown (+allocator) · T3 use cases (Create/Read/List/
|
||||
Update/UpdateCarnet/Link/AssignAgent, optimistic concurrency) · T4 surface MCP `idea_ticket_*` ·
|
||||
T5 commands Tauri + relay events · T6 attachments (fast-follow).
|
||||
Frontend : F1 gateway UI (`IssueGateway`, pas d'invoke direct) · F2 liste filtrable · F3 détail/
|
||||
édition (gestion conflits expectedVersion) · F4 éditeur Carnet Markdown · F5 liens & assignations ·
|
||||
F6 attachments (fast-follow) · F7 `#42` cliquable + pré-remplissage délégation.
|
||||
Réutilise : store FS par projet façon `FsBackgroundTaskStore`/`AppLiveStateProvider`, EventBus +
|
||||
TauriEventRelay, pattern gateway UI.
|
||||
|
||||
Lien : [[background-tasks-first-class-design]], [[agent-context-memory-and-profile-handoff]].
|
||||
15
.ideai/memory/tickets-frontend-v1-done.md
Normal file
15
.ideai/memory/tickets-frontend-v1-done.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: tickets-frontend-v1-done
|
||||
description: État du frontend du système de tickets — livré, vert, décisions de contrat clés.
|
||||
metadata:
|
||||
type: project
|
||||
---
|
||||
Frontend V1 du système de tickets livré sur `feature/issue-ticket-system` (non commité, attend QA/Git). Build + 459 tests verts.
|
||||
|
||||
Décisions figées :
|
||||
- Port nommé `TicketGateway` (pas IssueGateway) — aligné sur le wire `ticket_*`/`TicketDto` et le terme visible « ticket ».
|
||||
- Statut/priorité côté UI passent par `ticket_update` : `ticket_update_status`/`ticket_update_priority` ne sont PAS des commands Tauri (MCP-only, non enregistrées dans `lib.rs`).
|
||||
- Conflit de version = `code:"INVALID"` + message contenant `"issue version conflict"` (détection par message, pas de code dédié). Voir `isTicketVersionConflict`.
|
||||
- F7 = `#ref` cliquables + linkification desc + bouton clipboard « Travaille sur le ticket #N : <titre> » (pas d'écriture terminal directe en V1).
|
||||
|
||||
Surface : `features/tickets/` (panel liste + overlay détail/carnet/liens/assign), onglet sidebar « Tickets » dans ProjectsView entre Work et Agents, `MockTicketGateway` émet les events `Issue*`. Voir [[checkpoint-issue-ticket-backend-v1-done]] et [[issue-ticket-system-design]].
|
||||
15
.ideai/memory/tickets-t3-frontend-validation-verdict.md
Normal file
15
.ideai/memory/tickets-t3-frontend-validation-verdict.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: tickets-t3-frontend-validation-verdict
|
||||
description: Verdict de validation frontend du fix T3 (projection backgroundTasks par agent) sur feature/background-tasks-first-class — vert, avec 3 désalignements de contrat mineurs.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
Validation frontend du fix T3 (ticket #1), branche `feature/background-tasks-first-class`, 2026-07-03.
|
||||
|
||||
**Verdict : vert.** `npx vitest run` = 460/460, `npm run build` (tsc --noEmit + vite) OK. Le front était déjà câblé pour Cancel/Retry ; contre le vrai payload backend le mapping d'états et l'activation des boutons fonctionnent.
|
||||
|
||||
**Contrat backend réel** (`crates/app-tauri/src/dto.rs::AgentBackgroundTaskStateDto`, camelCase) : `taskId, kind, state, exitCode?, summary?, stdoutTail?, stderrTail?, createdAtMs, updatedAtMs`. `state` ∈ queued|running|waiting|completed|failed|cancelled|expired ; `kind` ∈ command|headlessRendezvous|sessionResume|maintenance. **Pas** de `status`, `ownerAgentId`, `projectId`, ni `finishedAtMs`.
|
||||
|
||||
**Fait :** FE-1 rendu explicite `queued`/`waiting`→`pending` dans `normalizeBackgroundStatus`. FE-2 ajout d'un test sur le vrai shape dans `src/features/workstate/workstate.test.tsx` (le mock passe par le vrai `normalizeProjectWorkState`, donc pas de faux-vert possible).
|
||||
|
||||
**Écarts de contrat à arbitrer (dette, panneau non modifié) :** (1) `ProjectWorkStatePanel.tsx` trie sur `finishedAtMs` jamais émis → tri retombe sur taskId, non chronologique ; (2) `summary` backend non porté par `BackgroundCompletion` → ignoré ; (3) `ownerAgentId`/`projectId` absents du payload par-agent (inoffensif : fallback = agentId). Voir [[workstate-background-tasks-projection-fix]] et [[b8-in-app-trigger-run-in-background]].
|
||||
15
.ideai/memory/tickets-v1-e2e-validated-qa.md
Normal file
15
.ideai/memory/tickets-v1-e2e-validated-qa.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: tickets-v1-e2e-validated-qa
|
||||
description: Verdict QA du système de tickets V1 sans attachments sur feature/issue-ticket-system — vert de bout en bout, avec la seule réserve du typage de conflit côté UI.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
Validation QA de bout en bout du système de tickets **V1 (sans attachments)** sur `feature/issue-ticket-system` (backend commité `8de7be0`, frontend non commité). **Verdict : OK.**
|
||||
|
||||
**Preuves réelles :**
|
||||
- `cargo build --workspace` OK. Tests verts sur domain/application ; infrastructure et app-tauri verts **sauf la dette pré-existante déclarée** (`orchestrator_watcher::ask_request_surfaces_reply_alongside_detail` + `app-tauri state::mcp_e2e_loopback_tests::*`, tous `Elapsed(())` du rendez-vous, sans rapport avec les tickets). Aucun échec imputable aux tickets.
|
||||
- Frontend : `npm run build` OK (tsc+vite), `npm test` = **459 passed / 49 files**.
|
||||
|
||||
**Invariants prouvés par tests :** `#N` séquentiel jamais réutilisé (`allocator_never_reuses_numbers`) ; create→read round-trip ; carnet remplaçable & scoped `.ideai/tickets/N/carnet.md` ; pas de self-link (`IssueError::SelfLink`, `domain/issue.rs`) ; assignation agent connu seulement (`create_issue_rejects_unknown_assignee`) ; concurrence optimiste (`update_issue_maps_version_conflict`, `IssueStoreError::VersionConflict`) ; énums fermés statut/priorité.
|
||||
|
||||
**Réserve non bloquante (dette technique) :** le conflit de version est détecté côté **front** par fragment de message (`message.includes("version conflict")`, `frontend/src/adapters/ticket.ts`, `useTicketDetail.ts`), s'appuyant sur `domain/ports.rs` `#[error("issue version conflict: …")]`. Un code typé `"versionConflict"` existe DÉJÀ mais uniquement sur la surface MCP (`app-tauri/src/tickets.rs:942`) ; le chemin Tauri command renvoie `INVALID`. Recommandation : propager le code typé dans l'enveloppe d'erreur des `ticket_*` commands et brancher l'UI sur `error.code`. Comportement actuel correct et testé, donc non bloquant.
|
||||
15
.ideai/memory/workstate-background-tasks-projection-fix.md
Normal file
15
.ideai/memory/workstate-background-tasks-projection-fix.md
Normal file
@ -0,0 +1,15 @@
|
||||
---
|
||||
name: workstate-background-tasks-projection-fix
|
||||
description: Décision d'archi pour rendre visibles Cancel/Retry dans le panneau Work — extension du read-model GetProjectWorkState, contrat DTO et borne de livraison.
|
||||
metadata:
|
||||
type: reference
|
||||
---
|
||||
**Défaut** : `AgentWorkState` (`crates/application/src/workstate/mod.rs:140`) ne portait pas les tâches de fond et `GetProjectWorkState` n'avait pas de dépendance `BackgroundTaskStore`. Le panneau Work masque la section (`ProjectWorkStatePanel.tsx:638`, `agent.backgroundTasks.length > 0`) → aucun bouton Cancel/Retry en live. Le frontend était déjà entièrement câblé (`normalizeAgent`/`normalizeBackgroundTask`), il ne manquait que la projection backend.
|
||||
|
||||
**Décision (frontière)** : étendre le read-model unique — ajouter `background_tasks: Vec<AgentBackgroundTaskState>` à `AgentWorkState` et brancher `BackgroundTaskStore` via un builder best-effort `with_background_tasks(store)` (calqué sur `with_conversation_sources`), `None` ⇒ zéro régression. **Pas** de fetch séparé côté front (garderait la jointure tâche→agent hors du domaine, casserait l'instantané cohérent, dupliquerait les cycles async). Aucun nouveau port/adapter. `list_background_tasks` (B7) reste comme read-model autonome, hors chemin du panneau.
|
||||
|
||||
**Contrat** : `AgentBackgroundTaskState` = miroir de `BackgroundTaskDto` (`dto.rs:2886`) sans owner/project. Projection dans `execute` = union `list_open_for_agent(agent.id)` (per-agent, running/queued/waiting) + `list_undelivered_completions()` (chargé UNE fois avant la boucle, dispatché par `owner_agent_id`, pour failed/cancelled → Retry). Best-effort strict : erreur store ⇒ `Vec::new()` pour l'agent, jamais d'`AppError` (live/busy/tickets intacts).
|
||||
|
||||
**Borne V1 assumée** : une tâche terminale **déjà livrée** (wake tiré, `completion_delivered=true`) n'est plus énumérable (droppée des deux listes) → disparaît du panneau ; Retry seulement dans la fenêtre non-livrée. Conforme à la note « retry session-scoped V1 » de `RetryBackgroundTask` (`background/mod.rs:212`). Historique Retry persistant = V2 (ajouterait `list_recent_terminal_for_agent` au port), ticketable si besoin.
|
||||
|
||||
**Wiring** : `.with_background_tasks(state.background_task_store.clone())` dans `crates/app-tauri/src/state.rs` (ancre `b7-wiring-anchor-state-rs`) ; le store y est déjà managé (utilisé par `list_background_tasks`). Lié à [[b8-in-app-trigger-run-in-background]], [[b8-command-runner-pty-framing]], [[background-tasks-first-class-design]], [[checkpoint-t1-wake-delivery-bug-fixed-rebuild-pending]].
|
||||
Reference in New Issue
Block a user