lex-synapse 0.2.2 → 0.3.0
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 +4 -4
- data/CHANGELOG.md +28 -0
- data/CLAUDE.md +30 -7
- data/lex-synapse.gemspec +1 -1
- data/lib/legion/extensions/synapse/actors/propose.rb +31 -0
- data/lib/legion/extensions/synapse/client.rb +23 -0
- data/lib/legion/extensions/synapse/data/migrations/004_create_synapse_proposals.rb +24 -0
- data/lib/legion/extensions/synapse/data/models/synapse.rb +17 -3
- data/lib/legion/extensions/synapse/data/models/synapse_mutation.rb +13 -2
- data/lib/legion/extensions/synapse/data/models/synapse_proposal.rb +26 -0
- data/lib/legion/extensions/synapse/data/models/synapse_signal.rb +13 -2
- data/lib/legion/extensions/synapse/helpers/proposals.rb +58 -0
- data/lib/legion/extensions/synapse/helpers/relationship_wrapper.rb +2 -0
- data/lib/legion/extensions/synapse/runners/crystallize.rb +1 -0
- data/lib/legion/extensions/synapse/runners/dream.rb +3 -0
- data/lib/legion/extensions/synapse/runners/evaluate.rb +18 -0
- data/lib/legion/extensions/synapse/runners/gaia_report.rb +3 -0
- data/lib/legion/extensions/synapse/runners/mutate.rb +2 -0
- data/lib/legion/extensions/synapse/runners/pain.rb +2 -0
- data/lib/legion/extensions/synapse/runners/promote.rb +2 -0
- data/lib/legion/extensions/synapse/runners/propose.rb +253 -0
- data/lib/legion/extensions/synapse/runners/report.rb +3 -0
- data/lib/legion/extensions/synapse/runners/retrieve.rb +1 -0
- data/lib/legion/extensions/synapse/runners/revert.rb +2 -0
- data/lib/legion/extensions/synapse/version.rb +1 -1
- metadata +8 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 60a95b064e889f6594f48ea66c0c12e8360b4679ef9daf572e31560e304ea277
|
|
4
|
+
data.tar.gz: a96ea18996d7b3d87ee309cbba68f2258b34f40fa9a0a61068562f81f347177d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9faa202ea887493c0ab6b3b9df9323757ca00e1fca347b0669876241ef4733aa4f333c5153c8b0a46d59fd28d6ba5e5286f5e7d541dc47d21e65ea4a9b6f554a
|
|
7
|
+
data.tar.gz: 85411a3ec047e7d9e944b61d08c03ab3ee3868f58887b6e13c3e6ab46d1fcad3ef5a56ddf73d12cc8a32a77b4d1c2d34386caa9d2711950c464a818229fdb495
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-03-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- Autonomous observation mode: proposal engine for AUTONOMOUS tier (confidence 0.8+)
|
|
7
|
+
- `synapse_proposals` table with migration 004
|
|
8
|
+
- `Runners::Propose` with reactive proposals (no-template, transform failure, pain correlation)
|
|
9
|
+
- `Runners::Propose` with proactive analysis (success rate degradation, payload drift)
|
|
10
|
+
- `Actors::Propose` periodic actor for proactive analysis (every 300s)
|
|
11
|
+
- `Helpers::Proposals` settings helper with configurable thresholds
|
|
12
|
+
- Proposal hook in `Runners::Evaluate` for autonomous synapses (gated by settings)
|
|
13
|
+
- Client `proposals(synapse_id:, status:)` query method
|
|
14
|
+
- Client `review_proposal(proposal_id:, status:)` for approving/rejecting proposals
|
|
15
|
+
- LLM-backed proposal generation via lex-transformer LLM engine
|
|
16
|
+
- Proposal deduplication within configurable window
|
|
17
|
+
- Integration specs for full proposal workflow
|
|
18
|
+
- Settings: `lex-synapse.proposals.*` for master switch, reactive/proactive toggles, max_per_run, LLM engine options, thresholds
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- `lex-transformer` dependency bumped to >= 0.3.0 (requires LLM engine with engine_options)
|
|
22
|
+
|
|
23
|
+
## [0.2.3] - 2026-03-19
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- 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
|
|
27
|
+
- Apply same lazy-define guard to `SynapseMutation` and `SynapseSignal` models
|
|
28
|
+
- 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
|
|
29
|
+
- Call `define_synapse_model` (and related) at the top of each runner method and `RelationshipWrapper` class method before first model reference
|
|
30
|
+
|
|
3
31
|
## [0.2.2] - 2026-03-18
|
|
4
32
|
|
|
5
33
|
### Fixed
|
data/CLAUDE.md
CHANGED
|
@@ -10,7 +10,7 @@ Cognitive routing layer that wraps task chain relationships with observation, le
|
|
|
10
10
|
|
|
11
11
|
**GitHub**: https://github.com/LegionIO/lex-synapse
|
|
12
12
|
**License**: MIT
|
|
13
|
-
**Version**: 0.
|
|
13
|
+
**Version**: 0.3.0
|
|
14
14
|
|
|
15
15
|
## Architecture
|
|
16
16
|
|
|
@@ -21,14 +21,20 @@ Legion::Extensions::Synapse
|
|
|
21
21
|
│ ├── Pain # Subscription — task.failed handler
|
|
22
22
|
│ ├── Crystallize # Every 300s — emergent synapse detection
|
|
23
23
|
│ ├── Homeostasis # Every 30s — spike/drought monitoring
|
|
24
|
-
│
|
|
24
|
+
│ ├── Decay # Every 3600s — idle confidence decay
|
|
25
|
+
│ └── Propose # Every 300s — proactive proposal analysis for AUTONOMOUS synapses
|
|
25
26
|
├── Runners/
|
|
26
27
|
│ ├── Evaluate # attention -> transform -> route -> record
|
|
27
28
|
│ ├── Pain # failure recording, confidence hit, auto-revert
|
|
28
29
|
│ ├── Crystallize # unrouted traffic analysis, emergent creation
|
|
29
30
|
│ ├── Mutate # versioned self-modification with snapshots
|
|
30
31
|
│ ├── Revert # rollback to previous mutation version
|
|
31
|
-
│
|
|
32
|
+
│ ├── Report # aggregate stats for GAIA consumption
|
|
33
|
+
│ ├── Dream # replay historical signals in simulation mode; replay/simulate
|
|
34
|
+
│ ├── GaiaReport # GAIA tick hook: report confidence and health per synapse
|
|
35
|
+
│ ├── Promote # Apollo integration: promote high-confidence synapse patterns to shared knowledge
|
|
36
|
+
│ ├── Retrieve # Apollo integration: retrieve relevant synapse patterns from shared knowledge
|
|
37
|
+
│ └── Propose # reactive (signal-driven) + proactive (periodic) proposal generation
|
|
32
38
|
├── Helpers/
|
|
33
39
|
│ ├── Confidence # scoring, adjustments, autonomy ranges, decay
|
|
34
40
|
│ ├── Homeostasis # spike/drought detection, baseline tracking
|
|
@@ -75,23 +81,40 @@ Legion::Extensions::Synapse
|
|
|
75
81
|
- **synapse_mutations**: Versioned change history with before/after JSON snapshots
|
|
76
82
|
- **synapse_signals**: Per-signal outcome records (attention pass, transform success, latency, downstream outcome)
|
|
77
83
|
|
|
84
|
+
## Autonomous Observation Mode (v0.3.0)
|
|
85
|
+
|
|
86
|
+
- **Proposal engine**: AUTONOMOUS tier (confidence 0.8+) generates proposals instead of executing autonomous actions
|
|
87
|
+
- **Reactive proposals**: on signal evaluation — no-template inference, transform failure fix, attention pain correlation
|
|
88
|
+
- **Proactive proposals**: periodic analysis — success rate degradation, payload drift detection
|
|
89
|
+
- **LLM-backed**: proposals call lex-transformer LLM engine for real output generation
|
|
90
|
+
- **Settings**: `lex-synapse.proposals.*` — enabled, reactive, proactive, max_per_run, llm_engine_options, thresholds
|
|
91
|
+
- **Data**: `synapse_proposals` table with status lifecycle (pending -> approved/rejected/applied/expired)
|
|
92
|
+
- **Client methods**: `proposals(synapse_id:, status:)`, `review_proposal(proposal_id:, status:)`
|
|
93
|
+
|
|
94
|
+
## GAIA / Apollo Integration (v0.2.2)
|
|
95
|
+
|
|
96
|
+
- **GaiaReport runner**: Called during the GAIA tick cycle to report per-synapse confidence and health metrics.
|
|
97
|
+
- **Dream runner**: Replays historical signals in simulation mode. Used by the dream cycle to test routing hypothesis changes without affecting live state.
|
|
98
|
+
- **Promote runner**: Publishes high-confidence synapse patterns to the Apollo shared knowledge store when confidence exceeds threshold.
|
|
99
|
+
- **Retrieve runner**: Pulls relevant synapse patterns from Apollo to seed new synapses or adjust confidence for cold-start scenarios.
|
|
100
|
+
|
|
78
101
|
## Dependencies
|
|
79
102
|
|
|
80
103
|
| Gem | Purpose |
|
|
81
104
|
|-----|---------|
|
|
82
105
|
| `lex-conditioner` >= 0.3.0 | Attention evaluation (condition rules) |
|
|
83
|
-
| `lex-transformer` >= 0.
|
|
106
|
+
| `lex-transformer` >= 0.3.0 | Payload transformation (template engines) |
|
|
84
107
|
| `legion-data` | Required — database persistence via Sequel |
|
|
85
108
|
|
|
86
109
|
## Testing
|
|
87
110
|
|
|
88
111
|
```bash
|
|
89
112
|
bundle install
|
|
90
|
-
bundle exec rspec
|
|
91
|
-
bundle exec rubocop
|
|
113
|
+
bundle exec rspec # 366 specs, 0 failures
|
|
114
|
+
bundle exec rubocop # 0 offenses
|
|
92
115
|
```
|
|
93
116
|
|
|
94
|
-
|
|
117
|
+
366 specs, 95%+ coverage. Uses in-memory SQLite for model/runner tests.
|
|
95
118
|
|
|
96
119
|
---
|
|
97
120
|
|
data/lex-synapse.gemspec
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Synapse
|
|
6
|
+
module Actor
|
|
7
|
+
class Propose < Legion::Extensions::Actors::Every
|
|
8
|
+
def runner_function
|
|
9
|
+
'propose_proactive'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def time
|
|
13
|
+
300
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def use_runner?
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def check_subtask?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def generate_task?
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -10,6 +10,9 @@ require_relative 'runners/gaia_report'
|
|
|
10
10
|
require_relative 'runners/dream'
|
|
11
11
|
require_relative 'runners/promote'
|
|
12
12
|
require_relative 'runners/retrieve'
|
|
13
|
+
require_relative 'runners/propose'
|
|
14
|
+
require_relative 'data/models/synapse_proposal'
|
|
15
|
+
require_relative 'helpers/proposals'
|
|
13
16
|
|
|
14
17
|
module Legion
|
|
15
18
|
module Extensions
|
|
@@ -25,6 +28,7 @@ module Legion
|
|
|
25
28
|
include Runners::Dream
|
|
26
29
|
include Runners::Promote
|
|
27
30
|
include Runners::Retrieve
|
|
31
|
+
include Runners::Propose
|
|
28
32
|
|
|
29
33
|
attr_reader :conditioner_client, :transformer_client
|
|
30
34
|
|
|
@@ -44,6 +48,7 @@ module Legion
|
|
|
44
48
|
|
|
45
49
|
def create(source_function_id:, target_function_id:, attention: nil, transform: nil,
|
|
46
50
|
routing_strategy: 'direct', origin: 'explicit', relationship_id: nil)
|
|
51
|
+
Data::Model.define_synapse_model
|
|
47
52
|
Data::Model::Synapse.create(
|
|
48
53
|
source_function_id: source_function_id,
|
|
49
54
|
target_function_id: target_function_id,
|
|
@@ -56,6 +61,24 @@ module Legion
|
|
|
56
61
|
status: origin == 'emergent' ? 'observing' : 'active'
|
|
57
62
|
)
|
|
58
63
|
end
|
|
64
|
+
|
|
65
|
+
def proposals(synapse_id:, status: nil)
|
|
66
|
+
Data::Model.define_synapse_proposal_model
|
|
67
|
+
dataset = Data::Model::SynapseProposal.where(synapse_id: synapse_id)
|
|
68
|
+
dataset = dataset.where(status: status) if status
|
|
69
|
+
dataset.order(Sequel.desc(:id)).all
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def review_proposal(proposal_id:, status:)
|
|
73
|
+
Data::Model.define_synapse_proposal_model
|
|
74
|
+
return { success: false, error: "invalid status: #{status}" } unless Helpers::Proposals::VALID_STATUSES.include?(status)
|
|
75
|
+
|
|
76
|
+
proposal = Data::Model::SynapseProposal[proposal_id]
|
|
77
|
+
return { success: false, error: 'proposal not found' } unless proposal
|
|
78
|
+
|
|
79
|
+
proposal.update(status: status, reviewed_at: Time.now)
|
|
80
|
+
{ success: true, proposal_id: proposal_id, status: status }
|
|
81
|
+
end
|
|
59
82
|
end
|
|
60
83
|
end
|
|
61
84
|
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Sequel.migration do
|
|
4
|
+
up do
|
|
5
|
+
create_table(:synapse_proposals) do
|
|
6
|
+
primary_key :id
|
|
7
|
+
foreign_key :synapse_id, :synapses, null: false, index: true
|
|
8
|
+
Integer :signal_id
|
|
9
|
+
String :proposal_type, null: false, size: 50
|
|
10
|
+
String :trigger, null: false, size: 50
|
|
11
|
+
String :inputs, text: true
|
|
12
|
+
String :output, text: true
|
|
13
|
+
String :rationale, text: true
|
|
14
|
+
String :status, default: 'pending', size: 50
|
|
15
|
+
Float :estimated_confidence_impact
|
|
16
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
|
17
|
+
DateTime :reviewed_at
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
down do
|
|
22
|
+
drop_table :synapse_proposals
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -5,9 +5,23 @@ module Legion
|
|
|
5
5
|
module Synapse
|
|
6
6
|
module Data
|
|
7
7
|
module Model
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
+
one_to_many :proposals, class: 'Legion::Extensions::Synapse::Data::Model::SynapseProposal',
|
|
21
|
+
key: :synapse_id
|
|
22
|
+
end
|
|
23
|
+
klass.set_primary_key :id
|
|
24
|
+
const_set(:Synapse, klass)
|
|
11
25
|
end
|
|
12
26
|
end
|
|
13
27
|
end
|
|
@@ -5,8 +5,19 @@ module Legion
|
|
|
5
5
|
module Synapse
|
|
6
6
|
module Data
|
|
7
7
|
module Model
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Synapse
|
|
6
|
+
module Data
|
|
7
|
+
module Model
|
|
8
|
+
def self.define_synapse_proposal_model
|
|
9
|
+
return if const_defined?(:SynapseProposal, 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_proposals)
|
|
14
|
+
|
|
15
|
+
klass = Class.new(Sequel::Model(:synapse_proposals)) 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(:SynapseProposal, klass)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -5,8 +5,19 @@ module Legion
|
|
|
5
5
|
module Synapse
|
|
6
6
|
module Data
|
|
7
7
|
module Model
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module Synapse
|
|
6
|
+
module Helpers
|
|
7
|
+
module Proposals
|
|
8
|
+
VALID_PROPOSAL_TYPES = %w[llm_transform attention_mutation transform_mutation route_change].freeze
|
|
9
|
+
VALID_TRIGGERS = %w[reactive proactive].freeze
|
|
10
|
+
VALID_STATUSES = %w[pending approved rejected applied expired].freeze
|
|
11
|
+
|
|
12
|
+
DEFAULT_SETTINGS = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
reactive: true,
|
|
15
|
+
proactive: true,
|
|
16
|
+
proactive_interval: 300,
|
|
17
|
+
max_per_run: 3,
|
|
18
|
+
llm_engine_options: { temperature: 0.3, max_tokens: 1024 },
|
|
19
|
+
success_rate_threshold: 0.8,
|
|
20
|
+
payload_drift_threshold: 0.2,
|
|
21
|
+
dedup_window_hours: 24
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
class << self
|
|
25
|
+
def settings
|
|
26
|
+
raw = Legion::Settings.dig('lex-synapse', 'proposals')
|
|
27
|
+
return DEFAULT_SETTINGS.dup unless raw.is_a?(Hash)
|
|
28
|
+
|
|
29
|
+
merged = DEFAULT_SETTINGS.dup
|
|
30
|
+
raw.each { |k, v| merged[k.to_sym] = v unless v.nil? }
|
|
31
|
+
merged
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def enabled?
|
|
35
|
+
settings[:enabled] == true
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def reactive?
|
|
39
|
+
s = settings
|
|
40
|
+
s[:enabled] == true && s[:reactive] == true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def proactive?
|
|
44
|
+
s = settings
|
|
45
|
+
s[:enabled] == true && s[:proactive] == true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def llm_engine_options
|
|
49
|
+
s = settings
|
|
50
|
+
opts = s[:llm_engine_options]
|
|
51
|
+
opts.is_a?(Hash) ? opts.transform_keys(&:to_sym) : DEFAULT_SETTINGS[:llm_engine_options].dup
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
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
|
|
@@ -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
|
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative '../helpers/confidence'
|
|
4
|
+
require_relative '../helpers/proposals'
|
|
4
5
|
require_relative '../data/models/synapse'
|
|
6
|
+
require_relative '../data/models/synapse_mutation'
|
|
5
7
|
require_relative '../data/models/synapse_signal'
|
|
8
|
+
require_relative 'propose'
|
|
6
9
|
|
|
7
10
|
module Legion
|
|
8
11
|
module Extensions
|
|
9
12
|
module Synapse
|
|
10
13
|
module Runners
|
|
11
14
|
module Evaluate
|
|
15
|
+
include Propose
|
|
16
|
+
|
|
12
17
|
def evaluate(synapse_id:, payload: {}, conditioner_client: nil, transformer_client: nil)
|
|
18
|
+
Data::Model.define_synapse_model
|
|
19
|
+
Data::Model.define_synapse_signal_model
|
|
20
|
+
Data::Model.define_synapse_proposal_model
|
|
13
21
|
synapse = Data::Model::Synapse[synapse_id]
|
|
14
22
|
return { success: false, error: 'synapse not found' } unless synapse
|
|
15
23
|
return { success: false, error: 'synapse not active' } unless Helpers::Confidence::EVALUABLE_STATUSES.include?(synapse.status)
|
|
@@ -37,6 +45,16 @@ module Legion
|
|
|
37
45
|
new_confidence = Helpers::Confidence.adjust(synapse.confidence, event)
|
|
38
46
|
synapse.update(confidence: new_confidence)
|
|
39
47
|
|
|
48
|
+
# Step 5: Generate proposals if autonomous
|
|
49
|
+
if Helpers::Confidence.can_self_modify?(new_confidence) && Helpers::Proposals.reactive?
|
|
50
|
+
signal_record = Data::Model::SynapseSignal.where(synapse_id: synapse.id).order(Sequel.desc(:id)).first
|
|
51
|
+
propose_reactive(
|
|
52
|
+
synapse: synapse, payload: payload, signal_id: signal_record&.id,
|
|
53
|
+
attention_result: attention_result, transform_result: transform_result,
|
|
54
|
+
transformer_client: transformer_client
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
|
|
40
58
|
{
|
|
41
59
|
success: transform_result[:success],
|
|
42
60
|
mode: mode,
|
|
@@ -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
|
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../helpers/confidence'
|
|
4
|
+
require_relative '../helpers/proposals'
|
|
5
|
+
require_relative '../data/models/synapse'
|
|
6
|
+
require_relative '../data/models/synapse_signal'
|
|
7
|
+
require_relative '../data/models/synapse_proposal'
|
|
8
|
+
|
|
9
|
+
module Legion
|
|
10
|
+
module Extensions
|
|
11
|
+
module Synapse
|
|
12
|
+
module Runners
|
|
13
|
+
module Propose
|
|
14
|
+
PAIN_CORRELATION_THRESHOLD = 3
|
|
15
|
+
|
|
16
|
+
def propose_reactive(synapse:, payload:, signal_id:, attention_result:, transform_result:,
|
|
17
|
+
transformer_client: nil)
|
|
18
|
+
Data::Model.define_synapse_proposal_model
|
|
19
|
+
return { proposals: [] } unless Helpers::Proposals.reactive?
|
|
20
|
+
return { proposals: [] } unless transformer_client
|
|
21
|
+
|
|
22
|
+
proposals = []
|
|
23
|
+
|
|
24
|
+
# Trigger 1: No transform template exists
|
|
25
|
+
proposals << propose_llm_transform(synapse, payload, signal_id, transformer_client) if synapse.transform.nil? || synapse.transform.to_s.strip.empty?
|
|
26
|
+
|
|
27
|
+
# Trigger 2: Transform failed
|
|
28
|
+
if transform_result[:success] == false && synapse.transform && !synapse.transform.to_s.strip.empty?
|
|
29
|
+
proposals << propose_transform_fix(synapse, payload, signal_id, transform_result, transformer_client)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Trigger 3: Pain correlation — attention passed but recent downstream failures
|
|
33
|
+
proposals << propose_attention_adjustment(synapse, payload, signal_id, transformer_client) if attention_result[:passed] && pain_pattern?(synapse)
|
|
34
|
+
|
|
35
|
+
{ proposals: proposals.compact }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def propose_proactive
|
|
39
|
+
Data::Model.define_synapse_model
|
|
40
|
+
Data::Model.define_synapse_proposal_model
|
|
41
|
+
Data::Model.define_synapse_signal_model
|
|
42
|
+
return { proposals: [] } unless Helpers::Proposals.proactive?
|
|
43
|
+
|
|
44
|
+
settings = Helpers::Proposals.settings
|
|
45
|
+
max_per_run = settings[:max_per_run] || 3
|
|
46
|
+
all_proposals = []
|
|
47
|
+
|
|
48
|
+
Data::Model::Synapse.where(status: 'active').all.each do |synapse|
|
|
49
|
+
next unless Helpers::Confidence.can_self_modify?(synapse.confidence)
|
|
50
|
+
|
|
51
|
+
count = 0
|
|
52
|
+
proposal = analyze_success_rate(synapse, settings)
|
|
53
|
+
if proposal
|
|
54
|
+
all_proposals << proposal
|
|
55
|
+
count += 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if count < max_per_run
|
|
59
|
+
proposal = analyze_payload_drift(synapse, settings)
|
|
60
|
+
if proposal
|
|
61
|
+
all_proposals << proposal
|
|
62
|
+
count += 1
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
if count < max_per_run
|
|
67
|
+
proposal = analyze_routing(synapse)
|
|
68
|
+
all_proposals << proposal if proposal
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
{ proposals: all_proposals }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def propose_llm_transform(synapse, payload, signal_id, transformer_client)
|
|
78
|
+
source_schema = infer_schema(payload)
|
|
79
|
+
target_schema = lookup_target_schema(synapse)
|
|
80
|
+
prompt = build_transform_prompt(source_schema, target_schema)
|
|
81
|
+
|
|
82
|
+
llm_result = call_llm(transformer_client, prompt)
|
|
83
|
+
create_proposal(
|
|
84
|
+
synapse: synapse, signal_id: signal_id, proposal_type: 'llm_transform',
|
|
85
|
+
trigger: 'reactive',
|
|
86
|
+
inputs: Legion::JSON.dump({ source_schema: source_schema, target_schema: target_schema }),
|
|
87
|
+
output: llm_result[:output],
|
|
88
|
+
rationale: 'no transform template exists for this synapse'
|
|
89
|
+
)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def propose_transform_fix(synapse, payload, signal_id, transform_result, transformer_client)
|
|
93
|
+
source_schema = infer_schema(payload)
|
|
94
|
+
current_transform = synapse.transform
|
|
95
|
+
errors = transform_result[:error]
|
|
96
|
+
prompt = build_fix_prompt(current_transform, source_schema, errors)
|
|
97
|
+
|
|
98
|
+
llm_result = call_llm(transformer_client, prompt)
|
|
99
|
+
create_proposal(
|
|
100
|
+
synapse: synapse, signal_id: signal_id, proposal_type: 'transform_mutation',
|
|
101
|
+
trigger: 'reactive',
|
|
102
|
+
inputs: Legion::JSON.dump({ current_transform: current_transform, errors: errors, payload_schema: source_schema }),
|
|
103
|
+
output: llm_result[:output],
|
|
104
|
+
rationale: "transform failed: #{Array(errors).first}"
|
|
105
|
+
)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def propose_attention_adjustment(synapse, payload, signal_id, transformer_client)
|
|
109
|
+
recent_failures = recent_failed_signals(synapse, 10)
|
|
110
|
+
prompt = build_attention_prompt(synapse.attention, payload, recent_failures)
|
|
111
|
+
|
|
112
|
+
llm_result = call_llm(transformer_client, prompt)
|
|
113
|
+
create_proposal(
|
|
114
|
+
synapse: synapse, signal_id: signal_id, proposal_type: 'attention_mutation',
|
|
115
|
+
trigger: 'reactive',
|
|
116
|
+
inputs: Legion::JSON.dump({ current_attention: synapse.attention, recent_failures: recent_failures.size }),
|
|
117
|
+
output: llm_result[:output],
|
|
118
|
+
rationale: "#{recent_failures.size} recent downstream failures despite attention passing"
|
|
119
|
+
)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def analyze_success_rate(synapse, settings)
|
|
123
|
+
threshold = settings[:success_rate_threshold] || 0.8
|
|
124
|
+
signals = Data::Model::SynapseSignal.where(synapse_id: synapse.id).order(Sequel.desc(:id)).limit(100).all
|
|
125
|
+
return nil if signals.size < 10
|
|
126
|
+
|
|
127
|
+
success_count = signals.count(&:transform_success)
|
|
128
|
+
rate = success_count.to_f / signals.size
|
|
129
|
+
return nil if rate >= threshold
|
|
130
|
+
return nil if dedup_exists?(synapse.id, 'transform_mutation', 'proactive', settings)
|
|
131
|
+
|
|
132
|
+
create_proposal(
|
|
133
|
+
synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
|
|
134
|
+
trigger: 'proactive',
|
|
135
|
+
inputs: Legion::JSON.dump({ success_rate: rate.round(3), sample_size: signals.size, threshold: threshold }),
|
|
136
|
+
output: nil,
|
|
137
|
+
rationale: "success rate #{(rate * 100).round(1)}% below threshold #{(threshold * 100).round(1)}%"
|
|
138
|
+
)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def analyze_payload_drift(synapse, settings)
|
|
142
|
+
return nil if synapse.transform.nil? || synapse.transform.to_s.strip.empty?
|
|
143
|
+
|
|
144
|
+
drift_threshold = settings[:payload_drift_threshold] || 0.2
|
|
145
|
+
signals = Data::Model::SynapseSignal.where(synapse_id: synapse.id).order(Sequel.desc(:id)).limit(50).all
|
|
146
|
+
return nil if signals.size < 10
|
|
147
|
+
|
|
148
|
+
failed = signals.count { |s| !s.transform_success }
|
|
149
|
+
drift_rate = failed.to_f / signals.size
|
|
150
|
+
return nil if drift_rate < drift_threshold
|
|
151
|
+
return nil if dedup_exists?(synapse.id, 'transform_mutation', 'proactive', settings)
|
|
152
|
+
|
|
153
|
+
create_proposal(
|
|
154
|
+
synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
|
|
155
|
+
trigger: 'proactive',
|
|
156
|
+
inputs: Legion::JSON.dump({ drift_rate: drift_rate.round(3), sample_size: signals.size }),
|
|
157
|
+
output: nil,
|
|
158
|
+
rationale: "payload drift detected: #{(drift_rate * 100).round(1)}% transform failures in recent signals"
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def analyze_routing(synapse)
|
|
163
|
+
return nil if dedup_exists?(synapse.id, 'route_change', 'proactive', Helpers::Proposals.settings)
|
|
164
|
+
|
|
165
|
+
signals = Data::Model::SynapseSignal.where(synapse_id: synapse.id).order(Sequel.desc(:id)).limit(50).all
|
|
166
|
+
return nil if signals.size < 10
|
|
167
|
+
|
|
168
|
+
nil
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def pain_pattern?(synapse)
|
|
172
|
+
recent = recent_failed_signals(synapse, 20)
|
|
173
|
+
recent.size >= PAIN_CORRELATION_THRESHOLD
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def recent_failed_signals(synapse, limit)
|
|
177
|
+
Data::Model::SynapseSignal.where(
|
|
178
|
+
synapse_id: synapse.id, downstream_outcome: 'failed'
|
|
179
|
+
).order(Sequel.desc(:id)).limit(limit).all
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def dedup_exists?(synapse_id, proposal_type, trigger, settings)
|
|
183
|
+
window = settings[:dedup_window_hours] || 24
|
|
184
|
+
cutoff = Time.now - (window * 3600)
|
|
185
|
+
Data::Model::SynapseProposal.where(
|
|
186
|
+
synapse_id: synapse_id, proposal_type: proposal_type,
|
|
187
|
+
trigger: trigger, status: 'pending'
|
|
188
|
+
).where(Sequel.lit('created_at >= ?', cutoff)).any?
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def create_proposal(synapse:, signal_id:, proposal_type:, trigger:, inputs:, output:, rationale:)
|
|
192
|
+
Data::Model::SynapseProposal.create(
|
|
193
|
+
synapse_id: synapse.id,
|
|
194
|
+
signal_id: signal_id,
|
|
195
|
+
proposal_type: proposal_type,
|
|
196
|
+
trigger: trigger,
|
|
197
|
+
inputs: inputs,
|
|
198
|
+
output: output,
|
|
199
|
+
rationale: rationale,
|
|
200
|
+
status: 'pending'
|
|
201
|
+
)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def call_llm(transformer_client, prompt)
|
|
205
|
+
return { output: nil } unless transformer_client
|
|
206
|
+
|
|
207
|
+
engine_options = Helpers::Proposals.llm_engine_options
|
|
208
|
+
result = transformer_client.transform(
|
|
209
|
+
transformation: prompt, payload: {}, engine: :llm, engine_options: engine_options
|
|
210
|
+
)
|
|
211
|
+
{ output: result[:success] ? Legion::JSON.dump(result[:result]) : nil }
|
|
212
|
+
rescue StandardError => e
|
|
213
|
+
Legion::Logging.warn("Proposal LLM call failed: #{e.message}")
|
|
214
|
+
{ output: nil }
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def infer_schema(payload)
|
|
218
|
+
return {} unless payload.is_a?(Hash)
|
|
219
|
+
|
|
220
|
+
payload.transform_values { |v| v.class.name }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def lookup_target_schema(synapse)
|
|
224
|
+
return {} unless synapse.target_function_id
|
|
225
|
+
return {} unless defined?(Legion::Extensions::Lex)
|
|
226
|
+
|
|
227
|
+
{}
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def build_transform_prompt(source_schema, target_schema)
|
|
231
|
+
"Given a payload with schema: #{Legion::JSON.dump(source_schema)}, " \
|
|
232
|
+
"generate a JSON transform template that maps it to target schema: #{Legion::JSON.dump(target_schema)}. " \
|
|
233
|
+
'Return only the JSON template string, no explanation.'
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def build_fix_prompt(current_transform, source_schema, errors)
|
|
237
|
+
"The current transform template is: #{current_transform}. " \
|
|
238
|
+
"It failed with errors: #{Array(errors).join(', ')}. " \
|
|
239
|
+
"The payload schema is: #{Legion::JSON.dump(source_schema)}. " \
|
|
240
|
+
'Suggest a corrected transform template. Return only the JSON template string.'
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def build_attention_prompt(current_attention, payload, recent_failures)
|
|
244
|
+
"The current attention rules are: #{current_attention}. " \
|
|
245
|
+
"Recent payload example: #{Legion::JSON.dump(payload)}. " \
|
|
246
|
+
"There have been #{recent_failures.size} downstream failures despite attention passing. " \
|
|
247
|
+
'Suggest refined attention rules as a JSON condition object. Return only JSON.'
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
@@ -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
|
|
|
@@ -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
|
|
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
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Esity
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 0.
|
|
32
|
+
version: 0.3.0
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 0.
|
|
39
|
+
version: 0.3.0
|
|
40
40
|
description: Attention, transformation, and routing with confidence scoring, pain
|
|
41
41
|
signals, homeostasis, and self-governance
|
|
42
42
|
email:
|
|
@@ -61,15 +61,19 @@ files:
|
|
|
61
61
|
- lib/legion/extensions/synapse/actors/evaluate.rb
|
|
62
62
|
- lib/legion/extensions/synapse/actors/homeostasis.rb
|
|
63
63
|
- lib/legion/extensions/synapse/actors/pain.rb
|
|
64
|
+
- lib/legion/extensions/synapse/actors/propose.rb
|
|
64
65
|
- lib/legion/extensions/synapse/client.rb
|
|
65
66
|
- lib/legion/extensions/synapse/data/migrations/001_create_synapses.rb
|
|
66
67
|
- lib/legion/extensions/synapse/data/migrations/002_create_synapse_mutations.rb
|
|
67
68
|
- lib/legion/extensions/synapse/data/migrations/003_create_synapse_signals.rb
|
|
69
|
+
- lib/legion/extensions/synapse/data/migrations/004_create_synapse_proposals.rb
|
|
68
70
|
- lib/legion/extensions/synapse/data/models/synapse.rb
|
|
69
71
|
- lib/legion/extensions/synapse/data/models/synapse_mutation.rb
|
|
72
|
+
- lib/legion/extensions/synapse/data/models/synapse_proposal.rb
|
|
70
73
|
- lib/legion/extensions/synapse/data/models/synapse_signal.rb
|
|
71
74
|
- lib/legion/extensions/synapse/helpers/confidence.rb
|
|
72
75
|
- lib/legion/extensions/synapse/helpers/homeostasis.rb
|
|
76
|
+
- lib/legion/extensions/synapse/helpers/proposals.rb
|
|
73
77
|
- lib/legion/extensions/synapse/helpers/relationship_wrapper.rb
|
|
74
78
|
- lib/legion/extensions/synapse/runners/crystallize.rb
|
|
75
79
|
- lib/legion/extensions/synapse/runners/dream.rb
|
|
@@ -78,6 +82,7 @@ files:
|
|
|
78
82
|
- lib/legion/extensions/synapse/runners/mutate.rb
|
|
79
83
|
- lib/legion/extensions/synapse/runners/pain.rb
|
|
80
84
|
- lib/legion/extensions/synapse/runners/promote.rb
|
|
85
|
+
- lib/legion/extensions/synapse/runners/propose.rb
|
|
81
86
|
- lib/legion/extensions/synapse/runners/report.rb
|
|
82
87
|
- lib/legion/extensions/synapse/runners/retrieve.rb
|
|
83
88
|
- lib/legion/extensions/synapse/runners/revert.rb
|