48108 frontend [ tasks ] Correct output field order and stale draft handling#268
48108 frontend [ tasks ] Correct output field order and stale draft handling#268aicarma-artyom-maslov wants to merge 2 commits into
Conversation
| @@ -158,10 +159,12 @@ export function TaskCard({ | |||
| useEffect(() => { | |||
There was a problem hiding this comment.
🟡 Medium TaskCard/TaskCard.tsx:159
The useEffect that rebuilds outputValues now depends on task.output, which races with the 300 ms debounced draft write in handleEditField. When a user edits a field, handleEditField updates outputValues optimistically but defers the localStorage write by 300 ms. If task.output changes identity in that window (e.g. after a server sync), the effect runs before the debounced write completes, reads the stale localStorage draft via getOutputFromStorage(id), and overwrites outputValues with the older value. The pending saveOutputsToStorageDebounced then writes the newer value to localStorage, but the UI never re-reads it, so the stale value persists and setTaskCompleted can submit the rolled-back output. Consider not reading from localStorage when the update originates from a user edit, or flush the pending debounced write before rebuilding from task.output.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @frontend/src/public/components/TaskCard/TaskCard.tsx around line 159:
The `useEffect` that rebuilds `outputValues` now depends on `task.output`, which races with the 300 ms debounced draft write in `handleEditField`. When a user edits a field, `handleEditField` updates `outputValues` optimistically but defers the localStorage write by 300 ms. If `task.output` changes identity in that window (e.g. after a server sync), the effect runs before the debounced write completes, reads the stale localStorage draft via `getOutputFromStorage(id)`, and overwrites `outputValues` with the older value. The pending `saveOutputsToStorageDebounced` then writes the newer value to localStorage, but the UI never re-reads it, so the stale value persists and `setTaskCompleted` can submit the rolled-back output. Consider not reading from localStorage when the update originates from a user edit, or flush the pending debounced write before rebuilding from `task.output`.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 850fff2. Configure here.

Note
Medium Risk
Changes merge rules for server vs local draft output and when TaskCard resets field state; wrong precedence could drop in-progress edits, but scope is task UI and storage only.
Overview
Fixes task output UX: fields render in template order, server data wins over stale local drafts, and file outputs stay in sync after server updates.
Task card now sorts outputs with
sortFieldsByOrderand only re-merges storage when the task changes, restarts (dateStarted), or server output changes (getTaskOutputFingerprint). Pending debounced saves are cancelled on task switch/restart so drafts do not bleed across tasks.ExtraFieldsHelper prefers server values when present (
hasServerValue); file fields use servermarkdownValue/attachments instead of local storage when the server already has data. ExtraFieldFile syncs its file list from props when attachments ormarkdownValuechange.Feed highlights treat file outputs with only
markdownValueas non-empty. Task revert clears local output storage like task complete already does.Reviewed by Cursor Bugbot for commit 2f199c0. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix output field order and stale draft handling in TaskCard
orderto match the template, using a newsortFieldsByOrderutility in workflows.ts.getTaskOutputFingerprintutil detects server-side output changes so the component refreshes field values on task restart or remote update without resetting unchanged local drafts.markdownValueorfield.attachments, falling back to storage only when the server has no value.field.attachmentsorfield.markdownValueprops change after initial render.removeOutputFromLocalStorageto clear stale drafts from local storage.Macroscope summarized 2f199c0.