fix(worker): depends_on-Nachfolger schon beim gelandeten Merge freigeben

Der Queue-Picker gatete eine task_dependencies-Kante auf status='done'.
review_task(skipVerify) laesst einen erfolgreich gemergten Task aber
bewusst auf WaitingForReview stehen, bis verify_merges einmal zentral
laeuft -- damit blockierte jeder Nachfolger ueber den gesamten Batch plus
Full-Suite-Verify hinweg, bei freien Slots.

Eine Kante gilt jetzt als erfuellt, wenn der Vorgaenger 'done' ist ODER
sein Merge gelandet ist (worktrees.state = 'merged'). TaskBlocking
(get_task/list_tasks/wait_for_task_change) und der UI-Wartehinweis folgen
derselben Regel, damit "blocked" nicht meldet, was der Picker claimt.

Abgeleitet: revert_merge/abort_merge setzen den Worktree auf Active und
blockieren wieder; reject_rerun/reject_park haben nie gemergt und bleiben
unerfuellt; ein Task ohne Worktree wird nur ueber 'done' erfuellt; ein
fehlgeschlagener verify_merges gibt Nachfolger frei, weil der Code so
oder so auf main liegt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Mika Kuns
2026-09-16 15:43:37 +02:00
committed by mika kuns
co-authored by Claude Opus 5
parent 50b6b56f87
commit c874bf7e52
8 changed files with 159 additions and 31 deletions
@@ -769,12 +769,16 @@ public sealed partial class TasksIslandViewModel : ViewModelBase, IDisposable
// A predecessor missing from both rowsById and the external cache counts as unmet -- mirrors
// QueuePicker/Worker's TaskBlocking.Unmet: an edge pointing at an unresolved/vanished task
// keeps blocking rather than being silently treated as satisfied.
// keeps blocking rather than being silently treated as satisfied. A landed merge satisfies
// the edge too (skipVerify parks a merged task in WaitingForReview until the batch verify);
// the external cache carries no worktree state, so a cross-list predecessor still shows as
// waiting until it reaches Done.
private static bool IsUnmet(
string id, Dictionary<string, TaskRowViewModel> rowsById,
IReadOnlyDictionary<string, (int Number, string Title, TaskStatus Status)> external)
{
if (rowsById.TryGetValue(id, out var p)) return p.Status != TaskStatus.Done;
if (rowsById.TryGetValue(id, out var p))
return p.Status != TaskStatus.Done && p.WorktreeState != WorktreeState.Merged;
if (external.TryGetValue(id, out var e)) return e.Status != TaskStatus.Done;
return true;
}