fix(validation): support hyphenated prefixes in ValidateIDFormat (#1013)

* test(validation): add failing tests for hyphenated prefix parsing

Reproduces bug where `bd create --parent` fails for projects with
hyphenated prefixes like "bead-me-up" or "web-app".

Root cause: ValidateIDFormat splits on first hyphen, so:
  "bead-me-up-3e9.1" → prefix "bead" (wrong, should be "bead-me-up")

The bug flow in create.go:
1. User runs: bd create "Child" --parent bead-me-up-3e9
2. GetNextChildID generates: bead-me-up-3e9.1
3. ValidateIDFormat extracts: "bead" (splits at first hyphen)
4. ValidatePrefix compares: "bead" vs "bead-me-up" → MISMATCH

Tests added:
- TestValidateIDFormat: 6 cases for hyphenated prefix IDs
- TestValidateIDFormat_ParentChildFlow: simulates exact --parent flow,
  showing simple prefixes pass while hyphenated prefixes fail

Workaround: use --force flag to bypass prefix validation.

* fix(validation): support hyphenated prefixes in ValidateIDFormat

Use utils.ExtractIssuePrefix instead of naive first-hyphen splitting.
This fixes bd create --parent failing for projects with hyphenated
prefixes like "bead-me-up" or "web-app".

Before: "bead-me-up-3e9" → prefix "bead" (wrong)
After:  "bead-me-up-3e9" → prefix "bead-me-up" (correct)

ExtractIssuePrefix uses smart heuristics: split on last hyphen,
check if suffix is hash-like (3-8 chars, alphanumeric, digits for 4+).

* Update internal/validation/bead_test.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Eugene Sukhodolin
2026-01-11 18:16:48 -08:00
committed by GitHub
parent 5941544a5e
commit d04bffb9b6
2 changed files with 101 additions and 3 deletions

View File

@@ -5,6 +5,7 @@ import (
"strings"
"github.com/steveyegge/beads/internal/types"
"github.com/steveyegge/beads/internal/utils"
)
// ParsePriority extracts and validates a priority value from content.
@@ -51,6 +52,7 @@ func ValidatePriority(priorityStr string) (int, error) {
// ValidateIDFormat validates that an ID has the correct format.
// Supports: prefix-number (bd-42), prefix-hash (bd-a3f8e9), or hierarchical (bd-a3f8e9.1)
// Also supports hyphenated prefixes like "bead-me-up-3e9" or "web-app-abc123".
// Returns the prefix part or an error if invalid.
func ValidateIDFormat(id string) (string, error) {
if id == "" {
@@ -62,9 +64,11 @@ func ValidateIDFormat(id string) (string, error) {
return "", fmt.Errorf("invalid ID format '%s' (expected format: prefix-hash or prefix-hash.number, e.g., 'bd-a3f8e9' or 'bd-a3f8e9.1')", id)
}
// Extract prefix (before the first hyphen)
hyphenIdx := strings.Index(id, "-")
prefix := id[:hyphenIdx]
// Use ExtractIssuePrefix which correctly handles hyphenated prefixes
// by looking at the last hyphen and checking if suffix is hash-like.
// This fixes the bug where "bead-me-up-3e9" was parsed as prefix "bead"
// instead of "bead-me-up".
prefix := utils.ExtractIssuePrefix(id)
return prefix, nil
}