lex-agentic-defense 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 438bf1f411bc8c25778ba2b7294eb8f9d2f5b0d917592e2840a8e3fc90456058
4
- data.tar.gz: d88fb5784d2d8c146f385d04f1b30c0c8347962161ce0f95d317bd2946c3d4c8
3
+ metadata.gz: 6d53484c4b3d4cc379b79f42e2a94fe6929f139c503399d10e07ed496c6afbe7
4
+ data.tar.gz: 7bdfe4bc6a78893edbbe26c3f5176a0f38dd1fcefbc0ff55df0336509b3e7486
5
5
  SHA512:
6
- metadata.gz: 6ea987da729a0f6da4eb313a8e7dbf9363c6bcbd5fdb165ba4849ec7f8a6a30e28e6dba79f1a26ea43709d95d756a61e365502d7d5625228ede0630b28ff9554
7
- data.tar.gz: df8661c7ddbe9d0ef6271308c2222671049fe8e5895e944fe6d7b1d5598b76c0513f80c6af6148588e8b02bc15a5d1ab0fde0b8b9b33c144368e4c862ab21827
6
+ metadata.gz: 37a236ec79ba72b1e31b2188bf5fc8b961b3c24950091b0119b0174abdac0ff2d21d52e77988ee1f0d2175999e9408ef2826ae782a50831bd87889f1c9cbef5c
7
+ data.tar.gz: 19afa627d4177d22c0820d98e025dcae485eb0fc0972d87fcf1cf2f1893ee44e3e1b4029361ab7e48fe5c988bc27de89cf4b6f27dacc8ec1ac4d5b5159aa0c7b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.10] - 2026-05-07
4
+ ### Fixed
5
+ - Extinction protocol authority checks now accept string authorities from JSON/API callers.
6
+ - Extinction state persistence failures are logged and return false below level 4, while level 4 erasure state failures raise instead of being swallowed.
7
+ - Level 4 Apollo erasure propagation now prefers the Apollo client when available.
8
+
3
9
  ## [0.1.9] - 2026-04-22
4
10
  ### Fixed
5
11
  - Confabulation decay actor now calls `decay_claims` instead of read-only `confabulation_report`; added `decay_claims` method to age out stale unverified claims
@@ -21,6 +21,7 @@ module Legion
21
21
  end
22
22
 
23
23
  def escalate(level, authority:, reason:)
24
+ authority = authority.to_sym if authority.respond_to?(:to_sym)
24
25
  return :invalid_level unless Levels.valid_level?(level)
25
26
  return :already_at_or_above if level <= @current_level
26
27
  return :insufficient_authority unless authority == Levels.required_authority(level)
@@ -37,6 +38,7 @@ module Legion
37
38
  end
38
39
 
39
40
  def deescalate(target_level, authority:, reason:)
41
+ authority = authority.to_sym if authority.respond_to?(:to_sym)
40
42
  return :not_active unless @active
41
43
  return :invalid_target if target_level >= @current_level
42
44
  return :irreversible unless Levels.reversible?(@current_level)
@@ -63,7 +65,7 @@ module Legion
63
65
  end
64
66
 
65
67
  def save_to_local
66
- return unless defined?(Legion::Data::Local) && local_data_connected?
68
+ return unless local_persistence_connected?
67
69
 
68
70
  row = {
69
71
  id: 1,
@@ -72,14 +74,18 @@ module Legion
72
74
  history: ::JSON.dump(@history.map { |h| h.merge(at: h[:at].to_s) }),
73
75
  updated_at: Time.now.utc
74
76
  }
75
- db = local_data_connection
77
+ db = local_persistence_connection
76
78
  if db[:extinction_state].where(id: 1).any?
77
79
  db[:extinction_state].where(id: 1).update(row.except(:id))
78
80
  else
79
81
  db[:extinction_state].insert(row)
80
82
  end
81
- rescue StandardError => _e
82
- nil
83
+ true
84
+ rescue StandardError => e
85
+ log.error("lex-extinction: save_to_local failed: #{e.message}")
86
+ raise if @current_level >= 4
87
+
88
+ false
83
89
  end
84
90
 
85
91
  private
@@ -89,17 +95,19 @@ module Legion
89
95
  end
90
96
 
91
97
  def load_from_local
92
- return unless defined?(Legion::Data::Local) && local_data_connected?
98
+ return unless local_persistence_connected?
93
99
 
94
- row = local_data_connection[:extinction_state].where(id: 1).first
100
+ row = local_persistence_connection[:extinction_state].where(id: 1).first
95
101
  return unless row
96
102
 
97
103
  db_level = row[:current_level].to_i
98
104
  @current_level = [db_level, @current_level].max
99
105
  @active = [true, 1].include?(row[:active])
100
106
  @history = parse_history(row[:history])
101
- rescue StandardError => _e
102
- nil
107
+ true
108
+ rescue StandardError => e
109
+ log.error("lex-extinction: load_from_local failed: #{e.message}")
110
+ false
103
111
  end
104
112
 
105
113
  def parse_history(raw)
@@ -116,6 +124,24 @@ module Legion
116
124
  rescue StandardError => _e
117
125
  []
118
126
  end
127
+
128
+ def local_persistence_connected?
129
+ local_data_connected?
130
+ rescue NoMethodError => e
131
+ log.debug("lex-extinction: local persistence availability unavailable: #{e.message}")
132
+ false
133
+ end
134
+
135
+ def local_persistence_connection
136
+ local_data_connection
137
+ rescue NoMethodError => e
138
+ log.debug("lex-extinction: local persistence connection unavailable: #{e.message}")
139
+ raise
140
+ end
141
+
142
+ def log
143
+ Legion::Logging
144
+ end
119
145
  end
120
146
  end
121
147
  end
@@ -103,6 +103,16 @@ module Legion
103
103
  end
104
104
  end
105
105
 
106
+ if defined?(Legion::Extensions::Apollo::Client)
107
+ begin
108
+ Legion::Extensions::Apollo::Client.new.handle_erasure_request(agent_id: 'system:extinction')
109
+ log.warn('[extinction] apollo erasure propagated')
110
+ return
111
+ rescue StandardError => e
112
+ log.error("[extinction] apollo erasure failed: #{e.message}")
113
+ end
114
+ end
115
+
106
116
  return unless defined?(Legion::Extensions::Apollo::Runners::Knowledge)
107
117
 
108
118
  begin
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Defense
7
- VERSION = '0.1.9'
7
+ VERSION = '0.1.10'
8
8
  end
9
9
  end
10
10
  end
@@ -78,6 +78,13 @@ RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Helpers::Protoc
78
78
  end
79
79
 
80
80
  context 'with valid escalation' do
81
+ it 'accepts string authorities from JSON/API callers' do
82
+ result = state.escalate(1, authority: 'governance_council', reason: 'threat')
83
+
84
+ expect(result).to eq(:escalated)
85
+ expect(state.history.last[:authority]).to eq(:governance_council)
86
+ end
87
+
81
88
  it 'returns :escalated for level 1 with governance_council' do
82
89
  expect(state.escalate(1, authority: :governance_council, reason: 'threat')).to eq(:escalated)
83
90
  end
@@ -207,6 +214,11 @@ RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Helpers::Protoc
207
214
  result = state.deescalate(0, authority: :council_plus_executive, reason: 'test')
208
215
  expect(result).to eq(:deescalated)
209
216
  end
217
+
218
+ it 'accepts string authority for deescalation' do
219
+ result = state.deescalate(0, authority: 'council_plus_executive', reason: 'test')
220
+ expect(result).to eq(:deescalated)
221
+ end
210
222
  end
211
223
 
212
224
  context 'with valid de-escalation' do
@@ -288,4 +300,24 @@ RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Helpers::Protoc
288
300
  expect(state.to_h[:history_size]).to eq(1)
289
301
  end
290
302
  end
303
+
304
+ describe '#save_to_local' do
305
+ it 'logs and returns false when persistence fails below level 4' do
306
+ state.instance_variable_set(:@current_level, 2)
307
+ allow(state).to receive(:local_data_connected?).and_return(true)
308
+ allow(state).to receive(:local_data_connection).and_raise(StandardError, 'disk full')
309
+
310
+ expect(Legion::Logging).to receive(:error).with(/save_to_local failed/)
311
+ expect(state.save_to_local).to be false
312
+ end
313
+
314
+ it 'raises when persistence fails for level 4 erasure state' do
315
+ state.instance_variable_set(:@current_level, 4)
316
+ allow(state).to receive(:local_data_connected?).and_return(true)
317
+ allow(state).to receive(:local_data_connection).and_raise(StandardError, 'disk full')
318
+ allow(Legion::Logging).to receive(:error)
319
+
320
+ expect { state.save_to_local }.to raise_error(StandardError, /disk full/)
321
+ end
322
+ end
291
323
  end
@@ -100,6 +100,25 @@ RSpec.describe Legion::Extensions::Agentic::Defense::Extinction::Runners::Extinc
100
100
  result = client.escalate(level: 4, authority: :physical_keyholders, reason: 'final')
101
101
  expect(result[:escalated]).to be true
102
102
  end
103
+
104
+ it 'uses Apollo client when it is available for level 4 erasure' do
105
+ events = Module.new { def self.emit(*, **); end }
106
+ stub_const('Legion::Events', events)
107
+ pc_mod = Module.new { def self.erase_all; end }
108
+ stub_const('Legion::Extensions::Privatecore::Runners::Privatecore', pc_mod)
109
+
110
+ apollo_client = instance_double('Legion::Extensions::Apollo::Client')
111
+ apollo_class = class_double('Legion::Extensions::Apollo::Client', new: apollo_client)
112
+ stub_const('Legion::Extensions::Apollo::Client', apollo_class)
113
+ allow(apollo_client).to receive(:handle_erasure_request).and_return({ deleted: 1 })
114
+
115
+ client.escalate(level: 1, authority: :governance_council, reason: 's1')
116
+ client.escalate(level: 2, authority: :governance_council, reason: 's2')
117
+ client.escalate(level: 3, authority: :council_plus_executive, reason: 's3')
118
+ client.escalate(level: 4, authority: :physical_keyholders, reason: 'final')
119
+
120
+ expect(apollo_client).to have_received(:handle_erasure_request).with(agent_id: 'system:extinction')
121
+ end
103
122
  end
104
123
 
105
124
  describe '#monitor_protocol' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-defense
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity