lex-agentic-executive 0.1.0 → 0.1.5

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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/README.md +50 -3
  4. data/lex-agentic-executive.gemspec +8 -0
  5. data/lib/legion/extensions/agentic/executive/chunking/helpers/constants.rb +1 -1
  6. data/lib/legion/extensions/agentic/executive/disengagement/helpers/disengagement_engine.rb +5 -0
  7. data/lib/legion/extensions/agentic/executive/disengagement/version.rb +1 -1
  8. data/lib/legion/extensions/agentic/executive/dissonance_resolution/helpers/resolution_engine.rb +2 -0
  9. data/lib/legion/extensions/agentic/executive/dissonance_resolution/version.rb +1 -1
  10. data/lib/legion/extensions/agentic/executive/dual_process/helpers/dual_process_engine.rb +2 -0
  11. data/lib/legion/extensions/agentic/executive/dual_process/version.rb +1 -1
  12. data/lib/legion/extensions/agentic/executive/inhibition/helpers/inhibition_store.rb +2 -0
  13. data/lib/legion/extensions/agentic/executive/inhibition/version.rb +1 -1
  14. data/lib/legion/extensions/agentic/executive/version.rb +1 -1
  15. data/lib/legion/extensions/agentic/executive/volition/runners/volition.rb +32 -0
  16. data/lib/legion/extensions/agentic/executive/working_memory/helpers/constants.rb +1 -1
  17. data/lib/legion/extensions/agentic/executive/working_memory/version.rb +1 -1
  18. data/spec/legion/extensions/agentic/executive/chunking/helpers/chunking_engine_spec.rb +1 -1
  19. data/spec/legion/extensions/agentic/executive/chunking/helpers/constants_spec.rb +2 -2
  20. data/spec/legion/extensions/agentic/executive/chunking/runners/cognitive_chunking_spec.rb +1 -1
  21. data/spec/legion/extensions/agentic/executive/disengagement/helpers/disengagement_engine_spec.rb +13 -0
  22. data/spec/legion/extensions/agentic/executive/dissonance_resolution/helpers/resolution_engine_spec.rb +13 -0
  23. data/spec/legion/extensions/agentic/executive/dual_process/helpers/dual_process_engine_spec.rb +15 -0
  24. data/spec/legion/extensions/agentic/executive/inhibition/helpers/inhibition_store_spec.rb +12 -0
  25. data/spec/legion/extensions/agentic/executive/volition/runners/volition_spec.rb +55 -0
  26. data/spec/legion/extensions/agentic/executive/working_memory/client_spec.rb +3 -3
  27. data/spec/legion/extensions/agentic/executive/working_memory/helpers/constants_spec.rb +2 -2
  28. data/spec/spec_helper.rb +21 -23
  29. metadata +99 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d156eef0f39f669acfc3f33e496196921f1b34e882c810d1416740349fc4fb84
4
- data.tar.gz: 97171fb40218dca7e06373731545b30e6eadc36a51c649b3e68e75d7e067e509
3
+ metadata.gz: cce9c8109ea22a2e4d9ecc71403cf6578a10aa6710c5b6f2ba01e67eda9402e4
4
+ data.tar.gz: 57ad258cca2492402369ad50e4530914f46814af543b415f15f8912bc7e7b124
5
5
  SHA512:
