lex-subliminal 0.1.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.
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Subliminal
6
+ module Runners
7
+ module Subliminal
8
+ include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
9
+
10
+ def create_subliminal_trace(content:, trace_type: :associative, domain: :general, activation: nil,
11
+ influence_target: :attention, engine: nil, **)
12
+ eng = engine || @default_engine
13
+ trace = eng.create_trace(content: content, trace_type: trace_type, domain: domain,
14
+ activation: activation || Helpers::Constants::DEFAULT_ACTIVATION,
15
+ influence_target: influence_target)
16
+ { success: true, trace: trace.to_h }
17
+ end
18
+
19
+ def boost_trace(trace_id:, amount: nil, engine: nil, **)
20
+ eng = engine || @default_engine
21
+ trace = eng.boost_trace(trace_id: trace_id, amount: amount || Helpers::Constants::ACTIVATION_BOOST)
22
+ return { success: false, error: 'trace not found' } unless trace
23
+
24
+ { success: true, trace: trace.to_h }
25
+ end
26
+
27
+ def process_influences(engine: nil, **)
28
+ eng = engine || @default_engine
29
+ result = eng.process_influences!
30
+ { success: true, **result }
31
+ end
32
+
33
+ def decay_all(engine: nil, **)
34
+ eng = engine || @default_engine
35
+ result = eng.decay_all!
36
+ { success: true, **result }
37
+ end
38
+
39
+ def active_traces(engine: nil, **)
40
+ eng = engine || @default_engine
41
+ traces = eng.active_traces
42
+ { success: true, count: traces.size, traces: traces.map(&:to_h) }
43
+ end
44
+
45
+ def near_threshold(engine: nil, **)
46
+ eng = engine || @default_engine
47
+ traces = eng.near_threshold_traces
48
+ { success: true, count: traces.size, traces: traces.map(&:to_h) }
49
+ end
50
+
51
+ def influence_on(target:, engine: nil, **)
52
+ eng = engine || @default_engine
53
+ level = eng.influence_on(target: target)
54
+ label = Helpers::Constants.label_for(Helpers::Constants::INFLUENCE_LABELS, level)
55
+ { success: true, target: target, influence: level, label: label }
56
+ end
57
+
58
+ def subliminal_status(engine: nil, **)
59
+ eng = engine || @default_engine
60
+ report = eng.subliminal_report
61
+ { success: true, **report }
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Subliminal
6
+ VERSION = '0.1.0'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'subliminal/version'
4
+ require_relative 'subliminal/helpers/constants'
5
+ require_relative 'subliminal/helpers/subliminal_trace'
6
+ require_relative 'subliminal/helpers/influence_event'
7
+ require_relative 'subliminal/helpers/subliminal_engine'
8
+ require_relative 'subliminal/runners/subliminal'
9
+ require_relative 'subliminal/client'
10
+
11
+ module Legion
12
+ module Extensions
13
+ module Subliminal
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'responds to runner methods' do
7
+ expect(client).to respond_to(:create_subliminal_trace, :process_influences, :subliminal_status)
8
+ end
9
+
10
+ it 'runs a full subliminal lifecycle' do
11
+ result = client.create_subliminal_trace(content: 'danger signal', domain: :security)
12
+ trace_id = result[:trace][:id]
13
+
14
+ client.boost_trace(trace_id: trace_id)
15
+ client.process_influences
16
+ client.decay_all
17
+
18
+ status = client.subliminal_status
19
+ expect(status[:total_traces]).to be >= 1
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal::Helpers::InfluenceEvent do
4
+ subject(:event) do
5
+ described_class.new(trace_id: 'abc-123', target: :attention, magnitude: 0.08, domain: :security)
6
+ end
7
+
8
+ describe '#initialize' do
9
+ it 'assigns a UUID id' do
10
+ expect(event.id).to match(/\A[0-9a-f-]{36}\z/)
11
+ end
12
+
13
+ it 'stores trace_id' do
14
+ expect(event.trace_id).to eq('abc-123')
15
+ end
16
+
17
+ it 'stores target' do
18
+ expect(event.target).to eq(:attention)
19
+ end
20
+
21
+ it 'stores magnitude' do
22
+ expect(event.magnitude).to eq(0.08)
23
+ end
24
+
25
+ it 'stores domain' do
26
+ expect(event.domain).to eq(:security)
27
+ end
28
+ end
29
+
30
+ describe '#significant?' do
31
+ it 'is true for magnitude >= 0.05' do
32
+ expect(event.significant?).to be true
33
+ end
34
+
35
+ it 'is false for small magnitude' do
36
+ small = described_class.new(trace_id: 'x', target: :emotion, magnitude: 0.03)
37
+ expect(small.significant?).to be false
38
+ end
39
+ end
40
+
41
+ describe '#subtle?' do
42
+ it 'is true for small positive magnitude' do
43
+ small = described_class.new(trace_id: 'x', target: :emotion, magnitude: 0.03)
44
+ expect(small.subtle?).to be true
45
+ end
46
+
47
+ it 'is false for significant magnitude' do
48
+ expect(event.subtle?).to be false
49
+ end
50
+ end
51
+
52
+ describe '#to_h' do
53
+ it 'includes all fields' do
54
+ hash = event.to_h
55
+ expect(hash).to include(:id, :trace_id, :target, :magnitude, :domain, :created_at)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal::Helpers::SubliminalEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ describe '#create_trace' do
7
+ it 'creates and stores a trace' do
8
+ trace = engine.create_trace(content: 'faint memory')
9
+ expect(trace.content).to eq('faint memory')
10
+ end
11
+ end
12
+
13
+ describe '#boost_trace' do
14
+ it 'boosts activation' do
15
+ trace = engine.create_trace(content: 'test')
16
+ original = trace.activation
17
+ engine.boost_trace(trace_id: trace.id)
18
+ expect(trace.activation).to be > original
19
+ end
20
+
21
+ it 'returns nil for unknown trace' do
22
+ expect(engine.boost_trace(trace_id: 'bad')).to be_nil
23
+ end
24
+ end
25
+
26
+ describe '#process_influences!' do
27
+ it 'generates influence events from active traces' do
28
+ engine.create_trace(content: 'a', activation: 0.3)
29
+ result = engine.process_influences!
30
+ expect(result[:influences_generated]).to be >= 1
31
+ end
32
+
33
+ it 'returns empty when no active traces' do
34
+ result = engine.process_influences!
35
+ expect(result[:influences_generated]).to eq(0)
36
+ end
37
+ end
38
+
39
+ describe '#decay_all!' do
40
+ it 'decays all traces' do
41
+ trace = engine.create_trace(content: 'test')
42
+ original = trace.activation
43
+ engine.decay_all!
44
+ expect(trace.activation).to be < original
45
+ end
46
+ end
47
+
48
+ describe '#active_traces' do
49
+ it 'returns non-extinct traces' do
50
+ engine.create_trace(content: 'active', activation: 0.2)
51
+ expect(engine.active_traces.size).to eq(1)
52
+ end
53
+ end
54
+
55
+ describe '#near_threshold_traces' do
56
+ it 'returns traces near conscious threshold' do
57
+ engine.create_trace(content: 'near', activation: 0.35)
58
+ engine.create_trace(content: 'far', activation: 0.1)
59
+ expect(engine.near_threshold_traces.size).to eq(1)
60
+ end
61
+ end
62
+
63
+ describe '#potent_traces' do
64
+ it 'returns traces with activation >= 0.2' do
65
+ engine.create_trace(content: 'potent', activation: 0.25)
66
+ engine.create_trace(content: 'weak', activation: 0.05)
67
+ expect(engine.potent_traces.size).to eq(1)
68
+ end
69
+ end
70
+
71
+ describe '#traces_by_domain' do
72
+ it 'filters by domain' do
73
+ engine.create_trace(content: 'a', domain: :security)
74
+ engine.create_trace(content: 'b', domain: :memory)
75
+ expect(engine.traces_by_domain(domain: :security).size).to eq(1)
76
+ end
77
+ end
78
+
79
+ describe '#traces_by_type' do
80
+ it 'filters by trace type' do
81
+ engine.create_trace(content: 'a', trace_type: :emotional)
82
+ engine.create_trace(content: 'b', trace_type: :procedural)
83
+ expect(engine.traces_by_type(trace_type: :emotional).size).to eq(1)
84
+ end
85
+ end
86
+
87
+ describe '#traces_by_target' do
88
+ it 'filters by influence target' do
89
+ engine.create_trace(content: 'a', influence_target: :emotion)
90
+ engine.create_trace(content: 'b', influence_target: :decision)
91
+ expect(engine.traces_by_target(target: :emotion).size).to eq(1)
92
+ end
93
+ end
94
+
95
+ describe '#influence_on' do
96
+ it 'returns 0.0 with no influences' do
97
+ expect(engine.influence_on(target: :attention)).to eq(0.0)
98
+ end
99
+
100
+ it 'returns accumulated influence after processing' do
101
+ engine.create_trace(content: 'a', activation: 0.3, influence_target: :attention)
102
+ engine.process_influences!
103
+ expect(engine.influence_on(target: :attention)).to be > 0.0
104
+ end
105
+ end
106
+
107
+ describe '#domain_saturation' do
108
+ it 'returns 0.0 for empty domain' do
109
+ expect(engine.domain_saturation(domain: :security)).to eq(0.0)
110
+ end
111
+
112
+ it 'returns positive for populated domain' do
113
+ engine.create_trace(content: 'a', domain: :security, activation: 0.3)
114
+ expect(engine.domain_saturation(domain: :security)).to be > 0.0
115
+ end
116
+ end
117
+
118
+ describe '#overall_subliminal_load' do
119
+ it 'returns 0.0 with no traces' do
120
+ expect(engine.overall_subliminal_load).to eq(0.0)
121
+ end
122
+
123
+ it 'returns positive with active traces' do
124
+ engine.create_trace(content: 'a', activation: 0.3)
125
+ expect(engine.overall_subliminal_load).to be > 0.0
126
+ end
127
+ end
128
+
129
+ describe '#strongest_traces' do
130
+ it 'returns sorted by activation descending' do
131
+ engine.create_trace(content: 'weak', activation: 0.1)
132
+ strong = engine.create_trace(content: 'strong', activation: 0.35)
133
+ expect(engine.strongest_traces(limit: 1).first.id).to eq(strong.id)
134
+ end
135
+ end
136
+
137
+ describe '#breached_traces' do
138
+ it 'returns empty when all below threshold' do
139
+ engine.create_trace(content: 'below', activation: 0.3)
140
+ expect(engine.breached_traces).to be_empty
141
+ end
142
+ end
143
+
144
+ describe '#subliminal_report' do
145
+ it 'includes all report fields' do
146
+ report = engine.subliminal_report
147
+ expect(report).to include(
148
+ :total_traces, :active_count, :near_threshold, :potent_count,
149
+ :total_influences, :subliminal_load, :saturation_label,
150
+ :breached_count, :strongest
151
+ )
152
+ end
153
+ end
154
+
155
+ describe '#to_h' do
156
+ it 'includes summary fields' do
157
+ hash = engine.to_h
158
+ expect(hash).to include(:total_traces, :active, :subliminal_load, :total_influences)
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,168 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal::Helpers::SubliminalTrace do
4
+ subject(:trace) { described_class.new(content: 'faint memory of danger') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a UUID id' do
8
+ expect(trace.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'stores content' do
12
+ expect(trace.content).to eq('faint memory of danger')
13
+ end
14
+
15
+ it 'defaults trace_type to :associative' do
16
+ expect(trace.trace_type).to eq(:associative)
17
+ end
18
+
19
+ it 'defaults domain to :general' do
20
+ expect(trace.domain).to eq(:general)
21
+ end
22
+
23
+ it 'defaults activation to DEFAULT_ACTIVATION' do
24
+ expect(trace.activation).to eq(0.2)
25
+ end
26
+
27
+ it 'clamps activation to subliminal ceiling' do
28
+ high = described_class.new(content: 'x', activation: 0.9)
29
+ expect(high.activation).to eq(0.39)
30
+ end
31
+
32
+ it 'clamps activation to subliminal floor' do
33
+ low = described_class.new(content: 'x', activation: 0.001)
34
+ expect(low.activation).to eq(0.02)
35
+ end
36
+
37
+ it 'defaults influence_target to :attention' do
38
+ expect(trace.influence_target).to eq(:attention)
39
+ end
40
+
41
+ it 'validates trace_type' do
42
+ bad = described_class.new(content: 'x', trace_type: :nonexistent)
43
+ expect(bad.trace_type).to eq(:associative)
44
+ end
45
+
46
+ it 'validates influence_target' do
47
+ bad = described_class.new(content: 'x', influence_target: :nonexistent)
48
+ expect(bad.influence_target).to eq(:attention)
49
+ end
50
+ end
51
+
52
+ describe '#boost!' do
53
+ it 'increases activation' do
54
+ original = trace.activation
55
+ trace.boost!
56
+ expect(trace.activation).to be > original
57
+ end
58
+
59
+ it 'clamps at subliminal ceiling' do
60
+ 10.times { trace.boost! }
61
+ expect(trace.activation).to eq(0.39)
62
+ end
63
+ end
64
+
65
+ describe '#decay!' do
66
+ it 'decreases activation' do
67
+ original = trace.activation
68
+ trace.decay!
69
+ expect(trace.activation).to be < original
70
+ end
71
+
72
+ it 'clamps at 0.0' do
73
+ 50.times { trace.decay! }
74
+ expect(trace.activation).to eq(0.0)
75
+ end
76
+ end
77
+
78
+ describe '#exert_influence!' do
79
+ it 'returns influence magnitude' do
80
+ mag = trace.exert_influence!
81
+ expect(mag).to be > 0.0
82
+ end
83
+
84
+ it 'increments influence_count' do
85
+ trace.exert_influence!
86
+ expect(trace.influence_count).to eq(1)
87
+ end
88
+
89
+ it 'slightly decreases activation' do
90
+ original = trace.activation
91
+ trace.exert_influence!
92
+ expect(trace.activation).to be < original
93
+ end
94
+ end
95
+
96
+ describe '#near_threshold?' do
97
+ it 'is false at default activation' do
98
+ expect(trace.near_threshold?).to be false
99
+ end
100
+
101
+ it 'is true when near conscious threshold' do
102
+ near = described_class.new(content: 'x', activation: 0.35)
103
+ expect(near.near_threshold?).to be true
104
+ end
105
+ end
106
+
107
+ describe '#active?' do
108
+ it 'is true at default activation' do
109
+ expect(trace.active?).to be true
110
+ end
111
+
112
+ it 'is false when fully decayed' do
113
+ 50.times { trace.decay! }
114
+ expect(trace.active?).to be false
115
+ end
116
+ end
117
+
118
+ describe '#extinct?' do
119
+ it 'is false at default activation' do
120
+ expect(trace.extinct?).to be false
121
+ end
122
+
123
+ it 'is true when nearly zero' do
124
+ 50.times { trace.decay! }
125
+ expect(trace.extinct?).to be true
126
+ end
127
+ end
128
+
129
+ describe '#potent?' do
130
+ it 'is true at default activation' do
131
+ expect(trace.potent?).to be true
132
+ end
133
+
134
+ it 'is false when low' do
135
+ faint = described_class.new(content: 'x', activation: 0.1)
136
+ expect(faint.potent?).to be false
137
+ end
138
+ end
139
+
140
+ describe '#breached_threshold?' do
141
+ it 'is false by default' do
142
+ expect(trace.breached_threshold?).to be false
143
+ end
144
+ end
145
+
146
+ describe '#persistence' do
147
+ it 'is 1.0 initially' do
148
+ expect(trace.persistence).to eq(1.0)
149
+ end
150
+
151
+ it 'decreases after decay' do
152
+ trace.decay!
153
+ expect(trace.persistence).to be < 1.0
154
+ end
155
+ end
156
+
157
+ describe '#to_h' do
158
+ it 'includes all fields' do
159
+ hash = trace.to_h
160
+ expect(hash).to include(
161
+ :id, :content, :trace_type, :domain, :activation,
162
+ :original_activation, :influence_target, :influence_count,
163
+ :influence_magnitude, :near_threshold, :active, :extinct,
164
+ :activation_label, :persistence, :created_at
165
+ )
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal::Runners::Subliminal do
4
+ let(:engine) { Legion::Extensions::Subliminal::Helpers::SubliminalEngine.new }
5
+ let(:runner) do
6
+ obj = Object.new
7
+ obj.extend(described_class)
8
+ obj.instance_variable_set(:@default_engine, engine)
9
+ obj
10
+ end
11
+
12
+ describe '#create_subliminal_trace' do
13
+ it 'returns success with trace hash' do
14
+ result = runner.create_subliminal_trace(content: 'test', engine: engine)
15
+ expect(result[:success]).to be true
16
+ expect(result[:trace][:content]).to eq('test')
17
+ end
18
+ end
19
+
20
+ describe '#boost_trace' do
21
+ it 'returns success for known trace' do
22
+ trace = engine.create_trace(content: 'test')
23
+ result = runner.boost_trace(trace_id: trace.id, engine: engine)
24
+ expect(result[:success]).to be true
25
+ end
26
+
27
+ it 'returns failure for unknown trace' do
28
+ result = runner.boost_trace(trace_id: 'bad', engine: engine)
29
+ expect(result[:success]).to be false
30
+ end
31
+ end
32
+
33
+ describe '#process_influences' do
34
+ it 'returns success' do
35
+ result = runner.process_influences(engine: engine)
36
+ expect(result[:success]).to be true
37
+ end
38
+ end
39
+
40
+ describe '#decay_all' do
41
+ it 'returns success' do
42
+ result = runner.decay_all(engine: engine)
43
+ expect(result[:success]).to be true
44
+ end
45
+ end
46
+
47
+ describe '#active_traces' do
48
+ it 'returns active list' do
49
+ engine.create_trace(content: 'test')
50
+ result = runner.active_traces(engine: engine)
51
+ expect(result[:count]).to eq(1)
52
+ end
53
+ end
54
+
55
+ describe '#near_threshold' do
56
+ it 'returns near-threshold list' do
57
+ engine.create_trace(content: 'near', activation: 0.35)
58
+ result = runner.near_threshold(engine: engine)
59
+ expect(result[:count]).to eq(1)
60
+ end
61
+ end
62
+
63
+ describe '#influence_on' do
64
+ it 'returns influence level' do
65
+ result = runner.influence_on(target: :attention, engine: engine)
66
+ expect(result[:success]).to be true
67
+ expect(result[:influence]).to eq(0.0)
68
+ end
69
+ end
70
+
71
+ describe '#subliminal_status' do
72
+ it 'returns comprehensive status' do
73
+ result = runner.subliminal_status(engine: engine)
74
+ expect(result[:success]).to be true
75
+ expect(result).to include(:total_traces, :subliminal_load)
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Subliminal do
4
+ it 'has a version number' do
5
+ expect(Legion::Extensions::Subliminal::VERSION).to eq('0.1.0')
6
+ end
7
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/subliminal'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Helpers
8
+ module Lex; end
9
+ end
10
+ end
11
+
12
+ module Logging
13
+ def self.method_missing(_, *) = nil
14
+ def self.respond_to_missing?(_, _ = false) = true
15
+ end
16
+ end
17
+
18
+ RSpec.configure do |config|
19
+ config.expect_with :rspec do |expectations|
20
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
21
+ end
22
+ config.mock_with :rspec do |mocks|
23
+ mocks.verify_partial_doubles = true
24
+ end
25
+ config.shared_context_metadata_behavior = :apply_to_host_groups
26
+ config.order = :random
27
+ Kernel.srand config.seed
28
+ end