From b9653d633888137d5e4e91a5d73d1e698f239b9d Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Mon, 16 Feb 2026 23:41:08 -0800 Subject: [PATCH] fix: Strip runtime and state fields when duplicating features --- .../views/board-view/hooks/use-board-actions.ts | 16 ++++++++++++++-- .../board-view/hooks/use-board-persistence.ts | 7 +++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/apps/ui/src/components/views/board-view/hooks/use-board-actions.ts b/apps/ui/src/components/views/board-view/hooks/use-board-actions.ts index 89446fc5..75d49030 100644 --- a/apps/ui/src/components/views/board-view/hooks/use-board-actions.ts +++ b/apps/ui/src/components/views/board-view/hooks/use-board-actions.ts @@ -1092,8 +1092,20 @@ export function useBoardActions({ const handleDuplicateFeature = useCallback( async (feature: Feature, asChild: boolean = false) => { - // Copy all feature data, only override id/status (handled by create) and dependencies if as child - const { id: _id, status: _status, ...featureData } = feature; + // Copy all feature data, stripping id, status (handled by create), and runtime/state fields + const { + id: _id, + status: _status, + startedAt: _startedAt, + error: _error, + summary: _summary, + spec: _spec, + passes: _passes, + planSpec: _planSpec, + descriptionHistory: _descriptionHistory, + titleGenerating: _titleGenerating, + ...featureData + } = feature; const duplicatedFeatureData = { ...featureData, // If duplicating as child, set source as dependency; otherwise keep existing diff --git a/apps/ui/src/components/views/board-view/hooks/use-board-persistence.ts b/apps/ui/src/components/views/board-view/hooks/use-board-persistence.ts index d0da2d5c..d3004f74 100644 --- a/apps/ui/src/components/views/board-view/hooks/use-board-persistence.ts +++ b/apps/ui/src/components/views/board-view/hooks/use-board-persistence.ts @@ -132,6 +132,13 @@ export function useBoardPersistence({ currentProject }: UseBoardPersistenceProps const api = getElectronAPI(); if (!api.features) { logger.error('Features API not available'); + // Rollback optimistic deletion since we can't persist + if (previousFeatures) { + queryClient.setQueryData(queryKeys.features.all(currentProject.path), previousFeatures); + } + queryClient.invalidateQueries({ + queryKey: queryKeys.features.all(currentProject.path), + }); return; }