Wire OrphanHandling through import pipeline (bd-8072)

- Added OrphanHandling type to sqlite package with 4 modes: strict/resurrect/skip/allow
- Updated EnsureIDs() to accept orphanHandling parameter and implement mode logic
- Added CreateIssuesWithOptions() that passes orphan handling through batch creation
- Made importer.OrphanHandling an alias to sqlite.OrphanHandling
- Importer now respects opts.OrphanHandling during batch issue creation

Next: Add import.orphan_handling config and wire through CLI commands
Amp-Thread-ID: https://ampcode.com/threads/T-bb7ffdd9-f444-4975-b5f7-bfff97cb92ff
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Steve Yegge
2025-11-04 23:53:44 -08:00
parent 09f2edafba
commit 0bf5c91cb3
4 changed files with 52 additions and 23 deletions

View File

@@ -6,7 +6,7 @@
{"id":"bd-28db","content_hash":"d5e519475ac57322f0ebe7a1f2499af199621f7cab7f7efcf5c4397845702766","title":"Add 'bd status' command for issue database overview","description":"Implement a bd status command that provides a quick snapshot of the issue database state, similar to how git status shows working tree state.\n\nExpected output: Show summary including counts by state (open, in-progress, blocked, closed), recent activity (last 7 days), and quick overview without needing multiple queries.\n\nExample output showing issue counts, recent activity stats, and pointer to bd list for details.\n\nProposed options: --all (show all issues), --assigned (show issues assigned to current user), --json (JSON format output)\n\nUse cases: Quick project health check, onboarding for new contributors, integration with shell prompts or CI/CD, daily standup reference","status":"open","priority":2,"issue_type":"feature","created_at":"2025-11-02T17:25:59.203549-08:00","updated_at":"2025-11-02T17:25:59.203549-08:00"}
{"id":"bd-307","content_hash":"2cc113604477642fff079015c84a0fea383a02c8f80a6ffc645c431e6e0517d4","title":"Multi-repo hydration layer","description":"Build core infrastructure to hydrate database from N repos (N≥1), with smart caching via file mtime tracking and routing writes to correct JSONL based on source_repo metadata.","design":"Components:\n- Config schema for repos.additional\n- source_repo metadata field (which repo owns each issue)\n- Hydration logic (read from N JSONLs)\n- Write routing (write to correct JSONL)\n- Smart caching (file mtime tracking to avoid re-parsing)\n- SQLite DB as cache layer","acceptance_criteria":"1. Can configure N repos via config.toml\n2. Database hydrates from all configured repos\n3. Writes route to correct JSONL via source_repo\n4. File mtime caching prevents re-parsing unchanged JSONLs\n5. Query performance \u003c100ms even with 5-10 polling interval\n6. N=1 (single repo) works unchanged","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-11-04T11:21:30.655765-08:00","updated_at":"2025-11-04T23:30:03.371715-08:00","closed_at":"2025-11-04T23:30:03.371715-08:00","dependencies":[{"issue_id":"bd-307","depends_on_id":"bd-4ms","type":"parent-child","created_at":"2025-11-04T11:22:21.823652-08:00","created_by":"daemon"}]}
{"id":"bd-3433","content_hash":"bbe4dc610fa35560d1b9bcfff3450f7e712235f3f34e3bb4de2272d66c83382f","title":"Implement topological sort for import ordering","description":"Refactor upsertIssues() to sort issues by hierarchy depth before batch creation. Ensures parents are created before children, fixing latent bug where parent-child pairs in same batch can fail if ordered wrong. Sort by dot count, create in depth-order batches (0→1→2→3).","status":"closed","priority":0,"issue_type":"task","created_at":"2025-11-04T12:31:42.22005-08:00","updated_at":"2025-11-04T23:30:03.410678-08:00","closed_at":"2025-11-04T23:30:03.410678-08:00"}
{"id":"bd-37dd","content_hash":"626b5d0931c1a926de172b42e594ae9f9b87fbb9ea026bc3f3763cba695db9fd","title":"Add topological sort utility functions","description":"Create internal/importer/sort.go with utilities for depth-based sorting of issues. Functions: GetHierarchyDepth(id), SortByDepth(issues), GroupByDepth(issues). Include stable sorting for same-depth issues.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:31:42.309207-08:00","updated_at":"2025-11-04T12:31:42.309207-08:00"}
{"id":"bd-37dd","content_hash":"626b5d0931c1a926de172b42e594ae9f9b87fbb9ea026bc3f3763cba695db9fd","title":"Add topological sort utility functions","description":"Create internal/importer/sort.go with utilities for depth-based sorting of issues. Functions: GetHierarchyDepth(id), SortByDepth(issues), GroupByDepth(issues). Include stable sorting for same-depth issues.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-04T12:31:42.309207-08:00","updated_at":"2025-11-04T23:38:04.837251-08:00","closed_at":"2025-11-04T23:38:04.837251-08:00"}
{"id":"bd-3852","content_hash":"bc2640e4d1c60e0b7a7c3b6d49cb05292f50facb5d4ea3887ba8c414aa7ffef3","title":"Add orphan detection migration","description":"Create migration to detect orphaned children in existing databases. Query: SELECT id FROM issues WHERE id LIKE '%.%' AND substr(id, 1, instr(id || '.', '.') - 1) NOT IN (SELECT id FROM issues). Log results, let user decide action (delete orphans or convert to top-level).","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-04T12:32:30.727044-08:00","updated_at":"2025-11-04T12:32:30.727044-08:00"}
{"id":"bd-3b2fe268","content_hash":"60b24230230cb6c49c45d7439787ee8a748164dfc9629946653814d447ea8c1a","title":"Add fsnotify dependency to go.mod","description":"","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-28T16:20:02.429763-07:00","updated_at":"2025-10-31T20:36:49.310833-07:00"}
{"id":"bd-3f80d9e0","content_hash":"10716746db7f5efcb9380e184d3ae8abfefd5b84d500340899e13e3b81d4e02a","title":"Improve internal/daemon test coverage (currently 22.5%)","description":"Daemon functionality needs better coverage:\n- Auto-start behavior\n- Lock file management\n- Discovery mechanisms\n- Connection handling\n- Error recovery","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:30.832728-07:00","updated_at":"2025-10-30T17:12:58.186077-07:00"}
@@ -32,7 +32,7 @@
{"id":"bd-7bbc4e6a","content_hash":"3251d757d9ad69cd4b3517862ec1b9b1cc13388ea4c93a2f3b2b54920112854f","title":"Add MCP server functions for repair commands","description":"Expose new repair commands via MCP server for agent access:\n\nFunctions to add:\n- beads_repair_deps()\n- beads_detect_pollution()\n- beads_validate()\n- beads_resolve_conflicts() (when implemented)\n\nUpdate integrations/beads-mcp/src/beads_mcp/server.py\n\nSee repair_commands.md lines 803-884 for design.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T19:37:55.72639-07:00","updated_at":"2025-10-30T17:12:58.179948-07:00"}
{"id":"bd-7kua","content_hash":"2dedc0d0d5444db45ab146cc59f3c51bc4bfc3c864da43d3c086a9153613c29f","title":"Reduce sync rounds in multiclone tests","description":"Analyze and reduce the number of sync rounds in hash multiclone tests.\n\nCurrent state:\n- TestHashIDs_MultiCloneConverge: 1 round of syncs across 3 clones\n- TestHashIDs_IdenticalContentDedup: 2 rounds across 2 clones\n\nInvestigation needed:\n- Profile to see how much time each sync takes\n- Determine minimum rounds needed for convergence\n- Consider making rounds configurable via env var\n\nFile: beads_hash_multiclone_test.go:70, :132","status":"closed","priority":2,"issue_type":"task","created_at":"2025-11-04T01:24:18.405038-08:00","updated_at":"2025-11-04T10:26:34.449434-08:00","closed_at":"2025-11-04T10:26:34.449434-08:00","dependencies":[{"issue_id":"bd-7kua","depends_on_id":"bd-l5gq","type":"blocks","created_at":"2025-11-04T01:24:18.405883-08:00","created_by":"daemon"}]}
{"id":"bd-8072","content_hash":"b203c5097ad16f89fd84c4c409888e7ae19d07c91b3359db8350193dc9389fe9","title":"Add import.orphan_handling config option","description":"Add configuration option to control orphan handling behavior: 'strict' (fail on missing parent, current behavior), 'resurrect' (auto-resurrect from JSONL, recommended default), 'skip' (skip orphaned issues with warning), 'allow' (import orphans without validation). Update CONFIG.md documentation.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:08.569239-08:00","updated_at":"2025-11-04T12:32:08.569239-08:00"}
{"id":"bd-812a","content_hash":"927e20d2ed3e9f5ef27e30776b2a5eee0afb977dda097c4fdcb6bbf69bf825f2","title":"Add unit tests for import ordering","description":"Test topological sort: import [child, parent] should succeed, import [parent.1.2, parent, parent.1] should sort correctly. Verify depth-based batching works. Test max depth limits.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:21.278448-08:00","updated_at":"2025-11-04T12:32:21.278448-08:00"}
{"id":"bd-812a","content_hash":"927e20d2ed3e9f5ef27e30776b2a5eee0afb977dda097c4fdcb6bbf69bf825f2","title":"Add unit tests for import ordering","description":"Test topological sort: import [child, parent] should succeed, import [parent.1.2, parent, parent.1] should sort correctly. Verify depth-based batching works. Test max depth limits.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:21.278448-08:00","updated_at":"2025-11-04T23:38:11.456985-08:00","closed_at":"2025-11-04T23:38:11.456985-08:00"}
{"id":"bd-824","content_hash":"c6895598595873d74698771b8687ffbd60999120fed85a5c1d7c2176d7d2976f","title":"Add migration guide for library consumers","description":"The contributor-workflow-analysis.md has excellent migration examples for CLI users (lines 508-549) but lacks examples for library consumers like VC that use beadsLib in Go/TypeScript code.\n\nLibrary consumers need to know:\n- Whether their existing code continues to work unchanged (backward compatibility)\n- How config.toml is automatically read (transparent hydration)\n- When and how to use explicit multi-repo configuration\n- What happens if config.toml doesn't exist (defaults)\n\nExample needed:\n```go\n// Before (v0.17.3)\nstore, err := beadsLib.NewSQLiteStorage(\".beads/vc.db\")\n\n// After (v0.18.0 with multi-repo) - still works!\nstore, err := beadsLib.NewSQLiteStorage(\".beads/vc.db\")\n// Automatically reads .beads/config.toml if present\n\n// Explicit multi-repo (if needed)\ncfg := beadsLib.Config{\n Primary: \".beads/vc.db\",\n Additional: []string{\"~/.beads-planning\"},\n}\nstore, err := beadsLib.NewStorageWithConfig(cfg)\n```","acceptance_criteria":"- Section added to contributor-workflow-analysis.md for library consumers\n- Code examples showing backward compatibility\n- Code examples showing explicit multi-repo configuration\n- Guidance on when library consumers should use multi-repo vs single-repo","status":"open","priority":2,"issue_type":"task","created_at":"2025-11-03T20:24:17.748337-08:00","updated_at":"2025-11-03T20:24:17.748337-08:00"}
{"id":"bd-833559b3","content_hash":"e75bad8689c6372ea7096401604ae998028b81551887f7164556917f4b123eef","title":"bd validate - Comprehensive health check","description":"Run all validation checks in one command.\n\nChecks:\n- Duplicates\n- Orphaned dependencies\n- Test pollution\n- Git conflicts\n\nSupports --fix-all for auto-repair.\n\nDepends on bd-cbed9619.1, bd-0dcea000, bd-2752a7a2, bd-9826b69a.\n\nFiles: cmd/bd/validate.go (new)","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-29T20:02:47.957692-07:00","updated_at":"2025-10-30T17:12:58.219095-07:00"}
{"id":"bd-85487065","content_hash":"637cbd56af122b175ff060b4df050871fe86124c5d883ba7f8a17f2f95479613","title":"Add tests for internal/autoimport package","description":"Currently 0.0% coverage. Need tests for auto-import functionality that detects and imports updated JSONL files.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-29T14:06:18.154805-07:00","updated_at":"2025-10-30T17:12:58.182987-07:00"}
@@ -57,7 +57,7 @@
{"id":"bd-b92a","content_hash":"e11921f05c84d5fb5fc9d2ca53ac821a2083b307a82e316265d688f063a37152","title":"Wire config to import pipeline","description":"Connect import.orphan_handling config to importer.go and sqlite validation functions. Pass mode flag through call chain. Implement all four modes (strict/resurrect/skip/allow) with proper error messages and logging.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:08.612142-08:00","updated_at":"2025-11-04T12:32:08.612142-08:00"}
{"id":"bd-bb08","content_hash":"6297b83658ee14e0a8cc77451ed25036cff62df65da013e0f63f37250f2313b1","title":"Add ON DELETE CASCADE to child_counters schema","description":"Update schema.go child_counters table foreign key with ON DELETE CASCADE. When parent deleted, child counter should also be deleted. If parent is resurrected, counter gets recreated from scratch. Add migration for existing databases.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:30.681452-08:00","updated_at":"2025-11-04T12:32:30.681452-08:00"}
{"id":"bd-bc2c6191","content_hash":"533e56b8628e24229a4beb52f8683355f6ca699e34a73650bf092003d73c2957","title":"Audit Current Cache Usage","description":"Understand exactly what code depends on the storage cache","acceptance_criteria":"- Document showing all cache dependencies\n- Confirmation that removing cache won't break MCP\n- List of tests that need updating\n\nFiles to examine:\n- internal/rpc/server_cache_storage.go (cache implementation)\n- internal/rpc/client.go (how req.Cwd is set)\n- internal/rpc/server_*.go (all getStorageForRequest calls)\n- integrations/beads-mcp/ (MCP multi-repo logic)\n\nTasks:\n- Document all callers of getStorageForRequest()\n- Verify req.Cwd is only set by RPC client for database discovery\n- Confirm MCP server doesn't rely on multi-repo cache behavior\n- Check if any tests assume multi-repo routing\n- Review environment variables: BEADS_DAEMON_MAX_CACHE_SIZE, BEADS_DAEMON_CACHE_TTL, BEADS_DAEMON_MEMORY_THRESHOLD_MB","status":"open","priority":1,"issue_type":"task","created_at":"2025-10-27T23:02:43.506373-07:00","updated_at":"2025-10-31T20:36:49.334214-07:00"}
{"id":"bd-c13f","content_hash":"5a7dc56e5591037db3d3b57898d67e37a05f061af0cab3ef6ac98d0af4963086","title":"Add unit tests for parent resurrection","description":"Test resurrection with deleted parent (should succeed), resurrection with never-existed parent (should fail gracefully), multi-level resurrection (bd-abc.1.2 with both parents missing). Verify tombstone creation and is_tombstone flag.","status":"open","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:21.325335-08:00","updated_at":"2025-11-04T12:32:21.325335-08:00"}
{"id":"bd-c13f","content_hash":"5a7dc56e5591037db3d3b57898d67e37a05f061af0cab3ef6ac98d0af4963086","title":"Add unit tests for parent resurrection","description":"Test resurrection with deleted parent (should succeed), resurrection with never-existed parent (should fail gracefully), multi-level resurrection (bd-abc.1.2 with both parents missing). Verify tombstone creation and is_tombstone flag.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-04T12:32:21.325335-08:00","updated_at":"2025-11-04T23:38:11.470441-08:00","closed_at":"2025-11-04T23:38:11.470441-08:00"}
{"id":"bd-c825f867","content_hash":"27cecaa2dc6cdabb2ae77fd65fbf8dca8f4c536bdf140a13b25cdd16376c9845","title":"Add docs/architecture/event_driven.md","description":"Copy event_driven_daemon.md into docs/ folder. Add to documentation index.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T16:20:02.431399-07:00","updated_at":"2025-10-30T17:12:58.221939-07:00"}
{"id":"bd-c9a482db","content_hash":"35c1ad124187c21b4e8dae7db46ea5d00173d33234a9b815ded7dcf0ab51078e","title":"Add internal/ai package for AI-assisted repairs","description":"Add AI integration package to support AI-powered repair commands.\n\nProviders:\n- Anthropic (Claude)\n- OpenAI\n- Ollama (local)\n\nFeatures:\n- Conflict resolution analysis\n- Duplicate detection via embeddings\n- Configuration via env vars (BEADS_AI_PROVIDER, BEADS_AI_API_KEY, etc.)\n\nSee repair_commands.md lines 357-425 for design.","status":"open","priority":2,"issue_type":"task","created_at":"2025-10-28T19:37:55.722841-07:00","updated_at":"2025-10-30T17:12:58.180177-07:00"}
{"id":"bd-caa9","content_hash":"6e8d4006d4f9b265e63fad9e30f24c6ab29fbf79ef47ec90a7e1225b5d662b67","title":"Migration tool for existing users","description":"Ensure smooth migration for existing users to separate branch workflow.\n\nTasks:\n- Add bd migrate --separate-branch command\n- Detect existing repos, migrate cleanly\n- Preserve git history\n- Add rollback mechanism\n- Test migration on beads' own repo (dogfooding)\n- Communication plan (GitHub discussion, docs)\n- Version compatibility checks\n\nEstimated effort: 2-3 days","acceptance_criteria":"- Existing users can migrate without data loss\n- Rollback works if migration fails\n- Clear communication about breaking changes (if any)\n- beads project itself migrated successfully (dogfooding)\n- Migration tested on 5+ real-world repos","status":"closed","priority":1,"issue_type":"task","created_at":"2025-11-02T15:22:35.627388-08:00","updated_at":"2025-11-04T12:36:53.789201-08:00","closed_at":"2025-11-04T12:36:53.789201-08:00","dependencies":[{"issue_id":"bd-caa9","depends_on_id":"bd-a101","type":"parent-child","created_at":"2025-11-02T15:22:48.382619-08:00","created_by":"stevey"}]}

View File

@@ -13,18 +13,18 @@ import (
"github.com/steveyegge/beads/internal/utils"
)
// OrphanHandling defines how to handle missing parent issues during import
type OrphanHandling string
// OrphanHandling is an alias to sqlite.OrphanHandling for convenience
type OrphanHandling = sqlite.OrphanHandling
const (
// OrphanStrict fails import on missing parent (safest)
OrphanStrict OrphanHandling = "strict"
OrphanStrict = sqlite.OrphanStrict
// OrphanResurrect auto-resurrects missing parents from JSONL history
OrphanResurrect OrphanHandling = "resurrect"
OrphanResurrect = sqlite.OrphanResurrect
// OrphanSkip skips orphaned issues with warning
OrphanSkip OrphanHandling = "skip"
OrphanSkip = sqlite.OrphanSkip
// OrphanAllow imports orphans without validation (default, works around bugs)
OrphanAllow OrphanHandling = "allow"
OrphanAllow = sqlite.OrphanAllow
)
// Options contains import configuration
@@ -566,14 +566,14 @@ if len(newIssues) > 0 {
// Create in batches by depth level (max depth 3)
for depth := 0; depth <= 3; depth++ {
var batchForDepth []*types.Issue
for _, issue := range newIssues {
if strings.Count(issue.ID, ".") == depth {
batchForDepth = append(batchForDepth, issue)
var batchForDepth []*types.Issue
for _, issue := range newIssues {
if strings.Count(issue.ID, ".") == depth {
batchForDepth = append(batchForDepth, issue)
}
}
if len(batchForDepth) > 0 {
if err := sqliteStore.CreateIssues(ctx, batchForDepth, "import"); err != nil {
if err := sqliteStore.CreateIssuesWithOptions(ctx, batchForDepth, "import", opts.OrphanHandling); err != nil {
return fmt.Errorf("error creating depth-%d issues: %w", depth, err)
}
result.Created += len(batchForDepth)

View File

@@ -33,7 +33,7 @@ func validateBatchIssues(issues []*types.Issue) error {
}
// generateBatchIDs generates IDs for all issues that need them atomically
func (s *SQLiteStorage) generateBatchIDs(ctx context.Context, conn *sql.Conn, issues []*types.Issue, actor string) error {
func (s *SQLiteStorage) generateBatchIDs(ctx context.Context, conn *sql.Conn, issues []*types.Issue, actor string, orphanHandling OrphanHandling) error {
// Get prefix from config (needed for both generation and validation)
var prefix string
err := conn.QueryRowContext(ctx, `SELECT value FROM config WHERE key = ?`, "issue_prefix").Scan(&prefix)
@@ -45,7 +45,7 @@ func (s *SQLiteStorage) generateBatchIDs(ctx context.Context, conn *sql.Conn, is
}
// Generate or validate IDs for all issues
if err := EnsureIDs(ctx, conn, prefix, issues, actor); err != nil {
if err := EnsureIDs(ctx, conn, prefix, issues, actor, orphanHandling); err != nil {
return err
}
@@ -122,6 +122,12 @@ func bulkMarkDirty(ctx context.Context, conn *sql.Conn, issues []*types.Issue) e
// - Single issue creation (use CreateIssue for simplicity)
// - Interactive user operations (use CreateIssue)
func (s *SQLiteStorage) CreateIssues(ctx context.Context, issues []*types.Issue, actor string) error {
// Default to OrphanResurrect for backward compatibility
return s.CreateIssuesWithOptions(ctx, issues, actor, OrphanResurrect)
}
// CreateIssuesWithOptions creates multiple issues with configurable orphan handling
func (s *SQLiteStorage) CreateIssuesWithOptions(ctx context.Context, issues []*types.Issue, actor string, orphanHandling OrphanHandling) error {
if len(issues) == 0 {
return nil
}
@@ -150,7 +156,7 @@ func (s *SQLiteStorage) CreateIssues(ctx context.Context, issues []*types.Issue,
}()
// Phase 3: Generate IDs for issues that need them
if err := s.generateBatchIDs(ctx, conn, issues, actor); err != nil {
if err := s.generateBatchIDs(ctx, conn, issues, actor, orphanHandling); err != nil {
return err
}

View File

@@ -183,11 +183,21 @@ func tryResurrectParent(parentID string, issues []*types.Issue) bool {
return false // Parent not in this batch
}
// OrphanHandling defines how to handle missing parent issues during import
type OrphanHandling string
const (
OrphanStrict OrphanHandling = "strict" // Fail import on missing parent
OrphanResurrect OrphanHandling = "resurrect" // Auto-resurrect from batch
OrphanSkip OrphanHandling = "skip" // Skip orphaned issues
OrphanAllow OrphanHandling = "allow" // Allow orphans (default)
)
// EnsureIDs generates or validates IDs for issues
// For issues with empty IDs, generates unique hash-based IDs
// For issues with existing IDs, validates they match the prefix and parent exists (if hierarchical)
// For hierarchical IDs with missing parents, attempts resurrection from the import batch
func EnsureIDs(ctx context.Context, conn *sql.Conn, prefix string, issues []*types.Issue, actor string) error {
// For hierarchical IDs with missing parents, behavior depends on orphanHandling mode
func EnsureIDs(ctx context.Context, conn *sql.Conn, prefix string, issues []*types.Issue, actor string, orphanHandling OrphanHandling) error {
usedIDs := make(map[string]bool)
// First pass: record explicitly provided IDs
@@ -210,11 +220,24 @@ func EnsureIDs(ctx context.Context, conn *sql.Conn, prefix string, issues []*typ
return fmt.Errorf("failed to check parent existence: %w", err)
}
if parentCount == 0 {
// Try to resurrect parent from import batch
if !tryResurrectParent(parentID, issues) {
return fmt.Errorf("parent issue %s does not exist and cannot be resurrected from import batch", parentID)
// Handle missing parent based on mode
switch orphanHandling {
case OrphanStrict:
return fmt.Errorf("parent issue %s does not exist (strict mode)", parentID)
case OrphanResurrect:
if !tryResurrectParent(parentID, issues) {
return fmt.Errorf("parent issue %s does not exist and cannot be resurrected from import batch", parentID)
}
// Parent will be created in this batch (due to depth-sorting), so allow this child
case OrphanSkip:
// Mark issue for skipping by clearing its ID (will be filtered out later)
issues[i].ID = ""
continue
case OrphanAllow:
// Allow orphan - no validation
default:
// Default to allow for backward compatibility
}
// Parent will be created in this batch (due to depth-sorting), so allow this child
}
}