lex-synapse 0.4.12 → 0.4.14

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: 868277c8084e7cd4e50c660e65cf93d3bd3554c183f8c7852bddf7ae28ff91dd
4
- data.tar.gz: c588730afaa91b1842f35eb3e20584445ebb6f62d2e1042831de6942f9b712e7
3
+ metadata.gz: ac485ed070081893c396ca551525535a381c7dd906f481768697978644611c81
4
+ data.tar.gz: fa1d81ddeaf2d7193b5aee2f5145077c30c6bfb9f3be70b6b943e6605af70ea0
5
5
  SHA512:
6
- metadata.gz: 63aa10dd7948c59e7f3f603748a2bfa5bca217aad2dd99d05e898cdf9b102358c21f66b73d4eb258f81fed54b1c90dca23ce6569f942fa9db632fd269c564a8b
7
- data.tar.gz: dc9a028d79dca386c03672a46237d1190c8001ee35c9704630ed9b8f310ba38322983176d02d178ab979b2695699cbd0178addb4f890d5fe03b498bce4c1008b
6
+ metadata.gz: abbe160b11aac0d146b2fdfbddde252f9a74e85fccceba0ac9c09a155d2f181ad58e928e4fc0a423b2aaa01ec181b35721bc7b7ceb268f0d5297ba1f5ba0c776
7
+ data.tar.gz: c3859b52b5edb5a68ccb21fd5866acf7a6a4a2ded6dd0cbc40e37f2a0b0cf195e37c04115ae7b892bc2b2e027798c51a04b18bcddbde8c0ecdfd492f9269a955
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.14] - 2026-06-01
4
+ ### Fixed
5
+ - Homeostasis actor: convert raw signal counts to signals/minute for correct spike/drought comparison; batch all updates in a single DB transaction
6
+ - Evaluate runner: prevent double confidence adjustment when validation fails (`run_transform` already adjusts)
7
+ - Revert mutation: use unique version (`synapse.version + 1`) instead of `restored_version` to avoid version collision
8
+
9
+ ## [0.4.13] - 2026-05-07
10
+ ### Fixed
11
+ - `Homeostasis` actor: replace per-synapse `signals_dataset.count` with a single batched `GROUP BY` query to eliminate N+1 pool contention that caused `Sequel::PoolTimeout` on Postgres
12
+
3
13
  ## [0.4.12] - 2026-05-07
4
14
  ### Fixed
5
15
  - Added challenge proposal application through the mutate runner so auto-accepted proposals can advance to `applied` and later resolve challenger outcomes.
@@ -17,25 +17,50 @@ module Legion
17
17
  results = { spikes: 0, droughts: 0, updated: 0 }
18
18
  return results unless defined?(Legion::Extensions::Synapse::Data::Model::Synapse)
19
19
 
20
- Legion::Extensions::Synapse::Data::Model::Synapse
21
- .where(status: 'active')
22
- .where { baseline_throughput > 0 } # rubocop:disable Style/NumericPredicate
23
- .each do |synapse|
20
+ cutoff = Time.now - 60
21
+ window_seconds = 60.0
22
+ signal_model = Legion::Extensions::Synapse::Data::Model::SynapseSignal
23
+ synapse_model = Legion::Extensions::Synapse::Data::Model::Synapse
24
+
25
+ # Single query: count signals per synapse in the last 60s window
26
+ signal_counts = signal_model.where { created_at > cutoff }
27
+ .group_and_count(:synapse_id)
28
+ .as_hash(:synapse_id, :count)
29
+
30
+ # Fetch only active synapses with a nonzero baseline — eager-load to avoid N+1
31
+ active_synapses = synapse_model.where(status: 'active')
32
+ .where { baseline_throughput > 0 } # rubocop:disable Style/NumericPredicate
33
+ .all
34
+ return results if active_synapses.empty?
35
+
36
+ # Collect updates in memory, then apply in a single batch to avoid connection churn
37
+ updates = []
38
+
39
+ active_synapses.each do |synapse|
24
40
  baseline = synapse.baseline_throughput