6
- metadata.gz: 97708ee5421c6401db3bd4899e1c0c6f62e059dfe6687d9524327e52b0b7c07ebcae937e8f5da1312467e082d8a56c5123064a0390b696cbbcb2de3b4adbbc72
7
- data.tar.gz: 77360d4645be017e164d28feb1420890e990661091261a6dcc0bc15b84f169af3346a3e63af38e71162c079513357d780dffd7b073a43fd0015aa5dc79bc07ea
6
+ metadata.gz: 2840c7a21271f2335c9006f3eb8139da82fa36f42b50836b89443bad01b36b1b6a80fb1504021d4199df4345131c7f6f6dc8e01b152d963069bd86a0a4d329a6
7
+ data.tar.gz: d5d7fd7a3dbc97ed211bd2aad9c794ae0c705a534d269740add93aeeb5cbe009b303f22e5b0f071f174f324a6c26a1c06d4461fc910c16df5be03bbdcfc5f44b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.1.5] - 2026-03-22
6
+
7
+ ### Changed
8
+ - Add 7 legion sub-gem runtime dependencies to gemspec (legion-cache, legion-crypt, legion-data, legion-json, legion-logging, legion-settings, legion-transport)
9
+ - Update spec_helper to require real sub-gem helpers and wire Helpers::Lex with all helper modules
10
+
11
+ ## [0.1.3] - 2026-03-21
12
+
13
+ ### Changed
14
+ - Working memory CAPACITY reduced from 7 to 4 (Cowan 2001)
15
+ - Chunking WORKING_MEMORY_CAPACITY updated from 7 to 4
16
+ - Effective max remains 7 via CHUNK_BONUS (4 base + 3 bonus)
17
+
18
+ ## [0.1.1] - 2026-03-18
19
+
20
+ ### Changed
21
+ - Enforce IMPULSE_TYPES validation in InhibitionStore#create_impulse (returns nil for invalid type)
22
+ - Enforce STRATEGIES validation in ResolutionEngine#apply_strategy (returns nil for invalid strategy)
23
+ - Enforce DISENGAGE_REASONS validation in DisengagementEngine#disengage_goal (raises ArgumentError)
24
+ - Enforce DECISION_OUTCOMES validation in DualProcessEngine#record_outcome (returns failure hash)
25
+
5
26
  ## [0.1.0] - 2026-03-18
6
27
 
7
28
  ### Added
data/README.md CHANGED
@@ -1,13 +1,60 @@
1
1
  # lex-agentic-executive
2
2
 
3
- LEX agentic executive domain: planning, working memory, cognitive control
3
+ Domain consolidation gem for executive function, goal management, planning, and cognitive control. Bundles 23 source extensions into one loadable unit under `Legion::Extensions::Agentic::Executive`.
4
4
 
5
- ## Sub-modules
5
+ ## Overview
6
6
 
7
- *(populated as extensions are consolidated)*
7
+ **Gem**: `lex-agentic-executive`
8
+ **Version**: 0.1.1
9
+ **Namespace**: `Legion::Extensions::Agentic::Executive`
10
+
11
+ ## Sub-Modules
12
+
13
+ | Sub-Module | Source Gem | Purpose |
14
+ |---|---|---|
15
+ | `Executive::Control` | `lex-cognitive-control` | Conflict monitoring, error detection, adaptive control signals |
16
+ | `Executive::ExecutiveFunction` | `lex-executive-function` | Miyake three-factor model: updating, flexibility, inhibition |
17
+ | `Executive::GoalManagement` | `lex-goal-management` | Hierarchical goal registry — decomposition, priority, lifecycle |
18
+ | `Executive::Inhibition` | `lex-inhibition` | Stop-signal model, prepotent response suppression |
19
+ | `Executive::Planning` | `lex-planning` | Goal-directed plan management — dependency graphs, replan limit |
20
+ | `Executive::Volition` | `lex-volition` | Five drives synthesized into intention stack — maps to `action_selection` tick phase |
21
+ | `Executive::WorkingMemory` | `lex-working-memory` | Baddeley & Hitch — capacity-limited buffer, verbal/spatial/episodic channels |
22
+ | `Executive::Flexibility` | `lex-cognitive-flexibility` | Cognitive flexibility — task switching, mental set shifting |
23
+ | `Executive::FlexibilityTraining` | `lex-cognitive-flexibility-training` | Structured training for cognitive flexibility improvement |
24
+ | `Executive::Load` | `lex-cognitive-load` | Sweller three-component model — intrinsic/extraneous/germane load |
25
+ | `Executive::LoadBalancing` | `lex-cognitive-load-balancing` | Load distribution across cognitive resources |
26
+ | `Executive::Disengagement` | `lex-cognitive-disengagement` | Controlled disengagement from tasks or mental sets |
27
+ | `Executive::Triage` | `lex-cognitive-triage` | Priority-based task selection under resource constraints |
28
+ | `Executive::Chunking` | `lex-cognitive-chunking` | Information compression into manageable units |
29
+ | `Executive::Inertia` | `lex-cognitive-inertia` | Resistance to switching — persistence in current cognitive mode |
30
+ | `Executive::Dwell` | `lex-cognitive-dwell` | Sustained focus on a single topic or problem |
31
+ | `Executive::Autopilot` | `lex-cognitive-autopilot` | Habitual/automatic processing mode |
32
+ | `Executive::DissonanceResolution` | `lex-cognitive-dissonance-resolution` | Resolution strategies for cognitive dissonance |
33
+ | `Executive::Compass` | `lex-cognitive-compass` | Goal-direction and navigation toward targets |
34
+ | `Executive::DecisionFatigue` | `lex-decision-fatigue` | Decision quality degradation after sustained choices |
35
+ | `Executive::DualProcess` | `lex-dual-process` | Kahneman System 1/System 2 routing |
36
+ | `Executive::ProspectiveMemory` | `lex-prospective-memory` | Memory for future intentions — reminder management |
37
+ | `Executive::CognitiveDebt` | `lex-cognitive-debt` | Accumulated cognitive obligations and deferred processing |
38
+
39
+ ## Actors
40
+
41
+ - `Executive::ExecutiveFunction::Actors::Recovery` — interval actor, runs executive function recovery cycle
42
+ - `Executive::Flexibility::Actors::Tick` — interval actor, processes cognitive flexibility tick
8
43
 
