lex-cognitive-debugging 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +11 -0
- data/LICENSE +21 -0
- data/README.md +65 -0
- data/lex-cognitive-debugging.gemspec +30 -0
- data/lib/legion/extensions/cognitive_debugging/client.rb +26 -0
- data/lib/legion/extensions/cognitive_debugging/helpers/causal_trace.rb +47 -0
- data/lib/legion/extensions/cognitive_debugging/helpers/constants.rb +54 -0
- data/lib/legion/extensions/cognitive_debugging/helpers/correction.rb +52 -0
- data/lib/legion/extensions/cognitive_debugging/helpers/debugging_engine.rb +152 -0
- data/lib/legion/extensions/cognitive_debugging/helpers/reasoning_error.rb +93 -0
- data/lib/legion/extensions/cognitive_debugging/runners/cognitive_debugging.rb +174 -0
- data/lib/legion/extensions/cognitive_debugging/version.rb +9 -0
- data/lib/legion/extensions/cognitive_debugging.rb +17 -0
- data/spec/legion/extensions/cognitive_debugging/client_spec.rb +46 -0
- data/spec/legion/extensions/cognitive_debugging/helpers/causal_trace_spec.rb +84 -0
- data/spec/legion/extensions/cognitive_debugging/helpers/constants_spec.rb +97 -0
- data/spec/legion/extensions/cognitive_debugging/helpers/correction_spec.rb +98 -0
- data/spec/legion/extensions/cognitive_debugging/helpers/debugging_engine_spec.rb +290 -0
- data/spec/legion/extensions/cognitive_debugging/helpers/reasoning_error_spec.rb +164 -0
- data/spec/legion/extensions/cognitive_debugging/runners/cognitive_debugging_spec.rb +301 -0
- data/spec/spec_helper.rb +26 -0
- metadata +82 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Helpers::DebuggingEngine do
|
|
4
|
+
subject(:engine) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:base_error_args) do
|
|
7
|
+
{
|
|
8
|
+
error_type: :inconsistency,
|
|
9
|
+
description: 'Claim A contradicts Claim B',
|
|
10
|
+
severity: 0.6,
|
|
11
|
+
source_phase: :prediction_engine,
|
|
12
|
+
confidence_at_detection: 0.8
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_error(overrides = {})
|
|
17
|
+
engine.detect_error(**base_error_args, **overrides)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#initialize' do
|
|
21
|
+
it 'starts with empty errors' do
|
|
22
|
+
expect(engine.errors).to be_empty
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'starts with empty traces' do
|
|
26
|
+
expect(engine.traces).to be_empty
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'starts with empty corrections' do
|
|
30
|
+
expect(engine.corrections).to be_empty
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#detect_error' do
|
|
35
|
+
it 'creates and stores a ReasoningError' do
|
|
36
|
+
err = add_error
|
|
37
|
+
expect(err).to be_a(Legion::Extensions::CognitiveDebugging::Helpers::ReasoningError)
|
|
38
|
+
expect(engine.errors[err.id]).to be(err)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'returns nil for invalid error_type' do
|
|
42
|
+
result = engine.detect_error(**base_error_args, error_type: :not_real)
|
|
43
|
+
expect(result).to be_nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'assigns unique ids to multiple errors' do
|
|
47
|
+
e1 = add_error
|
|
48
|
+
e2 = add_error(error_type: :circular_logic)
|
|
49
|
+
expect(e1.id).not_to eq(e2.id)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'stores all valid error types without error' do
|
|
53
|
+
Legion::Extensions::CognitiveDebugging::Helpers::Constants::ERROR_TYPES.each do |type|
|
|
54
|
+
result = engine.detect_error(**base_error_args, error_type: type)
|
|
55
|
+
expect(result).not_to be_nil
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe '#trace_error' do
|
|
61
|
+
let(:err) { add_error }
|
|
62
|
+
|
|
63
|
+
it 'creates a CausalTrace and links it to the error' do
|
|
64
|
+
steps = [{ phase: :prediction_engine, description: 'Overconfident prior' }]
|
|
65
|
+
trace = engine.trace_error(error_id: err.id, steps: steps, root_cause: :bad_prior, confidence: 0.7)
|
|
66
|
+
expect(trace).to be_a(Legion::Extensions::CognitiveDebugging::Helpers::CausalTrace)
|
|
67
|
+
expect(err.trace_ids).to include(trace.id)
|
|
68
|
+
expect(err.status).to eq(:traced)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'returns nil for unknown error_id' do
|
|
72
|
+
result = engine.trace_error(error_id: 'nope', steps: [], root_cause: :unknown, confidence: 0.5)
|
|
73
|
+
expect(result).to be_nil
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'stores the trace in the engine' do
|
|
77
|
+
steps = [{ phase: :tick, description: 'step 1' }]
|
|
78
|
+
trace = engine.trace_error(error_id: err.id, steps: steps, root_cause: :loop, confidence: 0.5)
|
|
79
|
+
expect(engine.traces[trace.id]).to be(trace)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'builds steps correctly' do
|
|
83
|
+
steps = [
|
|
84
|
+
{ phase: :emotional_evaluation, description: 'First step' },
|
|
85
|
+
{ phase: :memory_retrieval, description: 'Second step' }
|
|
86
|
+
]
|
|
87
|
+
trace = engine.trace_error(error_id: err.id, steps: steps, root_cause: :bias, confidence: 0.8)
|
|
88
|
+
expect(trace.depth).to eq(2)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe '#propose_correction' do
|
|
93
|
+
let(:err) { add_error }
|
|
94
|
+
|
|
95
|
+
it 'creates a Correction and links it to the error' do
|
|
96
|
+
correction = engine.propose_correction(error_id: err.id, strategy: :retrace,
|
|
97
|
+
description: 'Retrace reasoning path')
|
|
98
|
+
expect(correction).to be_a(Legion::Extensions::CognitiveDebugging::Helpers::Correction)
|
|
99
|
+
expect(err.correction_ids).to include(correction.id)
|
|
100
|
+
expect(err.status).to eq(:correcting)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'returns nil for invalid strategy' do
|
|
104
|
+
result = engine.propose_correction(error_id: err.id, strategy: :not_a_strategy, description: 'x')
|
|
105
|
+
expect(result).to be_nil
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'returns nil for unknown error_id' do
|
|
109
|
+
result = engine.propose_correction(error_id: 'nope', strategy: :retrace, description: 'x')
|
|
110
|
+
expect(result).to be_nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it 'stores correction in engine' do
|
|
114
|
+
correction = engine.propose_correction(error_id: err.id, strategy: :reframe, description: 'reframe it')
|
|
115
|
+
expect(engine.corrections[correction.id]).to be(correction)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe '#apply_correction' do
|
|
120
|
+
it 'marks correction as applied' do
|
|
121
|
+
err = add_error
|
|
122
|
+
correction = engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'x')
|
|
123
|
+
engine.apply_correction(correction_id: correction.id)
|
|
124
|
+
expect(correction.applied).to be true
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it 'returns nil for unknown correction_id' do
|
|
128
|
+
expect(engine.apply_correction(correction_id: 'nope')).to be_nil
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe '#measure_correction' do
|
|
133
|
+
it 'sets effectiveness on the correction' do
|
|
134
|
+
err = add_error
|
|
135
|
+
correction = engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'x')
|
|
136
|
+
engine.measure_correction(correction_id: correction.id, effectiveness: 0.85)
|
|
137
|
+
expect(correction.effectiveness).to eq(0.85)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it 'returns nil for unknown correction_id' do
|
|
141
|
+
expect(engine.measure_correction(correction_id: 'nope', effectiveness: 0.5)).to be_nil
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe '#resolve_error' do
|
|
146
|
+
it 'resolves the error' do
|
|
147
|
+
err = add_error
|
|
148
|
+
engine.resolve_error(error_id: err.id)
|
|
149
|
+
expect(err.status).to eq(:resolved)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'returns nil for unknown error_id' do
|
|
153
|
+
expect(engine.resolve_error(error_id: 'nope')).to be_nil
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe '#active_errors' do
|
|
158
|
+
it 'returns errors that are not resolved' do
|
|
159
|
+
e1 = add_error
|
|
160
|
+
e2 = add_error(error_type: :circular_logic)
|
|
161
|
+
engine.resolve_error(error_id: e1.id)
|
|
162
|
+
active = engine.active_errors
|
|
163
|
+
expect(active).to include(e2)
|
|
164
|
+
expect(active).not_to include(e1)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
describe '#resolved_errors' do
|
|
169
|
+
it 'returns only resolved errors' do
|
|
170
|
+
e1 = add_error
|
|
171
|
+
add_error(error_type: :circular_logic)
|
|
172
|
+
engine.resolve_error(error_id: e1.id)
|
|
173
|
+
expect(engine.resolved_errors).to contain_exactly(e1)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
describe '#errors_by_type' do
|
|
178
|
+
it 'returns a tally hash by error_type' do
|
|
179
|
+
add_error(error_type: :inconsistency)
|
|
180
|
+
add_error(error_type: :inconsistency)
|
|
181
|
+
add_error(error_type: :overconfidence)
|
|
182
|
+
tally = engine.errors_by_type
|
|
183
|
+
expect(tally[:inconsistency]).to eq(2)
|
|
184
|
+
expect(tally[:overconfidence]).to eq(1)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
describe '#errors_by_phase' do
|
|
189
|
+
it 'returns a tally hash by source_phase' do
|
|
190
|
+
add_error(source_phase: :prediction_engine)
|
|
191
|
+
add_error(source_phase: :prediction_engine)
|
|
192
|
+
add_error(source_phase: :emotional_evaluation)
|
|
193
|
+
tally = engine.errors_by_phase
|
|
194
|
+
expect(tally[:prediction_engine]).to eq(2)
|
|
195
|
+
expect(tally[:emotional_evaluation]).to eq(1)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
describe '#most_common_error_type' do
|
|
200
|
+
it 'returns nil when no errors' do
|
|
201
|
+
expect(engine.most_common_error_type).to be_nil
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'returns the most frequent error type' do
|
|
205
|
+
add_error(error_type: :overconfidence)
|
|
206
|
+
add_error(error_type: :overconfidence)
|
|
207
|
+
add_error(error_type: :inconsistency)
|
|
208
|
+
expect(engine.most_common_error_type).to eq(:overconfidence)
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
describe '#most_effective_strategy' do
|
|
213
|
+
it 'returns nil when no measured corrections' do
|
|
214
|
+
expect(engine.most_effective_strategy).to be_nil
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
it 'returns the strategy with highest average effectiveness' do
|
|
218
|
+
err = add_error
|
|
219
|
+
c1 = engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'x')
|
|
220
|
+
c2 = engine.propose_correction(error_id: err.id, strategy: :reframe, description: 'y')
|
|
221
|
+
engine.measure_correction(correction_id: c1.id, effectiveness: 0.4)
|
|
222
|
+
engine.measure_correction(correction_id: c2.id, effectiveness: 0.9)
|
|
223
|
+
expect(engine.most_effective_strategy).to eq(:reframe)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe '#error_rate_by_phase' do
|
|
228
|
+
it 'is an alias for errors_by_phase' do
|
|
229
|
+
add_error(source_phase: :tick)
|
|
230
|
+
expect(engine.error_rate_by_phase).to eq(engine.errors_by_phase)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
describe '#correction_success_rate' do
|
|
235
|
+
it 'returns 0.0 when no corrections applied' do
|
|
236
|
+
expect(engine.correction_success_rate).to eq(0.0)
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it 'returns 0.0 when applied but none measured' do
|
|
240
|
+
err = add_error
|
|
241
|
+
c = engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'x')
|
|
242
|
+
engine.apply_correction(correction_id: c.id)
|
|
243
|
+
expect(engine.correction_success_rate).to eq(0.0)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
it 'calculates the ratio of effective corrections' do
|
|
247
|
+
err = add_error
|
|
248
|
+
c1 = engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'a')
|
|
249
|
+
c2 = engine.propose_correction(error_id: err.id, strategy: :reframe, description: 'b')
|
|
250
|
+
engine.apply_correction(correction_id: c1.id)
|
|
251
|
+
engine.apply_correction(correction_id: c2.id)
|
|
252
|
+
engine.measure_correction(correction_id: c1.id, effectiveness: 0.8)
|
|
253
|
+
engine.measure_correction(correction_id: c2.id, effectiveness: 0.3)
|
|
254
|
+
expect(engine.correction_success_rate).to eq(0.5)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
describe '#debugging_report' do
|
|
259
|
+
it 'returns a hash with expected keys' do
|
|
260
|
+
report = engine.debugging_report
|
|
261
|
+
expect(report).to include(
|
|
262
|
+
:total_errors, :active_errors, :resolved_errors,
|
|
263
|
+
:total_traces, :total_corrections,
|
|
264
|
+
:correction_success_rate, :most_common_error_type,
|
|
265
|
+
:most_effective_strategy, :errors_by_type, :error_rate_by_phase
|
|
266
|
+
)
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
it 'reflects current state' do
|
|
270
|
+
add_error
|
|
271
|
+
report = engine.debugging_report
|
|
272
|
+
expect(report[:total_errors]).to eq(1)
|
|
273
|
+
expect(report[:active_errors]).to eq(1)
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
describe '#to_h' do
|
|
278
|
+
it 'returns nested hashes for errors, traces, corrections' do
|
|
279
|
+
err = add_error
|
|
280
|
+
steps = [{ phase: :tick, description: 'step' }]
|
|
281
|
+
engine.trace_error(error_id: err.id, steps: steps, root_cause: :bias, confidence: 0.6)
|
|
282
|
+
engine.propose_correction(error_id: err.id, strategy: :retrace, description: 'x')
|
|
283
|
+
h = engine.to_h
|
|
284
|
+
expect(h[:errors]).to be_a(Hash)
|
|
285
|
+
expect(h[:traces]).to be_a(Hash)
|
|
286
|
+
expect(h[:corrections]).to be_a(Hash)
|
|
287
|
+
expect(h[:errors][err.id]).to include(:error_type)
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Helpers::ReasoningError do
|
|
4
|
+
let(:error) do
|
|
5
|
+
described_class.new(
|
|
6
|
+
error_type: :inconsistency,
|
|
7
|
+
description: 'Contradicting earlier claim',
|
|
8
|
+
severity: 0.75,
|
|
9
|
+
source_phase: :prediction_engine,
|
|
10
|
+
confidence_at_detection: 0.9
|
|
11
|
+
)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '#initialize' do
|
|
15
|
+
it 'assigns a UUID id' do
|
|
16
|
+
expect(error.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'sets error_type' do
|
|
20
|
+
expect(error.error_type).to eq(:inconsistency)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'sets description' do
|
|
24
|
+
expect(error.description).to eq('Contradicting earlier claim')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'clamps severity to [0, 1]' do
|
|
28
|
+
e = described_class.new(error_type: :overconfidence, description: 'x',
|
|
29
|
+
severity: 1.5, source_phase: :tick, confidence_at_detection: 0.5)
|
|
30
|
+
expect(e.severity).to eq(1.0)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'clamps confidence_at_detection to [0, 1]' do
|
|
34
|
+
e = described_class.new(error_type: :overconfidence, description: 'x',
|
|
35
|
+
severity: 0.5, source_phase: :tick, confidence_at_detection: -0.1)
|
|
36
|
+
expect(e.confidence_at_detection).to eq(0.0)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'initializes status as :detected' do
|
|
40
|
+
expect(error.status).to eq(:detected)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'initializes empty trace_ids' do
|
|
44
|
+
expect(error.trace_ids).to be_empty
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'initializes empty correction_ids' do
|
|
48
|
+
expect(error.correction_ids).to be_empty
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'sets created_at' do
|
|
52
|
+
expect(error.created_at).to be_a(Time)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'initializes resolved_at as nil' do
|
|
56
|
+
expect(error.resolved_at).to be_nil
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe '#detect!' do
|
|
61
|
+
it 'sets status to :detected' do
|
|
62
|
+
error.trace!('trace-1')
|
|
63
|
+
error.detect!
|
|
64
|
+
expect(error.status).to eq(:detected)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe '#trace!' do
|
|
69
|
+
it 'adds trace_id and sets status to :traced' do
|
|
70
|
+
error.trace!('some-trace-uuid')
|
|
71
|
+
expect(error.trace_ids).to include('some-trace-uuid')
|
|
72
|
+
expect(error.status).to eq(:traced)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'accumulates multiple trace_ids' do
|
|
76
|
+
error.trace!('trace-1')
|
|
77
|
+
error.trace!('trace-2')
|
|
78
|
+
expect(error.trace_ids.size).to eq(2)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#correct!' do
|
|
83
|
+
it 'adds correction_id and sets status to :correcting' do
|
|
84
|
+
error.correct!('correction-uuid')
|
|
85
|
+
expect(error.correction_ids).to include('correction-uuid')
|
|
86
|
+
expect(error.status).to eq(:correcting)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe '#resolve!' do
|
|
91
|
+
it 'sets status to :resolved and resolved_at' do
|
|
92
|
+
error.resolve!
|
|
93
|
+
expect(error.status).to eq(:resolved)
|
|
94
|
+
expect(error.resolved_at).to be_a(Time)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#mark_unresolvable!' do
|
|
99
|
+
it 'sets status to :unresolvable and resolved_at' do
|
|
100
|
+
error.mark_unresolvable!
|
|
101
|
+
expect(error.status).to eq(:unresolvable)
|
|
102
|
+
expect(error.resolved_at).to be_a(Time)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#severe?' do
|
|
107
|
+
it 'returns true when severity >= 0.7' do
|
|
108
|
+
expect(error.severe?).to be true
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'returns false when severity < 0.7' do
|
|
112
|
+
e = described_class.new(error_type: :minor_type, description: 'x',
|
|
113
|
+
severity: 0.5, source_phase: :tick, confidence_at_detection: 0.5)
|
|
114
|
+
expect(e.severe?).to be false
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
describe '#resolved?' do
|
|
119
|
+
it 'returns false for a new error' do
|
|
120
|
+
expect(error.resolved?).to be false
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'returns true after resolve!' do
|
|
124
|
+
error.resolve!
|
|
125
|
+
expect(error.resolved?).to be true
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe '#active?' do
|
|
130
|
+
it 'returns true for :detected status' do
|
|
131
|
+
expect(error.active?).to be true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'returns false after resolved' do
|
|
135
|
+
error.resolve!
|
|
136
|
+
expect(error.active?).to be false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'returns false after mark_unresolvable!' do
|
|
140
|
+
error.mark_unresolvable!
|
|
141
|
+
expect(error.active?).to be false
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe '#severity_label' do
|
|
146
|
+
it 'returns :major for severity 0.75' do
|
|
147
|
+
expect(error.severity_label).to eq(:major)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
describe '#to_h' do
|
|
152
|
+
it 'returns a hash with expected keys' do
|
|
153
|
+
h = error.to_h
|
|
154
|
+
expect(h).to include(:id, :error_type, :description, :severity, :severity_label,
|
|
155
|
+
:source_phase, :confidence_at_detection, :status,
|
|
156
|
+
:trace_ids, :correction_ids, :created_at, :resolved_at)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'returns dup of trace_ids array' do
|
|
160
|
+
h = error.to_h
|
|
161
|
+
expect(h[:trace_ids]).not_to be(error.trace_ids)
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|