Class: Ace::Review::Models::FeedbackItem

Inherits:
Object
  • Object
show all
Defined in:
lib/ace/review/models/feedback_item.rb

Overview

Represents a single feedback item from a code review.

FeedbackItem is an immutable data structure containing all information about a review finding, including its status, priority, and resolution.

Examples:

Creating a feedback item (multiple reviewers with consensus)

item = FeedbackItem.new(
  id: "8o7abcd123",
  title: "Missing error handling",
  files: ["src/handlers/user.rb:42-55"],
  reviewers: ["google:gemini-2.5-flash", "anthropic:claude-3.5-sonnet", "openai:gpt-4"],
  status: "pending",
  priority: "high",
  consensus: true,
  finding: "The error handling is incomplete..."
)

Creating a modified copy

resolved_item = item.dup_with(status: "done", resolution: "Added try-catch block")

Constant Summary collapse

VALID_STATUSES =

Valid status values for feedback items

%w[draft pending invalid skip done].freeze
VALID_PRIORITIES =

Valid priority values for feedback items

%w[critical high medium low].freeze
CONSENSUS_THRESHOLD =

Minimum number of reviewers for consensus

3

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(attrs = {}) ⇒ FeedbackItem

Initialize a new FeedbackItem from a hash of attributes

Parameters:

  • attrs (Hash) (defaults to: {})

    Attributes for the feedback item

Options Hash (attrs):

  • :id (String)

    10-character Base36 ID (6-char timestamp + 4-char random)

  • :title (String)

    Short description of the finding

  • :files (Array<String>)

    File references (path:line-range format)

  • :reviewers (Array<String>)

    LLM models that found this

  • :reviewer (String)

    Single reviewer string (converted to reviewers array)

  • :status (String)

    One of: draft, pending, invalid, skip, done

  • :priority (String)

    One of: critical, high, medium, low

  • :consensus (Boolean)

    True if 3+ models agree on this finding

  • :created (String)

    ISO8601 timestamp

  • :updated (String)

    ISO8601 timestamp

  • :finding (String)

    Original finding text

  • :context (String, nil)

    Additional context (optional)

  • :research (String, nil)

    Verification research (optional)

  • :resolution (String, nil)

    How it was resolved (optional)

Raises:

  • (ArgumentError)

    If status or priority values are invalid



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/ace/review/models/feedback_item.rb', line 59

def initialize(attrs = {})
  # Support both symbol and string keys
  attrs = symbolize_keys(attrs)

  @id = attrs[:id]
  @title = attrs[:title]
  @files = Array(attrs[:files])

  @reviewers = normalize_reviewers(attrs[:reviewers], attrs[:reviewer])

  @status = attrs[:status] || "draft"
  @priority = attrs[:priority] || "medium"
  @created = attrs[:created] || Time.now.utc.iso8601
  @updated = attrs[:updated] || @created
  @finding = attrs[:finding]
  @context = attrs[:context]
  @research = attrs[:research]
  @resolution = attrs[:resolution]

  # Consensus: true if 3+ models agree (can be explicitly set or computed)
  @consensus = attrs.key?(:consensus) ? attrs[:consensus] : (@reviewers.length >= CONSENSUS_THRESHOLD)

  validate!
  freeze_arrays
end

Instance Attribute Details

#consensusObject (readonly)

Returns the value of attribute consensus.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def consensus
  @consensus
end

#contextObject (readonly)

Returns the value of attribute context.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def context
  @context
end

#createdObject (readonly)

Returns the value of attribute created.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def created
  @created
end

#filesObject (readonly)

Returns the value of attribute files.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def files
  @files
end

#findingObject (readonly)

Returns the value of attribute finding.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def finding
  @finding
end

#idObject (readonly)

Returns the value of attribute id.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def id
  @id
end

#priorityObject (readonly)

Returns the value of attribute priority.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def priority
  @priority
end

#researchObject (readonly)

Returns the value of attribute research.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def research
  @research
end

#resolutionObject (readonly)

Returns the value of attribute resolution.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def resolution
  @resolution
end

#reviewersObject (readonly)

Returns the value of attribute reviewers.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def reviewers
  @reviewers
end

#statusObject (readonly)

Returns the value of attribute status.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def status
  @status
end

#titleObject (readonly)

Returns the value of attribute title.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def title
  @title
end

#updatedObject (readonly)

Returns the value of attribute updated.



38
39
40
# File 'lib/ace/review/models/feedback_item.rb', line 38

def updated
  @updated
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Check if two feedback items are equal

Parameters:

Returns:

  • (Boolean)

    True if equal



141
142
143
144
145
146
147
148
149
150
151
# File 'lib/ace/review/models/feedback_item.rb', line 141

def ==(other)
  return false unless other.is_a?(FeedbackItem)

  id == other.id &&
    title == other.title &&
    files == other.files &&
    reviewers == other.reviewers &&
    status == other.status &&
    priority == other.priority &&
    finding == other.finding
end

#dup_with(**changes) ⇒ FeedbackItem

Create a new FeedbackItem with modified attributes

Parameters:

  • changes (Hash)

    Attributes to change

Returns:



131
132
133
134
135
# File 'lib/ace/review/models/feedback_item.rb', line 131

def dup_with(**changes)
  # Auto-update the updated timestamp when making changes
  changes[:updated] ||= Time.now.utc.iso8601
  FeedbackItem.new(to_h.merge(stringify_keys(changes)))
end

#hashInteger

Hash code for use in hash tables

Returns:

  • (Integer)

    Hash code



158
159
160
# File 'lib/ace/review/models/feedback_item.rb', line 158

def hash
  [id, title, files, reviewers, status, priority, finding].hash
end

#reviewerString?

Accessor for single reviewer (returns first reviewer)

Returns:

  • (String, nil)

    First reviewer or nil if none



87
88
89
# File 'lib/ace/review/models/feedback_item.rb', line 87

def reviewer
  @reviewers.first
end

#to_hHash

Convert the feedback item to a hash

Returns:

  • (Hash)

    Hash representation with string keys



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/ace/review/models/feedback_item.rb', line 94

def to_h
  hash = {
    "id" => id,
    "title" => title,
    "files" => files.dup,
    "status" => status,
    "priority" => priority,
    "created" => created,
    "updated" => updated,
    "finding" => finding,
    "context" => context,
    "research" => research,
    "resolution" => resolution
  }

  # Use reviewers array if multiple reviewers, otherwise use singular reviewer key
  if @reviewers.length > 1
    hash["reviewers"] = @reviewers.dup
    hash["consensus"] = consensus if consensus
  else
    hash["reviewer"] = reviewer
  end

  hash.compact
end

#to_yamlString

Convert the feedback item to YAML

Returns:

  • (String)

    YAML representation



123
124
125
# File 'lib/ace/review/models/feedback_item.rb', line 123

def to_yaml
  to_h.to_yaml
end