9
44
  ## Installation
10
45
 
11
46
  ```ruby
12
47
  gem 'lex-agentic-executive'
13
48
  ```
49
+
50
+ ## Development
51
+
52
+ ```bash
53
+ bundle install
54
+ bundle exec rspec # 2067 examples, 0 failures
55
+ bundle exec rubocop # 0 offenses
56
+ ```
57
+
58
+ ## License
59
+
60
+ MIT
@@ -24,6 +24,14 @@ Gem::Specification.new do |spec|
24
24
  end
25
25
  spec.require_paths = ['lib']
26
26
 
27
+ spec.add_dependency 'legion-cache', '>= 1.3.11'
28
+ spec.add_dependency 'legion-crypt', '>= 1.4.9'
29
+ spec.add_dependency 'legion-data', '>= 1.4.17'
30
+ spec.add_dependency 'legion-json', '>= 1.2.1'
31
+ spec.add_dependency 'legion-logging', '>= 1.3.2'
32
+ spec.add_dependency 'legion-settings', '>= 1.3.14'
33
+ spec.add_dependency 'legion-transport', '>= 1.3.9'
34
+
27
35
  spec.add_development_dependency 'rspec', '~> 3.13'
28
36
  spec.add_development_dependency 'rubocop', '~> 1.60'
29
37
  spec.add_development_dependency 'rubocop-rspec', '~> 2.26'
@@ -9,7 +9,7 @@ module Legion
9
9
  module Constants
10
10
  MAX_ITEMS = 500
11
11
  MAX_CHUNKS = 200
12
- WORKING_MEMORY_CAPACITY = 7 # Miller's magic number
12
+ WORKING_MEMORY_CAPACITY = 4 # Cowan (2001) core capacity
13
13
  CAPACITY_VARIANCE = 2 # +/- 2
14
14
  DEFAULT_COHERENCE = 0.5
15
15
  COHERENCE_BOOST = 0.08
@@ -42,6 +42,11 @@ module Legion
42
42
  end
43
43
 
44
44
  def disengage_goal(goal_id:, reason:)
45
+ unless Constants::DISENGAGE_REASONS.include?(reason.to_sym)
46
+ raise ArgumentError,
47
+ "invalid reason: #{reason.inspect}, must be one of #{Constants::DISENGAGE_REASONS}"
48
+ end
49
+
45
50
  goal = fetch_goal!(goal_id)
46
51
  goal.disengage!(reason: reason)
47
52
  goal
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Executive
7
7
  module Disengagement
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -32,6 +32,8 @@ module Legion
32
32
  return nil unless conflict
33
33
 
34
34
  strat = strategy.to_sym
35
+ return nil unless STRATEGIES.include?(strat)
36
+
35
37
  @strategy_history[strat] += 1
36
38
  conflict.apply_strategy!(strategy: strat, effectiveness: effectiveness)
