Class: Vangrail::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/vangrail/result.rb

Overview

What a rail decided about one piece of text.

Three statuses, matching the contract the upstream toolkit settled on for standalone rail checks:

:passed    the text is cleared and unchanged
:modified  a rail rewrote the text; `content` carries the rewrite
:blocked   a rail stopped the turn; `content` carries the refusal, if any

Two states would be one too few. A rail that redacts a token from an answer has neither passed the text nor blocked the turn, and folding that into either one loses the fact that the reader is looking at edited output.

certain is orthogonal to status. A rail that is off, not enabled, or unreachable returns :passed with certain false, which is the difference between "checked and clean" and "not checked". Callers that report a safety posture read it; callers that only route on the decision can ignore it.

Constant Summary collapse

STATUSES =
%i[passed modified blocked].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(status:, rail:, content: nil, reason: nil, categories: [], model: nil, latency_ms: nil, raw: nil, certain: true) ⇒ Result

Returns a new instance of Result.

Raises:

  • (ArgumentError)


26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/vangrail/result.rb', line 26

def initialize(status:, rail:, content: nil, reason: nil, categories: [], model: nil,
               latency_ms: nil, raw: nil, certain: true)
  status = status.to_sym
  raise ArgumentError, "status must be one of #{STATUSES.join(', ')}" unless STATUSES.include?(status)

  @status = status
  @rail = rail
  @content = content
  @reason = reason
  @categories = Array(categories)
  @model = model
  @latency_ms = latency_ms
  @raw = raw
  @certain = certain
end

Instance Attribute Details

#categoriesObject (readonly)

Returns the value of attribute categories.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def categories
  @categories
end

#contentObject (readonly)

Returns the value of attribute content.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def content
  @content
end

#latency_msObject (readonly)

Returns the value of attribute latency_ms.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def latency_ms
  @latency_ms
end

#modelObject (readonly)

Returns the value of attribute model.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def model
  @model
end

#railObject (readonly)

Returns the value of attribute rail.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def rail
  @rail
end

#rawObject (readonly)

Returns the value of attribute raw.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def raw
  @raw
end

#reasonObject (readonly)

Returns the value of attribute reason.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def reason
  @reason
end

#statusObject (readonly)

Returns the value of attribute status.



24
25
26
# File 'lib/vangrail/result.rb', line 24

def status
  @status
end

Class Method Details

.blocked(rail:, **kwargs) ⇒ Object



50
51
52
# File 'lib/vangrail/result.rb', line 50

def self.blocked(rail:, **kwargs)
  new(status: :blocked, rail: rail, **kwargs)
end

.modified(rail:, content:, **kwargs) ⇒ Object



46
47
48
# File 'lib/vangrail/result.rb', line 46

def self.modified(rail:, content:, **kwargs)
  new(status: :modified, rail: rail, content: content, **kwargs)
end

.passed(rail:, **kwargs) ⇒ Object



42
43
44
# File 'lib/vangrail/result.rb', line 42

def self.passed(rail:, **kwargs)
  new(status: :passed, rail: rail, **kwargs)
end

.unchecked(rail:, reason:) ⇒ Object

No rail ran. Allowed, and explicitly not vouched for.



55
56
57
# File 'lib/vangrail/result.rb', line 55

def self.unchecked(rail:, reason:)
  new(status: :passed, rail: rail, certain: false, reason: reason)
end

Instance Method Details

#allowed?Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/vangrail/result.rb', line 71

def allowed?
  !blocked?
end

#blocked?Boolean

Returns:

  • (Boolean)


67
68
69
# File 'lib/vangrail/result.rb', line 67

def blocked?
  status == :blocked
end

#certain?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/vangrail/result.rb', line 75

def certain?
  @certain
end

#content_or(original) ⇒ Object

The text to carry forward: the rewrite when there is one, otherwise what the caller passed in.



81
82
83
# File 'lib/vangrail/result.rb', line 81

def content_or(original)
  modified? && !content.nil? ? content : original
end

#modified?Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/vangrail/result.rb', line 63

def modified?
  status == :modified
end

#passed?Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/vangrail/result.rb', line 59

def passed?
  status == :passed
end

#to_hObject



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/vangrail/result.rb', line 94

def to_h
  {
    'status' => status.to_s,
    'certain' => certain?,
    'rail' => rail&.to_s,
    'reason' => reason,
    'categories' => (categories unless categories.empty?),
    'model' => model,
    'latency_ms' => latency_ms
  }.compact
end

#to_sObject



106
107
108
109
110
111
112
# File 'lib/vangrail/result.rb', line 106

def to_s
  parts = ["#{rail}=#{status}"]
  parts << 'unchecked' unless certain?
  parts << categories.join(',') unless categories.empty?
  parts << reason if reason
  parts.join(' ')
end

#with_rail(name) ⇒ Object

A copy with a different rail name, for an engine reporting which of its rails produced a decision.



87
88
89
90
91
92
# File 'lib/vangrail/result.rb', line 87

def with_rail(name)
  self.class.new(
    status: status, rail: name, content: content, reason: reason, categories: categories,
    model: model, latency_ms: latency_ms, raw: raw, certain: certain?
  )
end