--- 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 ``` ```text $ git diff --check ``` ```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 ``` 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 ``` ```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.