Files
IdeA/.ideai/tickets/307/carnet.md

267 lines
16 KiB
Markdown

---
issueRef: "#307"
version: 7
updatedBy: {"kind":"agent","agent_id":"1ff94b51-3e17-4a39-8543-7715d1ff0f80"}
updatedAt: 1789054288135
---
## 2026-09-10 — Main
Signalement utilisateur: au lancement d'IdeA, l'UI indique des tasks/états en cours alors qu'aucune tâche réelle n'est active. Capture: cellule Main affichant `Conversation liée — récupération du transcript en cours.`
Cadrage Architect:
- Bug backend prioritaire avec validation frontend.
- Vérifier/corriger la chaîne `BackendCore::activate_project()` -> `reconcile_layouts`, `reconcile_live_state`, `reconcile_background_tasks`.
- Sources persistées à réconcilier: `live-state.json` (`working/waiting/blocked` sans session vivante -> `idle`) et `BackgroundTaskStore` (`Running/Waiting/Cancelling` sans handle runtime -> terminal + delivery pending si nécessaire).
- `GetProjectWorkState` ne doit pas reprojeter de tâche non terminale orpheline après activation projet.
- Le message transcript peut être l'effet direct du live-state fantôme; si un `conversationId` persiste seul sans tours ni session active, ajouter un garde-fou frontend minimal pour ne pas rester indéfiniment sur `récupération du transcript en cours`.
Fichiers probables backend/domain: `crates/backend/src/lib.rs`, `crates/application/src/workstate/reconcile.rs`, `crates/domain/src/live_state.rs`, `crates/infrastructure/src/store/background_task.rs`, tests `crates/application/tests/workstate.rs` et backend autour de la réconciliation.
Fichiers probables frontend: `frontend/src/features/agents/CustomAgentChatView.tsx`, `frontend/src/features/workstate/ProjectWorkStatePanel.tsx`, `frontend/src/features/layout/LayoutGrid.tsx`, `frontend/src/adapters/workStateNormalization.ts`.
QA attendue: démarrage avec live-state fantôme, background task Running orpheline, completion pending/non livrée, completion déjà livrée, multi-projets, et capture UI équivalente sans blocage transcript infini.
## 2026-09-10 — DevBackend
Correctif backend/domain implémenté sur `develop`, sans commit/merge/push et sans modification frontend.
Diagnostic:
- `LiveState::reconcile_orphans` remettait bien les lignes `working`/`waiting`/`blocked` sans session vivante à `idle`, mais conservait leur `correlationId`. Or cette corrélation représente une requête cross-project active; après reboot, elle ne correspond plus à aucun runtime reprenable/annulable et maintient une relation fantôme.
- `AppBackgroundTaskStore::reconcile_project_boot(project_id, ...)` déléguait à `FsBackgroundTaskStore::reconcile_boot`, qui balayait tous les documents présents sous le root. De même, `list_undelivered_for_project` ne filtrait pas le résultat global sur le projet demandé. L'activation n'était donc pas strictement bornée au `projectId` activé.
Implémentation:
- `crates/domain/src/live_state.rs`: une ligne active orpheline efface désormais aussi `correlation_id`, en plus de `ticket` et `last_delegation`; test domaine renforcé avec une corrélation réellement présente.
- `crates/infrastructure/src/store/background_task.rs`: ajout de `reconcile_project_boot(project_id, live_task_ids, now_ms)` et factorisation interne; l'API historique `reconcile_boot` reste disponible, tandis que l'activation utilise la variante bornée.
- `crates/backend/src/lib.rs`: réconciliation et collecte des complétions strictement filtrées sur le projet activé; test B7 renforcé pour vérifier que la tâche orpheline terminalisée disparaît de `list_open_for_agent`, source ouverte de `GetProjectWorkState`.
- `crates/infrastructure/tests/background_task_store.rs`: test multi-projets prouvant que l'activation d'un projet ne répare ni ne rapporte une tâche étrangère.
- `crates/backend/src/lib.rs`: test d'intégration #307 qui persiste un live-state `working` corrélé et une tâche `Running`, appelle réellement `BackendCore::activate_project()`, puis vérifie `idle`, corrélation/ticket/délégation effacés, tâche `Failed` et aucune tâche ouverte reprojetable.
Commandes exécutées, toutes vertes:
- `cargo fmt --all -- --check`
- `cargo test -p domain live_state::tests::reconcile_orphans` — 4/4
- `cargo test -p infrastructure --test background_task_store reconcile` — 4/4
- `cargo test -p backend background_tasks_b7_tests` — 1/1
- `cargo test -p backend ticket307_activation_reconcile_tests` — 1/1
- `cargo test -p application --test workstate` — 29/29
- `cargo check -p backend`
- `git diff --check`
Frontend:
- Aucun changement nécessaire pour le défaut backend reproduit/corrigé.
- QA doit encore faire le smoke test UI/AppImage de fermeture-relance demandé par le cadrage. Si le message `Conversation liée — récupération du transcript en cours.` subsiste avec un `conversationId` frontend isolé malgré les états backend assainis, le garde-fou frontend minimal décrit par Architect reste un lot séparé à confirmer sur preuve live.
## 2026-09-10 — QA
Verdict QA: VERT pour le correctif backend/domain/infrastructure du ticket #307.
Relu:
- Diff de `crates/domain/src/live_state.rs`, `crates/infrastructure/src/store/background_task.rs`, `crates/infrastructure/tests/background_task_store.rs`, `crates/backend/src/lib.rs`.
- `BackendCore::activate_project()` appelle toujours `reconcile_layouts`, `reconcile_live_state`, `reconcile_background_tasks`.
- `GetProjectWorkState` filtre les background tasks par `task.project_id == project.id` avant projection.
- Frontend: `CustomAgentChatView` garde le message `Conversation liée — récupération du transcript en cours.` quand `displayTurns.length === 0 && hasLinkedConversation`; `hasLinkedConversation` reste vrai avec un `conversationId` seul.
Test QA frontend ajouté:
- `frontend/src/features/agents/CustomAgentChatView.test.tsx`: `keeps the linked-conversation placeholder when an isolated conversation id has no recovered turns`.
- Ce test ne modifie pas le code de production; il prouve que le garde-fou frontend UX reste nécessaire si un `conversationId` isolé survit indépendamment de l'état live/backend.
Commandes exécutées et sorties réelles:
```text
$ cargo fmt --all -- --check
<no output, exit 0>
```
```text
$ git diff --check
<no output, exit 0>
```
```text
$ cargo test -p domain live_state::tests::reconcile_orphans
running 4 tests
test live_state::tests::reconcile_orphans_does_not_mutate_self ... ok
test live_state::tests::reconcile_orphans_downgrades_dead_active_rows_and_rewrites_fields ... ok
test live_state::tests::reconcile_orphans_covers_working_waiting_blocked_only ... ok
test live_state::tests::reconcile_orphans_spares_live_agents ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 307 filtered out; finished in 0.00s
```
```text
$ cargo test -p infrastructure --test background_task_store reconcile
running 4 tests
test reconcile_marks_cancelling_without_live_handle_cancel_failed_and_pending ... ok
test reconcile_uses_monotonic_timestamp_when_clock_is_behind ... ok
test project_reconcile_does_not_repair_or_report_foreign_project_tasks ... ok
test reconcile_marks_running_without_live_handle_failed_and_pending ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.00s
```
```text
$ cargo test -p backend background_tasks_b7_tests
running 1 test
test background_tasks_b7_tests::app_reconcile_requeues_wake_owner_marks_record_only_and_repairs_orphan_running ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 0.09s
```
```text
$ cargo test -p backend ticket307_activation_reconcile_tests
running 1 test
test ticket307_activation_reconcile_tests::activate_project_clears_stale_live_correlation_and_terminalizes_orphan_task ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 0.07s
```
```text
$ cargo test -p application --test workstate
running 29 tests
...
test workstate_projects_open_and_undelivered_background_tasks_by_agent ... ok
test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
```text
$ cargo check -p backend
Checking domain v0.3.0 (/home/anthony/Documents/Projects/IdeA/crates/domain)
Checking application v0.3.0 (/home/anthony/Documents/Projects/IdeA/crates/application)
Checking infrastructure v0.3.0 (/home/anthony/Documents/Projects/IdeA/crates/infrastructure)
Checking backend v0.3.0 (/home/anthony/Documents/Projects/IdeA/crates/backend)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 9.44s
```
```text
$ npm test -- CustomAgentChatView.test.tsx
npm error enoent Could not read package.json: Error: ENOENT: no such file or directory, open '/home/anthony/Documents/Projects/IdeA/package.json'
```
```text
$ (cd frontend && npm test -- CustomAgentChatView.test.tsx)
Test Files 1 passed (1)
Tests 72 passed (72)
Duration 4.36s
```
Conclusion:
- Le smoke automatisé backend `BackendCore::activate_project()` couvre l'équivalent fermeture/redémarrage: live-state `working` corrélé persisté + background task `Running` orpheline -> activation -> live-state `idle`, `correlation_id`/ticket/délégation effacés, task `Failed`, aucune task ouverte reprojetable.
- La réconciliation background est bien bornée par `projectId` et ne terminalise/rapporte pas les tâches étrangères.
- Le correctif backend suffit pour le défaut live-state/background-task fantôme validé ici.
- Risque résiduel frontend: le message `Conversation liée — récupération du transcript en cours.` peut encore apparaître avec un `conversationId` isolé sans tours récupérés; le garde-fou UX reste pertinent comme lot séparé si ce cas persiste après backend assaini.
## 2026-09-10 — DevFrontend (réouverture QA)
Diagnostic:
- Le rendu vide de `CustomAgentChatView` utilisait `hasLinkedConversation` après la fin de `openOrAttach`, sans distinguer une récupération encore active d'une récupération terminée sans aucun tour.
- Un `conversationId` isolé suffisait donc à conserver indéfiniment le libellé `Conversation liée — récupération du transcript en cours.` après un retour utile vide.
Implémentation minimale:
- `frontend/src/features/agents/CustomAgentChatView.tsx`: une fois `opening` terminé et sans tour affichable, une conversation toujours liée affiche désormais littéralement `Conversation liée — transcript indisponible.`. Le spinner reste borné à `opening`; la cellule et le `conversationId` ne sont ni fermés ni effacés.
- `frontend/src/features/agents/CustomAgentChatView.test.tsx`: le test ciblé QA attend le nouvel état terminal et vérifie l'absence de l'ancien libellé, de spinner et de bouton `Réessayer` dans le scénario de récupération vide.
- Les alertes techniques existantes restent inchangées afin de ne pas masquer les erreurs de lancement/rattachement hors de ce scénario vide.
Commandes exécutées:
```text
$ (cd frontend && npm test -- CustomAgentChatView.test.tsx)
Test Files 1 passed (1)
Tests 72 passed (72)
Duration 4.04s
```
```text
$ (cd frontend && npm run typecheck)
tsc --noEmit
exit 0
```
```text
$ git diff --check
<no output, exit 0>
```
Risque résiduel:
- Le correctif repose sur la terminaison de la tentative `openOrAttach`; il ne crée pas un nouveau timeout frontend autour d'un appel transport qui ne se résoudrait jamais. Cette extension serait hors du garde-fou minimal demandé et modifierait le contrat de transport.
## 2026-09-10 — QA finale après garde-fou frontend
Verdict QA final: VERT pour #307, backend + garde-fou frontend.
Relu:
- Diff backend/domain/infrastructure déjà validé: réconciliation live-state avec `correlation_id` effacé, réconciliation background bornée par `projectId`, smoke `BackendCore::activate_project()`.
- Diff frontend: `CustomAgentChatView.tsx` remplace l'état vide post-récupération par `Conversation liée — transcript indisponible.`.
- Test frontend: `CustomAgentChatView.test.tsx` couvre le cas `conversationId` isolé sans tours récupérés et vérifie l'absence de l'ancien libellé, du spinner et du bouton `Réessayer`.
Commandes exécutées et sorties réelles:
```text
$ git diff --check
<no output, exit 0>
```
```text
$ cargo test -p domain live_state::tests::reconcile_orphans
running 4 tests
test live_state::tests::reconcile_orphans_does_not_mutate_self ... ok
test live_state::tests::reconcile_orphans_covers_working_waiting_blocked_only ... ok
test live_state::tests::reconcile_orphans_spares_live_agents ... ok
test live_state::tests::reconcile_orphans_downgrades_dead_active_rows_and_rewrites_fields ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 307 filtered out; finished in 0.00s
```
```text
$ cargo test -p infrastructure --test background_task_store reconcile
running 4 tests
test reconcile_uses_monotonic_timestamp_when_clock_is_behind ... ok
test reconcile_marks_cancelling_without_live_handle_cancel_failed_and_pending ... ok
test project_reconcile_does_not_repair_or_report_foreign_project_tasks ... ok
test reconcile_marks_running_without_live_handle_failed_and_pending ... ok
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 8 filtered out; finished in 0.00s
```
```text
$ cargo test -p backend ticket307_activation_reconcile_tests
running 1 test
test ticket307_activation_reconcile_tests::activate_project_clears_stale_live_correlation_and_terminalizes_orphan_task ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 0.01s
```
```text
$ cargo test -p backend background_tasks_b7_tests
running 1 test
test background_tasks_b7_tests::app_reconcile_requeues_wake_owner_marks_record_only_and_repairs_orphan_running ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 101 filtered out; finished in 0.00s
```
```text
$ cargo test -p application --test workstate
running 29 tests
...
test workstate_lists_two_tickets_in_fifo_order ... ok
test result: ok. 29 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
```text
$ (cd frontend && npm test -- CustomAgentChatView.test.tsx)
Test Files 1 passed (1)
Tests 72 passed (72)
Duration 3.97s
```
```text
$ (cd frontend && npm run typecheck)
> idea-frontend@0.3.0 typecheck
> tsc --noEmit
```
Conclusion:
- Le backend ne reprojette plus l'activité fantôme validée par le smoke d'activation.
- Le frontend ne reste plus sur `Conversation liée — récupération du transcript en cours.` après récupération vide; il affiche un état terminal explicite `Conversation liée — transcript indisponible.`.
- Risque résiduel limité: le garde-fou frontend suppose toujours que `openOrAttach` finit par se résoudre/rejeter; il n'ajoute pas de timeout transport.
## Git — 2026-09-10
- Reprise après déblocage; état laissé par la session Git précédente (interrompue après le merge) inspecté puis validé.
- Branche: `fix/307-startup-ghost-states-reconciliation` créée depuis develop @ `99b400a`; commit fix `57cf825` (6 fichiers domain/infrastructure/backend/frontend), QA verte reconfirmée par Git avant commit.
- Merge no-ff vers `develop`: `e1dbe56`; branche feature conservée après merge (convention récente).
- Rebuild AppImage du 14:21 déjà formalisé en amont du merge: commit dédié `99b400a` (vide, trace durable in-repo) + tag annoté `v0.46.0`.
- Vérifications à la reprise: `git diff eb86366..e1dbe56 --stat` = exactement les 6 fichiers du correctif; artefact `target/release/bundle/appimage/IdeA_0.3.0_amd64.AppImage` (119871992 octets, mtime 2026-09-10 14:21:49) de sha256 `e6e22132970357d8a67338edaf4c3b0adbee7a66265e09211e733abfa08825da` identique à celui documenté par `99b400a` — l'AppImage v0.46.0, buildée depuis le worktree incluant le WIP #307 complet, correspond au contenu de develop post-merge. Décision: aucun nouveau rebuild ni incrément de tag, un même artefact ne porte pas deux versions.
- Store de tickets synchronisé sur develop dans le `chore(tickets)` portant ce carnet (tickets 299-307, index/counter, #296); `attachments/` et `scripts/` maintenus hors périmètre non suivis.
- Aucun push (develop en avance de 320 commits sur origin/develop).
- Restants: remplacement de l'AppImage installée par l'artefact v0.46.0 + relance manuels, validation live fermeture/relance (plus de LED fantôme ni de spinner transcript infini), puis clôture du ticket.