lex-synapse 0.2.2 → 0.2.3

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: c1961edd72029f290abdb673e1a4b23736cdc52b963d11243e4f47e4f38c65f1
4
- data.tar.gz: 83be98e416e226e960e331fa24c197f99ff236cc419ea5afd26b050ee6e09fcd
3
+ metadata.gz: 15e9a0134efeddb2987af089e90c91d5f954524aa44c147ec5e11ae9eda9fd0f
4
+ data.tar.gz: b08d225fdd4d3db84155deb3a707dcc3f6f9ebfeb6e34cb1e71e057c1ef54801
5
5
  SHA512:
6
- metadata.gz: ef8000741910d6a3532cafb21a4c82924e17067359609524d41df993947677bc7fe6f505f3230cbdc94a89cca0c6a8e3db7a026a77aed2a4edb5f1a43030c227
7
- data.tar.gz: 86fccd6c3ecb7f4a43c0a5030c21a82af341ea50fc7e0b4e334ef77718c637358018a5fca556361ab2a26c2870879db1d54eb91505a947b9fbf3779aa05f16a4
6
+ metadata.gz: c6a75eff3fff57732dd4c50f2e5d2f9b94fde785ae4b5f7a3d7eedb3937eb96983c5ef1bb4f85f55229b744e80a4c98f779e69fca4d6cec3ff1fb3568694533a
7
+ data.tar.gz: da3a2b72741ddc1ac70319e3c2693c77ab050bc5c4b6fd6cefee301ba12bdfe820667356634de93ef8c614ea4a56e1e54f5761cc47ba76d42c1e32ae0ccb0745
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.3] - 2026-03-19
4
+
5
+ ### Fixed
6
+ - Guard synapse model definition against missing table at require time; replace eager `class Synapse < Sequel::Model(:synapses)` with lazy `define_synapse_model` module method that checks `Legion::Data` connected and `table_exists?` before defining the constant — prevents `PG::UndefinedTable` error when gem loads before migrations run
7
+ - Apply same lazy-define guard to `SynapseMutation` and `SynapseSignal` models
8
+ - Add explicit `set_primary_key :id` and `key:` options on associations in anonymous Sequel model classes to prevent Sequel inferring `_id` column name for unnamed classes
9
+ - Call `define_synapse_model` (and related) at the top of each runner method and `RelationshipWrapper` class method before first model reference
10
+
3
11
  ## [0.2.2] - 2026-03-18
4
12
 
5
13
  ### Fixed
data/CLAUDE.md CHANGED
@@ -28,7 +28,11 @@ Legion::Extensions::Synapse
28
28
  │ ├── Crystallize # unrouted traffic analysis, emergent creation
29
29
  │ ├── Mutate # versioned self-modification with snapshots
30
30
  │ ├── Revert # rollback to previous mutation version
31
- └── Report # aggregate stats for GAIA consumption
31
+ ├── Report # aggregate stats for GAIA consumption
32
+ │ ├── Dream # replay historical signals in simulation mode; replay/simulate
33
+ │ ├── GaiaReport # GAIA tick hook: report confidence and health per synapse
34
+ │ ├── Promote # Apollo integration: promote high-confidence synapse patterns to shared knowledge
35
+ │ └── Retrieve # Apollo integration: retrieve relevant synapse patterns from shared knowledge
32
36
  ├── Helpers/
33
37
  │ ├── Confidence # scoring, adjustments, autonomy ranges, decay
34
38
  │ ├── Homeostasis # spike/drought detection, baseline tracking
@@ -75,6 +79,13 @@ Legion::Extensions::Synapse
75
79
  - **synapse_mutations**: Versioned change history with before/after JSON snapshots
76
80
  - **synapse_signals**: Per-signal outcome records (attention pass, transform success, latency, downstream outcome)
77
81
 
82
+ ## GAIA / Apollo Integration (v0.2.2)
83
+
84
+ - **GaiaReport runner**: Called during the GAIA tick cycle to report per-synapse confidence and health metrics.
85
+ - **Dream runner**: Replays historical signals in simulation mode. Used by the dream cycle to test routing hypothesis changes without affecting live state.
86
+ - **Promote runner**: Publishes high-confidence synapse patterns to the Apollo shared knowledge store when confidence exceeds threshold.
87
+ - **Retrieve runner**: Pulls relevant synapse patterns from Apollo to seed new synapses or adjust confidence for cold-start scenarios.
88
+
78
89
  ## Dependencies
79
90
 
80
91
  | Gem | Purpose |
@@ -87,8 +98,8 @@ Legion::Extensions::Synapse
87
98
 
88
99
  ```bash
89
100
  bundle install
90
- bundle exec rspec
91
- bundle exec rubocop
101
+ bundle exec rspec # 308 specs, 0 failures
102
+ bundle exec rubocop # 0 offenses
92
103
  ```
93
104
 
94
105
  308 specs, 96%+ coverage. Uses in-memory SQLite for model/runner tests.
@@ -44,6 +44,7 @@ module Legion
44
44
 
