You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(w21-24kl): batch 17 — CLI-native ticket health guards implementation
Add bug-close-reason guard to ticket-transition.sh: requires --reason
with "Fixed:" or "Escalated to user:" prefix when closing bug tickets.
Add open-children guard: blocks closing tickets with open children.
Add closed-parent guard to ticket-create.sh and ticket-link.sh (depends_on
only). Update ticket-cli-reference.md with --reason documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .tickets/dso-1459.md
+31-1Lines changed: 31 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
---
2
2
id: dso-1459
3
-
status: open
3
+
status: in_progress
4
4
deps: [dso-bdk5, dso-sroj]
5
5
links: []
6
6
created: 2026-03-23T17:34:49Z
@@ -19,3 +19,33 @@ parent: dso-k4sw
19
19
## Description
20
20
Add closed-parent guard to ticket-create.sh. After validating parent_id exists (lines 60-70), add: read parent status via ticket_read_status(). If status='closed', exit 1 with error: 'Cannot create child of closed ticket <parent_id>. Reopen the parent first.'
CHECKPOINT 5/6: Validation passed ✓ — all 33 tests pass (0 failures). Implementation required guards in both ticket-link.sh (bash _write_link_event) and ticket-graph.py (add_dependency), since ticket link command routes to ticket-graph.py.
52
+
53
+
**2026-03-23T19:48:39Z**
54
+
55
+
CHECKPOINT 6/6: Done ✓ — All 3 acceptance criteria satisfied.
- Optimistic concurrency: reads the actual current status inside an `fcntl.flock` lock and compares it to `current_status`. If they differ (another process changed the ticket since the caller last read it), exits non-zero with a conflict error.
283
284
- Idempotent: if `current_status == target_status`, exits 0 immediately with "No transition needed".
284
285
- Ghost-prevention: verifies the ticket directory and CREATE event exist before acquiring the lock.
286
+
- Bug-close guard: when `target_status=closed` and the ticket type is `bug`, `--reason` is required and must begin with `Fixed:` or `Escalated to user:`. Exits non-zero if missing or malformed.
287
+
- Open-children guard: when `target_status=closed`, checks for open (non-closed) child tickets. Exits non-zero listing the open children if any are found.
285
288
- On close (`target_status=closed`): runs `ticket-unblock.py` to detect newly unblocked tickets and prints `UNBLOCKED: <ids>` (or `UNBLOCKED: none`) to stdout.
286
289
287
290
**Exit codes:**
@@ -299,6 +302,13 @@ UNBLOCKED: none
299
302
300
303
$ ticket transition w21-a3f7 open closed
301
304
Error: current status is "in_progress", not "open"
305
+
306
+
# Closing a bug ticket requires --reason
307
+
$ ticket transition w21-b1c2 open closed
308
+
Error: closing a bug ticket requires --reason with prefix "Fixed:" or "Escalated to user:"
309
+
310
+
$ ticket transition w21-b1c2 open closed --reason "Fixed: corrected null check in parser"
0 commit comments