From aa068efc688ae42c38cbf1c72205e90e02e626cf Mon Sep 17 00:00:00 2001 From: 777genius Date: Sun, 31 May 2026 17:49:32 +0300 Subject: [PATCH] fix(team): preserve task projection cache shape --- src/main/workers/team-fs-worker.ts | 78 ++++++++++++++++--- .../team/TeamFsWorker.integration.test.ts | 5 ++ 2 files changed, 74 insertions(+), 9 deletions(-) diff --git a/src/main/workers/team-fs-worker.ts b/src/main/workers/team-fs-worker.ts index 3ac26cb2..d7ad69b4 100644 --- a/src/main/workers/team-fs-worker.ts +++ b/src/main/workers/team-fs-worker.ts @@ -736,16 +736,76 @@ function normalizePersistentTaskReadResult( if (task.teamName !== teamName) return null; if (typeof task.id !== 'string') return null; if (typeof task.subject !== 'string') return null; - if ( - task.status !== 'pending' && - task.status !== 'in_progress' && - task.status !== 'completed' && - task.status !== 'deleted' - ) { - return null; - } + const status = + task.status === 'pending' || + task.status === 'in_progress' || + task.status === 'completed' || + task.status === 'deleted' + ? task.status + : null; + if (!status) return null; - return { task }; + return { task: restorePersistentTaskProjectionShape(task, teamName, status) }; +} + +function restorePersistentTaskProjectionShape( + task: Record, + teamName: string, + status: string +): Record { + const id = typeof task.id === 'string' ? task.id : ''; + const subject = typeof task.subject === 'string' ? task.subject : ''; + const displayId = task.displayId; + const reviewState = normalizeFallbackReviewState(task.reviewState, status); + return { + id, + displayId: + typeof displayId === 'string' && displayId.trim().length > 0 + ? displayId.trim() + : deriveTaskDisplayId(id), + subject, + description: typeof task.description === 'string' ? task.description : undefined, + descriptionTaskRefs: Array.isArray(task.descriptionTaskRefs) + ? task.descriptionTaskRefs + : undefined, + activeForm: typeof task.activeForm === 'string' ? task.activeForm : undefined, + prompt: typeof task.prompt === 'string' ? task.prompt : undefined, + promptTaskRefs: Array.isArray(task.promptTaskRefs) ? task.promptTaskRefs : undefined, + owner: typeof task.owner === 'string' ? task.owner : undefined, + createdBy: typeof task.createdBy === 'string' ? task.createdBy : undefined, + status, + workIntervals: Array.isArray(task.workIntervals) ? task.workIntervals : undefined, + reviewIntervals: Array.isArray(task.reviewIntervals) ? task.reviewIntervals : undefined, + historyEvents: Array.isArray(task.historyEvents) ? task.historyEvents : undefined, + blocks: Array.isArray(task.blocks) ? task.blocks : undefined, + blockedBy: Array.isArray(task.blockedBy) ? task.blockedBy : undefined, + related: Array.isArray(task.related) + ? (task.related as unknown[]).filter((id): id is string => typeof id === 'string') + : undefined, + createdAt: typeof task.createdAt === 'string' ? task.createdAt : undefined, + updatedAt: typeof task.updatedAt === 'string' ? task.updatedAt : undefined, + projectPath: typeof task.projectPath === 'string' ? task.projectPath : undefined, + comments: Array.isArray(task.comments) ? task.comments : undefined, + needsClarification: + task.needsClarification === 'lead' || task.needsClarification === 'user' + ? task.needsClarification + : undefined, + reviewState, + deletedAt: undefined, + attachments: Array.isArray(task.attachments) ? task.attachments : undefined, + sourceMessageId: + typeof task.sourceMessageId === 'string' && task.sourceMessageId.trim() + ? task.sourceMessageId.trim() + : undefined, + sourceMessage: + isRecord(task.sourceMessage) && + typeof task.sourceMessage.text === 'string' && + typeof task.sourceMessage.from === 'string' && + typeof task.sourceMessage.timestamp === 'string' + ? task.sourceMessage + : undefined, + teamName, + }; } function normalizePersistentTaskProjectionEntry( diff --git a/test/main/services/team/TeamFsWorker.integration.test.ts b/test/main/services/team/TeamFsWorker.integration.test.ts index 177e3728..9655d0ae 100644 --- a/test/main/services/team/TeamFsWorker.integration.test.ts +++ b/test/main/services/team/TeamFsWorker.integration.test.ts @@ -598,9 +598,11 @@ describe('team-fs-worker integration', () => { ); const firstWorker = createWorker(workerPath); + let firstTaskKeys: string[] = []; try { const first = await callGetAllTasks(firstWorker, tasksBase, projectionCacheBase); expect(first.tasks[0]).toMatchObject({ teamName, subject: 'Persisted subject' }); + firstTaskKeys = Object.keys(first.tasks[0] as Record); expect(first.diag?.cacheMisses).toBe(1); expect(first.diag?.persistentCacheWrites).toBe(1); } finally { @@ -611,6 +613,9 @@ describe('team-fs-worker integration', () => { try { const second = await callGetAllTasks(secondWorker, tasksBase, projectionCacheBase); expect(second.tasks[0]).toMatchObject({ teamName, subject: 'Persisted subject' }); + expect(Object.keys(second.tasks[0] as Record)).toEqual( + firstTaskKeys + ); expect(second.diag?.cacheHits).toBe(0); expect(second.diag?.cacheMisses).toBe(0); expect(second.diag?.persistentCacheLoads).toBe(1);