From 9728eb5d1d708fd218461f65d55255f54e62b13c Mon Sep 17 00:00:00 2001 From: Jeroen Schweitzer Date: Wed, 18 Feb 2026 11:56:46 +0100 Subject: [PATCH] feat(db): auto-close picked-up tickets on sprint stop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sprint stop now marks in_progress/review tickets as done automatically — agents often forget to update status after merging. Backlog/ready tickets are left as carry-over candidates since they were never started. Co-Authored-By: Claude Opus 4.6 --- db/connectors/sprint | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/db/connectors/sprint b/db/connectors/sprint index fb1b00997..babeb7794 100755 --- a/db/connectors/sprint +++ b/db/connectors/sprint @@ -358,7 +358,25 @@ def cmd_stop(args): cancelled = [t for t in tickets if t["status"] == "cancelled"] incomplete = [t for t in tickets if t["status"] not in ("done", "cancelled")] - # Complete + # Auto-close: mark picked-up tickets (in_progress, review) as done. + # Work merged to main before sprint close means the ticket is done — + # agents just forget to update status. Backlog/ready tickets were + # never started, so they stay as carry-over candidates. + picked_up_statuses = ("in_progress", "review") + picked_up = [t for t in incomplete if t["status"] in picked_up_statuses] + auto_closed = [] + if picked_up: + conn = get_connection() + for t in picked_up: + conn.execute("UPDATE tickets SET status='done' WHERE id=?", (t["id"],)) + auto_closed.append(t) + conn.commit() + conn.close() + # Move auto-closed into done count, remove from incomplete + done = done + auto_closed + incomplete = [t for t in incomplete if t["status"] not in picked_up_statuses] + + # Complete the sprint conn = get_connection() conn.execute( "UPDATE sprints SET status='completed', end_date=date('now') WHERE id=?", @@ -372,10 +390,14 @@ def cmd_stop(args): print(f"Done: {len(done)}/{len(tickets)}") if cancelled: print(f"Cancelled: {len(cancelled)}") + if auto_closed: + print(f"Auto-closed: {len(auto_closed)} tickets marked done on sprint close:") + for t in auto_closed: + print(f" #{t['id']}: {t['title']} ({t['status']} → done)") print() if incomplete: - print("Carry-over candidates (incomplete):") + print("Carry-over candidates (never started):") format_ticket_table(incomplete) print()