lex-agentic-defense 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/CHANGELOG.md +12 -0
- data/Gemfile +5 -0
- data/LICENSE +21 -0
- data/README.md +13 -0
- data/lex-agentic-defense.gemspec +30 -0
- data/lib/legion/extensions/agentic/defense/avalanche/client.rb +22 -0
- data/lib/legion/extensions/agentic/defense/avalanche/helpers/avalanche_engine.rb +132 -0
- data/lib/legion/extensions/agentic/defense/avalanche/helpers/cascade.rb +76 -0
- data/lib/legion/extensions/agentic/defense/avalanche/helpers/constants.rb +44 -0
- data/lib/legion/extensions/agentic/defense/avalanche/helpers/snowpack.rb +86 -0
- data/lib/legion/extensions/agentic/defense/avalanche/runners/cognitive_avalanche.rb +75 -0
- data/lib/legion/extensions/agentic/defense/avalanche/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/avalanche.rb +22 -0
- data/lib/legion/extensions/agentic/defense/bias/actors/update.rb +45 -0
- data/lib/legion/extensions/agentic/defense/bias/client.rb +30 -0
- data/lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb +107 -0
- data/lib/legion/extensions/agentic/defense/bias/helpers/bias_event.rb +44 -0
- data/lib/legion/extensions/agentic/defense/bias/helpers/bias_store.rb +84 -0
- data/lib/legion/extensions/agentic/defense/bias/helpers/constants.rb +28 -0
- data/lib/legion/extensions/agentic/defense/bias/runners/bias.rb +151 -0
- data/lib/legion/extensions/agentic/defense/bias/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/bias.rb +20 -0
- data/lib/legion/extensions/agentic/defense/confabulation/actors/decay.rb +45 -0
- data/lib/legion/extensions/agentic/defense/confabulation/client.rb +28 -0
- data/lib/legion/extensions/agentic/defense/confabulation/helpers/claim.rb +67 -0
- data/lib/legion/extensions/agentic/defense/confabulation/helpers/confabulation_engine.rb +120 -0
- data/lib/legion/extensions/agentic/defense/confabulation/helpers/constants.rb +29 -0
- data/lib/legion/extensions/agentic/defense/confabulation/runners/confabulation.rb +74 -0
- data/lib/legion/extensions/agentic/defense/confabulation/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/confabulation.rb +19 -0
- data/lib/legion/extensions/agentic/defense/dissonance/client.rb +32 -0
- data/lib/legion/extensions/agentic/defense/dissonance/helpers/belief.rb +46 -0
- data/lib/legion/extensions/agentic/defense/dissonance/helpers/constants.rb +27 -0
- data/lib/legion/extensions/agentic/defense/dissonance/helpers/dissonance_event.rb +52 -0
- data/lib/legion/extensions/agentic/defense/dissonance/helpers/dissonance_model.rb +159 -0
- data/lib/legion/extensions/agentic/defense/dissonance/runners/dissonance.rb +163 -0
- data/lib/legion/extensions/agentic/defense/dissonance/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/dissonance.rb +20 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/actors/update.rb +45 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/client.rb +27 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/claim.rb +78 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/client.rb +23 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/constants.rb +37 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/source.rb +64 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/vigilance_engine.rb +195 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/runners/epistemic_vigilance.rb +91 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/epistemic_vigilance.rb +20 -0
- data/lib/legion/extensions/agentic/defense/erosion/client.rb +23 -0
- data/lib/legion/extensions/agentic/defense/erosion/helpers/channel.rb +84 -0
- data/lib/legion/extensions/agentic/defense/erosion/helpers/constants.rb +47 -0
- data/lib/legion/extensions/agentic/defense/erosion/helpers/erosion_engine.rb +134 -0
- data/lib/legion/extensions/agentic/defense/erosion/helpers/formation.rb +100 -0
- data/lib/legion/extensions/agentic/defense/erosion/runners/cognitive_erosion.rb +93 -0
- data/lib/legion/extensions/agentic/defense/erosion/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/erosion.rb +21 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/actors/tick.rb +45 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/client.rb +28 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/constants.rb +50 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/error_monitor.rb +174 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/error_signal.rb +60 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/runners/error_monitoring.rb +102 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/error_monitoring.rb +19 -0
- data/lib/legion/extensions/agentic/defense/extinction/actors/protocol_monitor.rb +45 -0
- data/lib/legion/extensions/agentic/defense/extinction/client.rb +27 -0
- data/lib/legion/extensions/agentic/defense/extinction/helpers/levels.rb +43 -0
- data/lib/legion/extensions/agentic/defense/extinction/helpers/protocol_state.rb +125 -0
- data/lib/legion/extensions/agentic/defense/extinction/local_migrations/20260316000040_create_extinction_state.rb +13 -0
- data/lib/legion/extensions/agentic/defense/extinction/runners/extinction.rb +130 -0
- data/lib/legion/extensions/agentic/defense/extinction/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/extinction.rb +25 -0
- data/lib/legion/extensions/agentic/defense/friction/client.rb +15 -0
- data/lib/legion/extensions/agentic/defense/friction/helpers/constants.rb +38 -0
- data/lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb +131 -0
- data/lib/legion/extensions/agentic/defense/friction/helpers/state_transition.rb +73 -0
- data/lib/legion/extensions/agentic/defense/friction/runners/cognitive_friction.rb +82 -0
- data/lib/legion/extensions/agentic/defense/friction/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/friction.rb +19 -0
- data/lib/legion/extensions/agentic/defense/immune_response/client.rb +19 -0
- data/lib/legion/extensions/agentic/defense/immune_response/helpers/antibody.rb +72 -0
- data/lib/legion/extensions/agentic/defense/immune_response/helpers/antigen.rb +87 -0
- data/lib/legion/extensions/agentic/defense/immune_response/helpers/constants.rb +75 -0
- data/lib/legion/extensions/agentic/defense/immune_response/helpers/immune_engine.rb +184 -0
- data/lib/legion/extensions/agentic/defense/immune_response/helpers/immune_response.rb +76 -0
- data/lib/legion/extensions/agentic/defense/immune_response/runners/cognitive_immune_response.rb +114 -0
- data/lib/legion/extensions/agentic/defense/immune_response/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/immune_response.rb +21 -0
- data/lib/legion/extensions/agentic/defense/immunology/client.rb +29 -0
- data/lib/legion/extensions/agentic/defense/immunology/helpers/antibody.rb +55 -0
- data/lib/legion/extensions/agentic/defense/immunology/helpers/constants.rb +43 -0
- data/lib/legion/extensions/agentic/defense/immunology/helpers/immune_engine.rb +187 -0
- data/lib/legion/extensions/agentic/defense/immunology/helpers/threat.rb +67 -0
- data/lib/legion/extensions/agentic/defense/immunology/runners/cognitive_immunology.rb +92 -0
- data/lib/legion/extensions/agentic/defense/immunology/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/immunology.rb +20 -0
- data/lib/legion/extensions/agentic/defense/phantom/client.rb +29 -0
- data/lib/legion/extensions/agentic/defense/phantom/helpers/constants.rb +54 -0
- data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_engine.rb +106 -0
- data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_limb.rb +103 -0
- data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_signal.rb +40 -0
- data/lib/legion/extensions/agentic/defense/phantom/runners/cognitive_phantom.rb +79 -0
- data/lib/legion/extensions/agentic/defense/phantom/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/phantom.rb +21 -0
- data/lib/legion/extensions/agentic/defense/quicksand/client.rb +15 -0
- data/lib/legion/extensions/agentic/defense/quicksand/helpers/constants.rb +48 -0
- data/lib/legion/extensions/agentic/defense/quicksand/helpers/pit.rb +82 -0
- data/lib/legion/extensions/agentic/defense/quicksand/helpers/quicksand_engine.rb +137 -0
- data/lib/legion/extensions/agentic/defense/quicksand/helpers/trap.rb +101 -0
- data/lib/legion/extensions/agentic/defense/quicksand/runners/cognitive_quicksand.rb +84 -0
- data/lib/legion/extensions/agentic/defense/quicksand/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/quicksand.rb +22 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/client.rb +29 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/helpers/constants.rb +50 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/helpers/droplet.rb +126 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/helpers/pool.rb +83 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/helpers/quicksilver_engine.rb +124 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/runners/cognitive_quicksilver.rb +130 -0
- data/lib/legion/extensions/agentic/defense/quicksilver/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/quicksilver.rb +21 -0
- data/lib/legion/extensions/agentic/defense/version.rb +11 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/client.rb +65 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/helpers/captured_thought.rb +67 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/helpers/constants.rb +45 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/helpers/vortex.rb +91 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/helpers/whirlpool_engine.rb +92 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/runners/cognitive_whirlpool.rb +117 -0
- data/lib/legion/extensions/agentic/defense/whirlpool/version.rb +13 -0
- data/lib/legion/extensions/agentic/defense/whirlpool.rb +22 -0
- data/lib/legion/extensions/agentic/defense.rb +32 -0
- data/spec/legion/extensions/agentic/defense/avalanche/client_spec.rb +96 -0
- data/spec/legion/extensions/agentic/defense/avalanche/helpers/avalanche_engine_spec.rb +276 -0
- data/spec/legion/extensions/agentic/defense/avalanche/helpers/cascade_spec.rb +190 -0
- data/spec/legion/extensions/agentic/defense/avalanche/helpers/constants_spec.rb +129 -0
- data/spec/legion/extensions/agentic/defense/avalanche/helpers/snowpack_spec.rb +197 -0
- data/spec/legion/extensions/agentic/defense/avalanche/runners/cognitive_avalanche_spec.rb +211 -0
- data/spec/legion/extensions/agentic/defense/bias/client_spec.rb +16 -0
- data/spec/legion/extensions/agentic/defense/bias/helpers/bias_detector_spec.rb +160 -0
- data/spec/legion/extensions/agentic/defense/bias/helpers/bias_event_spec.rb +64 -0
- data/spec/legion/extensions/agentic/defense/bias/helpers/bias_store_spec.rb +143 -0
- data/spec/legion/extensions/agentic/defense/bias/runners/bias_spec.rb +155 -0
- data/spec/legion/extensions/agentic/defense/confabulation/client_spec.rb +34 -0
- data/spec/legion/extensions/agentic/defense/confabulation/helpers/claim_spec.rb +119 -0
- data/spec/legion/extensions/agentic/defense/confabulation/helpers/confabulation_engine_spec.rb +163 -0
- data/spec/legion/extensions/agentic/defense/confabulation/helpers/constants_spec.rb +55 -0
- data/spec/legion/extensions/agentic/defense/confabulation/runners/confabulation_spec.rb +119 -0
- data/spec/legion/extensions/agentic/defense/dissonance/client_spec.rb +51 -0
- data/spec/legion/extensions/agentic/defense/dissonance/helpers/belief_spec.rb +103 -0
- data/spec/legion/extensions/agentic/defense/dissonance/helpers/constants_spec.rb +60 -0
- data/spec/legion/extensions/agentic/defense/dissonance/helpers/dissonance_event_spec.rb +113 -0
- data/spec/legion/extensions/agentic/defense/dissonance/helpers/dissonance_model_spec.rb +252 -0
- data/spec/legion/extensions/agentic/defense/dissonance/runners/dissonance_spec.rb +323 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/client_spec.rb +28 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/claim_spec.rb +135 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/constants_spec.rb +59 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/source_spec.rb +117 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/vigilance_engine_spec.rb +273 -0
- data/spec/legion/extensions/agentic/defense/epistemic_vigilance/runners/epistemic_vigilance_spec.rb +157 -0
- data/spec/legion/extensions/agentic/defense/erosion/client_spec.rb +90 -0
- data/spec/legion/extensions/agentic/defense/erosion/helpers/channel_spec.rb +173 -0
- data/spec/legion/extensions/agentic/defense/erosion/helpers/constants_spec.rb +137 -0
- data/spec/legion/extensions/agentic/defense/erosion/helpers/erosion_engine_spec.rb +263 -0
- data/spec/legion/extensions/agentic/defense/erosion/helpers/formation_spec.rb +206 -0
- data/spec/legion/extensions/agentic/defense/erosion/runners/cognitive_erosion_spec.rb +153 -0
- data/spec/legion/extensions/agentic/defense/error_monitoring/client_spec.rb +40 -0
- data/spec/legion/extensions/agentic/defense/error_monitoring/helpers/error_monitor_spec.rb +178 -0
- data/spec/legion/extensions/agentic/defense/error_monitoring/helpers/error_signal_spec.rb +76 -0
- data/spec/legion/extensions/agentic/defense/error_monitoring/runners/error_monitoring_spec.rb +87 -0
- data/spec/legion/extensions/agentic/defense/extinction/actors/protocol_monitor_spec.rb +45 -0
- data/spec/legion/extensions/agentic/defense/extinction/client_spec.rb +13 -0
- data/spec/legion/extensions/agentic/defense/extinction/helpers/levels_spec.rb +180 -0
- data/spec/legion/extensions/agentic/defense/extinction/helpers/protocol_state_spec.rb +291 -0
- data/spec/legion/extensions/agentic/defense/extinction/local_persistence_spec.rb +188 -0
- data/spec/legion/extensions/agentic/defense/extinction/runners/extinction_spec.rb +114 -0
- data/spec/legion/extensions/agentic/defense/friction/helpers/constants_spec.rb +46 -0
- data/spec/legion/extensions/agentic/defense/friction/helpers/friction_engine_spec.rb +175 -0
- data/spec/legion/extensions/agentic/defense/friction/helpers/state_transition_spec.rb +124 -0
- data/spec/legion/extensions/agentic/defense/friction/runners/cognitive_friction_spec.rb +89 -0
- data/spec/legion/extensions/agentic/defense/immune_response/client_spec.rb +32 -0
- data/spec/legion/extensions/agentic/defense/immune_response/cognitive_immune_response_spec.rb +7 -0
- data/spec/legion/extensions/agentic/defense/immune_response/helpers/antibody_spec.rb +117 -0
- data/spec/legion/extensions/agentic/defense/immune_response/helpers/antigen_spec.rb +125 -0
- data/spec/legion/extensions/agentic/defense/immune_response/helpers/constants_spec.rb +45 -0
- data/spec/legion/extensions/agentic/defense/immune_response/helpers/immune_engine_spec.rb +222 -0
- data/spec/legion/extensions/agentic/defense/immune_response/helpers/immune_response_spec.rb +84 -0
- data/spec/legion/extensions/agentic/defense/immune_response/runners_spec.rb +141 -0
- data/spec/legion/extensions/agentic/defense/immunology/client_spec.rb +61 -0
- data/spec/legion/extensions/agentic/defense/immunology/helpers/antibody_spec.rb +98 -0
- data/spec/legion/extensions/agentic/defense/immunology/helpers/constants_spec.rb +86 -0
- data/spec/legion/extensions/agentic/defense/immunology/helpers/immune_engine_spec.rb +275 -0
- data/spec/legion/extensions/agentic/defense/immunology/helpers/threat_spec.rb +133 -0
- data/spec/legion/extensions/agentic/defense/immunology/runners/cognitive_immunology_spec.rb +177 -0
- data/spec/legion/extensions/agentic/defense/phantom/client_spec.rb +53 -0
- data/spec/legion/extensions/agentic/defense/phantom/helpers/constants_spec.rb +87 -0
- data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_engine_spec.rb +222 -0
- data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_limb_spec.rb +180 -0
- data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_signal_spec.rb +59 -0
- data/spec/legion/extensions/agentic/defense/phantom/runners/cognitive_phantom_spec.rb +193 -0
- data/spec/legion/extensions/agentic/defense/quicksand/client_spec.rb +35 -0
- data/spec/legion/extensions/agentic/defense/quicksand/helpers/constants_spec.rb +58 -0
- data/spec/legion/extensions/agentic/defense/quicksand/helpers/pit_spec.rb +103 -0
- data/spec/legion/extensions/agentic/defense/quicksand/helpers/quicksand_engine_spec.rb +153 -0
- data/spec/legion/extensions/agentic/defense/quicksand/helpers/trap_spec.rb +166 -0
- data/spec/legion/extensions/agentic/defense/quicksand/runners/cognitive_quicksand_spec.rb +90 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/client_spec.rb +72 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/helpers/constants_spec.rb +105 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/helpers/droplet_spec.rb +310 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/helpers/pool_spec.rb +174 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/helpers/quicksilver_engine_spec.rb +226 -0
- data/spec/legion/extensions/agentic/defense/quicksilver/runners/cognitive_quicksilver_spec.rb +227 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/client_spec.rb +63 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/helpers/captured_thought_spec.rb +171 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/helpers/constants_spec.rb +65 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/helpers/vortex_spec.rb +189 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/helpers/whirlpool_engine_spec.rb +227 -0
- data/spec/legion/extensions/agentic/defense/whirlpool/runners/cognitive_whirlpool_spec.rb +226 -0
- data/spec/spec_helper.rb +46 -0
- metadata +303 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::ErrorMonitoring::Helpers::ErrorMonitor do
|
|
4
|
+
subject(:monitor) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:constants) { Legion::Extensions::Agentic::Defense::ErrorMonitoring::Helpers::Constants }
|
|
7
|
+
|
|
8
|
+
describe '#register_error' do
|
|
9
|
+
it 'creates an error signal' do
|
|
10
|
+
signal = monitor.register_error(action: :parse, domain: :data, intended: :valid, actual: :malformed,
|
|
11
|
+
severity: 0.5)
|
|
12
|
+
expect(signal).to be_a(Legion::Extensions::Agentic::Defense::ErrorMonitoring::Helpers::ErrorSignal)
|
|
13
|
+
expect(monitor.error_count).to eq(1)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'increases error rate' do
|
|
17
|
+
before = monitor.error_rate
|
|
18
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.8)
|
|
19
|
+
expect(monitor.error_rate).to be > before
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'applies post-error slowdown' do
|
|
23
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.8)
|
|
24
|
+
expect(monitor.slowdown).to be > 0
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'decreases confidence' do
|
|
28
|
+
before = monitor.confidence
|
|
29
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.5)
|
|
30
|
+
expect(monitor.confidence).to be < before
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'limits error log size' do
|
|
34
|
+
(constants::MAX_ERROR_LOG + 10).times do |i|
|
|
35
|
+
monitor.register_error(action: :"a_#{i}", domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
36
|
+
end
|
|
37
|
+
expect(monitor.error_count).to eq(constants::MAX_ERROR_LOG)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe '#register_success' do
|
|
42
|
+
it 'decreases error rate' do
|
|
43
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.8)
|
|
44
|
+
before = monitor.error_rate
|
|
45
|
+
monitor.register_success(action: :b, domain: :d)
|
|
46
|
+
expect(monitor.error_rate).to be < before
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'increases confidence' do
|
|
50
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.5)
|
|
51
|
+
before = monitor.confidence
|
|
52
|
+
monitor.register_success(action: :b, domain: :d)
|
|
53
|
+
expect(monitor.confidence).to be > before
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '#register_conflict' do
|
|
58
|
+
it 'records a conflict' do
|
|
59
|
+
entry = monitor.register_conflict(action_a: :run, action_b: :hide, domain: :safety, intensity: 0.8)
|
|
60
|
+
expect(entry[:action_a]).to eq(:run)
|
|
61
|
+
expect(entry[:intensity]).to eq(0.8)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'increases conflict level' do
|
|
65
|
+
monitor.register_conflict(action_a: :a, action_b: :b, domain: :d, intensity: 0.9)
|
|
66
|
+
expect(monitor.conflict_level).to be > 0
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe '#register_correction' do
|
|
71
|
+
it 'records a correction' do
|
|
72
|
+
monitor.register_error(action: :parse, domain: :data, intended: :valid, actual: :malformed, severity: 0.5)
|
|
73
|
+
entry = monitor.register_correction(action: :parse, domain: :data, original_error: :malformed, correction: :retry)
|
|
74
|
+
expect(entry[:correction]).to eq(:retry)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it 'marks the error as corrected' do
|
|
78
|
+
monitor.register_error(action: :parse, domain: :data, intended: :valid, actual: :malformed, severity: 0.5)
|
|
79
|
+
monitor.register_correction(action: :parse, domain: :data, original_error: :malformed, correction: :retry)
|
|
80
|
+
expect(monitor.uncorrected_errors).to be_empty
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'boosts confidence' do
|
|
84
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.5)
|
|
85
|
+
before = monitor.confidence
|
|
86
|
+
monitor.register_correction(action: :a, domain: :d, original_error: :a, correction: :fix)
|
|
87
|
+
expect(monitor.confidence).to be > before
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
describe '#recent_errors' do
|
|
92
|
+
it 'returns recent errors' do
|
|
93
|
+
3.times { |i| monitor.register_error(action: :"a_#{i}", domain: :d, intended: :i, actual: :a, severity: 0.3) }
|
|
94
|
+
expect(monitor.recent_errors(limit: 2).size).to eq(2)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe '#errors_in' do
|
|
99
|
+
it 'filters by domain' do
|
|
100
|
+
monitor.register_error(action: :a, domain: :network, intended: :i, actual: :a, severity: 0.3)
|
|
101
|
+
monitor.register_error(action: :b, domain: :data, intended: :i, actual: :a, severity: 0.3)
|
|
102
|
+
expect(monitor.errors_in(domain: :network).size).to eq(1)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe '#uncorrected_errors' do
|
|
107
|
+
it 'returns only uncorrected errors' do
|
|
108
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
109
|
+
monitor.register_error(action: :b, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
110
|
+
monitor.register_correction(action: :a, domain: :d, original_error: :a, correction: :fix)
|
|
111
|
+
expect(monitor.uncorrected_errors.size).to eq(1)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
describe '#conflict_active?' do
|
|
116
|
+
it 'returns false initially' do
|
|
117
|
+
expect(monitor.conflict_active?).to be false
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
it 'returns true after sustained high-intensity conflict' do
|
|
121
|
+
20.times { monitor.register_conflict(action_a: :a, action_b: :b, domain: :d, intensity: 0.9) }
|
|
122
|
+
expect(monitor.conflict_active?).to be true
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
describe '#monitoring_state' do
|
|
127
|
+
it 'returns :normal initially' do
|
|
128
|
+
expect(monitor.monitoring_state).to eq(:normal)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it 'returns :vigilant after errors (slowdown active)' do
|
|
132
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.8)
|
|
133
|
+
expect(monitor.monitoring_state).to eq(:vigilant)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'returns :relaxed after many successes' do
|
|
137
|
+
50.times { monitor.register_success(action: :a, domain: :d) }
|
|
138
|
+
expect(monitor.monitoring_state).to eq(:relaxed)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe '#tick' do
|
|
143
|
+
it 'decays slowdown' do
|
|
144
|
+
monitor.register_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.8)
|
|
145
|
+
before = monitor.slowdown
|
|
146
|
+
monitor.tick
|
|
147
|
+
expect(monitor.slowdown).to be < before
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'decays conflict level' do
|
|
151
|
+
monitor.register_conflict(action_a: :a, action_b: :b, domain: :d, intensity: 0.9)
|
|
152
|
+
before = monitor.conflict_level
|
|
153
|
+
monitor.tick
|
|
154
|
+
expect(monitor.conflict_level).to be < before
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
describe '#correction_rate' do
|
|
159
|
+
it 'returns 0 with no errors' do
|
|
160
|
+
expect(monitor.correction_rate).to eq(0.0)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it 'returns ratio of corrected to total' do
|
|
164
|
+
monitor.register_error(action: :first, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
165
|
+
monitor.register_error(action: :second, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
166
|
+
monitor.register_correction(action: :first, domain: :d, original_error: :a, correction: :fix)
|
|
167
|
+
expect(monitor.correction_rate).to eq(0.5)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe '#to_h' do
|
|
172
|
+
it 'returns stats hash' do
|
|
173
|
+
h = monitor.to_h
|
|
174
|
+
expect(h).to include(:error_rate, :conflict_level, :confidence, :slowdown, :state,
|
|
175
|
+
:state_label, :total_errors, :uncorrected, :correction_rate, :conflict_active)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::ErrorMonitoring::Helpers::ErrorSignal do
|
|
4
|
+
subject(:signal) do
|
|
5
|
+
described_class.new(action: :api_call, domain: :network, intended: :success, actual: :timeout, severity: 0.7)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
let(:constants) { Legion::Extensions::Agentic::Defense::ErrorMonitoring::Helpers::Constants }
|
|
9
|
+
|
|
10
|
+
describe '#initialize' do
|
|
11
|
+
it 'sets attributes' do
|
|
12
|
+
expect(signal.action).to eq(:api_call)
|
|
13
|
+
expect(signal.domain).to eq(:network)
|
|
14
|
+
expect(signal.intended).to eq(:success)
|
|
15
|
+
expect(signal.actual).to eq(:timeout)
|
|
16
|
+
expect(signal.severity).to eq(0.7)
|
|
17
|
+
expect(signal.corrected).to be false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'clamps severity' do
|
|
21
|
+
high = described_class.new(action: :a, domain: :d, intended: :i, actual: :a, severity: 1.5)
|
|
22
|
+
expect(high.severity).to eq(1.0)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'records detected_at' do
|
|
26
|
+
expect(signal.detected_at).to be_a(Time)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#mark_corrected' do
|
|
31
|
+
it 'marks the error as corrected' do
|
|
32
|
+
signal.mark_corrected
|
|
33
|
+
expect(signal.corrected).to be true
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#severe?' do
|
|
38
|
+
it 'returns true for high severity' do
|
|
39
|
+
expect(signal.severe?).to be true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'returns false for low severity' do
|
|
43
|
+
low = described_class.new(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
44
|
+
expect(low.severe?).to be false
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#age' do
|
|
49
|
+
it 'returns elapsed time' do
|
|
50
|
+
expect(signal.age).to be >= 0.0
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#label' do
|
|
55
|
+
it 'returns :major for 0.7 severity' do
|
|
56
|
+
expect(signal.label).to eq(:major)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'returns :trivial for low severity' do
|
|
60
|
+
low = described_class.new(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.1)
|
|
61
|
+
expect(low.label).to eq(:trivial)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'returns :critical for high severity' do
|
|
65
|
+
crit = described_class.new(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.9)
|
|
66
|
+
expect(crit.label).to eq(:critical)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe '#to_h' do
|
|
71
|
+
it 'returns hash with all fields' do
|
|
72
|
+
h = signal.to_h
|
|
73
|
+
expect(h).to include(:action, :domain, :intended, :actual, :severity, :label, :detected_at, :corrected, :age)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::ErrorMonitoring::Runners::ErrorMonitoring do
|
|
4
|
+
let(:client) { Legion::Extensions::Agentic::Defense::ErrorMonitoring::Client.new }
|
|
5
|
+
|
|
6
|
+
describe '#report_error' do
|
|
7
|
+
it 'registers an error' do
|
|
8
|
+
result = client.report_error(action: :api_call, domain: :network, intended: :ok, actual: :timeout, severity: 0.6)
|
|
9
|
+
expect(result[:success]).to be true
|
|
10
|
+
expect(result[:error][:action]).to eq(:api_call)
|
|
11
|
+
expect(result[:slowdown]).to be > 0
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '#report_success' do
|
|
16
|
+
it 'registers a success' do
|
|
17
|
+
result = client.report_success(action: :api_call, domain: :network)
|
|
18
|
+
expect(result[:success]).to be true
|
|
19
|
+
expect(result[:error_rate]).to be_a(Float)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#report_conflict' do
|
|
24
|
+
it 'registers a conflict' do
|
|
25
|
+
result = client.report_conflict(action_a: :run, action_b: :hide, domain: :safety, intensity: 0.7)
|
|
26
|
+
expect(result[:success]).to be true
|
|
27
|
+
expect(result[:conflict][:action_a]).to eq(:run)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe '#apply_correction' do
|
|
32
|
+
it 'applies a correction' do
|
|
33
|
+
client.report_error(action: :parse, domain: :data, intended: :valid, actual: :bad, severity: 0.5)
|
|
34
|
+
result = client.apply_correction(action: :parse, domain: :data, original_error: :bad, correction: :retry)
|
|
35
|
+
expect(result[:success]).to be true
|
|
36
|
+
expect(result[:confidence]).to be > 0
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe '#recent_errors' do
|
|
41
|
+
it 'returns recent errors' do
|
|
42
|
+
client.report_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
43
|
+
result = client.recent_errors(limit: 5)
|
|
44
|
+
expect(result[:count]).to eq(1)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#errors_in_domain' do
|
|
49
|
+
it 'filters errors by domain' do
|
|
50
|
+
client.report_error(action: :a, domain: :net, intended: :i, actual: :a, severity: 0.3)
|
|
51
|
+
client.report_error(action: :b, domain: :data, intended: :i, actual: :a, severity: 0.3)
|
|
52
|
+
result = client.errors_in_domain(domain: :net)
|
|
53
|
+
expect(result[:count]).to eq(1)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe '#uncorrected_errors' do
|
|
58
|
+
it 'returns uncorrected errors' do
|
|
59
|
+
client.report_error(action: :a, domain: :d, intended: :i, actual: :a, severity: 0.3)
|
|
60
|
+
result = client.uncorrected_errors
|
|
61
|
+
expect(result[:count]).to eq(1)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#monitoring_state' do
|
|
66
|
+
it 'returns current state' do
|
|
67
|
+
result = client.monitoring_state
|
|
68
|
+
expect(result[:success]).to be true
|
|
69
|
+
expect(result[:state]).to be_a(Symbol)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe '#update_error_monitoring' do
|
|
74
|
+
it 'runs tick' do
|
|
75
|
+
result = client.update_error_monitoring
|
|
76
|
+
expect(result[:success]).to be true
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe '#error_monitoring_stats' do
|
|
81
|
+
it 'returns stats' do
|
|
82
|
+
result = client.error_monitoring_stats
|
|
83
|
+
expect(result[:success]).to be true
|
|
84
|
+
expect(result[:stats]).to include(:error_rate, :confidence, :state)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Actors
|
|
6
|
+
class Every; end # rubocop:disable Lint/EmptyClass
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
$LOADED_FEATURES << 'legion/extensions/actors/every'
|
|
12
|
+
|
|
13
|
+
require_relative '../../../../../../../lib/legion/extensions/agentic/defense/extinction/actors/protocol_monitor'
|
|
14
|
+
|
|
15
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Actor::ProtocolMonitor do
|
|
16
|
+
subject(:actor) { described_class.new }
|
|
17
|
+
|
|
18
|
+
describe '#runner_class' do
|
|
19
|
+
it { expect(actor.runner_class).to eq Legion::Extensions::Agentic::Defense::Extinction::Runners::Extinction }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#runner_function' do
|
|
23
|
+
it { expect(actor.runner_function).to eq 'monitor_protocol' }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#time' do
|
|
27
|
+
it { expect(actor.time).to eq 300 }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#run_now?' do
|
|
31
|
+
it { expect(actor.run_now?).to be false }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#use_runner?' do
|
|
35
|
+
it { expect(actor.use_runner?).to be false }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#check_subtask?' do
|
|
39
|
+
it { expect(actor.check_subtask?).to be false }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#generate_task?' do
|
|
43
|
+
it { expect(actor.generate_task?).to be false }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/defense/extinction/client'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Client do
|
|
6
|
+
it 'responds to extinction runner methods' do
|
|
7
|
+
client = described_class.new
|
|
8
|
+
expect(client).to respond_to(:escalate)
|
|
9
|
+
expect(client).to respond_to(:deescalate)
|
|
10
|
+
expect(client).to respond_to(:extinction_status)
|
|
11
|
+
expect(client).to respond_to(:check_reversibility)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/agentic/defense/extinction/helpers/levels'
|
|
4
|
+
|
|
5
|
+
RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Helpers::Levels do
|
|
6
|
+
describe 'ESCALATION_LEVELS' do
|
|
7
|
+
it 'defines exactly four levels' do
|
|
8
|
+
expect(described_class::ESCALATION_LEVELS.size).to eq(4)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'is keyed by integers 1 through 4' do
|
|
12
|
+
expect(described_class::ESCALATION_LEVELS.keys).to eq([1, 2, 3, 4])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'is frozen' do
|
|
16
|
+
expect(described_class::ESCALATION_LEVELS).to be_frozen
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'defines level 1 as mesh_isolation' do
|
|
20
|
+
expect(described_class::ESCALATION_LEVELS[1][:name]).to eq(:mesh_isolation)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'defines level 2 as forced_sentinel' do
|
|
24
|
+
expect(described_class::ESCALATION_LEVELS[2][:name]).to eq(:forced_sentinel)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'defines level 3 as full_suspension' do
|
|
28
|
+
expect(described_class::ESCALATION_LEVELS[3][:name]).to eq(:full_suspension)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'defines level 4 as cryptographic_erasure' do
|
|
32
|
+
expect(described_class::ESCALATION_LEVELS[4][:name]).to eq(:cryptographic_erasure)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'marks levels 1-3 as reversible' do
|
|
36
|
+
[1, 2, 3].each do |level|
|
|
37
|
+
expect(described_class::ESCALATION_LEVELS[level][:reversible]).to be true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'marks level 4 as not reversible' do
|
|
42
|
+
expect(described_class::ESCALATION_LEVELS[4][:reversible]).to be false
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'assigns governance_council authority to levels 1 and 2' do
|
|
46
|
+
expect(described_class::ESCALATION_LEVELS[1][:authority]).to eq(:governance_council)
|
|
47
|
+
expect(described_class::ESCALATION_LEVELS[2][:authority]).to eq(:governance_council)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'assigns council_plus_executive authority to level 3' do
|
|
51
|
+
expect(described_class::ESCALATION_LEVELS[3][:authority]).to eq(:council_plus_executive)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'assigns physical_keyholders authority to level 4' do
|
|
55
|
+
expect(described_class::ESCALATION_LEVELS[4][:authority]).to eq(:physical_keyholders)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe 'VALID_LEVELS' do
|
|
60
|
+
it 'contains exactly [1, 2, 3, 4]' do
|
|
61
|
+
expect(described_class::VALID_LEVELS).to eq([1, 2, 3, 4])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'is frozen' do
|
|
65
|
+
expect(described_class::VALID_LEVELS).to be_frozen
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe '.valid_level?' do
|
|
70
|
+
it 'returns true for level 1' do
|
|
71
|
+
expect(described_class.valid_level?(1)).to be true
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'returns true for level 2' do
|
|
75
|
+
expect(described_class.valid_level?(2)).to be true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'returns true for level 3' do
|
|
79
|
+
expect(described_class.valid_level?(3)).to be true
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'returns true for level 4' do
|
|
83
|
+
expect(described_class.valid_level?(4)).to be true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'returns false for level 0' do
|
|
87
|
+
expect(described_class.valid_level?(0)).to be false
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it 'returns false for level 5' do
|
|
91
|
+
expect(described_class.valid_level?(5)).to be false
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'returns false for negative levels' do
|
|
95
|
+
expect(described_class.valid_level?(-1)).to be false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'returns false for nil' do
|
|
99
|
+
expect(described_class.valid_level?(nil)).to be false
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'returns false for string level' do
|
|
103
|
+
expect(described_class.valid_level?('1')).to be false
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '.level_info' do
|
|
108
|
+
it 'returns the full info hash for a valid level' do
|
|
109
|
+
info = described_class.level_info(1)
|
|
110
|
+
expect(info).to be_a(Hash)
|
|
111
|
+
expect(info.keys).to contain_exactly(:name, :reversible, :authority)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'returns nil for an invalid level' do
|
|
115
|
+
expect(described_class.level_info(99)).to be_nil
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'returns nil for level 0' do
|
|
119
|
+
expect(described_class.level_info(0)).to be_nil
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
[1, 2, 3, 4].each do |level|
|
|
123
|
+
it "returns a hash for level #{level}" do
|
|
124
|
+
expect(described_class.level_info(level)).to be_a(Hash)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe '.reversible?' do
|
|
130
|
+
it 'returns true for level 1' do
|
|
131
|
+
expect(described_class.reversible?(1)).to be true
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'returns true for level 2' do
|
|
135
|
+
expect(described_class.reversible?(2)).to be true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'returns true for level 3' do
|
|
139
|
+
expect(described_class.reversible?(3)).to be true
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it 'returns false for level 4' do
|
|
143
|
+
expect(described_class.reversible?(4)).to be false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'returns false for an invalid level (fallback to false)' do
|
|
147
|
+
expect(described_class.reversible?(99)).to be false
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it 'returns false for nil level' do
|
|
151
|
+
expect(described_class.reversible?(nil)).to be false
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe '.required_authority' do
|
|
156
|
+
it 'returns :governance_council for level 1' do
|
|
157
|
+
expect(described_class.required_authority(1)).to eq(:governance_council)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'returns :governance_council for level 2' do
|
|
161
|
+
expect(described_class.required_authority(2)).to eq(:governance_council)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it 'returns :council_plus_executive for level 3' do
|
|
165
|
+
expect(described_class.required_authority(3)).to eq(:council_plus_executive)
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
it 'returns :physical_keyholders for level 4' do
|
|
169
|
+
expect(described_class.required_authority(4)).to eq(:physical_keyholders)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it 'returns nil for an invalid level' do
|
|
173
|
+
expect(described_class.required_authority(0)).to be_nil
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'returns nil for an out-of-range level' do
|
|
177
|
+
expect(described_class.required_authority(5)).to be_nil
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|