lex-prospective-memory 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,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::ProspectiveMemory::Helpers::Intention do
4
+ subject(:intention) do
5
+ described_class.new(
6
+ description: 'send follow-up email',
7
+ trigger_type: :time_based,
8
+ trigger_condition: { at: '2026-04-01T09:00:00Z' },
9
+ urgency: 0.6,
10
+ domain: 'communication'
11
+ )
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'assigns a UUID id' do
16
+ expect(intention.id).to match(/\A[0-9a-f-]{36}\z/)
17
+ end
18
+
19
+ it 'sets status to :pending' do
20
+ expect(intention.status).to eq(:pending)
21
+ end
22
+
23
+ it 'clamps urgency to 0.0-1.0' do
24
+ over = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 1.5)
25
+ expect(over.urgency).to eq(1.0)
26
+ end
27
+
28
+ it 'clamps urgency below 0.0' do
29
+ under = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: -0.3)
30
+ expect(under.urgency).to eq(0.0)
31
+ end
32
+
33
+ it 'defaults urgency to DEFAULT_URGENCY' do
34
+ default_intention = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {})
35
+ expect(default_intention.urgency).to eq(Legion::Extensions::ProspectiveMemory::Helpers::Constants::DEFAULT_URGENCY)
36
+ end
37
+
38
+ it 'sets created_at to a UTC time' do
39
+ expect(intention.created_at).to be_a(Time)
40
+ end
41
+
42
+ it 'leaves triggered_at nil initially' do
43
+ expect(intention.triggered_at).to be_nil
44
+ end
45
+
46
+ it 'leaves executed_at nil initially' do
47
+ expect(intention.executed_at).to be_nil
48
+ end
49
+ end
50
+
51
+ describe '#monitor!' do
52
+ it 'sets status to :monitoring' do
53
+ intention.monitor!
54
+ expect(intention.status).to eq(:monitoring)
55
+ end
56
+ end
57
+
58
+ describe '#trigger!' do
59
+ it 'sets status to :triggered' do
60
+ intention.trigger!
61
+ expect(intention.status).to eq(:triggered)
62
+ end
63
+
64
+ it 'sets triggered_at' do
65
+ intention.trigger!
66
+ expect(intention.triggered_at).to be_a(Time)
67
+ end
68
+ end
69
+
70
+ describe '#execute!' do
71
+ it 'sets status to :executed' do
72
+ intention.execute!
73
+ expect(intention.status).to eq(:executed)
74
+ end
75
+
76
+ it 'sets executed_at' do
77
+ intention.execute!
78
+ expect(intention.executed_at).to be_a(Time)
79
+ end
80
+ end
81
+
82
+ describe '#expire!' do
83
+ it 'sets status to :expired' do
84
+ intention.expire!
85
+ expect(intention.status).to eq(:expired)
86
+ end
87
+ end
88
+
89
+ describe '#cancel!' do
90
+ it 'sets status to :cancelled' do
91
+ intention.cancel!
92
+ expect(intention.status).to eq(:cancelled)
93
+ end
94
+ end
95
+
96
+ describe '#expired?' do
97
+ it 'returns false when expires_at is nil' do
98
+ expect(intention.expired?).to be false
99
+ end
100
+
101
+ it 'returns false when expires_at is in the future' do
102
+ future = described_class.new(
103
+ description: 'x', trigger_type: :time_based, trigger_condition: {},
104
+ expires_at: Time.now.utc + 3600
105
+ )
106
+ expect(future.expired?).to be false
107
+ end
108
+
109
+ it 'returns true when expires_at is in the past' do
110
+ past = described_class.new(
111
+ description: 'x', trigger_type: :time_based, trigger_condition: {},
112
+ expires_at: Time.now.utc - 1
113
+ )
114
+ expect(past.expired?).to be true
115
+ end
116
+ end
117
+
118
+ describe '#boost_urgency!' do
119
+ it 'increases urgency by URGENCY_BOOST by default' do
120
+ original = intention.urgency
121
+ intention.boost_urgency!
122
+ expect(intention.urgency).to eq((original + Legion::Extensions::ProspectiveMemory::Helpers::Constants::URGENCY_BOOST).clamp(0.0, 1.0).round(10))
123
+ end
124
+
125
+ it 'accepts a custom amount' do
126
+ intention.boost_urgency!(amount: 0.2)
127
+ expect(intention.urgency).to be > 0.6
128
+ end
129
+
130
+ it 'does not exceed 1.0' do
131
+ high = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.95)
132
+ high.boost_urgency!(amount: 0.5)
133
+ expect(high.urgency).to eq(1.0)
134
+ end
135
+ end
136
+
137
+ describe '#decay_urgency!' do
138
+ it 'decreases urgency by URGENCY_DECAY' do
139
+ original = intention.urgency
140
+ intention.decay_urgency!
141
+ expect(intention.urgency).to be < original
142
+ end
143
+
144
+ it 'does not go below 0.0' do
145
+ low = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.005)
146
+ low.decay_urgency!
147
+ expect(low.urgency).to eq(0.0)
148
+ end
149
+
150
+ it 'rounds to 10 decimal places' do
151
+ intention.decay_urgency!
152
+ expect(intention.urgency.to_s.split('.').last.length).to be <= 10
153
+ end
154
+ end
155
+
156
+ describe '#urgency_label' do
157
+ it 'returns :critical for urgency >= 0.8' do
158
+ high = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.9)
159
+ expect(high.urgency_label).to eq(:critical)
160
+ end
161
+
162
+ it 'returns :high for urgency in 0.6...0.8' do
163
+ expect(intention.urgency_label).to eq(:high)
164
+ end
165
+
166
+ it 'returns :moderate for urgency in 0.4...0.6' do
167
+ mid = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.5)
168
+ expect(mid.urgency_label).to eq(:moderate)
169
+ end
170
+
171
+ it 'returns :low for urgency in 0.2...0.4' do
172
+ low = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.3)
173
+ expect(low.urgency_label).to eq(:low)
174
+ end
175
+
176
+ it 'returns :deferred for urgency < 0.2' do
177
+ very_low = described_class.new(description: 'x', trigger_type: :time_based, trigger_condition: {}, urgency: 0.1)
178
+ expect(very_low.urgency_label).to eq(:deferred)
179
+ end
180
+ end
181
+
182
+ describe '#to_h' do
183
+ it 'returns a hash with all fields' do
184
+ h = intention.to_h
185
+ expect(h[:id]).to eq(intention.id)
186
+ expect(h[:description]).to eq('send follow-up email')
187
+ expect(h[:trigger_type]).to eq(:time_based)
188
+ expect(h[:status]).to eq(:pending)
189
+ expect(h[:domain]).to eq('communication')
190
+ expect(h[:urgency_label]).to eq(:high)
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,255 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::ProspectiveMemory::Helpers::ProspectiveEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ let(:basic_params) do
7
+ {
8
+ description: 'check in with team',
9
+ trigger_type: :event_based,
10
+ trigger_condition: { event: 'sprint_end' },
11
+ domain: 'work'
12
+ }
13
+ end
14
+
15
+ def make_intention(**overrides)
16
+ engine.create_intention(**basic_params, **overrides)
17
+ end
18
+
19
+ describe '#create_intention' do
20
+ it 'returns an Intention object' do
21
+ expect(make_intention).to be_a(Legion::Extensions::ProspectiveMemory::Helpers::Intention)
22
+ end
23
+
24
+ it 'stores the intention' do
25
+ intention = make_intention
26
+ expect(engine.intentions[intention.id]).to eq(intention)
27
+ end
28
+
29
+ it 'creates intention with :pending status' do
30
+ expect(make_intention.status).to eq(:pending)
31
+ end
32
+
33
+ it 'respects custom urgency' do
34
+ intention = make_intention(urgency: 0.8)
35
+ expect(intention.urgency).to eq(0.8)
36
+ end
37
+
38
+ it 'evicts oldest when at capacity' do
39
+ stub_const('Legion::Extensions::ProspectiveMemory::Helpers::Constants::MAX_INTENTIONS', 2)
40
+ first = make_intention
41
+ _second = make_intention
42
+ _third = make_intention
43
+ expect(engine.intentions.key?(first.id)).to be false
44
+ expect(engine.intentions.size).to eq(2)
45
+ end
46
+ end
47
+
48
+ describe '#monitor_intention' do
49
+ it 'sets status to :monitoring' do
50
+ intention = make_intention
51
+ engine.monitor_intention(intention_id: intention.id)
52
+ expect(intention.status).to eq(:monitoring)
53
+ end
54
+
55
+ it 'returns nil for unknown id' do
56
+ expect(engine.monitor_intention(intention_id: 'nope')).to be_nil
57
+ end
58
+ end
59
+
60
+ describe '#trigger_intention' do
61
+ it 'sets status to :triggered' do
62
+ intention = make_intention
63
+ engine.trigger_intention(intention_id: intention.id)
64
+ expect(intention.status).to eq(:triggered)
65
+ end
66
+
67
+ it 'returns nil for unknown id' do
68
+ expect(engine.trigger_intention(intention_id: 'nope')).to be_nil
69
+ end
70
+ end
71
+
72
+ describe '#execute_intention' do
73
+ it 'sets status to :executed' do
74
+ intention = make_intention
75
+ engine.execute_intention(intention_id: intention.id)
76
+ expect(intention.status).to eq(:executed)
77
+ end
78
+ end
79
+
80
+ describe '#cancel_intention' do
81
+ it 'sets status to :cancelled' do
82
+ intention = make_intention
83
+ engine.cancel_intention(intention_id: intention.id)
84
+ expect(intention.status).to eq(:cancelled)
85
+ end
86
+ end
87
+
88
+ describe '#check_expirations' do
89
+ it 'expires overdue pending intentions' do
90
+ expired_intention = make_intention(expires_at: Time.now.utc - 1)
91
+ engine.check_expirations
92
+ expect(expired_intention.status).to eq(:expired)
93
+ end
94
+
95
+ it 'expires overdue monitoring intentions' do
96
+ intention = make_intention(expires_at: Time.now.utc - 1)
97
+ engine.monitor_intention(intention_id: intention.id)
98
+ engine.check_expirations
99
+ expect(intention.status).to eq(:expired)
100
+ end
101
+
102
+ it 'does not expire future intentions' do
103
+ future = make_intention(expires_at: Time.now.utc + 3600)
104
+ engine.check_expirations
105
+ expect(future.status).to eq(:pending)
106
+ end
107
+
108
+ it 'does not expire already-executed intentions' do
109
+ intention = make_intention(expires_at: Time.now.utc - 1)
110
+ engine.execute_intention(intention_id: intention.id)
111
+ engine.check_expirations
112
+ expect(intention.status).to eq(:executed)
113
+ end
114
+
115
+ it 'returns the count of expired intentions' do
116
+ make_intention(expires_at: Time.now.utc - 1)
117
+ make_intention(expires_at: Time.now.utc - 1)
118
+ make_intention(expires_at: Time.now.utc + 3600)
119
+ expect(engine.check_expirations).to eq(2)
120
+ end
121
+ end
122
+
123
+ describe '#pending_intentions' do
124
+ it 'returns only pending intentions' do
125
+ i1 = make_intention
126
+ i2 = make_intention
127
+ engine.monitor_intention(intention_id: i2.id)
128
+ expect(engine.pending_intentions).to contain_exactly(i1)
129
+ end
130
+ end
131
+
132
+ describe '#monitoring_intentions' do
133
+ it 'returns only monitoring intentions' do
134
+ intention = make_intention
135
+ engine.monitor_intention(intention_id: intention.id)
136
+ expect(engine.monitoring_intentions).to contain_exactly(intention)
137
+ end
138
+ end
139
+
140
+ describe '#triggered_intentions' do
141
+ it 'returns only triggered intentions' do
142
+ intention = make_intention
143
+ engine.trigger_intention(intention_id: intention.id)
144
+ expect(engine.triggered_intentions).to contain_exactly(intention)
145
+ end
146
+ end
147
+
148
+ describe '#by_domain' do
149
+ it 'filters by domain' do
150
+ work_intention = make_intention(domain: 'work')
151
+ make_intention(domain: 'personal')
152
+ results = engine.by_domain(domain: 'work')
153
+ expect(results).to contain_exactly(work_intention)
154
+ end
155
+ end
156
+
157
+ describe '#by_urgency' do
158
+ it 'returns intentions at or above min_urgency' do
159
+ high = make_intention(urgency: 0.8)
160
+ _low = make_intention(urgency: 0.3)
161
+ result = engine.by_urgency(min_urgency: 0.5)
162
+ expect(result).to contain_exactly(high)
163
+ end
164
+ end
165
+
166
+ describe '#most_urgent' do
167
+ it 'returns intentions sorted by descending urgency' do
168
+ i1 = make_intention(urgency: 0.9)
169
+ i2 = make_intention(urgency: 0.4)
170
+ i3 = make_intention(urgency: 0.7)
171
+ result = engine.most_urgent(limit: 3)
172
+ expect(result).to eq([i1, i3, i2])
173
+ end
174
+
175
+ it 'excludes executed/expired/cancelled intentions' do
176
+ executed = make_intention(urgency: 0.9)
177
+ active = make_intention(urgency: 0.5)
178
+ engine.execute_intention(intention_id: executed.id)
179
+ result = engine.most_urgent(limit: 5)
180
+ expect(result).to contain_exactly(active)
181
+ end
182
+
183
+ it 'respects the limit parameter' do
184
+ 5.times { make_intention }
185
+ expect(engine.most_urgent(limit: 3).size).to eq(3)
186
+ end
187
+ end
188
+
189
+ describe '#decay_all_urgency' do
190
+ it 'decreases urgency of pending intentions' do
191
+ intention = make_intention(urgency: 0.5)
192
+ engine.decay_all_urgency
193
+ expect(intention.urgency).to be < 0.5
194
+ end
195
+
196
+ it 'decreases urgency of monitoring intentions' do
197
+ intention = make_intention(urgency: 0.5)
198
+ engine.monitor_intention(intention_id: intention.id)
199
+ engine.decay_all_urgency
200
+ expect(intention.urgency).to be < 0.5
201
+ end
202
+
203
+ it 'does not decay executed intentions' do
204
+ intention = make_intention(urgency: 0.5)
205
+ engine.execute_intention(intention_id: intention.id)
206
+ engine.decay_all_urgency
207
+ expect(intention.urgency).to eq(0.5)
208
+ end
209
+ end
210
+
211
+ describe '#execution_rate' do
212
+ it 'returns 0.0 with no terminal intentions' do
213
+ make_intention
214
+ expect(engine.execution_rate).to eq(0.0)
215
+ end
216
+
217
+ it 'computes fraction of executed vs total terminal' do
218
+ i1 = make_intention
219
+ i2 = make_intention
220
+ i3 = make_intention
221
+ engine.execute_intention(intention_id: i1.id)
222
+ engine.execute_intention(intention_id: i2.id)
223
+ engine.cancel_intention(intention_id: i3.id)
224
+ expect(engine.execution_rate).to be_within(0.001).of(2.0 / 3.0)
225
+ end
226
+ end
227
+
228
+ describe '#intention_report' do
229
+ it 'returns a hash with total, by_status, execution_rate, most_urgent' do
230
+ make_intention
231
+ report = engine.intention_report
232
+ expect(report[:total]).to eq(1)
233
+ expect(report[:by_status]).to be_a(Hash)
234
+ expect(report[:execution_rate]).to be_a(Float)
235
+ expect(report[:most_urgent]).to be_an(Array)
236
+ end
237
+
238
+ it 'includes all status types in by_status' do
239
+ report = engine.intention_report
240
+ Legion::Extensions::ProspectiveMemory::Helpers::Constants::STATUS_TYPES.each do |status|
241
+ expect(report[:by_status]).to have_key(status)
242
+ end
243
+ end
244
+ end
245
+
246
+ describe '#to_h' do
247
+ it 'serializes the engine state' do
248
+ make_intention
249
+ h = engine.to_h
250
+ expect(h[:intention_count]).to eq(1)
251
+ expect(h[:intentions]).to be_a(Hash)
252
+ expect(h[:execution_rate]).to be_a(Float)
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/prospective_memory/client'
4
+
5
+ RSpec.describe Legion::Extensions::ProspectiveMemory::Runners::ProspectiveMemory do
6
+ let(:client) { Legion::Extensions::ProspectiveMemory::Client.new }
7
+
8
+ let(:base_params) do
9
+ {
10
+ description: 'review open pull requests',
11
+ trigger_type: :activity_based,
12
+ trigger_condition: { activity: 'commit_pushed' }
13
+ }
14
+ end
15
+
16
+ def create(**overrides)
17
+ client.create_intention(**base_params, **overrides)
18
+ end
19
+
20
+ describe '#create_intention' do
21
+ it 'creates an intention and returns a hash with :created true' do
22
+ result = create
23
+ expect(result[:created]).to be true
24
+ expect(result[:intention]).to be_a(Hash)
25
+ expect(result[:intention][:id]).to match(/\A[0-9a-f-]{36}\z/)
26
+ end
27
+
28
+ it 'rejects invalid trigger_type' do
29
+ result = create(trigger_type: :bogus)
30
+ expect(result[:error]).to eq(:invalid_trigger_type)
31
+ expect(result[:valid_types]).to include(:time_based)
32
+ end
33
+
34
+ it 'stores urgency on the intention' do
35
+ result = create(urgency: 0.75)
36
+ expect(result[:intention][:urgency]).to eq(0.75)
37
+ end
38
+
39
+ it 'stores domain on the intention' do
40
+ result = create(domain: 'engineering')
41
+ expect(result[:intention][:domain]).to eq('engineering')
42
+ end
43
+
44
+ it 'sets status to :pending' do
45
+ result = create
46
+ expect(result[:intention][:status]).to eq(:pending)
47
+ end
48
+ end
49
+
50
+ describe '#monitor_intention' do
51
+ it 'transitions status to :monitoring' do
52
+ created = create
53
+ result = client.monitor_intention(intention_id: created[:intention][:id])
54
+ expect(result[:updated]).to be true
55
+ expect(result[:intention][:status]).to eq(:monitoring)
56
+ end
57
+
58
+ it 'returns not_found for unknown id' do
59
+ result = client.monitor_intention(intention_id: 'nonexistent')
60
+ expect(result[:updated]).to be false
61
+ expect(result[:reason]).to eq(:not_found)
62
+ end
63
+ end
64
+
65
+ describe '#trigger_intention' do
66
+ it 'transitions status to :triggered' do
67
+ created = create
68
+ result = client.trigger_intention(intention_id: created[:intention][:id])
69
+ expect(result[:updated]).to be true
70
+ expect(result[:intention][:status]).to eq(:triggered)
71
+ end
72
+
73
+ it 'records triggered_at timestamp' do
74
+ created = create
75
+ result = client.trigger_intention(intention_id: created[:intention][:id])
76
+ expect(result[:intention][:triggered_at]).not_to be_nil
77
+ end
78
+ end
79
+
80
+ describe '#execute_intention' do
81
+ it 'transitions status to :executed' do
82
+ created = create
83
+ result = client.execute_intention(intention_id: created[:intention][:id])
84
+ expect(result[:updated]).to be true
85
+ expect(result[:intention][:status]).to eq(:executed)
86
+ end
87
+
88
+ it 'records executed_at timestamp' do
89
+ created = create
90
+ result = client.execute_intention(intention_id: created[:intention][:id])
91
+ expect(result[:intention][:executed_at]).not_to be_nil
92
+ end
93
+
94
+ it 'returns not_found for unknown id' do
95
+ result = client.execute_intention(intention_id: 'nope')
96
+ expect(result[:updated]).to be false
97
+ end
98
+ end
99
+
100
+ describe '#cancel_intention' do
101
+ it 'transitions status to :cancelled' do
102
+ created = create
103
+ result = client.cancel_intention(intention_id: created[:intention][:id])
104
+ expect(result[:updated]).to be true
105
+ expect(result[:intention][:status]).to eq(:cancelled)
106
+ end
107
+ end
108
+
109
+ describe '#check_expirations' do
110
+ it 'returns expired_count' do
111
+ client.create_intention(
112
+ description: 'expired',
113
+ trigger_type: :time_based,
114
+ trigger_condition: {},
115
+ expires_at: Time.now.utc - 1
116
+ )
117
+ result = client.check_expirations
118
+ expect(result[:expired_count]).to eq(1)
119
+ end
120
+ end
121
+
122
+ describe '#pending_intentions' do
123
+ it 'lists pending intentions with count' do
124
+ create
125
+ create
126
+ result = client.pending_intentions
127
+ expect(result[:count]).to eq(2)
128
+ expect(result[:intentions]).to all(include(status: :pending))
129
+ end
130
+ end
131
+
132
+ describe '#monitoring_intentions' do
133
+ it 'lists monitoring intentions' do
134
+ created = create
135
+ client.monitor_intention(intention_id: created[:intention][:id])
136
+ result = client.monitoring_intentions
137
+ expect(result[:count]).to eq(1)
138
+ expect(result[:intentions].first[:status]).to eq(:monitoring)
139
+ end
140
+ end
141
+
142
+ describe '#triggered_intentions' do
143
+ it 'lists triggered intentions' do
144
+ created = create
145
+ client.trigger_intention(intention_id: created[:intention][:id])
146
+ result = client.triggered_intentions
147
+ expect(result[:count]).to eq(1)
148
+ end
149
+ end
150
+
151
+ describe '#intentions_by_domain' do
152
+ it 'filters by domain' do
153
+ create(domain: 'ops')
154
+ create(domain: 'dev')
155
+ result = client.intentions_by_domain(domain: 'ops')
156
+ expect(result[:count]).to eq(1)
157
+ expect(result[:domain]).to eq('ops')
158
+ end
159
+ end
160
+
161
+ describe '#intentions_by_urgency' do
162
+ it 'filters by min_urgency' do
163
+ create(urgency: 0.9)
164
+ create(urgency: 0.2)
165
+ result = client.intentions_by_urgency(min_urgency: 0.5)
166
+ expect(result[:count]).to eq(1)
167
+ end
168
+ end
169
+
170
+ describe '#most_urgent_intentions' do
171
+ it 'returns sorted by descending urgency' do
172
+ create(urgency: 0.3)
173
+ create(urgency: 0.8)
174
+ result = client.most_urgent_intentions(limit: 5)
175
+ urgencies = result[:intentions].map { |i| i[:urgency] }
176
+ expect(urgencies).to eq(urgencies.sort.reverse)
177
+ end
178
+
179
+ it 'respects the limit' do
180
+ 3.times { create }
181
+ result = client.most_urgent_intentions(limit: 2)
182
+ expect(result[:count]).to eq(2)
183
+ end
184
+ end
185
+
186
+ describe '#decay_urgency' do
187
+ it 'returns decayed: true' do
188
+ create
189
+ result = client.decay_urgency
190
+ expect(result[:decayed]).to be true
191
+ end
192
+ end
193
+
194
+ describe '#execution_rate' do
195
+ it 'returns a float execution_rate' do
196
+ result = client.execution_rate
197
+ expect(result[:execution_rate]).to be_a(Float)
198
+ end
199
+
200
+ it 'computes rate after executions' do
201
+ c1 = create
202
+ c2 = create
203
+ client.execute_intention(intention_id: c1[:intention][:id])
204
+ client.cancel_intention(intention_id: c2[:intention][:id])
205
+ result = client.execution_rate
206
+ expect(result[:execution_rate]).to be_within(0.001).of(0.5)
207
+ end
208
+ end
209
+
210
+ describe '#intention_report' do
211
+ it 'returns total, by_status, execution_rate, most_urgent' do
212
+ create
213
+ report = client.intention_report
214
+ expect(report[:total]).to be >= 1
215
+ expect(report[:by_status]).to be_a(Hash)
216
+ expect(report[:execution_rate]).to be_a(Float)
217
+ expect(report[:most_urgent]).to be_an(Array)
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+
5
+ 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
+ end
12
+ end
13
+
14
+ require 'legion/extensions/prospective_memory'
15
+
16
+ RSpec.configure do |config|
17
+ config.example_status_persistence_file_path = '.rspec_status'
18
+ config.disable_monkey_patching!
19
+ config.expect_with(:rspec) { |c| c.syntax = :expect }
20
+ end