37
39
  @strategy_successes[strat] += 1 if conflict.resolved?
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Executive
7
7
  module DissonanceResolution
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -92,6 +92,8 @@ module Legion
92
92
  end
93
93
 
94
94
  def record_outcome(decision_id:, outcome:)
95
+ return { success: false, reason: :invalid_outcome } unless Constants::DECISION_OUTCOMES.include?(outcome)
96
+
95
97
  decision = @decisions.find { |d| d.id == decision_id }
96
98
  return { success: false, reason: :not_found } unless decision
97
99
 
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Executive
7
7
  module DualProcess
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -15,6 +15,8 @@ module Legion
15
15
  end
16
16
 
17
17
  def create_impulse(type:, action:, strength:, source: nil, context: {})
18
+ return nil unless Constants::IMPULSE_TYPES.include?(type.to_sym)
19
+
18
20
  resolved_strength = resolve_strength(strength)
19
21
 
20
22
  impulse = Impulse.new(
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Executive
7
7
  module Inhibition
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Executive
7
- VERSION = '0.1.0'
7
+ VERSION = '0.1.5'
8
8
  end
9
9
  end
10
10
  end
@@ -76,6 +76,38 @@ module Legion
76
76
  { status: result, intention_id: intention_id }
77
77
  end
78
78
 
79
+ def form_absorption_intention(domains_at_risk:, neighboring_agents: [], severity: :warning, **)
80
+ domains = Array(domains_at_risk)
81
+ neighbors = Array(neighboring_agents)
82
+
83
+ return { success: false, reason: :no_domains } if domains.empty?
84
+
85
+ base_salience = severity.to_sym == :critical ? 0.85 : 0.55
86
+ salience = [base_salience + (domains.size * 0.05), 1.0].min
87
+
88
+ intention = Helpers::Intention.new_intention(
89
+ drive: :epistemic,
90
+ domain: :knowledge,
91
+ goal: "absorb knowledge for domains: #{domains.join(', ')}",
92
+ salience: salience,
93
+ context: { domains_at_risk: domains, target_agents: neighbors, severity: severity,
94
+ triggered_by: :knowledge_vulnerability }
95
+ )
96
+
97
+ result = intention_stack.push(intention)
98
+ Legion::Logging.info "[volition] absorption intention formed: domains=#{domains.join(',')} " \
99
+ "neighbors=#{neighbors.size} salience=#{salience.round(2)} result=#{result}"
100
+
101
+ {
102
+ success: %i[pushed duplicate].include?(result),
103
+ result: result,
104
+ intention_id: intention[:intention_id],
105
+ salience: salience,
106
+ domains: domains,
107
+ targets: neighbors
108
+ }
109
+ end
110
+
79
111
  def volition_status(**)
80
112
  stats = intention_stack.stats
81
113
  drives = Helpers::DriveSynthesizer.synthesize(tick_results: {}, cognitive_state: {})
@@ -7,7 +7,7 @@ module Legion
7
7
  module WorkingMemory
8
8
  module Helpers
9
9
  module Constants
10
- CAPACITY = 7
10
+ CAPACITY = 4
11
11
 
12
12
  CHUNK_BONUS = 3
13
13
 
@@ -5,7 +5,7 @@ module Legion
5
5
  module Agentic
6
6
  module Executive
7
7
  module WorkingMemory
8
- VERSION = '0.1.0'
8
+ VERSION = '0.1.1'
9
9
  end
10
10
  end
11
11
  end
@@ -174,7 +174,7 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Chunking::Helpers::Chunki
174
174
  id = engine.add_item(content: 'x')[:item_id]
175
175
  cid = engine.create_chunk(label: 'x', item_ids: [id])[:chunk_id]
176
176
  engine.load_to_working_memory(chunk_id: cid)
177
- expected = (1.0 / 7).round(10)
177
+ expected = (1.0 / 4).round(10)
178
178
  expect(engine.working_memory_load).to be_within(0.0001).of(expected)
179
179
  end
180
180
  end
@@ -10,8 +10,8 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Chunking::Helpers::Consta
10
10
  expect(described_class::MAX_CHUNKS).to eq(200)
11
11
  end
12
12
 
13
- it 'defines WORKING_MEMORY_CAPACITY as 7' do
14
- expect(described_class::WORKING_MEMORY_CAPACITY).to eq(7)
13
+ it 'defines WORKING_MEMORY_CAPACITY as 4' do
14
+ expect(described_class::WORKING_MEMORY_CAPACITY).to eq(4)
15
15
  end
16
16
 
17
17
  it 'defines CAPACITY_VARIANCE as 2' do
@@ -97,7 +97,7 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Chunking::Runners::Cognit
97
97
  it 'returns success with capacity info' do
98
98
  result = client.working_memory_status(engine: engine)
99
99
  expect(result[:success]).to be true
100
- expect(result[:capacity]).to eq(7)
100
+ expect(result[:capacity]).to eq(4)
101
101
  end
102
102
 
103
103
  it 'returns a capacity label' do
@@ -77,6 +77,19 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Disengagement::Helpers::D
77
77
  expect { engine.disengage_goal(goal_id: 'nope', reason: :sunk_cost) }
78
78
  .to raise_error(ArgumentError)
79
79
  end
80
+
81
+ it 'raises ArgumentError for invalid reason' do
82
+ expect { engine.disengage_goal(goal_id: goal.id, reason: :boredom) }
83
+ .to raise_error(ArgumentError, /invalid reason/)
84
+ end
85
+
86
+ it 'accepts all valid DISENGAGE_REASONS' do
87
+ constants = Legion::Extensions::Agentic::Executive::Disengagement::Helpers::Constants
88
+ constants::DISENGAGE_REASONS.each do |reason|
89
+ g = engine.create_goal(label: "goal_#{reason}", domain: :test)
90
+ expect { engine.disengage_goal(goal_id: g.id, reason: reason) }.not_to raise_error
91
+ end
92
+ end
80
93
  end
81
94
 
82
95
  describe '#stalled_goals' do
@@ -29,6 +29,19 @@ RSpec.describe Legion::Extensions::Agentic::Executive::DissonanceResolution::Hel
29
29
  reframe = report.find { |s| s[:strategy] == :reframe }
30
30
  expect(reframe[:uses]).to eq(1)
31
31
  end
32
+
33
+ it 'rejects invalid strategy' do
34
+ expect(engine.apply_strategy(conflict_id: conflict.id, strategy: :magic)).to be_nil
35
+ end
36
+
37
+ it 'accepts all valid STRATEGIES' do
38
+ constants = Legion::Extensions::Agentic::Executive::DissonanceResolution::Helpers::Constants
39
+ constants::STRATEGIES.each do |strat|
40
+ c = engine.create_conflict(belief_a: 'a', belief_b: 'b')
41
+ result = engine.apply_strategy(conflict_id: c.id, strategy: strat)
42
+ expect(result).not_to be_nil
43
+ end
44
+ end
32
45
  end
33
46
 
34
47
  describe '#escalate_conflict' do
@@ -165,6 +165,21 @@ RSpec.describe Legion::Extensions::Agentic::Executive::DualProcess::Helpers::Dua
165
165
  expect(result[:success]).to be false
166
166
  expect(result[:reason]).to eq(:not_found)
167
167
  end
168
+
169
+ it 'rejects invalid outcome' do
170
+ result = engine.record_outcome(decision_id: decision_id, outcome: :maybe)
171
+ expect(result[:success]).to be false
172
+ expect(result[:reason]).to eq(:invalid_outcome)
173
+ end
174
+
175
+ it 'accepts all valid DECISION_OUTCOMES' do
176
+ constants = Legion::Extensions::Agentic::Executive::DualProcess::Helpers::Constants
177
+ constants::DECISION_OUTCOMES.each do |out|
178
+ did = engine.execute_system_one(query: "test_#{out}", domain: :work)[:decision_id]
179
+ result = engine.record_outcome(decision_id: did, outcome: out)
180
+ expect(result[:success]).to be true
181
+ end
182
+ end
168
183
  end
169
184
 
170
185
  describe '#effort_level' do
@@ -55,6 +55,18 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Inhibition::Helpers::Inhi
55
55
  impulse = store.create_impulse(type: :reactive, action: :act, strength: :unknown_level)
56
56
  expect(impulse.strength).to eq(Legion::Extensions::Agentic::Executive::Inhibition::Helpers::Constants::IMPULSE_STRENGTHS[:moderate])
57
57
  end
58
+
59
+ it 'rejects invalid impulse type' do
60
+ expect(store.create_impulse(type: :telepathic, action: :act, strength: :moderate)).to be_nil
61
+ end
62
+
63
+ it 'accepts all valid IMPULSE_TYPES' do
64
+ constants = Legion::Extensions::Agentic::Executive::Inhibition::Helpers::Constants
65
+ constants::IMPULSE_TYPES.each do |itype|
66
+ result = store.create_impulse(type: itype, action: :act, strength: :moderate)
67
+ expect(result).not_to be_nil
68
+ end
69
+ end
58
70
  end
59
71
 
60
72
  describe '#evaluate_and_apply' do
@@ -132,4 +132,59 @@ RSpec.describe Legion::Extensions::Agentic::Executive::Volition::Runners::Voliti
132
132
  expect(result[:count]).to be >= 1
133
133
  end
134
134
  end
135
+
136
+ describe '#form_absorption_intention' do
137
+ it 'returns success false when no domains provided' do
138
+ result = client.form_absorption_intention(domains_at_risk: [])
139
+ expect(result[:success]).to be false
140
+ expect(result[:reason]).to eq(:no_domains)
141
+ end
142
+
143
+ it 'pushes an epistemic absorption intention onto the stack' do
144
+ result = client.form_absorption_intention(
145
+ domains_at_risk: %w[pki dns],
146
+ neighboring_agents: %w[agent-b agent-c]
147
+ )
148
+ expect(result[:success]).to be true
149
+ expect(result[:result]).to eq(:pushed)
150
+ expect(result[:domains]).to eq(%w[pki dns])
151
+ expect(result[:targets]).to eq(%w[agent-b agent-c])
152
+ end
153
+
154
+ it 'returns the intention_id' do
155
+ result = client.form_absorption_intention(domains_at_risk: ['vault'])
156
+ expect(result[:intention_id]).to be_a(String)
157
+ end
158
+
159
+ it 'assigns higher salience for critical severity' do
160
+ warning = client.form_absorption_intention(
161
+ domains_at_risk: ['pki'], severity: :warning
162
+ )
163
+ critical_client = Legion::Extensions::Agentic::Executive::Volition::Client.new
164
+ critical = critical_client.form_absorption_intention(
165
+ domains_at_risk: ['pki'], severity: :critical
166
+ )
167
+ expect(critical[:salience]).to be > warning[:salience]
168
+ end
169
+
170
+ it 'scales salience with number of at-risk domains' do
171
+ few = client.form_absorption_intention(domains_at_risk: ['pki'])
172
+ many_client = Legion::Extensions::Agentic::Executive::Volition::Client.new
173
+ many = many_client.form_absorption_intention(domains_at_risk: %w[pki dns vault ssh consul nomad])
174
+ expect(many[:salience]).to be >= few[:salience]
175
+ end
176
+
177
+ it 'stores knowledge_vulnerability trigger context' do
178
+ result = client.form_absorption_intention(domains_at_risk: ['pki'])
179
+ intention = client.intention_stack.find(result[:intention_id])
180
+ expect(intention[:context][:triggered_by]).to eq(:knowledge_vulnerability)
181
+ end
182
+
183
+ it 'returns :duplicate on second call for same domains (capacity protection)' do
184
+ client.form_absorption_intention(domains_at_risk: ['pki'])
185
+ second = client.form_absorption_intention(domains_at_risk: ['pki'])
186
+ # Either duplicate (same drive/domain/goal match) or pushed — both acceptable
187
+ expect(%i[pushed duplicate]).to include(second[:result])
188
+ end
189
+ end
135
190
  end
@@ -71,10 +71,10 @@ RSpec.describe Legion::Extensions::Agentic::Executive::WorkingMemory::Client do
71
71
  expect(client.working_memory_stats[:size]).to eq(0)
72
72
  end
73
73
 
74
- it 'models the 7 plus-or-minus 2 capacity limit' do
74
+ it 'models the 4 plus-or-minus 2 capacity limit' do
75
75
  # Fill to base capacity
76
- 7.times { |i| client.store_item(content: "item #{i}", priority: :normal) }
77
- expect(client.buffer.size).to eq(7)
76
+ 4.times { |i| client.store_item(content: "item #{i}", priority: :normal) }
77
+ expect(client.buffer.size).to eq(4)
78
78
 
79
79
  # Without chunking, adding more evicts lowest activation
80
80
  3.times { |i| client.store_item(content: "overflow #{i}", priority: :high) }
@@ -4,8 +4,8 @@ require 'spec_helper'
4
4
 
5
5
  RSpec.describe Legion::Extensions::Agentic::Executive::WorkingMemory::Helpers::Constants do
6
6
  describe 'CAPACITY' do
7
- it 'is 7 (Miller\'s Law)' do
8
- expect(described_class::CAPACITY).to eq(7)
7
+ it 'is 4 (Cowan 2001)' do
8
+ expect(described_class::CAPACITY).to eq(4)
9
9
  end
10
10
  end
11
11
 
data/spec/spec_helper.rb CHANGED
@@ -1,41 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
+ require 'legion/logging'
5
+ require 'legion/settings'
6
+ require 'legion/cache/helper'
7
+ require 'legion/crypt/helper'
8
+ require 'legion/data/helper'
9
+ require 'legion/json/helper'
10
+ require 'legion/transport/helper'
4
11
 
5
12
  module Legion
6
- module Logging
7
- def self.debug(_msg); end
8
- def self.info(_msg); end
9
- def self.warn(_msg); end
10
- def self.error(_msg); end
11
- def self.fatal(_msg); end
12
- end
13
-
14
13
  module Extensions
15
- module Core
16
- def self.extended(_base); end
17
- end
18
-
19
14
  module Helpers
20
15
  module Lex
21
- def self.included(_base); end
16
+ include Legion::Logging::Helper
17
+ include Legion::Settings::Helper
18
+ include Legion::Cache::Helper
19
+ include Legion::Crypt::Helper
20
+ include Legion::Data::Helper
21
+ include Legion::JSON::Helper
22
+ include Legion::Transport::Helper
22
23
  end
23
24
  end
24
- end
25
- end
26
25
 
27
- # rubocop:disable Lint/EmptyClass, Style/OneClassPerFile
28
- module Legion
29
- module Extensions
30
26
  module Actors
31
- class Every; end
32
- class Once; end
27
+ class Every
28
+ include Helpers::Lex
29
+ end
30
+
31
+ class Once
32
+ include Helpers::Lex
33
+ end
33
34
  end
34
35
  end
35
36
  end
36
- $LOADED_FEATURES << 'legion/extensions/actors/every'
37
- $LOADED_FEATURES << 'legion/extensions/actors/once'
38
- # rubocop:enable Lint/EmptyClass, Style/OneClassPerFile
39
37
 
40
38
  require 'legion/extensions/agentic/executive'
41
39
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-agentic-executive
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -9,6 +9,104 @@ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: legion-cache
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 1.3.11
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 1.3.11
26
+ - !ruby/object:Gem::Dependency
27
+ name: legion-crypt
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.4.9
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.4.9
40
+ - !ruby/object:Gem::Dependency
41
+ name: legion-data
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.4.17
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 1.4.17
54
+ - !ruby/object:Gem::Dependency
55
+ name: legion-json
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 1.2.1
61
+ type: :runtime
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: 1.2.1
68
+ - !ruby/object:Gem::Dependency
69
+ name: legion-logging
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: 1.3.2
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 1.3.2
82
+ - !ruby/object:Gem::Dependency
83
+ name: legion-settings
84
+ requirement: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.3.14
89
+ type: :runtime
90
+ prerelease: false
91
+ version_requirements: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 1.3.14
96
+ - !ruby/object:Gem::Dependency
97
+ name: legion-transport
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.3.9
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 1.3.9
12
110
  - !ruby/object:Gem::Dependency
13
111
  name: rspec
14
112
  requirement: !ruby/object:Gem::Requirement