task_gate_finished sets a task to Review whenever its gate exits non-zero, without looking at the task's current status. So a gate run that finishes after the task has merged puts a merged task back to review. The branch and the merge note stay on luvus/integration, but the board shows the task as needing a person again.
A second gate can be running because complete_task refuses only Merging and Merged. A second task done while the first gate is still running starts another gate for the same task.
Reproduce
Luvus 0.14.2. The same code is on main at 732c81c.
luvus task add "gate race" --workspace-id <ws> --gate 'if [ -e /tmp/race ]; then sleep 6; exit 1; fi; touch /tmp/race; sleep 1; exit 0'
luvus task start t1 --agent sh --workspace-id <ws> --no-focus
luvus task done t1 # gate 1: passes after 1s
luvus task done t1 # gate 2: starts while gate 1 runs, fails after 6s
# wait for status done, then
luvus task merge t1
09:23:24.296 status: done
09:23:24.328 merge: merged
09:23:24.369 status: merged
09:23:31.395 status: review
note: merged luvus/t1 into luvus/integration at 9df07bbba9c1
Getting it back
Once it has happened, the task can't be marked merged directly:
$ luvus task merge t1
not_done: t1 cannot be integrated while review
$ luvus task update t1 --status merged
protected_status: merged is set only by task.merge
Setting it to done and merging again works (outcome: merged, with a second identical merge note), but only while the task's worktree still exists. If it has been removed, task merge fails with the task's repository is no longer available.
Where
src/app/board.rs, task_gate_finished: set_status(id, TaskStatus::Review) on a non-zero exit, with no check of the current status.
src/orch/mod.rs, set_status: assigns whatever status it is given.
src/app/board.rs, complete_task: refuses Merging and Merged only, so it will start a second gate while one is running.
Where we met it
A scheduler built on the task API merged a lane as soon as its gate passed and then removed the lane's worktree. A second gate for the same task, started before the merge, failed in the removed worktree and set the merged task back to review. It kept a lane slot and showed as needing a person.
A possible fix
Your call, but either of these would stop it: ignore a gate result for a task that is already Merging or Merged, or refuse task done while a gate for that task is still running.
task_gate_finishedsets a task toReviewwhenever its gate exits non-zero, without looking at the task's current status. So a gate run that finishes after the task has merged puts a merged task back toreview. The branch and the merge note stay onluvus/integration, but the board shows the task as needing a person again.A second gate can be running because
complete_taskrefuses onlyMergingandMerged. A secondtask donewhile the first gate is still running starts another gate for the same task.Reproduce
Luvus 0.14.2. The same code is on
mainat 732c81c.Getting it back
Once it has happened, the task can't be marked merged directly:
Setting it to
doneand merging again works (outcome: merged, with a second identical merge note), but only while the task's worktree still exists. If it has been removed,task mergefails withthe task's repository is no longer available.Where
src/app/board.rs,task_gate_finished:set_status(id, TaskStatus::Review)on a non-zero exit, with no check of the current status.src/orch/mod.rs,set_status: assigns whatever status it is given.src/app/board.rs,complete_task: refusesMergingandMergedonly, so it will start a second gate while one is running.Where we met it
A scheduler built on the task API merged a lane as soon as its gate passed and then removed the lane's worktree. A second gate for the same task, started before the merge, failed in the removed worktree and set the merged task back to
review. It kept a lane slot and showed as needing a person.A possible fix
Your call, but either of these would stop it: ignore a gate result for a task that is already
MergingorMerged, or refusetask donewhile a gate for that task is still running.