45
45
  def create(source_function_id:, target_function_id:, attention: nil, transform: nil,
46
46
  routing_strategy: 'direct', origin: 'explicit', relationship_id: nil)
47
+ Data::Model.define_synapse_model
47
48
  Data::Model::Synapse.create(
48
49
  source_function_id: source_function_id,
49
50
  target_function_id: target_function_id,
@@ -5,9 +5,21 @@ module Legion
5
5
  module Synapse
6
6
  module Data
7
7
  module Model
8
- class Synapse < Sequel::Model(:synapses)
9
- one_to_many :mutations, class: 'Legion::Extensions::Synapse::Data::Model::SynapseMutation'
10
- one_to_many :signals, class: 'Legion::Extensions::Synapse::Data::Model::SynapseSignal'
8
+ def self.define_synapse_model
9
+ return if const_defined?(:Synapse, false)
10
+ return unless defined?(Legion::Data) && Legion::Settings.dig(:data, :connected)
11
+
12
+ db = Sequel::Model.db
13
+ return unless db&.table_exists?(:synapses)
14
+
15
+ klass = Class.new(Sequel::Model(:synapses)) do
16
+ one_to_many :mutations, class: 'Legion::Extensions::Synapse::Data::Model::SynapseMutation',
17
+ key: :synapse_id
18
+ one_to_many :signals, class: 'Legion::Extensions::Synapse::Data::Model::SynapseSignal',
19
+ key: :synapse_id
20
+ end
21
+ klass.set_primary_key :id
22
+ const_set(:Synapse, klass)
11
23
  end
12
24
  end
13
25
  end
@@ -5,8 +5,19 @@ module Legion
5
5
  module Synapse
6
6
  module Data
7
7
  module Model
8
- class SynapseMutation < Sequel::Model(:synapse_mutations)
9
- many_to_one :synapse, class: 'Legion::Extensions::Synapse::Data::Model::Synapse'
8
+ def self.define_synapse_mutation_model
9
+ return if const_defined?(:SynapseMutation, false)
10
+ return unless defined?(Legion::Data) && Legion::Settings.dig(:data, :connected)
11
+
12
+ db = Sequel::Model.db
13
+ return unless db&.table_exists?(:synapse_mutations)
14
+
15
+ klass = Class.new(Sequel::Model(:synapse_mutations)) do
16
+ many_to_one :synapse, class: 'Legion::Extensions::Synapse::Data::Model::Synapse',
17
+ key: :synapse_id
18
+ end
19
+ klass.set_primary_key :id
20
+ const_set(:SynapseMutation, klass)
10
21
  end
11
22
  end
12
23
  end
@@ -5,8 +5,19 @@ module Legion
5
5
  module Synapse
6
6
  module Data
7
7
  module Model
8
- class SynapseSignal < Sequel::Model(:synapse_signals)
9
- many_to_one :synapse, class: 'Legion::Extensions::Synapse::Data::Model::Synapse'
8
+ def self.define_synapse_signal_model
9
+ return if const_defined?(:SynapseSignal, false)
10
+ return unless defined?(Legion::Data) && Legion::Settings.dig(:data, :connected)
11
+
12
+ db = Sequel::Model.db
13
+ return unless db&.table_exists?(:synapse_signals)
14
+
15
+ klass = Class.new(Sequel::Model(:synapse_signals)) do
16
+ many_to_one :synapse, class: 'Legion::Extensions::Synapse::Data::Model::Synapse',
17
+ key: :synapse_id
18
+ end
19
+ klass.set_primary_key :id
20
+ const_set(:SynapseSignal, klass)
10
21
  end
11
22
  end
12
23
  end
@@ -10,6 +10,7 @@ module Legion
10
10
  module RelationshipWrapper
11
11
  class << self
12
12
  def wrap(relationship)
13
+ Data::Model.define_synapse_model
13
14
  existing = Data::Model::Synapse.where(relationship_id: relationship[:id]).first
14
15
  return existing if existing
15
16
 
@@ -27,6 +28,7 @@ module Legion
27
28
  end
28
29
 
29
30
  def unwrap(synapse_id)
31
+ Data::Model.define_synapse_model
30
32
  synapse = Data::Model::Synapse[synapse_id]
31
33
  return { success: false, error: 'synapse not found' } unless synapse
32
34
  return { success: false, error: 'not a wrapped relationship' } unless synapse.relationship_id
@@ -11,6 +11,7 @@ module Legion
11
11
  EMERGENCE_THRESHOLD = 20
12
12
 
13
13
  def crystallize(signal_pairs: [], threshold: EMERGENCE_THRESHOLD)
14
+ Data::Model.define_synapse_model
14
15
  created = []
15
16
 
16
17
  signal_pairs.each do |pair|
@@ -10,6 +10,8 @@ module Legion
10
10
  module Runners
11
11
  module Dream
12
12
  def dream_replay(synapse_id: nil, **)
13
+ Data::Model.define_synapse_model
14
+ Data::Model.define_synapse_mutation_model
13
15
  synapses = if synapse_id
14
16
  s = Data::Model::Synapse[synapse_id]
15
17
  s ? [s] : []
@@ -27,6 +29,7 @@ module Legion
27
29
  end
28
30
 
29
31
  def dream_simulate(synapse_id:, mutation_type:, changes:, **)
32
+ Data::Model.define_synapse_model
30
33
  synapse = Data::Model::Synapse[synapse_id]
31
34
  return { success: false, error: 'synapse not found' } unless synapse
32
35
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../helpers/confidence'
4
4
  require_relative '../data/models/synapse'
5
+ require_relative '../data/models/synapse_mutation'
5
6
  require_relative '../data/models/synapse_signal'
6
7
 
7
8
  module Legion
@@ -10,6 +11,8 @@ module Legion
10
11
  module Runners
11
12
  module Evaluate
12
13
  def evaluate(synapse_id:, payload: {}, conditioner_client: nil, transformer_client: nil)
14
+ Data::Model.define_synapse_model
15
+ Data::Model.define_synapse_signal_model
13
16
  synapse = Data::Model::Synapse[synapse_id]
14
17
  return { success: false, error: 'synapse not found' } unless synapse
15
18
  return { success: false, error: 'synapse not active' } unless Helpers::Confidence::EVALUABLE_STATUSES.include?(synapse.status)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../data/models/synapse'
4
+ require_relative '../data/models/synapse_mutation'
4
5
  require_relative '../data/models/synapse_signal'
5
6
  require_relative '../helpers/confidence'
6
7
 
@@ -10,6 +11,7 @@ module Legion
10
11
  module Runners
11
12
  module GaiaReport
12
13
  def gaia_summary(**)
14
+ Data::Model.define_synapse_model
13
15
  synapses = Data::Model::Synapse.all
14
16
  active = synapses.select { |s| s.status == 'active' }
15
17
  dampened = synapses.select { |s| s.status == 'dampened' }
@@ -32,6 +34,7 @@ module Legion
32
34
  end
33
35
 
34
36
  def gaia_reflection(**)
37
+ Data::Model.define_synapse_mutation_model
35
38
  summary = gaia_summary
36
39
  recent_mutations = Data::Model::SynapseMutation
37
40
  .where { created_at >= Time.now - 3600 }
@@ -12,6 +12,8 @@ module Legion
12
12
  VALID_TRIGGERS = %w[hebbian pain dream gaia manual].freeze
13
13
 
14
14
  def mutate(synapse_id:, mutation_type:, changes:, trigger:)
15
+ Data::Model.define_synapse_model
16
+ Data::Model.define_synapse_mutation_model
15
17
  synapse = Data::Model::Synapse[synapse_id]
16
18
  return { success: false, error: 'synapse not found' } unless synapse
17
19
  return { success: false, error: "invalid mutation_type: #{mutation_type}" } unless VALID_MUTATION_TYPES.include?(mutation_type)
@@ -12,6 +12,8 @@ module Legion
12
12
  CONSECUTIVE_FAILURE_THRESHOLD = 3
13
13
 
14
14
  def handle_pain(synapse_id:, task_id: nil)
15
+ Data::Model.define_synapse_model
16
+ Data::Model.define_synapse_signal_model
15
17
  synapse = Data::Model::Synapse[synapse_id]
16
18
  return { success: false, error: 'synapse not found' } unless synapse
17
19
 
@@ -12,6 +12,8 @@ module Legion
12
12
  STABILITY_HOURS = 24
13
13
 
14
14
  def promote(synapse_id: nil, **)
15
+ Data::Model.define_synapse_model
16
+ Data::Model.define_synapse_mutation_model
15
17
  candidates = if synapse_id
16
18
  s = Data::Model::Synapse[synapse_id]
17
19
  s ? [s] : []
@@ -10,6 +10,9 @@ module Legion
10
10
  module Runners
11
11
  module Report
12
12
  def report(synapse_id:)
13
+ Data::Model.define_synapse_model
14
+ Data::Model.define_synapse_mutation_model
15
+ Data::Model.define_synapse_signal_model
13
16
  synapse = Data::Model::Synapse[synapse_id]
14
17
  return { success: false, error: 'synapse not found' } unless synapse
15
18
 
@@ -11,6 +11,7 @@ module Legion
11
11
  SEED_CONFIDENCE_THRESHOLD = 0.7
12
12
 
13
13
  def retrieve_and_seed(knowledge_entries:, **)
14
+ Data::Model.define_synapse_model
14
15
  seeded = []
15
16
 
16
17
  knowledge_entries.each do |entry|
@@ -9,6 +9,8 @@ module Legion
9
9
  module Runners
10
10
  module Revert
11
11
  def revert(synapse_id:, to_version: nil, trigger: 'pain')
12
+ Data::Model.define_synapse_model
13
+ Data::Model.define_synapse_mutation_model
12
14
  synapse = Data::Model::Synapse[synapse_id]
13
15
  return { success: false, error: 'synapse not found' } unless synapse
14
16
 
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Synapse
6
- VERSION = '0.2.2'
6
+ VERSION = '0.2.3'
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.2.2
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity