fix(types): add tombstone validation and block direct status update (bd-md2, bd-y68)

- Add validation in ValidateWithCustomStatuses() requiring deleted_at for tombstones
- Add validation that non-tombstones cannot have deleted_at set
- Block direct status update to tombstone in validateStatusWithCustom()
- Users must use 'bd delete' instead of 'bd update --status=tombstone'

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-05 15:41:35 -08:00
parent 08e43d9fc7
commit b689ea1b28
2 changed files with 13 additions and 0 deletions

View File

@@ -22,8 +22,14 @@ func validateStatus(value interface{}) error {
}
// validateStatusWithCustom validates a status value, allowing custom statuses.
// Note: tombstone status is blocked here (bd-y68) - use bd delete instead of bd update --status=tombstone
func validateStatusWithCustom(value interface{}, customStatuses []string) error {
if status, ok := value.(string); ok {
// Block direct status update to tombstone (bd-y68)
// Tombstones should only be created via bd delete, not bd update --status=tombstone
if types.Status(status) == types.StatusTombstone {
return fmt.Errorf("cannot set status to tombstone directly; use 'bd delete' instead")
}
if !types.Status(status).IsValidWithCustom(customStatuses) {
return fmt.Errorf("invalid status: %s", status)
}

View File

@@ -112,6 +112,13 @@ func (i *Issue) ValidateWithCustomStatuses(customStatuses []string) error {
if i.Status != StatusClosed && i.ClosedAt != nil {
return fmt.Errorf("non-closed issues cannot have closed_at timestamp")
}
// Enforce tombstone invariants (bd-md2): deleted_at must be set for tombstones, and only for tombstones
if i.Status == StatusTombstone && i.DeletedAt == nil {
return fmt.Errorf("tombstone issues must have deleted_at timestamp")
}
if i.Status != StatusTombstone && i.DeletedAt != nil {
return fmt.Errorf("non-tombstone issues cannot have deleted_at timestamp")
}
return nil
}