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,174 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveDebugging
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveDebugging
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
|
|
9
|
+
Legion::Extensions::Helpers.const_defined?(:Lex)
|
|
10
|
+
|
|
11
|
+
def detect_error(error_type:, description:, severity:, source_phase:, confidence_at_detection: 0.5, **)
|
|
12
|
+
unless Helpers::Constants::ERROR_TYPES.include?(error_type)
|
|
13
|
+
Legion::Logging.debug "[cognitive_debugging] detect_error: invalid error_type=#{error_type}"
|
|
14
|
+
return { success: false, error: :invalid_error_type, valid: Helpers::Constants::ERROR_TYPES }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
err = engine.detect_error(
|
|
18
|
+
error_type: error_type,
|
|
19
|
+
description: description,
|
|
20
|
+
severity: severity,
|
|
21
|
+
source_phase: source_phase,
|
|
22
|
+
confidence_at_detection: confidence_at_detection
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if err
|
|
26
|
+
Legion::Logging.info "[cognitive_debugging] error detected: id=#{err.id[0..7]} type=#{error_type} " \
|
|
27
|
+
"phase=#{source_phase} severity=#{err.severity_label}"
|
|
28
|
+
{ success: true, error_id: err.id, error_type: error_type, severity_label: err.severity_label }
|
|
29
|
+
else
|
|
30
|
+
Legion::Logging.warn '[cognitive_debugging] detect_error: engine returned nil (cap reached?)'
|
|
31
|
+
{ success: false, error: :cap_reached }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def trace_error(error_id:, steps:, root_cause:, confidence: 0.5, **)
|
|
36
|
+
trace = engine.trace_error(
|
|
37
|
+
error_id: error_id,
|
|
38
|
+
steps: steps,
|
|
39
|
+
root_cause: root_cause,
|
|
40
|
+
confidence: confidence
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
if trace
|
|
44
|
+
Legion::Logging.info "[cognitive_debugging] error traced: error_id=#{error_id[0..7]} " \
|
|
45
|
+
"trace_id=#{trace.id[0..7]} depth=#{trace.depth} root_cause=#{root_cause}"
|
|
46
|
+
{ success: true, trace_id: trace.id, depth: trace.depth, root_cause: root_cause }
|
|
47
|
+
else
|
|
48
|
+
Legion::Logging.debug "[cognitive_debugging] trace_error: error_id=#{error_id[0..7]} not found or cap"
|
|
49
|
+
{ success: false, error: :not_found_or_cap }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def propose_correction(error_id:, strategy:, description:, **)
|
|
54
|
+
unless Helpers::Constants::CORRECTION_STRATEGIES.include?(strategy)
|
|
55
|
+
Legion::Logging.debug "[cognitive_debugging] propose_correction: invalid strategy=#{strategy}"
|
|
56
|
+
return { success: false, error: :invalid_strategy, valid: Helpers::Constants::CORRECTION_STRATEGIES }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
correction = engine.propose_correction(error_id: error_id, strategy: strategy, description: description)
|
|
60
|
+
|
|
61
|
+
if correction
|
|
62
|
+
Legion::Logging.info "[cognitive_debugging] correction proposed: error_id=#{error_id[0..7]} " \
|
|
63
|
+
"correction_id=#{correction.id[0..7]} strategy=#{strategy}"
|
|
64
|
+
{ success: true, correction_id: correction.id, strategy: strategy }
|
|
65
|
+
else
|
|
66
|
+
Legion::Logging.debug "[cognitive_debugging] propose_correction: error_id=#{error_id[0..7]} not found"
|
|
67
|
+
{ success: false, error: :not_found }
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def apply_correction(correction_id:, **)
|
|
72
|
+
correction = engine.apply_correction(correction_id: correction_id)
|
|
73
|
+
|
|
74
|
+
if correction
|
|
75
|
+
Legion::Logging.info "[cognitive_debugging] correction applied: id=#{correction_id[0..7]}"
|
|
76
|
+
{ success: true, correction_id: correction_id, applied: true }
|
|
77
|
+
else
|
|
78
|
+
Legion::Logging.debug "[cognitive_debugging] apply_correction: id=#{correction_id[0..7]} not found"
|
|
79
|
+
{ success: false, error: :not_found }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def measure_correction(correction_id:, effectiveness:, **)
|
|
84
|
+
correction = engine.measure_correction(correction_id: correction_id, effectiveness: effectiveness)
|
|
85
|
+
|
|
86
|
+
if correction
|
|
87
|
+
Legion::Logging.info "[cognitive_debugging] correction measured: id=#{correction_id[0..7]} " \
|
|
88
|
+
"effectiveness=#{correction.effectiveness} effective=#{correction.effective?}"
|
|
89
|
+
{ success: true, correction_id: correction_id, effectiveness: correction.effectiveness,
|
|
90
|
+
effective: correction.effective? }
|
|
91
|
+
else
|
|
92
|
+
Legion::Logging.debug "[cognitive_debugging] measure_correction: id=#{correction_id[0..7]} not found"
|
|
93
|
+
{ success: false, error: :not_found }
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def resolve_error(error_id:, **)
|
|
98
|
+
err = engine.resolve_error(error_id: error_id)
|
|
99
|
+
|
|
100
|
+
if err
|
|
101
|
+
Legion::Logging.info "[cognitive_debugging] error resolved: id=#{error_id[0..7]}"
|
|
102
|
+
{ success: true, error_id: error_id, resolved: true }
|
|
103
|
+
else
|
|
104
|
+
Legion::Logging.debug "[cognitive_debugging] resolve_error: id=#{error_id[0..7]} not found"
|
|
105
|
+
{ success: false, error: :not_found }
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def active_errors(**)
|
|
110
|
+
errors = engine.active_errors
|
|
111
|
+
Legion::Logging.debug "[cognitive_debugging] active_errors: count=#{errors.size}"
|
|
112
|
+
{ success: true, errors: errors.map(&:to_h), count: errors.size }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def resolved_errors(**)
|
|
116
|
+
errors = engine.resolved_errors
|
|
117
|
+
Legion::Logging.debug "[cognitive_debugging] resolved_errors: count=#{errors.size}"
|
|
118
|
+
{ success: true, errors: errors.map(&:to_h), count: errors.size }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def errors_by_type(**)
|
|
122
|
+
tally = engine.errors_by_type
|
|
123
|
+
Legion::Logging.debug "[cognitive_debugging] errors_by_type: types=#{tally.keys.join(',')}"
|
|
124
|
+
{ success: true, tally: tally }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def errors_by_phase(**)
|
|
128
|
+
tally = engine.errors_by_phase
|
|
129
|
+
Legion::Logging.debug "[cognitive_debugging] errors_by_phase: phases=#{tally.keys.join(',')}"
|
|
130
|
+
{ success: true, tally: tally }
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def most_common_error_type(**)
|
|
134
|
+
type = engine.most_common_error_type
|
|
135
|
+
Legion::Logging.debug "[cognitive_debugging] most_common_error_type: type=#{type}"
|
|
136
|
+
{ success: true, error_type: type }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def most_effective_strategy(**)
|
|
140
|
+
strategy = engine.most_effective_strategy
|
|
141
|
+
Legion::Logging.debug "[cognitive_debugging] most_effective_strategy: strategy=#{strategy}"
|
|
142
|
+
{ success: true, strategy: strategy }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def correction_success_rate(**)
|
|
146
|
+
rate = engine.correction_success_rate
|
|
147
|
+
Legion::Logging.debug "[cognitive_debugging] correction_success_rate: rate=#{rate}"
|
|
148
|
+
{ success: true, rate: rate }
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def debugging_report(**)
|
|
152
|
+
report = engine.debugging_report
|
|
153
|
+
Legion::Logging.info "[cognitive_debugging] debugging_report: total_errors=#{report[:total_errors]} " \
|
|
154
|
+
"active=#{report[:active_errors]}"
|
|
155
|
+
{ success: true, report: report }
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def snapshot(**)
|
|
159
|
+
data = engine.to_h
|
|
160
|
+
Legion::Logging.debug "[cognitive_debugging] snapshot: errors=#{data[:errors].size} " \
|
|
161
|
+
"traces=#{data[:traces].size} corrections=#{data[:corrections].size}"
|
|
162
|
+
{ success: true, snapshot: data }
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
private
|
|
166
|
+
|
|
167
|
+
def engine
|
|
168
|
+
@engine ||= Helpers::DebuggingEngine.new
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_debugging/version'
|
|
4
|
+
require 'legion/extensions/cognitive_debugging/helpers/constants'
|
|
5
|
+
require 'legion/extensions/cognitive_debugging/helpers/reasoning_error'
|
|
6
|
+
require 'legion/extensions/cognitive_debugging/helpers/causal_trace'
|
|
7
|
+
require 'legion/extensions/cognitive_debugging/helpers/correction'
|
|
8
|
+
require 'legion/extensions/cognitive_debugging/helpers/debugging_engine'
|
|
9
|
+
require 'legion/extensions/cognitive_debugging/runners/cognitive_debugging'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module CognitiveDebugging
|
|
14
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/cognitive_debugging/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Client do
|
|
6
|
+
it 'responds to all runner methods' do
|
|
7
|
+
client = described_class.new
|
|
8
|
+
expect(client).to respond_to(:detect_error)
|
|
9
|
+
expect(client).to respond_to(:trace_error)
|
|
10
|
+
expect(client).to respond_to(:propose_correction)
|
|
11
|
+
expect(client).to respond_to(:apply_correction)
|
|
12
|
+
expect(client).to respond_to(:measure_correction)
|
|
13
|
+
expect(client).to respond_to(:resolve_error)
|
|
14
|
+
expect(client).to respond_to(:active_errors)
|
|
15
|
+
expect(client).to respond_to(:resolved_errors)
|
|
16
|
+
expect(client).to respond_to(:errors_by_type)
|
|
17
|
+
expect(client).to respond_to(:errors_by_phase)
|
|
18
|
+
expect(client).to respond_to(:most_common_error_type)
|
|
19
|
+
expect(client).to respond_to(:most_effective_strategy)
|
|
20
|
+
expect(client).to respond_to(:correction_success_rate)
|
|
21
|
+
expect(client).to respond_to(:debugging_report)
|
|
22
|
+
expect(client).to respond_to(:snapshot)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'accepts an injected engine' do
|
|
26
|
+
engine = Legion::Extensions::CognitiveDebugging::Helpers::DebuggingEngine.new
|
|
27
|
+
client = described_class.new(engine: engine)
|
|
28
|
+
result = client.detect_error(
|
|
29
|
+
error_type: :overconfidence,
|
|
30
|
+
description: 'Test injection',
|
|
31
|
+
severity: 0.5,
|
|
32
|
+
source_phase: :tick,
|
|
33
|
+
confidence_at_detection: 0.8
|
|
34
|
+
)
|
|
35
|
+
expect(result[:success]).to be true
|
|
36
|
+
expect(engine.errors.size).to eq(1)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'creates a fresh engine when none injected' do
|
|
40
|
+
c1 = described_class.new
|
|
41
|
+
c2 = described_class.new
|
|
42
|
+
c1.detect_error(error_type: :inconsistency, description: 'x', severity: 0.5,
|
|
43
|
+
source_phase: :tick, confidence_at_detection: 0.5)
|
|
44
|
+
expect(c2.active_errors[:count]).to eq(0)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Helpers::CausalTrace do
|
|
4
|
+
let(:trace) do
|
|
5
|
+
described_class.new(error_id: 'error-uuid', root_cause: :faulty_premise, confidence: 0.8)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'assigns a UUID id' do
|
|
10
|
+
expect(trace.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'sets error_id' do
|
|
14
|
+
expect(trace.error_id).to eq('error-uuid')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'sets root_cause' do
|
|
18
|
+
expect(trace.root_cause).to eq(:faulty_premise)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'clamps confidence to [0, 1]' do
|
|
22
|
+
t = described_class.new(error_id: 'x', root_cause: :y, confidence: 1.5)
|
|
23
|
+
expect(t.confidence).to eq(1.0)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'initializes empty steps' do
|
|
27
|
+
expect(trace.steps).to be_empty
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#add_step!' do
|
|
32
|
+
it 'appends a step with phase, description, and timestamp' do
|
|
33
|
+
trace.add_step!(phase: :emotional_evaluation, description: 'Urgency spike caused premature conclusion')
|
|
34
|
+
expect(trace.steps.size).to eq(1)
|
|
35
|
+
step = trace.steps.first
|
|
36
|
+
expect(step[:phase]).to eq(:emotional_evaluation)
|
|
37
|
+
expect(step[:description]).to eq('Urgency spike caused premature conclusion')
|
|
38
|
+
expect(step[:timestamp]).to be_a(Time)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'returns self for chaining' do
|
|
42
|
+
result = trace.add_step!(phase: :tick, description: 'step 1')
|
|
43
|
+
expect(result).to be(trace)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'accumulates multiple steps' do
|
|
47
|
+
trace.add_step!(phase: :tick, description: 'step 1')
|
|
48
|
+
trace.add_step!(phase: :memory_retrieval, description: 'step 2')
|
|
49
|
+
trace.add_step!(phase: :prediction_engine, description: 'step 3')
|
|
50
|
+
expect(trace.steps.size).to eq(3)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#depth' do
|
|
55
|
+
it 'returns 0 for empty trace' do
|
|
56
|
+
expect(trace.depth).to eq(0)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns step count' do
|
|
60
|
+
trace.add_step!(phase: :tick, description: 'a')
|
|
61
|
+
trace.add_step!(phase: :tick, description: 'b')
|
|
62
|
+
expect(trace.depth).to eq(2)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#to_h' do
|
|
67
|
+
it 'returns a hash with expected keys' do
|
|
68
|
+
trace.add_step!(phase: :tick, description: 'step')
|
|
69
|
+
h = trace.to_h
|
|
70
|
+
expect(h).to include(:id, :error_id, :steps, :root_cause, :confidence, :depth)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it 'includes depth in hash' do
|
|
74
|
+
trace.add_step!(phase: :tick, description: 'step')
|
|
75
|
+
expect(trace.to_h[:depth]).to eq(1)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'returns dup of steps' do
|
|
79
|
+
trace.add_step!(phase: :tick, description: 'step')
|
|
80
|
+
h = trace.to_h
|
|
81
|
+
expect(h[:steps]).not_to be(trace.steps)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Helpers::Constants do
|
|
4
|
+
describe 'ERROR_TYPES' do
|
|
5
|
+
it 'contains 8 error types' do
|
|
6
|
+
expect(described_class::ERROR_TYPES.size).to eq(8)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'includes :inconsistency' do
|
|
10
|
+
expect(described_class::ERROR_TYPES).to include(:inconsistency)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'includes :circular_logic' do
|
|
14
|
+
expect(described_class::ERROR_TYPES).to include(:circular_logic)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'includes :overconfidence' do
|
|
18
|
+
expect(described_class::ERROR_TYPES).to include(:overconfidence)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'includes :confirmation_bias' do
|
|
22
|
+
expect(described_class::ERROR_TYPES).to include(:confirmation_bias)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'is frozen' do
|
|
26
|
+
expect(described_class::ERROR_TYPES).to be_frozen
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe 'CORRECTION_STRATEGIES' do
|
|
31
|
+
it 'contains 7 strategies' do
|
|
32
|
+
expect(described_class::CORRECTION_STRATEGIES.size).to eq(7)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'includes :retrace' do
|
|
36
|
+
expect(described_class::CORRECTION_STRATEGIES).to include(:retrace)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'includes :devil_advocate' do
|
|
40
|
+
expect(described_class::CORRECTION_STRATEGIES).to include(:devil_advocate)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'is frozen' do
|
|
44
|
+
expect(described_class::CORRECTION_STRATEGIES).to be_frozen
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'capacity limits' do
|
|
49
|
+
it 'sets MAX_ERRORS to 300' do
|
|
50
|
+
expect(described_class::MAX_ERRORS).to eq(300)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'sets MAX_TRACES to 500' do
|
|
54
|
+
expect(described_class::MAX_TRACES).to eq(500)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'sets MAX_CORRECTIONS to 200' do
|
|
58
|
+
expect(described_class::MAX_CORRECTIONS).to eq(200)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
describe '.severity_label' do
|
|
63
|
+
it 'returns :trivial for 0.0' do
|
|
64
|
+
expect(described_class.severity_label(0.0)).to eq(:trivial)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'returns :trivial for 0.1' do
|
|
68
|
+
expect(described_class.severity_label(0.1)).to eq(:trivial)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'returns :minor for 0.2' do
|
|
72
|
+
expect(described_class.severity_label(0.2)).to eq(:minor)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'returns :moderate for 0.4' do
|
|
76
|
+
expect(described_class.severity_label(0.4)).to eq(:moderate)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'returns :major for 0.6' do
|
|
80
|
+
expect(described_class.severity_label(0.6)).to eq(:major)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'returns :critical for 0.8' do
|
|
84
|
+
expect(described_class.severity_label(0.8)).to eq(:critical)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns :critical for 1.0' do
|
|
88
|
+
expect(described_class.severity_label(1.0)).to eq(:critical)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe 'STATUS_LABELS' do
|
|
93
|
+
it 'contains expected statuses' do
|
|
94
|
+
expect(described_class::STATUS_LABELS).to include(:detected, :traced, :correcting, :resolved, :unresolvable)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::CognitiveDebugging::Helpers::Correction do
|
|
4
|
+
let(:correction) do
|
|
5
|
+
described_class.new(error_id: 'error-uuid', strategy: :retrace, description: 'Re-examine assumptions')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe '#initialize' do
|
|
9
|
+
it 'assigns a UUID id' do
|
|
10
|
+
expect(correction.id).to match(/\A[0-9a-f-]{36}\z/)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'sets error_id' do
|
|
14
|
+
expect(correction.error_id).to eq('error-uuid')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'sets strategy' do
|
|
18
|
+
expect(correction.strategy).to eq(:retrace)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'sets description' do
|
|
22
|
+
expect(correction.description).to eq('Re-examine assumptions')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'initializes applied as false' do
|
|
26
|
+
expect(correction.applied).to be false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'initializes effectiveness as nil' do
|
|
30
|
+
expect(correction.effectiveness).to be_nil
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#apply!' do
|
|
35
|
+
it 'sets applied to true' do
|
|
36
|
+
correction.apply!
|
|
37
|
+
expect(correction.applied).to be true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'returns self for chaining' do
|
|
41
|
+
expect(correction.apply!).to be(correction)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe '#measure_effectiveness!' do
|
|
46
|
+
it 'sets effectiveness' do
|
|
47
|
+
correction.measure_effectiveness!(0.8)
|
|
48
|
+
expect(correction.effectiveness).to eq(0.8)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'clamps effectiveness to [0, 1]' do
|
|
52
|
+
correction.measure_effectiveness!(1.5)
|
|
53
|
+
expect(correction.effectiveness).to eq(1.0)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'clamps negative values to 0.0' do
|
|
57
|
+
correction.measure_effectiveness!(-0.2)
|
|
58
|
+
expect(correction.effectiveness).to eq(0.0)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'returns self for chaining' do
|
|
62
|
+
expect(correction.measure_effectiveness!(0.7)).to be(correction)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe '#effective?' do
|
|
67
|
+
it 'returns false when effectiveness is nil' do
|
|
68
|
+
expect(correction.effective?).to be false
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it 'returns true when effectiveness >= 0.6' do
|
|
72
|
+
correction.measure_effectiveness!(0.6)
|
|
73
|
+
expect(correction.effective?).to be true
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'returns true for high effectiveness' do
|
|
77
|
+
correction.measure_effectiveness!(0.9)
|
|
78
|
+
expect(correction.effective?).to be true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'returns false when effectiveness < 0.6' do
|
|
82
|
+
correction.measure_effectiveness!(0.5)
|
|
83
|
+
expect(correction.effective?).to be false
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe '#to_h' do
|
|
88
|
+
it 'includes expected keys' do
|
|
89
|
+
h = correction.to_h
|
|
90
|
+
expect(h).to include(:id, :error_id, :strategy, :description, :applied, :effectiveness, :effective)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'reflects effective? result' do
|
|
94
|
+
correction.measure_effectiveness!(0.7)
|
|
95
|
+
expect(correction.to_h[:effective]).to be true
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|