Module: Ace::Review::Molecules::DeltaResolver
- Defined in:
- lib/ace/review/molecules/delta_resolver.rb
Overview
Resolves and validates the reference head for a delta review round.
A delta round reviews only the diff between a reference head (an earlier reviewed commit) and the PR's current head. The reference is either given explicitly or auto-resolved from the most recent prior review session of the same PR. Every failure mode fails closed: no prior session, a non-ancestor reference (e.g. rewritten history) or missing local objects refuse the round instead of falling back to a full review.
Constant Summary collapse
- SHA_PATTERN =
/\A[0-9a-f]{40}\z/
Class Method Summary collapse
-
.latest_session_head(pr_url, project_root: nil) ⇒ Hash
Find the head SHA recorded by the most recent prior session of this PR.
-
.resolve(reference, pr_metadata, project_root: nil) ⇒ Hash
Resolve the reference head and compute the delta diff.
- .rev_parse(reference, project_root:) ⇒ Object
Class Method Details
.latest_session_head(pr_url, project_root: nil) ⇒ Hash
Find the head SHA recorded by the most recent prior session of this PR.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/ace/review/molecules/delta_resolver.rb', line 61 def self.latest_session_head(pr_url, project_root: nil) root = project_root || Dir.pwd sessions_dir = File.join(root, ".ace-local", "review", "sessions") return {success: false, error: (pr_url)} unless Dir.exist?(sessions_dir) candidates = Dir.glob(File.join(sessions_dir, "review-*")) .select { |path| File.directory?(path) } # Order by the session's own last write (metadata.yml), not the # directory entry — directory mtimes tie when sessions are created # within the same second. .sort_by { |path| -session_mtime(path).to_f } candidates.each do |dir| = File.join(dir, "metadata.yml") next unless File.file?() = YAML.safe_load_file(, permitted_classes: [Time, Date, Symbol]) next unless .is_a?(Hash) next unless ["pr_url"].to_s == pr_url head = .dig("diff_manifest", "head_sha") || .dig("diff_manifest", :head_sha) next unless head.to_s.match?(SHA_PATTERN) return {success: true, reference_head: head, session_dir: dir} end {success: false, error: (pr_url)} rescue Psych::Exception, Errno::ENOENT => e {success: false, error: "Cannot read prior review sessions for delta resolution: #{e.}"} end |
.resolve(reference, pr_metadata, project_root: nil) ⇒ Hash
Resolve the reference head and compute the delta diff.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/ace/review/molecules/delta_resolver.rb', line 27 def self.resolve(reference, , project_root: nil) head = ["headRefOid"].to_s return {success: false, error: "Delta review requires the PR head SHA"} unless head.match?(SHA_PATTERN) if reference == :auto || reference.nil? session = latest_session_head(["url"].to_s, project_root: project_root) return session unless session[:success] reference = session[:reference_head] session_dir = session[:session_dir] source = :session else source = :explicit end resolved = rev_parse(reference, project_root: project_root) return resolved unless resolved[:success] reference_head = resolved[:stdout] return {success: false, error: "Delta reference '#{reference}' is not a commit SHA"} unless reference_head.match?(SHA_PATTERN) return {success: false, error: "Delta reference head #{reference_head} is not an ancestor of the current PR head #{head}; history was likely rewritten — re-run a full review round"} unless ancestor?(reference_head, head, project_root: project_root) diff = run_git(["diff", "#{reference_head}..#{head}"], project_root: project_root) return diff unless diff[:success] {success: true, reference_head: reference_head, source: source, session_dir: session_dir, diff: diff[:stdout]} end |
.rev_parse(reference, project_root:) ⇒ Object
105 106 107 108 109 110 111 |
# File 'lib/ace/review/molecules/delta_resolver.rb', line 105 def self.rev_parse(reference, project_root:) result = run_git(["rev-parse", "#{reference}^{commit}"], project_root: project_root) return result unless result[:success] result[:stdout] = result[:stdout].strip result end |