fix(backend,domain,infrastructure,frontend): réconcilie les états et tâches fantômes au démarrage — #307 (cause: l'activation projet balayait tous les documents background-task sous le root sans filtre project_id et LiveState::reconcile_orphans conservait correlation_id des lignes mortes, laissant après reboot des LED working fantômes et des tâches Running orphelines reprojetées par GetProjectWorkState, tandis qu'un conversationId isolé affichait indéfiniment « Conversation liée — récupération du transcript en cours. »; fix backend: FsBackgroundTaskStore::reconcile_project_boot borne la réconciliation boot au document du projet activé (API reconcile_boot historique préservée), AppBackgroundTaskStore filtre list_undelivered_completions sur project_id, et une ligne active orpheline efface désormais aussi correlation_id en plus de ticket/last_delegation; garde-fou frontend: CustomAgentChatView affiche l'état terminal « Conversation liée — transcript indisponible. » quand openOrAttach terminé n'a récupéré aucun tour, spinner borné à opening, conversationId et cellule préservés; QA verte reconfirmée par Git: rustup run stable cargo fmt --all -- --check, git diff --check, cargo test -p infrastructure --test background_task_store 12/12 dont project_reconcile_does_not_repair_or_report_foreign_project_tasks, -p domain --lib live_state 15/15, -p backend ticket307_activation_reconcile_tests 1/1 (activate_project_clears_stale_live_correlation_and_terminalizes_orphan_task) et background_tasks_b7 1/1 renforcé (orphan évicté de list_open_for_agent), -p application --test workstate 29/29, cargo check -p backend, frontend npm test CustomAgentChatView 72/72 dont garde-fou transcript indisponible, npm run typecheck; risque résiduel documenté: le garde-fou suppose que openOrAttach finit par se résoudre, pas de timeout transport ajouté; fichiers .ideai/tickets/296/*, tickets/299-307/*, counter/index, attachments/ et scripts/ hors périmètre et préservés en worktree; aucun push)
This commit is contained in:
@ -226,8 +226,9 @@ impl LiveState {
|
||||
/// "ghost" rows for agents whose sessions are dead. This pure transform returns
|
||||
/// the **rewritten** rows to upsert (it does **not** mutate `self`): each orphan
|
||||
/// is downgraded to [`WorkStatus::Idle`], keeping its `intent` (trace), clearing
|
||||
/// the now-dead `ticket` and `last_delegation`, stamping a `progress` stale
|
||||
/// marker and a fresh `updated_at_ms = now_ms` (last-writer-wins).
|
||||
/// the now-dead `ticket`, `last_delegation` and `correlation_id`, stamping a
|
||||
/// `progress` stale marker and a fresh `updated_at_ms = now_ms`
|
||||
/// (last-writer-wins).
|
||||
///
|
||||
/// Rows that are already `Idle`/`Done`, or whose agent is still live, are
|
||||
/// **never** touched and are absent from the result. The caller persists each
|
||||
@ -253,7 +254,10 @@ impl LiveState {
|
||||
status: WorkStatus::Idle,
|
||||
progress: Some(STALE_AT_RESTART_MARKER.to_owned()),
|
||||
last_delegation: None,
|
||||
correlation_id: e.correlation_id.clone(),
|
||||
// A correlation identifies an active cross-project request. If
|
||||
// the owning session is gone, retaining it would keep exposing a
|
||||
// relationship that no runtime can resume or cancel.
|
||||
correlation_id: None,
|
||||
updated_at_ms: now_ms,
|
||||
})
|
||||
.collect()
|
||||
@ -451,6 +455,8 @@ mod tests {
|
||||
Some(tid(8)),
|
||||
100,
|
||||
)
|
||||
.unwrap()
|
||||
.with_correlation_id(Some("cross-project-request".to_owned()))
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
@ -468,6 +474,7 @@ mod tests {
|
||||
assert_eq!(row.intent, "implementing lot 2", "intent kept as trace");
|
||||
assert_eq!(row.ticket, None, "dead ticket cleared");
|
||||
assert_eq!(row.last_delegation, None, "dead delegation cleared");
|
||||
assert_eq!(row.correlation_id, None, "dead correlation cleared");
|
||||
assert_eq!(row.progress.as_deref(), Some(STALE_AT_RESTART_MARKER));
|
||||
assert_eq!(row.updated_at_ms, 999, "stamped with the fresh now");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user