diff --git a/internal/storage/sqlite/resurrection.go b/internal/storage/sqlite/resurrection.go index 39b0cf21..1a4a2f11 100644 --- a/internal/storage/sqlite/resurrection.go +++ b/internal/storage/sqlite/resurrection.go @@ -224,17 +224,24 @@ func (s *SQLiteStorage) tryResurrectParentChainWithConn(ctx context.Context, con // extractParentChain returns all parent IDs in a hierarchical chain, ordered from root to leaf. // Example: "bd-abc.1.2" → ["bd-abc", "bd-abc.1"] +// Example: "test.example-abc.1" → ["test.example-abc"] (prefix with dot is preserved) +// +// This function uses IsHierarchicalID to correctly handle prefixes containing dots (GH#664). +// It only splits on dots followed by numeric suffixes (the hierarchy delimiter). func extractParentChain(id string) []string { - parts := strings.Split(id, ".") - if len(parts) <= 1 { - return nil // No parents (top-level ID) + var parents []string + current := id + + // Walk up the hierarchy by repeatedly finding the parent + for { + isHierarchical, parentID := IsHierarchicalID(current) + if !isHierarchical { + break // No more parents + } + // Prepend to build root-to-leaf order + parents = append([]string{parentID}, parents...) + current = parentID } - - parents := make([]string, 0, len(parts)-1) - for i := 1; i < len(parts); i++ { - parent := strings.Join(parts[:i], ".") - parents = append(parents, parent) - } - + return parents } diff --git a/internal/storage/sqlite/resurrection_test.go b/internal/storage/sqlite/resurrection_test.go index 49423420..aa7b5dcd 100644 --- a/internal/storage/sqlite/resurrection_test.go +++ b/internal/storage/sqlite/resurrection_test.go @@ -446,6 +446,27 @@ func TestExtractParentChain(t *testing.T) { id: "test-abc.1.2.3", expected: []string{"test-abc", "test-abc.1", "test-abc.1.2"}, }, + // GH#664: Prefixes with dots should be handled correctly + { + name: "prefix with dot - top-level", + id: "test.example-abc", + expected: nil, // No numeric suffix, not hierarchical + }, + { + name: "prefix with dot - one level deep", + id: "test.example-abc.1", + expected: []string{"test.example-abc"}, + }, + { + name: "prefix with dot - two levels deep", + id: "test.example-abc.1.2", + expected: []string{"test.example-abc", "test.example-abc.1"}, + }, + { + name: "prefix with multiple dots - one level deep", + id: "my.company.project-xyz.1", + expected: []string{"my.company.project-xyz"}, + }, } for _, tt := range tests {