lex-synapse 0.4.11 → 0.4.12

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: 712f9976e4ce62962405f83fd39b3bd2dfa2ea678bed7f183a246b80506f6623
4
- data.tar.gz: 73c470450fd5d6800054c81441bc48bd603e12e161cc0e963a4306853de5fa5d
3
+ metadata.gz: 868277c8084e7cd4e50c660e65cf93d3bd3554c183f8c7852bddf7ae28ff91dd
4
+ data.tar.gz: c588730afaa91b1842f35eb3e20584445ebb6f62d2e1042831de6942f9b712e7
5
5
  SHA512:
6
- metadata.gz: 6356f7f31a55ac536e5d7d3d2aa2923bae4e723c1f4f3be68adf83027d8916020d19a44d363e199af015c825c5ccf0eeeeee0126e33396623e95b4af5b1cf7eb
7
- data.tar.gz: 0677dfdaa1c422b1db309036c2872d8b22473e376050a259ca16e8733d91cbfa720a18291b46c9119d28f6430b0d889cd5ab09ba83217fcca8dad3fcaa1f9b46
6
+ metadata.gz: 63aa10dd7948c59e7f3f603748a2bfa5bca217aad2dd99d05e898cdf9b102358c21f66b73d4eb258f81fed54b1c90dca23ce6569f942fa9db632fd269c564a8b
7
+ data.tar.gz: dc9a028d79dca386c03672a46237d1190c8001ee35c9704630ed9b8f310ba38322983176d02d178ab979b2695699cbd0178addb4f890d5fe03b498bce4c1008b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.12] - 2026-05-07
4
+ ### Fixed
5
+ - Added challenge proposal application through the mutate runner so auto-accepted proposals can advance to `applied` and later resolve challenger outcomes.
6
+ - Averaged resolved LLM challenger confidence, auto-accepted all-abstain challenges, and ensured proactive proposals store a non-empty candidate output.
7
+ - Look up target function schemas through extension discovery when building transform proposals.
8
+
3
9
  ## [0.4.11] - 2026-04-22
4
10
  ### Fixed
5
11
  - `handle_pain` now actually calls `revert` when consecutive failures reach threshold (was only setting a flag)
@@ -7,6 +7,7 @@ require_relative '../data/models/synapse_proposal'
7
7
  require_relative '../data/models/synapse_challenge'
8
8
  require_relative '../data/models/synapse_signal'
9
9
  require_relative 'blast_radius'
10
+ require_relative 'mutate'
10
11
 
11
12
  module Legion
12
13
  module Extensions
@@ -87,10 +88,37 @@ module Legion
87
88
  { success: true, proposal_id: proposal_id, success_rate: success_rate, resolved: challenges.size }
88
89
  end
89
90
 
91
+ def apply_proposal(proposal_id:)
92
+ Data::Model.define_synapse_proposal_model
93
+ Data::Model.define_synapse_model
94
+
95
+ proposal = Data::Model::SynapseProposal[proposal_id]
96
+ return { success: false, error: 'proposal not found' } unless proposal
97
+ return { success: false, error: 'proposal not approved' } unless %w[approved auto_accepted].include?(proposal.status)
98
+ return { success: false, error: 'proposal output missing' } if proposal.output.nil? || proposal.output.to_s.strip.empty?
99
+
100
+ synapse = Data::Model::Synapse[proposal.synapse_id]
101
+ return { success: false, error: 'synapse not found' } unless synapse
102
+
103
+ mutation = mutation_for_proposal(proposal)
104
+ return { success: false, error: "unsupported proposal_type: #{proposal.proposal_type}" } unless mutation
105
+
106
+ result = Object.new.extend(Mutate).mutate(
107
+ synapse_id: proposal.synapse_id,
108
+ mutation_type: mutation[:mutation_type],
109
+ changes: mutation[:changes],
110
+ trigger: 'gaia'
111
+ )
112
+ return result unless result[:success]
113
+
114
+ proposal.update(status: 'applied', reviewed_at: Time.now)
115
+ result.merge(proposal_id: proposal.id, status: 'applied', decision: 'applied')
116
+ end
117
+
90
118
  def run_challenge_cycle(transformer_client: nil)
91
119
  Data::Model.define_synapse_proposal_model
92
120
  Data::Model.define_synapse_challenge_model
93
- return { challenged: 0, resolved: 0 } unless Helpers::Challenge.enabled?
121
+ return { challenged: 0, applied: 0, resolved: 0 } unless Helpers::Challenge.enabled?
94
122
 
95
123
  settings = Helpers::Challenge.settings
96
124
  max = settings[:max_per_cycle] || 5
@@ -101,6 +129,12 @@ module Legion
101
129
  challenged += 1
102
130
  end
103
131
 
132
+ applied = 0
133
+ Data::Model::SynapseProposal.where(status: 'auto_accepted').order(Sequel.asc(:id)).limit(max).each do |proposal|
134
+ result = apply_proposal(proposal_id: proposal.id)
135
+ applied += 1 if result[:success]
136
+ end
137
+
104
138
  resolved = 0
105
139
  window = settings[:outcome_observation_window] || 50
106
140
  Data::Model.define_synapse_signal_model
@@ -118,11 +152,22 @@ module Legion
118
152
  resolved += 1
119
153
  end
120
154
 
121
- { challenged: challenged, resolved: resolved }
155
+ { challenged: challenged, applied: applied, resolved: resolved }
122
156
  end
123
157
 
124
158
  private
125
159
 
160
+ def mutation_for_proposal(proposal)
161
+ case proposal.proposal_type
162
+ when 'llm_transform', 'transform_mutation'
163
+ { mutation_type: 'transform_adjusted', changes: { transform: proposal.output } }
164
+ when 'attention_mutation'
165
+ { mutation_type: 'attention_adjusted', changes: { attention: proposal.output } }
166
+ when 'route_change'
167
+ { mutation_type: 'route_changed', changes: { routing_strategy: proposal.output } }
168
+ end
169
+ end
170
+
126
171
  def conflict_check(proposal)
127
172
  conflicts = Data::Model::SynapseProposal.where(
128
173
  synapse_id: proposal.synapse_id,
@@ -176,8 +221,8 @@ module Legion
176
221
  .exclude(verdict: 'abstain').all
177
222
 
178
223
  if challenges.empty?
179
- proposal.update(challenge_state: 'challenged', challenge_score: 0.5)
180
- return { success: true, challenge_score: 0.5, decision: 'challenged' }
224
+ proposal.update(status: 'auto_accepted', challenge_state: 'challenged', challenge_score: 0.0)
225
+ return { success: true, challenge_score: 0.0, decision: 'auto_accepted' }
181
226
  end
182
227
 
183
228
  support_weight = challenges.select { |c| c.verdict == 'support' }.sum(&:challenger_confidence)
@@ -253,7 +298,7 @@ module Legion
253
298
  .order(Sequel.desc(:id)).limit(20).all
254
299
  return Helpers::Challenge.settings[:challenger_starting_confidence] if recent.empty?
255
300
 
256
- recent.first.challenger_confidence
301
+ recent.sum(&:challenger_confidence).to_f / recent.size
257
302
  end
258
303
 
259
304
  include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
@@ -135,7 +135,7 @@ module Legion
135
135
  synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
136
136
  trigger: 'proactive',
137
137
  inputs: Legion::JSON.dump({ success_rate: rate.round(3), sample_size: signals.size, threshold: threshold }),
138
- output: nil,
138
+ output: proactive_transform_output(synapse, success_rate: rate.round(3), sample_size: signals.size),
139
139
  rationale: "success rate #{(rate * 100).round(1)}% below threshold #{(threshold * 100).round(1)}%"
140
140
  )
141
141
  end
@@ -156,7 +156,7 @@ module Legion
156
156
  synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
157
157
  trigger: 'proactive',
158
158
  inputs: Legion::JSON.dump({ drift_rate: drift_rate.round(3), sample_size: signals.size }),
159
- output: nil,
159
+ output: proactive_transform_output(synapse, drift_rate: drift_rate.round(3), sample_size: signals.size),
160
160
  rationale: "payload drift detected: #{(drift_rate * 100).round(1)}% transform failures in recent signals"
161
161
  )
162
162
  end
@@ -226,9 +226,25 @@ module Legion
226
226
 
227
227
  def lookup_target_schema(synapse)
228
228
  return {} unless synapse.target_function_id
229
- return {} unless defined?(Legion::Extensions::Lex)
230
229
 
231
- {}
230
+ discovery_schema(synapse.target_function_id) || {}
231
+ end
232
+
233
+ def discovery_schema(function_id)
234
+ discovery = defined?(Legion::Extensions::Discovery) && Legion::Extensions::Discovery
235
+ return unless discovery.respond_to?(:function_schema)
236
+
237
+ discovery.function_schema(function_id)
238
+ rescue StandardError => e
239
+ log.debug("lookup_target_schema failed for #{function_id}: #{e.message}")
240
+ nil
241
+ end
242
+
243
+ def proactive_transform_output(synapse, **metadata)
244
+ existing = synapse.transform.to_s.strip
245
+ return existing unless existing.empty?
246
+
247
+ Legion::JSON.dump(metadata.merge(action: 'review_transform', synapse_id: synapse.id))
232
248
  end
233
249
 
234
250
  def build_transform_prompt(source_schema, target_schema)
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Synapse
6
- VERSION = '0.4.11'
6
+ VERSION = '0.4.12'
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.11
4
+ version: 0.4.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity