lex-synapse 0.4.7 → 0.4.8

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: b6960778e841594a06db2ac55e26f4618d66c5d0316f7e4e586d784586509171
4
- data.tar.gz: cdf7db39426842d09a38241eb7ab3fb27e1329a6451d36de5bed80a669c96aa0
3
+ metadata.gz: 84bfe76b9dd10227586c084c8005ad9824ee092ba47d9c8dcf71f2756de07b12
4
+ data.tar.gz: 2d7f842ce4b07913213051c3a3bdf80dbdbeca2bad3b4613d873856a22f41cf0
5
5
  SHA512:
6
- metadata.gz: 2ece1da6b1a9ad7e142927113f23a9f10a05aee0a8cebea0aaf49dcec41fde032f9e98435254d5c7fe7ddda2d9d859c86fec6087607c2895841c5bb0eb36dbc9
7
- data.tar.gz: 48564fffc100fba87f7ab707e518b76322d556cea1dc2e11a3165b2a41d9e5c1572056bbe930810dc7f91a9c621f5994b3582781ac11469785509e5a4b266922
6
+ metadata.gz: 3c2a5c3ce4e8d4d4b86743234efc513a7b5540548331080b5a06db22ca6a018b1ea0abfdb4598496b29dae1ca67bc6553020ec880dc6cf66e3f58ebeee41f6be
7
+ data.tar.gz: 8853c5d3b0b8f814e49df2de326ad8d5070823b7210535d1d4a3d643b32a029aadc8add1bf9f879e99c11a4465eb7770522f473943095e2851cb04270ddc0911
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.8] - 2026-03-31
4
+
5
+ ### Added
6
+ - Migration 007: add blast radius columns to synapses (`blast_radius`, `propagation_depth`, `downstream_count`, `blast_radius_updated_at`)
7
+ - `Runners::BlastRadius`: BFS graph traversal computing propagation depth and downstream count per synapse; tier classification (LOW/MED/HIGH/CRITICAL) based on depth, downstream count, and throughput
8
+ - `Actor::BlastRadius`: periodic interval actor (every 30 minutes) calling `Runners::BlastRadius#compute`
9
+ - Blast radius multiplier wired into `Challenge#calculate_impact_score` (1.0x LOW, 1.5x MED, 2.0x HIGH, 3.0x CRITICAL)
10
+ - HIGH and CRITICAL synapses require LLM challenge review regardless of impact threshold
11
+ - `estimated_confidence_impact` on proposals now populated during challenge phase
12
+ - `GaiaReport#gaia_summary` includes `blast_distribution` breakdown (LOW/MED/HIGH/CRITICAL/unknown counts)
13
+
3
14
  ## [0.4.7] - 2026-03-30
4
15
 
5
16
  ### Changed
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../runners/blast_radius'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Synapse
8
+ module Actor
9
+ class BlastRadius < Legion::Extensions::Actors::Every
10
+ include Legion::Extensions::Synapse::Runners::BlastRadius
11
+
12
+ def runner_class = self.class
13
+
14
+ def runner_function
15
+ 'compute'
16
+ end
17
+
18
+ def time
19
+ 1800
20
+ end
21
+
22
+ def use_runner?
23
+ false
24
+ end
25
+
26
+ def check_subtask?
27
+ false
28
+ end
29
+
30
+ def generate_task?
31
+ false
32
+ end
33
+
34
+ def action(**_opts)
35
+ compute
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -11,6 +11,7 @@ require_relative 'runners/dream'
11
11
  require_relative 'runners/promote'
12
12
  require_relative 'runners/retrieve'
13
13
  require_relative 'runners/propose'
14
+ require_relative 'runners/blast_radius'
14
15
  require_relative 'runners/challenge'
15
16
  require_relative 'data/models/synapse_proposal'
16
17
  require_relative 'helpers/proposals'
@@ -30,6 +31,7 @@ module Legion
30
31
  include Runners::Promote
31
32
  include Runners::Retrieve
32
33
  include Runners::Propose
34
+ include Runners::BlastRadius
33
35
  include Runners::Challenge
34
36
 
35
37
  attr_reader :conditioner_client, :transformer_client
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ up do
5
+ alter_table(:synapses) do
6
+ add_column :blast_radius, String, size: 10
7
+ add_column :propagation_depth, Integer, default: 0
8
+ add_column :downstream_count, Integer, default: 0
9
+ add_column :blast_radius_updated_at, DateTime
10
+ end
11
+ end
12
+
13
+ down do
14
+ alter_table(:synapses) do
15
+ drop_column :blast_radius
16
+ drop_column :propagation_depth
17
+ drop_column :downstream_count
18
+ drop_column :blast_radius_updated_at
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../data/models/synapse'
4
+ require_relative '../data/models/synapse_proposal'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Synapse
9
+ module Runners
10
+ module BlastRadius
11
+ TIER_CRITICAL = 'CRITICAL'
12
+ TIER_HIGH = 'HIGH'
13
+ TIER_MED = 'MED'
14
+ TIER_LOW = 'LOW'
15
+
16
+ BLAST_MULTIPLIERS = {
17
+ TIER_LOW => 1.0,
18
+ TIER_MED => 1.5,
19
+ TIER_HIGH => 2.0,
20
+ TIER_CRITICAL => 3.0
21
+ }.freeze
22
+
23
+ def compute(**_opts)
24
+ Data::Model.define_synapse_model
25
+ return { success: false, error: 'data unavailable' } unless data_available?
26
+
27
+ synapses = Data::Model::Synapse.where(status: 'active').all
28
+ return { success: true, updated: 0, skipped: 0 } if synapses.empty?
29
+
30
+ graph = build_graph(synapses)
31
+ updated = 0
32
+ skipped = 0
33
+
34
+ synapses.each do |synapse|
35
+ depth, count = bfs_reachable(synapse.id, graph)
36
+ tier = classify_tier(
37
+ depth: depth,
38
+ downstream: count,
39
+ throughput: synapse.baseline_throughput.to_f
40
+ )
41
+
42
+ synapse.update(
43
+ propagation_depth: depth,
44
+ downstream_count: count,
45
+ blast_radius: tier,
46
+ blast_radius_updated_at: Time.now
47
+ )
48
+ updated += 1
49
+ rescue StandardError => e
50
+ log.warn("blast_radius update failed for synapse #{synapse.id}: #{e.message}")
51
+ skipped += 1
52
+ end
53
+
54
+ { success: true, updated: updated, skipped: skipped }
55
+ end
56
+
57
+ def blast_tier(synapse_id:)
58
+ Data::Model.define_synapse_model
59
+ synapse = Data::Model::Synapse[synapse_id]
60
+ return nil unless synapse
61
+
62
+ synapse.blast_radius
63
+ end
64
+
65
+ def blast_multiplier_for(blast_radius_tier)
66
+ BLAST_MULTIPLIERS.fetch(blast_radius_tier.to_s.upcase, 1.0)
67
+ end
68
+
69
+ def requires_llm_review?(blast_radius_tier)
70
+ tier = blast_radius_tier.to_s.upcase
71
+ [TIER_HIGH, TIER_CRITICAL].include?(tier)
72
+ end
73
+
74
+ private
75
+
76
+ def data_available?
77
+ defined?(Legion::Data) && Legion::Settings.dig(:data, :connected)
78
+ end
79
+
80
+ def build_graph(synapses)
81
+ graph = Hash.new { |h, k| h[k] = [] }
82
+ synapses.each do |s|
83
+ next unless s.source_function_id && s.target_function_id
84
+
85
+ graph[s.source_function_id] << s.target_function_id
86
+ end
87
+ graph
88
+ end
89
+
90
+ def bfs_reachable(synapse_id, graph)
91
+ synapse = Data::Model::Synapse[synapse_id]
92
+ return [0, 0] unless synapse&.source_function_id && synapse.target_function_id
93
+
94
+ start = synapse.source_function_id
95
+ visited = {}
96
+ queue = [[start, 0]]
97
+ max_depth = 0
98
+ reachable = 0
99
+
100
+ until queue.empty?
101
+ node, depth = queue.shift
102
+ next if visited[node]
103
+
104
+ visited[node] = true
105
+
106
+ if depth.positive?
107
+ reachable += 1
108
+ max_depth = depth if depth > max_depth
109
+ end
110
+
111
+ graph[node].each do |neighbor|
112
+ queue << [neighbor, depth + 1] unless visited[neighbor]
113
+ end
114
+ end
115
+
116
+ [max_depth, reachable]
117
+ end
118
+
119
+ def classify_tier(depth:, downstream:, throughput:)
120
+ if depth > 5 || downstream > 25 || throughput > 500
121
+ TIER_CRITICAL
122
+ elsif depth > 3 || downstream > 10 || throughput > 100
123
+ TIER_HIGH
124
+ elsif depth > 1 || downstream > 3
125
+ TIER_MED
126
+ else
127
+ TIER_LOW
128
+ end
129
+ end
130
+
131
+ def log_warn(message)
132
+ log.warn(message)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
@@ -6,12 +6,15 @@ require_relative '../data/models/synapse'
6
6
  require_relative '../data/models/synapse_proposal'
7
7
  require_relative '../data/models/synapse_challenge'
8
8
  require_relative '../data/models/synapse_signal'
9
+ require_relative 'blast_radius'
9
10
 
10
11
  module Legion
11
12
  module Extensions
12
13
  module Synapse
13
14
  module Runners
14
15
  module Challenge
16
+ include BlastRadius
17
+
15
18
  def pending_challenges
16
19
  Data::Model.define_synapse_proposal_model
17
20
  Data::Model::SynapseProposal.where(status: 'pending', challenge_state: nil)
@@ -36,11 +39,14 @@ module Legion
36
39
  proposal.update(challenge_state: 'challenging')
37
40
 
38
41
  impact = calculate_impact_score(proposal, synapse)
39
- proposal.update(impact_score: impact)
42
+ confidence_impact = estimate_confidence_impact(proposal, synapse)
43
+ proposal.update(impact_score: impact, estimated_confidence_impact: confidence_impact)
40
44
 
41
45
  conflict_check(proposal)
42
46
 
43
- llm_challenge(proposal, synapse, transformer_client) if Helpers::Challenge.above_impact_threshold?(impact) && transformer_client
47
+ needs_llm = Helpers::Challenge.above_impact_threshold?(impact) ||
48
+ requires_llm_review?(synapse.blast_radius.to_s)
49
+ llm_challenge(proposal, synapse, transformer_client) if needs_llm && transformer_client
44
50
 
45
51
  aggregate_challenges(proposal)
46
52
  end
@@ -201,7 +207,14 @@ module Legion
201
207
  baseline = [synapse.respond_to?(:baseline_throughput) && synapse.baseline_throughput ? synapse.baseline_throughput : 1.0, 1.0].max
202
208
  throughput_factor = [recent_signals.to_f / baseline, 2.0].min
203
209
 
204
- (base * synapse.confidence * throughput_factor).clamp(0.0, 1.0)
210
+ multiplier = blast_multiplier_for(synapse.blast_radius.to_s)
211
+ (base * synapse.confidence * throughput_factor * multiplier).clamp(0.0, 1.0)
212
+ end
213
+
214
+ def estimate_confidence_impact(proposal, synapse)
215
+ base = Helpers::Challenge::IMPACT_WEIGHTS.fetch(proposal.proposal_type, 0.5)
216
+ multiplier = blast_multiplier_for(synapse.blast_radius.to_s)
217
+ (base * multiplier * 0.1).clamp(0.0, 1.0)
205
218
  end
206
219
 
207
220
  def build_challenge_prompt(proposal, synapse)
@@ -29,7 +29,8 @@ module Legion
29
29
  elevated_pain_count: elevated_pain.size,
30
30
  avg_confidence: avg_confidence(active),
31
31
  emergent_candidates: observing.size,
32
- health_score: compute_health_score(active, dampened, elevated_pain)
32
+ health_score: compute_health_score(active, dampened, elevated_pain),
33
+ blast_distribution: blast_distribution(synapses)
33
34
  }
34
35
  end
35
36
 
@@ -64,6 +65,23 @@ module Legion
64
65
  healthy = active.size - elevated_pain.size
65
66
  (healthy.to_f / total).round(4).clamp(0.0, 1.0)
66
67
  end
68
+
69
+ def blast_distribution(synapses)
70
+ tiers = %w[LOW MED HIGH CRITICAL]
71
+ dist = tiers.to_h { |t| [t, 0] }
72
+ dist['unknown'] = 0
73
+
74
+ synapses.each do |s|
75
+ tier = s.respond_to?(:blast_radius) && s.blast_radius ? s.blast_radius.upcase : 'unknown'
76
+ if dist.key?(tier)
77
+ dist[tier] += 1
78
+ else
79
+ dist['unknown'] += 1
80
+ end
81
+ end
82
+
83
+ dist
84
+ end
67
85
  end
68
86
  end
69
87
  end
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Synapse
6
- VERSION = '0.4.7'
6
+ VERSION = '0.4.8'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-synapse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.7
4
+ version: 0.4.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -157,6 +157,7 @@ files:
157
157
  - Rakefile
158
158
  - lex-synapse.gemspec
159
159
  - lib/legion/extensions/synapse.rb
160
+ - lib/legion/extensions/synapse/actors/blast_radius.rb
160
161
  - lib/legion/extensions/synapse/actors/challenge.rb
161
162
  - lib/legion/extensions/synapse/actors/crystallize.rb
162
163
  - lib/legion/extensions/synapse/actors/decay.rb
@@ -171,6 +172,7 @@ files:
171
172
  - lib/legion/extensions/synapse/data/migrations/004_create_synapse_proposals.rb
172
173
  - lib/legion/extensions/synapse/data/migrations/005_add_synapse_challenges.rb
173
174
  - lib/legion/extensions/synapse/data/migrations/006_add_slow_query_indexes.rb
175
+ - lib/legion/extensions/synapse/data/migrations/007_add_blast_radius.rb
174
176
  - lib/legion/extensions/synapse/data/models/synapse.rb
175
177
  - lib/legion/extensions/synapse/data/models/synapse_challenge.rb
176
178
  - lib/legion/extensions/synapse/data/models/synapse_mutation.rb
@@ -181,6 +183,7 @@ files:
181
183
  - lib/legion/extensions/synapse/helpers/homeostasis.rb
182
184
  - lib/legion/extensions/synapse/helpers/proposals.rb
183
185
  - lib/legion/extensions/synapse/helpers/relationship_wrapper.rb
186
+ - lib/legion/extensions/synapse/runners/blast_radius.rb
184
187
  - lib/legion/extensions/synapse/runners/challenge.rb
185
188
  - lib/legion/extensions/synapse/runners/crystallize.rb
186
189
  - lib/legion/extensions/synapse/runners/dream.rb