Class: Ace::Git::Worktree::Molecules::ParentTaskResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/git/worktree/molecules/parent_task_resolver.rb

Overview

Parent task resolver molecule

Determines the target branch for a task’s PR by resolving the parent task’s worktree branch. This enables subtasks to target their orchestrator branch instead of defaulting to main.

Examples:

Resolve target branch for a subtask

resolver = ParentTaskResolver.new
target = resolver.resolve_target_branch(subtask_data)
target # => "202-rename-support-gems" or "main"

Constant Summary collapse

DEFAULT_TARGET =

Default fallback target branch when no parent is found

"main"
TASK_ID_PATTERN =

Regex pattern for extracting task number from full task ID Pattern: v.0.9.0+task.202.01 -> captures “202.01”

/task\.(\d+(?:\.\d+)?)\z/
SHA_PATTERN =

SHA pattern for detecting detached HEAD state Git returns 7-40 hex characters for SHAs (7 for short, 40 for full)

/\A[0-9a-f]{7,40}\z/i

Instance Method Summary collapse

Constructor Details

#initialize(project_root: Dir.pwd, task_fetcher: nil) ⇒ ParentTaskResolver

Initialize a new ParentTaskResolver

Parameters:

  • project_root (String) (defaults to: Dir.pwd)

    Project root directory

  • task_fetcher (TaskFetcher) (defaults to: nil)

    Optional TaskFetcher instance (for testing)



37
38
39
40
# File 'lib/ace/git/worktree/molecules/parent_task_resolver.rb', line 37

def initialize(project_root: Dir.pwd, task_fetcher: nil)
  @project_root = project_root
  @task_fetcher = task_fetcher || TaskFetcher.new
end

Instance Method Details

#extract_parent_branch(parent_data) ⇒ String

Extract parent’s worktree branch from task data

Implements a 3-level fallback priority chain for determining the target branch:

Priority 1: Parent worktree branch

- If parent task has worktree metadata with a branch, use that branch
- This enables subtasks to target their orchestrator's feature branch

Priority 2: Current branch fallback

- If parent has no worktree metadata, use the current branch
- Skipped if in detached HEAD state (SHA detected)
- Allows creating subtask worktrees from the parent's context

Priority 3: DEFAULT_TARGET (“main”)

- Final fallback when no branch context is available
- Ensures a valid target branch is always returned

Examples:

Parent with worktree metadata

extract_parent_branch({ worktree: { branch: "202-feature" } })
# => "202-feature"

Parent without worktree (uses current branch)

# When current branch is "develop"
extract_parent_branch({ id: "task.202" })
# => "develop"

Detached HEAD state (falls back to main)

# When in detached HEAD state
extract_parent_branch({ id: "task.202" })
# => "main"

Parameters:

  • parent_data (Hash)

    Parent task data hash

Returns:

  • (String)

    Parent’s worktree branch, current branch, or DEFAULT_TARGET



116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ace/git/worktree/molecules/parent_task_resolver.rb', line 116

def extract_parent_branch(parent_data)
  # Try parent worktree branch first
  if parent_data
    worktree_data = parent_data[:worktree] || parent_data["worktree"]
    if worktree_data.is_a?(Hash)
      branch = worktree_data[:branch] || worktree_data["branch"]
      return branch if branch
    end
  end

  # Fallback: current branch (if valid) or default
  current_branch_fallback || DEFAULT_TARGET
end

#load_parent_task(parent_id) ⇒ Hash?

Load parent task data

Parameters:

  • parent_id (String)

    Parent task ID (e.g., “202”)

Returns:

  • (Hash, nil)

    Parent task data or nil



77
78
79
80
81
# File 'lib/ace/git/worktree/molecules/parent_task_resolver.rb', line 77

def load_parent_task(parent_id)
  return nil unless parent_id

  @task_fetcher.fetch(parent_id)
end

#resolve_target_branch(task_data) ⇒ String

Resolve target branch for a task

Examples:

Subtask with parent

resolve_target_branch(subtask_data) # => "202-orchestrator-branch"

Orchestrator task (no parent)

resolve_target_branch(orchestrator_data) # => "main"

Parameters:

  • task_data (Hash)

    Task data hash from ace-task

Returns:

  • (String)

    Parent’s worktree branch or DEFAULT_TARGET



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/ace/git/worktree/molecules/parent_task_resolver.rb', line 52

def resolve_target_branch(task_data)
  return DEFAULT_TARGET unless task_data

  # Extract parent task ID from task ID
  parent_id = extract_parent_id(task_data[:id])
  unless parent_id
    # Non-subtask: use current branch (e.g., feature branch) instead of defaulting to main
    return current_branch_fallback || DEFAULT_TARGET
  end

  # Load parent task data
  parent_task = load_parent_task(parent_id)
  return DEFAULT_TARGET unless parent_task

  # Extract parent's worktree branch
  extract_parent_branch(parent_task)
rescue
  # Silently fall back to default - debugging info available via --verbose flag on CLI
  DEFAULT_TARGET
end