lex-synapse 0.2.2

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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +16 -0
  3. data/.gitignore +11 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +53 -0
  6. data/CHANGELOG.md +36 -0
  7. data/CLAUDE.md +98 -0
  8. data/Gemfile +16 -0
  9. data/README.md +156 -0
  10. data/Rakefile +7 -0
  11. data/lex-synapse.gemspec +31 -0
  12. data/lib/legion/extensions/synapse/actors/crystallize.rb +31 -0
  13. data/lib/legion/extensions/synapse/actors/decay.rb +31 -0
  14. data/lib/legion/extensions/synapse/actors/evaluate.rb +23 -0
  15. data/lib/legion/extensions/synapse/actors/homeostasis.rb +31 -0
  16. data/lib/legion/extensions/synapse/actors/pain.rb +23 -0
  17. data/lib/legion/extensions/synapse/client.rb +62 -0
  18. data/lib/legion/extensions/synapse/data/migrations/001_create_synapses.rb +26 -0
  19. data/lib/legion/extensions/synapse/data/migrations/002_create_synapse_mutations.rb +21 -0
  20. data/lib/legion/extensions/synapse/data/migrations/003_create_synapse_signals.rb +20 -0
  21. data/lib/legion/extensions/synapse/data/models/synapse.rb +16 -0
  22. data/lib/legion/extensions/synapse/data/models/synapse_mutation.rb +15 -0
  23. data/lib/legion/extensions/synapse/data/models/synapse_signal.rb +15 -0
  24. data/lib/legion/extensions/synapse/helpers/confidence.rb +75 -0
  25. data/lib/legion/extensions/synapse/helpers/homeostasis.rb +43 -0
  26. data/lib/legion/extensions/synapse/helpers/relationship_wrapper.rb +42 -0
  27. data/lib/legion/extensions/synapse/runners/crystallize.rb +45 -0
  28. data/lib/legion/extensions/synapse/runners/dream.rb +106 -0
  29. data/lib/legion/extensions/synapse/runners/evaluate.rb +101 -0
  30. data/lib/legion/extensions/synapse/runners/gaia_report.rb +68 -0
  31. data/lib/legion/extensions/synapse/runners/mutate.rb +67 -0
  32. data/lib/legion/extensions/synapse/runners/pain.rb +78 -0
  33. data/lib/legion/extensions/synapse/runners/promote.rb +79 -0
  34. data/lib/legion/extensions/synapse/runners/report.rb +50 -0
  35. data/lib/legion/extensions/synapse/runners/retrieve.rb +61 -0
  36. data/lib/legion/extensions/synapse/runners/revert.rb +58 -0
  37. data/lib/legion/extensions/synapse/transport/exchanges/synapse.rb +16 -0
  38. data/lib/legion/extensions/synapse/transport/messages/pain.rb +23 -0
  39. data/lib/legion/extensions/synapse/transport/messages/signal.rb +23 -0
  40. data/lib/legion/extensions/synapse/transport/queues/evaluate.rb +19 -0
  41. data/lib/legion/extensions/synapse/transport/queues/pain.rb +19 -0
  42. data/lib/legion/extensions/synapse/transport.rb +18 -0
  43. data/lib/legion/extensions/synapse/version.rb +9 -0
  44. data/lib/legion/extensions/synapse.rb +20 -0
  45. metadata +118 -0
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../helpers/confidence'
4
+ require_relative '../data/models/synapse'
5
+ require_relative '../data/models/synapse_signal'
6
+
7
+ module Legion
8
+ module Extensions
9
+ module Synapse
10
+ module Runners
11
+ module Pain
12
+ CONSECUTIVE_FAILURE_THRESHOLD = 3
13
+
14
+ def handle_pain(synapse_id:, task_id: nil)
15
+ synapse = Data::Model::Synapse[synapse_id]
16
+ return { success: false, error: 'synapse not found' } unless synapse
17
+
18
+ # Record failed signal
19
+ Data::Model::SynapseSignal.create(
20
+ synapse_id: synapse.id,
21
+ task_id: task_id,
22
+ passed_attention: true,
23
+ transform_success: true,
24
+ downstream_outcome: 'failed'
25
+ )
26
+
27
+ # Adjust confidence
28
+ new_confidence = Helpers::Confidence.adjust(synapse.confidence, :failure)
29
+ synapse.update(confidence: new_confidence)
30
+
31
+ # Check consecutive failures
32
+ consecutive = count_consecutive_failures(synapse)
33
+
34
+ result = { success: true, confidence: new_confidence, consecutive_failures: consecutive }
35
+
36
+ # Auto-revert on 3+ consecutive failures
37
+ if consecutive >= CONSECUTIVE_FAILURE_THRESHOLD
38
+ result[:action] = :auto_revert
39
+ result[:reverted] = true
40
+ end
41
+
42
+ # Check if confidence dropped below autonomy threshold
43
+ new_mode = Helpers::Confidence.autonomy_mode(new_confidence)
44
+ result[:mode] = new_mode
45
+
46
+ # Dampen if failure rate is extreme
47
+ if should_dampen_from_pain?(synapse)
48
+ synapse.update(status: 'dampened')
49
+ result[:dampened] = true
50
+ end
51
+
52
+ result
53
+ end
54
+
55
+ private
56
+
57
+ def count_consecutive_failures(synapse)
58
+ recent = synapse.signals_dataset
59
+ .order(Sequel.desc(:id))
60
+ .limit(CONSECUTIVE_FAILURE_THRESHOLD)
61
+ .all
62
+ recent.take_while { |s| s.downstream_outcome == 'failed' }.size
63
+ end
64
+
65
+ def should_dampen_from_pain?(synapse)
66
+ window_start = Time.now - 300
67
+ recent = synapse.signals_dataset
68
+ .where(downstream_outcome: 'failed')
69
+ .where { created_at >= window_start }
70
+ .count
71
+ baseline_signals = [synapse.baseline_throughput * 5, 5].max
72
+ recent > (baseline_signals * 2)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../data/models/synapse'
4
+ require_relative '../data/models/synapse_mutation'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Synapse
9
+ module Runners
10
+ module Promote
11
+ CONFIDENCE_THRESHOLD = 0.9
12
+ STABILITY_HOURS = 24
13
+
14
+ def promote(synapse_id: nil, **)
15
+ candidates = if synapse_id
16
+ s = Data::Model::Synapse[synapse_id]
17
+ s ? [s] : []
18
+ else
19
+ find_promotable
20
+ end
21
+
22
+ promoted = []
23
+ candidates.each do |synapse|
24
+ next unless promotable?(synapse)
25
+
26
+ entry = build_knowledge_entry(synapse)
27
+ promoted << entry
28
+ end
29
+
30
+ {
31
+ success: true,
32
+ promoted: promoted,
33
+ count: promoted.size
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ def find_promotable
40
+ Data::Model::Synapse
41
+ .where { confidence >= CONFIDENCE_THRESHOLD }
42
+ .where(status: 'active')
43
+ .all
44
+ end
45
+
46
+ def promotable?(synapse)
47
+ return false if synapse.confidence < CONFIDENCE_THRESHOLD
48
+ return false unless synapse.status == 'active'
49
+
50
+ recent_reverts = synapse.mutations_dataset
51
+ .where(outcome: 'reverted')
52
+ .where { created_at >= Time.now - (STABILITY_HOURS * 3600) }
53
+ .count
54
+ recent_reverts.zero?
55
+ end
56
+
57
+ def build_knowledge_entry(synapse)
58
+ {
59
+ content_type: 'synapse_pattern',
60
+ content: Legion::JSON.dump(
61
+ source_function_id: synapse.source_function_id,
62
+ target_function_id: synapse.target_function_id,
63
+ attention: synapse.attention,
64
+ transform: synapse.transform,
65
+ routing_strategy: synapse.routing_strategy,
66
+ confidence: synapse.confidence,
67
+ origin: synapse.origin,
68
+ version: synapse.version
69
+ ),
70
+ tags: ['synapse', "origin:#{synapse.origin}", "route:#{synapse.routing_strategy}"],
71
+ source_agent: 'lex-synapse',
72
+ synapse_id: synapse.id
73
+ }
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../data/models/synapse'
4
+ require_relative '../data/models/synapse_mutation'
5
+ require_relative '../data/models/synapse_signal'
6
+
7
+ module Legion
8
+ module Extensions
9
+ module Synapse
10
+ module Runners
11
+ module Report
12
+ def report(synapse_id:)
13
+ synapse = Data::Model::Synapse[synapse_id]
14
+ return { success: false, error: 'synapse not found' } unless synapse
15
+
16
+ signals = synapse.signals_dataset
17
+ window_start = Time.now - 86_400
18
+ recent_signals = signals.where { created_at >= window_start }
19
+
20
+ total_recent = recent_signals.count
21
+ successful = recent_signals.where(downstream_outcome: 'success').count
22
+ success_rate = total_recent.positive? ? (successful.to_f / total_recent).round(4) : 0.0
23
+
24
+ last_mutation = synapse.mutations_dataset.order(Sequel.desc(:id)).first
25
+
26
+ {
27
+ success: true,
28
+ synapse_id: synapse.id,
29
+ confidence: synapse.confidence,
30
+ status: synapse.status,
31
+ origin: synapse.origin,
32
+ version: synapse.version,
33
+ signals_24h: total_recent,
34
+ success_rate: success_rate,
35
+ total_signals: signals.count,
36
+ last_mutation: if last_mutation
37
+ {
38
+ type: last_mutation.mutation_type,
39
+ trigger: last_mutation.trigger,
40
+ version: last_mutation.version,
41
+ outcome: last_mutation.outcome
42
+ }
43
+ end
44
+ }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../data/models/synapse'
4
+ require_relative '../helpers/confidence'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Synapse
9
+ module Runners
10
+ module Retrieve
11
+ SEED_CONFIDENCE_THRESHOLD = 0.7
12
+
13
+ def retrieve_and_seed(knowledge_entries:, **)
14
+ seeded = []
15
+
16
+ knowledge_entries.each do |entry|
17
+ next unless entry[:confidence] && entry[:confidence] >= SEED_CONFIDENCE_THRESHOLD
18
+ next unless entry[:content_type] == 'synapse_pattern'
19
+
20
+ pattern = parse_pattern(entry)
21
+ next unless pattern
22
+ next if synapse_exists?(pattern[:source_function_id], pattern[:target_function_id])
23
+
24
+ synapse = Data::Model::Synapse.create(
25
+ source_function_id: pattern[:source_function_id],
26
+ target_function_id: pattern[:target_function_id],
27
+ attention: pattern[:attention],
28
+ transform: pattern[:transform],
29
+ routing_strategy: pattern[:routing_strategy] || 'direct',
30
+ origin: 'seeded',
31
+ confidence: Helpers::Confidence.starting_score(:seeded),
32
+ status: 'active'
33
+ )
34
+ seeded << { id: synapse.id, source: pattern[:source_function_id], target: pattern[:target_function_id] }
35
+ end
36
+
37
+ { success: true, seeded: seeded, count: seeded.size }
38
+ end
39
+
40
+ private
41
+
42
+ def parse_pattern(entry)
43
+ content = entry[:content]
44
+ return nil unless content
45
+
46
+ content.is_a?(String) ? Legion::JSON.load(content) : content
47
+ rescue StandardError
48
+ nil
49
+ end
50
+
51
+ def synapse_exists?(source_id, target_id)
52
+ Data::Model::Synapse.where(
53
+ source_function_id: source_id,
54
+ target_function_id: target_id
55
+ ).any?
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../data/models/synapse'
4
+ require_relative '../data/models/synapse_mutation'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Synapse
9
+ module Runners
10
+ module Revert
11
+ def revert(synapse_id:, to_version: nil, trigger: 'pain')
12
+ synapse = Data::Model::Synapse[synapse_id]
13
+ return { success: false, error: 'synapse not found' } unless synapse
14
+
15
+ # to_version specifies which mutation record to look up (by version number).
16
+ # Reverting mutation at version N restores its before_state, landing at N-1.
17
+ mutation_version = to_version || synapse.version
18
+ return { success: false, error: 'no previous version' } if mutation_version < 2
19
+
20
+ mutation = Data::Model::SynapseMutation.where(
21
+ synapse_id: synapse.id,
22
+ version: mutation_version
23
+ ).first
24
+
25
+ return { success: false, error: "mutation version #{mutation_version} not found" } unless mutation
26
+
27
+ restored_version = mutation_version - 1
28
+ before_state = Legion::JSON.load(mutation.before_state)
29
+ synapse.update(
30
+ attention: before_state[:attention],
31
+ transform: before_state[:transform],
32
+ routing_strategy: before_state[:routing_strategy],
33
+ confidence: before_state[:confidence] || synapse.confidence,
34
+ status: before_state[:status] || synapse.status,
35
+ version: restored_version
36
+ )
37
+
38
+ # Mark the reverted mutation
39
+ mutation.update(outcome: 'reverted')
40
+
41
+ # Record the revert as a new mutation
42
+ Data::Model::SynapseMutation.create(
43
+ synapse_id: synapse.id,
44
+ version: restored_version,
45
+ mutation_type: 'confidence_changed',
46
+ before_state: mutation.after_state,
47
+ after_state: mutation.before_state,
48
+ trigger: trigger,
49
+ outcome: 'reverted'
50
+ )
51
+
52
+ { success: true, reverted_to: restored_version, synapse_id: synapse.id }
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ module Exchanges
8
+ if defined?(Legion::Transport::Exchanges::Task)
9
+ class Synapse < Legion::Transport::Exchanges::Task
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ module Messages
8
+ if defined?(Legion::Transport::Message)
9
+ class Pain < Legion::Transport::Message
10
+ def routing_key
11
+ 'synapse.pain'
12
+ end
13
+
14
+ def exchange
15
+ Legion::Transport::Exchanges::Task
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ module Messages
8
+ if defined?(Legion::Transport::Message)
9
+ class Signal < Legion::Transport::Message
10
+ def routing_key
11
+ 'synapse.signal'
12
+ end
13
+
14
+ def exchange
15
+ Legion::Transport::Exchanges::Task
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ module Queues
8
+ if defined?(Legion::Transport::Queue)
9
+ class Evaluate < Legion::Transport::Queue
10
+ def queue_name
11
+ 'synapse.evaluate'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ module Queues
8
+ if defined?(Legion::Transport::Queue)
9
+ class Pain < Legion::Transport::Queue
10
+ def queue_name
11
+ 'synapse.pain'
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ module Transport
7
+ extend Legion::Extensions::Transport if defined?(Legion::Extensions::Transport)
8
+
9
+ def self.additional_e_to_q
10
+ [
11
+ { from: 'synapse', to: 'evaluate', routing_key: 'synapse.evaluate' },
12
+ { from: 'task', to: 'pain', routing_key: 'task.failed' }
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Synapse
6
+ VERSION = '0.2.2'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/synapse/version'
4
+ require_relative 'synapse/client'
5
+
6
+ module Legion
7
+ module Extensions
8
+ module Synapse
9
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
10
+
11
+ def self.data_required?
12
+ true
13
+ end
14
+
15
+ def data_required?
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lex-synapse
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Esity
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: lex-conditioner
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 0.3.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 0.3.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: lex-transformer
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.0
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.2.0
40
+ description: Attention, transformation, and routing with confidence scoring, pain
41
+ signals, homeostasis, and self-governance
42
+ email:
43
+ - matthewdiverson@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".github/workflows/ci.yml"
49
+ - ".gitignore"
50
+ - ".rspec"
51
+ - ".rubocop.yml"
52
+ - CHANGELOG.md
53
+ - CLAUDE.md
54
+ - Gemfile
55
+ - README.md
56
+ - Rakefile
57
+ - lex-synapse.gemspec
58
+ - lib/legion/extensions/synapse.rb
59
+ - lib/legion/extensions/synapse/actors/crystallize.rb
60
+ - lib/legion/extensions/synapse/actors/decay.rb
61
+ - lib/legion/extensions/synapse/actors/evaluate.rb
62
+ - lib/legion/extensions/synapse/actors/homeostasis.rb
63
+ - lib/legion/extensions/synapse/actors/pain.rb
64
+ - lib/legion/extensions/synapse/client.rb
65
+ - lib/legion/extensions/synapse/data/migrations/001_create_synapses.rb
66
+ - lib/legion/extensions/synapse/data/migrations/002_create_synapse_mutations.rb
67
+ - lib/legion/extensions/synapse/data/migrations/003_create_synapse_signals.rb
68
+ - lib/legion/extensions/synapse/data/models/synapse.rb
69
+ - lib/legion/extensions/synapse/data/models/synapse_mutation.rb
70
+ - lib/legion/extensions/synapse/data/models/synapse_signal.rb
71
+ - lib/legion/extensions/synapse/helpers/confidence.rb
72
+ - lib/legion/extensions/synapse/helpers/homeostasis.rb
73
+ - lib/legion/extensions/synapse/helpers/relationship_wrapper.rb
74
+ - lib/legion/extensions/synapse/runners/crystallize.rb
75
+ - lib/legion/extensions/synapse/runners/dream.rb
76
+ - lib/legion/extensions/synapse/runners/evaluate.rb
77
+ - lib/legion/extensions/synapse/runners/gaia_report.rb
78
+ - lib/legion/extensions/synapse/runners/mutate.rb
79
+ - lib/legion/extensions/synapse/runners/pain.rb
80
+ - lib/legion/extensions/synapse/runners/promote.rb
81
+ - lib/legion/extensions/synapse/runners/report.rb
82
+ - lib/legion/extensions/synapse/runners/retrieve.rb
83
+ - lib/legion/extensions/synapse/runners/revert.rb
84
+ - lib/legion/extensions/synapse/transport.rb
85
+ - lib/legion/extensions/synapse/transport/exchanges/synapse.rb
86
+ - lib/legion/extensions/synapse/transport/messages/pain.rb
87
+ - lib/legion/extensions/synapse/transport/messages/signal.rb
88
+ - lib/legion/extensions/synapse/transport/queues/evaluate.rb
89
+ - lib/legion/extensions/synapse/transport/queues/pain.rb
90
+ - lib/legion/extensions/synapse/version.rb
91
+ homepage: https://github.com/LegionIO/lex-synapse
92
+ licenses:
93
+ - MIT
94
+ metadata:
95
+ homepage_uri: https://github.com/LegionIO/lex-synapse
96
+ source_code_uri: https://github.com/LegionIO/lex-synapse
97
+ documentation_uri: https://github.com/LegionIO/lex-synapse
98
+ changelog_uri: https://github.com/LegionIO/lex-synapse/blob/main/CHANGELOG.md
99
+ bug_tracker_uri: https://github.com/LegionIO/lex-synapse/issues
100
+ rubygems_mfa_required: 'true'
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '3.4'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.6.9
116
+ specification_version: 4
117
+ summary: Cognitive routing layer for LegionIO task chains
118
+ test_files: []