25
- signals = synapse.signals_dataset.where { created_at > (Time.now - 60) }.count
26
- current = signals.to_f
41
+ # Convert raw count in the window to signals/minute for apples-to-apples comparison
42
+ current = (signal_counts.fetch(synapse.id, 0).to_f / window_seconds) * 60.0
27
43
 
28
- if Helpers::Homeostasis.spike?(current, baseline, duration_seconds: 60)
44
+ if Helpers::Homeostasis.spike?(current, baseline, duration_seconds: window_seconds)
29
45
  results[:spikes] += 1
30
- elsif Helpers::Homeostasis.drought?(current, baseline, silent_seconds: 60)
46
+ elsif Helpers::Homeostasis.drought?(current, baseline, silent_seconds: window_seconds)
31
47
  results[:droughts] += 1
32
48
  end
33
49
 
34
50
  new_baseline = Helpers::Homeostasis.update_baseline(baseline, current)
35
- synapse.update(baseline_throughput: new_baseline)
51
+ updates << { synapse_id: synapse.id, baseline_throughput: new_baseline }
36
52
  results[:updated] += 1
37
53
  end
38
54
 
55
+ # Batch-update all baselines in a single transaction
56
+ unless updates.empty?
57
+ synapse_model.db.transaction do
58
+ updates.each do |u|
59
+ synapse_model.where(id: u[:synapse_id]).update(baseline_throughput: u[:baseline_throughput])
60
+ end
61
+ end
62
+ end
63
+
39
64
  results
40
65
  end
41
66
  end
@@ -40,10 +40,15 @@ module Legion
40
40
  # Step 3: Record signal
41
41
  record_signal(synapse, attention_result[:passed], transform_result[:success], elapsed)
42
42
 
43
- # Step 4: Adjust confidence
44
- event = transform_result[:success] ? :success : :failure
45
- new_confidence = Helpers::Confidence.adjust(synapse.confidence, event)
46
- synapse.update(confidence: new_confidence)
43
+ # Step 4: Adjust confidence (skip if run_transform already penalized for validation failure)
44
+ if transform_result[:validation_failure]
45
+ # run_transform already adjusted confidence; reload to get the updated value
46
+ new_confidence = synapse.confidence
47
+ else
48
+ event = transform_result[:success] ? :success : :failure
49
+ new_confidence = Helpers::Confidence.adjust(synapse.confidence, event)
50
+ synapse.update(confidence: new_confidence)
51
+ end
47
52
 
48
53
  # Step 5: Generate proposals if autonomous
49
54
  if Helpers::Confidence.can_self_modify?(new_confidence) && Helpers::Proposals.reactive?
@@ -100,7 +105,7 @@ module Legion
100
105
  else
101
106
  new_conf = Helpers::Confidence.adjust(synapse.confidence, :validation_failure)
102
107
  synapse.update(confidence: new_conf)
103
- { success: false, result: payload, error: result[:errors] }
108
+ { success: false, result: payload, error: result[:errors], validation_failure: true }
104
109
  end
105
110
  end
106
111
 
@@ -28,6 +28,7 @@ module Legion
28
28
 
29
29
  restored_version = mutation_version - 1
30
30
  before_state = Legion::JSON.load(mutation.before_state)
31
+ revert_version = synapse.version + 1
31
32
  synapse.update(
32
33
  attention: before_state[:attention],
33
34
  transform: before_state[:transform],
@@ -40,10 +41,10 @@ module Legion
40
41
  # Mark the reverted mutation
41
42
  mutation.update(outcome: 'reverted')
42
43
 
43
- # Record the revert as a new mutation
44
+ # Record the revert as a new mutation (uses a unique version to avoid collision)
44
45
  Data::Model::SynapseMutation.create(
45
46
  synapse_id: synapse.id,
46
- version: restored_version,
47
+ version: revert_version,
47
48
  mutation_type: 'confidence_changed',
48
49
  before_state: mutation.after_state,
49
50
  after_state: mutation.before_state,
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Synapse
6
- VERSION = '0.4.12'
6
+ VERSION = '0.4.14'
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.12
4
+ version: 0.4.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity