Class: HunkReviewChanges::Bundle

Inherits:
Object
  • Object
show all
Defined in:
lib/hunk_review_changes/bundle.rb

Overview

Loads and validates a bundle.json written by the companion skill. Validation exists to catch the exact failure modes the skill warns about (a malformed diff, missing pieces, non-sequential ids) and report them with a message the agent that wrote the bundle can act on, instead of a blank or broken page.

Defined Under Namespace

Classes: Error

Constant Summary collapse

STANCES =

The adversarial stances a piece's challenge may take, weakest to strongest. Shared so the validator, the viewer's badge map, and the export all agree on the same four strings instead of each carrying its own copy.

%w[concede nitpick concern blocking].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ Bundle

Returns a new instance of Bundle.



26
27
28
29
30
31
32
33
34
# File 'lib/hunk_review_changes/bundle.rb', line 26

def initialize(path)
  @path = path
  raise Error, "no such bundle: #{path}" unless File.exist?(path)

  @data = JSON.parse(File.read(path))
rescue JSON::ParserError => e
  raise Error, "bundle is not valid JSON (#{e.message}). " \
               "Write it with real JSON — no trailing commas or comments."
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



20
21
22
# File 'lib/hunk_review_changes/bundle.rb', line 20

def data
  @data
end

#pathObject (readonly)

Returns the value of attribute path.



20
21
22
# File 'lib/hunk_review_changes/bundle.rb', line 20

def path
  @path
end

Class Method Details

.load(path) ⇒ Object



22
23
24
# File 'lib/hunk_review_changes/bundle.rb', line 22

def self.load(path)
  new(path).tap(&:validate!)
end

Instance Method Details

#adversaryObject



40
# File 'lib/hunk_review_changes/bundle.rb', line 40

def adversary = data["adversary"]

#dirObject



41
# File 'lib/hunk_review_changes/bundle.rb', line 41

def dir = File.dirname(File.expand_path(path))

#fingerprintObject

Stable identity for this bundle's content, used to scope persisted review state so a reused directory never replays another bundle's comments.



45
# File 'lib/hunk_review_changes/bundle.rb', line 45

def fingerprint = Digest::SHA256.hexdigest(JSON.generate(data))

#framingObject



38
# File 'lib/hunk_review_changes/bundle.rb', line 38

def framing = data["framing"]

#piecesObject



39
# File 'lib/hunk_review_changes/bundle.rb', line 39

def pieces = data["pieces"]

#resolved_byObject



37
# File 'lib/hunk_review_changes/bundle.rb', line 37

def resolved_by = data["resolved_by"]

#targetObject



36
# File 'lib/hunk_review_changes/bundle.rb', line 36

def target = data["target"]

#validate!Object

Raises:



47
48
49
50
51
52
53
54
55
56
# File 'lib/hunk_review_changes/bundle.rb', line 47

def validate!
  raise Error, "bundle must be a JSON object with a \"pieces\" array" unless data.is_a?(Hash)

  list = data["pieces"]
  raise Error, "bundle has no \"pieces\" array" unless list.is_a?(Array)
  raise Error, "bundle \"pieces\" array is empty — nothing to review" if list.empty?

  list.each_with_index { |piece, index| validate_piece!(piece, index) }
  self
end