From 6688c92bc69060ed7372d30d9e2493accd86c476 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 30 Aug 2026 10:55:19 +0200 Subject: [PATCH] fix(app): stop calling new agent work reopened (#4068) Task snapshots reuse identities after completed work, so backward status transitions do not prove that an old task resumed. Report active work as started and keep pending work in the current task snapshot instead of inventing a reopened event. --- packages/app/src/components/message.tsx | 3 --- packages/app/src/i18n/resources.test.ts | 1 - packages/app/src/i18n/resources/ar.ts | 1 - packages/app/src/i18n/resources/en.ts | 1 - packages/app/src/i18n/resources/es.ts | 1 - packages/app/src/i18n/resources/fr.ts | 1 - packages/app/src/i18n/resources/ja.ts | 1 - packages/app/src/i18n/resources/ko.ts | 1 - packages/app/src/i18n/resources/pt-BR.ts | 1 - packages/app/src/i18n/resources/ru.ts | 1 - packages/app/src/i18n/resources/zh-CN.ts | 1 - .../app/src/runtime/replica-cache/index.ts | 2 +- packages/app/src/types/stream.test.ts | 24 +++++++++++++++++++ packages/app/src/types/stream.ts | 4 +--- 14 files changed, 26 insertions(+), 17 deletions(-) diff --git a/packages/app/src/components/message.tsx b/packages/app/src/components/message.tsx index 1658076273..a44cfe592e 100644 --- a/packages/app/src/components/message.tsx +++ b/packages/app/src/components/message.tsx @@ -42,7 +42,6 @@ import { CircleDot, Copy, Plus, - RotateCcw, TriangleAlertIcon, Scissors, MicVocal, @@ -2290,8 +2289,6 @@ function taskActivityIcon(activity: TaskActivity) { return CircleDot; case "completed": return Check; - case "reopened": - return RotateCcw; default: return CheckSquare; } diff --git a/packages/app/src/i18n/resources.test.ts b/packages/app/src/i18n/resources.test.ts index 4484a57857..17be56be3b 100644 --- a/packages/app/src/i18n/resources.test.ts +++ b/packages/app/src/i18n/resources.test.ts @@ -422,7 +422,6 @@ describe("translation resources", () => { added: "Added", started: "Started", completed: "Completed", - reopened: "Reopened", }); }); diff --git a/packages/app/src/i18n/resources/ar.ts b/packages/app/src/i18n/resources/ar.ts index cc1eb185d3..ed12f32ed6 100644 --- a/packages/app/src/i18n/resources/ar.ts +++ b/packages/app/src/i18n/resources/ar.ts @@ -345,7 +345,6 @@ export const ar: TranslationResources = { added: "أُضيفت", started: "بدأت", completed: "اكتملت", - reopened: "أُعيد فتحها", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/en.ts b/packages/app/src/i18n/resources/en.ts index 10f80ddc47..dbb90fb1f9 100644 --- a/packages/app/src/i18n/resources/en.ts +++ b/packages/app/src/i18n/resources/en.ts @@ -343,7 +343,6 @@ export const en = { added: "Added", started: "Started", completed: "Completed", - reopened: "Reopened", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/es.ts b/packages/app/src/i18n/resources/es.ts index e65c8c63ac..7986619f57 100644 --- a/packages/app/src/i18n/resources/es.ts +++ b/packages/app/src/i18n/resources/es.ts @@ -348,7 +348,6 @@ export const es: TranslationResources = { added: "Añadida", started: "Iniciada", completed: "Completada", - reopened: "Reabierta", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/fr.ts b/packages/app/src/i18n/resources/fr.ts index b18d54a70d..69bc8da578 100644 --- a/packages/app/src/i18n/resources/fr.ts +++ b/packages/app/src/i18n/resources/fr.ts @@ -349,7 +349,6 @@ export const fr: TranslationResources = { added: "Ajoutée", started: "Commencée", completed: "Terminée", - reopened: "Rouverte", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/ja.ts b/packages/app/src/i18n/resources/ja.ts index ea254d43c4..036fcba571 100644 --- a/packages/app/src/i18n/resources/ja.ts +++ b/packages/app/src/i18n/resources/ja.ts @@ -348,7 +348,6 @@ export const ja: TranslationResources = { added: "追加", started: "開始", completed: "完了", - reopened: "再開", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/ko.ts b/packages/app/src/i18n/resources/ko.ts index 1a4351aad4..bae2910423 100644 --- a/packages/app/src/i18n/resources/ko.ts +++ b/packages/app/src/i18n/resources/ko.ts @@ -346,7 +346,6 @@ export const ko: TranslationResources = { added: "추가됨", started: "시작됨", completed: "완료됨", - reopened: "다시 열림", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/pt-BR.ts b/packages/app/src/i18n/resources/pt-BR.ts index 15346caa74..e84156e096 100644 --- a/packages/app/src/i18n/resources/pt-BR.ts +++ b/packages/app/src/i18n/resources/pt-BR.ts @@ -348,7 +348,6 @@ export const ptBR: TranslationResources = { added: "Adicionada", started: "Iniciada", completed: "Concluída", - reopened: "Reaberta", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/ru.ts b/packages/app/src/i18n/resources/ru.ts index a6eb0cedb8..aab8a0245e 100644 --- a/packages/app/src/i18n/resources/ru.ts +++ b/packages/app/src/i18n/resources/ru.ts @@ -347,7 +347,6 @@ export const ru: TranslationResources = { added: "Добавлена", started: "Начата", completed: "Завершена", - reopened: "Возобновлена", }, }, compaction: { diff --git a/packages/app/src/i18n/resources/zh-CN.ts b/packages/app/src/i18n/resources/zh-CN.ts index 2c19dd98d0..c6ab40af4c 100644 --- a/packages/app/src/i18n/resources/zh-CN.ts +++ b/packages/app/src/i18n/resources/zh-CN.ts @@ -345,7 +345,6 @@ export const zhCN: TranslationResources = { added: "已添加", started: "已开始", completed: "已完成", - reopened: "已重新打开", }, }, compaction: { diff --git a/packages/app/src/runtime/replica-cache/index.ts b/packages/app/src/runtime/replica-cache/index.ts index 40cdc4c691..6d581aa268 100644 --- a/packages/app/src/runtime/replica-cache/index.ts +++ b/packages/app/src/runtime/replica-cache/index.ts @@ -69,7 +69,7 @@ const TodoEntrySchema = z.strictObject({ const TaskActivitySchema = z.discriminatedUnion("type", [ z.strictObject({ type: z.literal("created"), count: z.number().int().nonnegative() }), z.strictObject({ - type: z.enum(["added", "started", "completed", "reopened"]), + type: z.enum(["added", "started", "completed"]), task: z.string(), }), ]); diff --git a/packages/app/src/types/stream.test.ts b/packages/app/src/types/stream.test.ts index 1208368b53..580856fbfd 100644 --- a/packages/app/src/types/stream.test.ts +++ b/packages/app/src/types/stream.test.ts @@ -1094,6 +1094,30 @@ describe("stream reducer canonical tool calls", () => { ]); }); + it("reports new work after completed tasks without reopening anything", () => { + const state = hydrateStreamState([ + { + event: todoTimeline([ + { id: "0", text: "Finish old work", completed: true, status: "completed" }, + { id: "1", text: "Verify old work", completed: true, status: "completed" }, + ]), + timestamp: new Date("2025-01-01T10:50:00Z"), + }, + { + event: todoTimeline([ + { id: "0", text: "Investigate unrelated bug", completed: false, status: "in_progress" }, + { id: "1", text: "Write unrelated test", completed: false, status: "pending" }, + ]), + timestamp: new Date("2025-01-01T10:51:00Z"), + }, + ]); + + expect(state.flatMap((item) => (item.kind === "todo_list" ? [item.activity] : []))).toEqual([ + { type: "created", count: 2 }, + { type: "started", task: "Investigate unrelated bug" }, + ]); + }); + it("groups consecutive initial Claude TaskCreate snapshots", () => { const state = hydrateStreamState([ { diff --git a/packages/app/src/types/stream.ts b/packages/app/src/types/stream.ts index fda0ad03aa..b56f20932b 100644 --- a/packages/app/src/types/stream.ts +++ b/packages/app/src/types/stream.ts @@ -799,7 +799,7 @@ export interface TodoEntry { export type TaskActivity = | { type: "created"; count: number } - | { type: "added" | "started" | "completed" | "reopened"; task: string }; + | { type: "added" | "started" | "completed"; task: string }; export interface TodoListItem { kind: "todo_list"; @@ -1307,8 +1307,6 @@ function deriveTaskActivities( if (before === after) continue; if (after === "completed") { activities.push({ type: "completed", task: task.text }); - } else if (before === "completed") { - activities.push({ type: "reopened", task: task.text }); } else if (after === "in_progress") { activities.push({ type: "started", task: task.text }); }