feat(tasks): PR 1.5 — return refreshed subtask + parent from completion

Change complete_subtask_and_check_parent to return
(TaskRow, Option<TaskRow>): the refreshed subtask, plus the parent when
the cascade auto-completed it. Both rows are read inside the same
transaction so the frontend never observes partial state.

Wrap the cmd in a CompleteSubtaskResult { updatedSubtask,
autoCompletedParent } DTO. MicroSteps now applies the refreshed subtask
locally and, when present, calls a new replaceTaskFromDto helper on the
Tasks store so the parent's done/doneAt/badge counts update without a
follow-up list_tasks_cmd round-trip.

Test: complete_subtask_returns_updated_subtask_and_optional_parent
covers both paths (sibling-pending → None, last-sibling → Some(parent)).
All 61 kon-storage tests pass; svelte-check clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 18:17:30 +01:00
parent 0a8cb55447
commit 6e663a3625
4 changed files with 126 additions and 7 deletions

View File

@@ -432,6 +432,21 @@ function applyLocalTaskUpdate(id: string, updates: Partial<TaskEntry>) {
}
}
/**
* PR 1.5: replace an in-store task with a fresh DTO from the backend
* (e.g. the auto-completed parent returned by `complete_subtask_cmd`).
* No-op if the task is not in the store — that's expected when a parent
* has already been pruned client-side. Broadcasts on success so other
* windows pick up the new state.
*/
export function replaceTaskFromDto(row: TaskDto) {
const idx = tasks.findIndex((task) => task.id === row.id);
if (idx >= 0) {
tasks[idx] = mapTaskRow(row);
broadcastTasks();
}
}
export async function updateTask(id: string, updates: TaskUpdate) {
if (!hasTauriRuntime()) {
applyLocalTaskUpdate(id, updates as Partial<TaskEntry>);